Skip to content
Snippets Groups Projects
Commit ef189114 authored by Eemeli Lehtonen's avatar Eemeli Lehtonen
Browse files

vga println

parent f6ad75b6
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,47 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "hyperion"
version = "0.1.0"
dependencies = [
"spin",
"volatile",
]
[[package]]
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "spin"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
dependencies = [
"lock_api",
]
[[package]]
name = "volatile"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ca98349dda8a60ae74e04fd90c7fb4d6a4fbe01e6d3be095478aa0b76f6c0c"
......@@ -9,3 +9,6 @@ edition = "2021"
crate-type = ["staticlib"]
[dependencies]
spin = "0.9.4"
volatile = "0.4.5"
#tracing = { version = "0.1.37", default-features = false }
......@@ -57,17 +57,17 @@ start:
error:
;; print 'ERR: <err>'
mov dword [0xb8000], 0x4f524f45
mov dword [0xb8004], 0x4f3a4f52
mov dword [0xb8008], 0x4f204f20
mov dword [0xb8000], 0x4F524F45
mov dword [0xb8004], 0x4F3A4F52
mov dword [0xb8008], 0x4F204F20
mov byte [0xb800a], al
jmp halt
halt:
;; print ZZZ
mov word [0xb8f00], 0x0f5a
mov word [0xb8f02], 0x0f5a
mov word [0xb8f04], 0x0f5a
mov word [0xb8f00], 0x0F5A
mov word [0xb8f02], 0x0F5A
mov word [0xb8f04], 0x0F5A
hlt
jmp halt
......@@ -199,8 +199,9 @@ long_mode_start:
mov gs, ax
; print 'OK'
mov dword [0xb8000], 0x2f4b2f4f
mov dword [0xb8000], 0x2F4B2F4F
mov rdi, 42
call kernel_main
.halt:
hlt
......
#![no_std]
#![no_main]
pub mod vga;
#[panic_handler]
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
loop {}
......@@ -8,10 +10,10 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! {
#[no_mangle]
#[link_section = ".boot"]
pub extern "C" fn kernel_main() -> ! {
unsafe {
*(0xB8000 as *mut u32) = 0x4f524f45;
}
pub extern "C" fn kernel_main(magic_num: u64) -> ! {
// null byte clears the VGA buffer
print!("\0");
println!("Hello from Hyperion, magic_num = {magic_num}");
loop {
unsafe {
......
use core::{
fmt::{Arguments, Write},
ops::{Deref, DerefMut},
};
use spin::{Mutex, MutexGuard};
use volatile::Volatile;
//
#[macro_export]
macro_rules! println {
() => {
println!("");
};
($($arg:tt)*) => {
$crate::vga::_println(format_args!($($arg)*))
}
}
#[macro_export]
macro_rules! print {
() => {
print!("");
};
($($arg:tt)*) => {
$crate::vga::_print(format_args!($($arg)*))
};
}
//
pub struct Writer {
cursor: [usize; 2],
color: ColorCode,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(C)]
pub enum Color {
#[default]
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGrey = 7,
DarkGrey = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
Pink = 13,
Yellow = 14,
White = 15,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct ColorCode(u8);
//
impl Writer {
pub fn lock() -> MutexGuard<'static, Self> {
WRITER.lock()
}
pub fn write_str(&mut self, s: &str) {
for byte in s.bytes() {
self.write_byte(byte);
}
}
pub fn write_char(&mut self, c: char) {
self.write_str(c.encode_utf8(&mut [0; 4]))
}
pub fn write_byte(&mut self, byte: u8) {
match byte {
// 'special' ascii chars
b'\r' => self.cursor[0] = 0,
b'\n' => self.new_line(),
b'\0' => self.clear(),
// 'normal' ascii chars
byte => {
// line wrapping
if self.cursor[0] >= WIDTH {
self.new_line();
}
// insert the byte
self.set_char(
self.cursor,
Char {
byte,
color: self.color,
},
);
// move the cursor
self.cursor[0] += 1;
}
}
}
pub fn clear(&mut self) {
self.cursor = [0, 0];
for row in 0..HEIGHT {
self.clear_row(row);
}
}
/// SAFETY: Only one [`Writer`] should ever exist
const unsafe fn new() -> Self {
Self {
cursor: [0, 0],
color: ColorCode::new(Color::White, Color::Black),
}
}
fn buffer(&self) -> &'static [[Volatile<Char>; WIDTH]; HEIGHT] {
// SAFETY: Only one [`Writer`] should ever exist
// then multiple immutable refs are allowed
unsafe { &*(0xB8000 as *const _) }
}
fn buffer_mut(&mut self) -> &'static mut [[Volatile<Char>; WIDTH]; HEIGHT] {
// SAFETY: Only one [`Writer`] should ever exist
// then one mutable ref is allowed
unsafe { &mut *(0xB8000 as *mut _) }
}
fn new_line(&mut self) {
if self.cursor[1] + 1 >= HEIGHT {
// move all rows upwards
for row in 0..HEIGHT - 1 {
for col in 0..WIDTH {
self.set_char([col, row], self.get_char([col, row + 1]));
}
}
} else {
// next row
self.cursor[1] += 1;
}
self.clear_row(HEIGHT - 1);
self.cursor[0] = 0;
}
fn clear_row(&mut self, row: usize) {
self.fill_row(
row,
Char {
byte: b' ',
color: ColorCode::default(),
},
)
}
fn fill_row(&mut self, row: usize, fill: Char) {
for col in 0..WIDTH {
self.set_char([col, row], fill);
}
}
fn get_char(&self, cursor: [usize; 2]) -> Char {
self.buffer()[cursor[1]][cursor[0]].read()
}
fn set_char(&mut self, cursor: [usize; 2], ch: Char) {
self.buffer_mut()[cursor[1]][cursor[0]].write(ch);
}
}
impl ColorCode {
pub const fn new(fg: Color, bg: Color) -> ColorCode {
ColorCode((bg as u8) << 4 | (fg as u8))
}
}
impl Default for ColorCode {
fn default() -> Self {
Self::new(Color::White, Color::Black)
}
}
//
const WIDTH: usize = 80;
const HEIGHT: usize = 25;
//
/// SAFETY: safe, because this is the only Writer
static WRITER: Mutex<Writer> = Mutex::new(unsafe { Writer::new() });
//
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct Char {
// ascii
byte: u8,
// foreground and background
color: ColorCode,
}
//
impl Write for Writer {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.write_str(s);
Ok(())
}
}
impl Deref for Char {
type Target = Self;
fn deref(&self) -> &Self::Target {
self
}
}
impl DerefMut for Char {
fn deref_mut(&mut self) -> &mut Self::Target {
self
}
}
//
#[doc(hidden)]
pub fn _print(args: Arguments) {
let mut writer = WRITER.lock();
writer.write_fmt(args).unwrap();
}
#[doc(hidden)]
pub fn _println(args: Arguments) {
let mut writer = WRITER.lock();
writer.write_fmt(args).unwrap();
writer.write_byte(b'\n');
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment