diff --git a/boot1/asm/prelude.s b/boot1/asm/prelude.s index b1c10da..4b906ec 100644 --- a/boot1/asm/prelude.s +++ b/boot1/asm/prelude.s @@ -338,6 +338,11 @@ prelude_main: mov ax, 0x0003 int 0x10 + ; Disable cursor + mov ax, 0x0100 + mov cx, 0x3f00 + int 0x10 + ; Ensure interrupts are definitely disabled. cli diff --git a/boot1/src/main.rs b/boot1/src/main.rs index 391da11..57b8b2c 100644 --- a/boot1/src/main.rs +++ b/boot1/src/main.rs @@ -1,14 +1,11 @@ #![no_std] #![no_main] -use core::{arch::asm, panic::PanicInfo}; +mod vga; -const VGA_WIDTH: usize = 80; -const VGA_HEIGHT: usize = 25; -const VGA_SIZE: usize = VGA_WIDTH * VGA_HEIGHT; -const VGA_ADDR: usize = 0xb8000; +use core::{arch::asm, panic::PanicInfo, fmt::Write}; -const STR: &[u8] = b"sphinx of black quartz, judge my vow"; +use vga::VgaBuf; #[repr(C)] #[derive(Clone, Debug)] @@ -35,11 +32,9 @@ fn panic(_info: &PanicInfo) -> ! { #[no_mangle] pub extern "C" fn _start() -> ! { - let vga_buf: &'static mut [u16; VGA_SIZE] = unsafe { &mut *(VGA_ADDR as *mut [u16; VGA_SIZE]) }; + let mut vga_buf = unsafe { VgaBuf::new(0xb8000 as *mut u16) }; - for (i, b) in STR.iter().copied().enumerate() { - vga_buf[i] = 0x1f00 | u16::from(b); - } + writeln!(&mut vga_buf, "hello from rust").ok(); let mut args = BiosIntr { eax: 0xe820, @@ -57,9 +52,7 @@ pub extern "C" fn _start() -> ! { _bios_call(0x15, &raw mut args); } - for (i, b) in STR.iter().copied().enumerate() { - vga_buf[i + VGA_WIDTH] = 0x1f00 | u16::from(b); - } + writeln!(&mut vga_buf, "eax = {:x}", args.eax).ok(); hlt() } diff --git a/boot1/src/vga.rs b/boot1/src/vga.rs new file mode 100644 index 0000000..cdd0125 --- /dev/null +++ b/boot1/src/vga.rs @@ -0,0 +1,84 @@ +use core::{fmt, ptr}; + +const VGA_WIDTH: usize = 80; +const VGA_HEIGHT: usize = 25; + +const COLOUR_MASK: u16 = 0x0a00; + +pub struct VgaBuf { + buf: *mut u16, + col: usize, + row: usize, +} + +impl VgaBuf { + pub unsafe fn new(buf: *mut u16) -> Self { + Self { buf, col: 0, row: 0 } + } + + pub fn vga_write_str(&mut self, s: &str) { + for c in s.chars() { + self.vga_write_char(c); + } + } + + pub fn vga_write_char(&mut self, c: char) { + let newline = c == '\n'; + + if newline || self.col >= VGA_WIDTH { + self.col = 0; + self.row += 1; + } + + if self.row >= VGA_HEIGHT { + self.scroll(); + self.row -= 1; + } + + if !newline { + self.vga_write_char_at(c, self.col, self.row); + self.col += 1; + } + } + + pub fn vga_write_ascii_char_at(&mut self, c: u8, col: usize, row: usize) { + let vga_val = COLOUR_MASK | u16::from(c); + + if col < VGA_WIDTH && row < VGA_HEIGHT { + unsafe { + self.coord_ptr(col, row) + .write_volatile(vga_val); + } + } + } + + pub fn vga_write_char_at(&mut self, c: char, col: usize, row: usize) { + let c = u8::try_from(c).unwrap_or(0xfe); + self.vga_write_ascii_char_at(c, col, row); + } + + fn scroll(&mut self) { + unsafe { + ptr::copy( + self.coord_ptr(0, 1), + self.coord_ptr(0, 0), + VGA_WIDTH * (VGA_HEIGHT - 1) + ); + + for col in 0..VGA_WIDTH { + self.vga_write_ascii_char_at(0, col, VGA_HEIGHT - 1); + } + } + } + + unsafe fn coord_ptr(&self, col: usize, row: usize) -> *mut u16 { + unsafe { self.buf.add((row * VGA_WIDTH) + col) } + } +} + +impl fmt::Write for VgaBuf { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.vga_write_str(s); + Ok(()) + } +}