diff --git a/.gitignore b/.gitignore index eccd7b4a..a2f4b3c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target/ **/*.rs.bk +*.swp diff --git a/Cargo.toml b/Cargo.toml index 26c64252..b9b6624b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ llvm-tools = "0.1" [features] default = [] vga_320x200 = [] +vesa_800x600 = [] recursive_page_table = [] map_physical_memory = [] diff --git a/src/main.rs b/src/main.rs index 9d050c46..4687af3e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,9 +31,11 @@ global_asm!(include_str!("stage_2.s")); global_asm!(include_str!("e820.s")); global_asm!(include_str!("stage_3.s")); +#[cfg(feature = "vesa_800x600")] +global_asm!(include_str!("video_mode/vesa_800x600.s")); #[cfg(feature = "vga_320x200")] global_asm!(include_str!("video_mode/vga_320x200.s")); -#[cfg(not(feature = "vga_320x200"))] +#[cfg(not(any(feature = "vesa_800x600", feature = "vga_320x200")))] global_asm!(include_str!("video_mode/vga_text_80x25.s")); unsafe fn context_switch(boot_info: VirtAddr, entry_point: VirtAddr, stack_pointer: VirtAddr) -> ! { @@ -91,6 +93,7 @@ pub unsafe extern "C" fn stage_4() -> ! { let bootloader_start = &__bootloader_start as *const _ as u64; let bootloader_end = &__bootloader_end as *const _ as u64; + load_elf( IdentityMappedAddr(PhysAddr::new(kernel_start)), kernel_size, @@ -290,6 +293,8 @@ fn load_elf( let entry_point = VirtAddr::new(entry_point); + panic!("Test"); + unsafe { context_switch(boot_info_addr, entry_point, stack_end) }; } diff --git a/src/printer/mod.rs b/src/printer/mod.rs index b4ecd7b3..fe2f45ac 100644 --- a/src/printer/mod.rs +++ b/src/printer/mod.rs @@ -1,8 +1,12 @@ -#[cfg(not(feature = "vga_320x200"))] -pub use self::vga_text_80x25::*; - #[cfg(feature = "vga_320x200")] pub use self::vga_320x200::*; -mod vga_320x200; +#[cfg(feature = "vesa_800x600")] +pub use self::vesa_800x600::*; + +#[cfg(not(any(feature = "vesa_800x600", feature = "vga_320x200")))] +pub use self::vga_text_80x25::*; + mod vga_text_80x25; +mod vga_320x200; +mod vesa_800x600; diff --git a/src/printer/vesa_800x600.rs b/src/printer/vesa_800x600.rs new file mode 100644 index 00000000..10bdb22f --- /dev/null +++ b/src/printer/vesa_800x600.rs @@ -0,0 +1,81 @@ +use core::fmt::{Result, Write}; +use core::slice; +use core::sync::atomic::{AtomicUsize, Ordering}; + +const VGA_BUFFER: *mut u16 = (500 * 512 * 4096) as *mut _; +const SCREEN_WIDTH: usize = 800; +const SCREEN_HEIGHT: usize = 600; + +pub static X_POS: AtomicUsize = AtomicUsize::new(1); // must not be 0 so that we don't have a .bss section +pub static Y_POS: AtomicUsize = AtomicUsize::new(1); // must not be 0 so that we don't have a .bss section + +pub struct Printer; + +impl Printer { + pub fn clear_screen(&mut self) { + let vga_buffer = Self::vga_buffer(); + for pixel in vga_buffer { + *pixel = 0x66; + } + X_POS.store(0, Ordering::SeqCst); + Y_POS.store(0, Ordering::SeqCst); + } + + fn vga_buffer() -> &'static mut [u16] { + unsafe { slice::from_raw_parts_mut(VGA_BUFFER, SCREEN_WIDTH * SCREEN_HEIGHT) } + } + + fn newline(&mut self) { + let y_pos = Y_POS.fetch_add(8, Ordering::SeqCst); + X_POS.store(0, Ordering::SeqCst); + if y_pos >= SCREEN_HEIGHT { + self.clear_screen(); + } + } + + fn write_char(&mut self, c: char) { + use font8x8::UnicodeFonts; + + if c == '\n' { + self.newline(); + return; + } + + let vga_buffer = Self::vga_buffer(); + + let x_pos = X_POS.fetch_add(8, Ordering::SeqCst); + let y_pos = Y_POS.load(Ordering::SeqCst); + + match c { + ' '..='~' => { + let rendered = font8x8::BASIC_FONTS + .get(c) + .expect("character not found in basic font"); + for (y, byte) in rendered.iter().enumerate() { + for (x, bit) in (0..8).enumerate() { + if *byte & (1 << bit) == 0 { + continue; + } + let color = 0xff; + vga_buffer[(y_pos + y) * SCREEN_WIDTH + x_pos + x] = color; + } + } + } + _ => panic!("unprintable character"), + } + + if x_pos + 8 >= SCREEN_WIDTH { + self.newline(); + } + } +} + +impl Write for Printer { + fn write_str(&mut self, s: &str) -> Result { + for c in s.chars() { + self.write_char(c); + } + + Ok(()) + } +} diff --git a/src/stage_1.s b/src/stage_1.s index ebfa1a08..8296fb1c 100644 --- a/src/stage_1.s +++ b/src/stage_1.s @@ -35,7 +35,6 @@ enable_a20: out 0x92, al enable_a20_after: - enter_protected_mode: # clear interrupts cli diff --git a/src/video_mode/vesa_800x600.s b/src/video_mode/vesa_800x600.s new file mode 100644 index 00000000..1a7e2fb8 --- /dev/null +++ b/src/video_mode/vesa_800x600.s @@ -0,0 +1,60 @@ +.section .boot, "awx" +.intel_syntax noprefix +.code16 + +# This code is responsible for enabling VESA graphics while in +# real mode. +config_video_mode: + # Try VESA + mov ax, 0x9000 + mov es, ax + mov di, 0 + mov ax, 0x4f00 + int 0x10 + cmp ax, 0x004f + jne vesa_out + # Check VESA version 2 or 3 + mov ax, es:[di+4] + cmp ax, 0x0300 + je init_vesa + cmp ax, 0x0200 + jne vesa_out + # Hard coded 800x600x16bit mode; this gets us the PHY-addr of the FB +init_vesa: + mov ax, 0x4f01 + mov cx, 0x114 + mov di, VESAInfo + int 0x10 + mov VESAfb, [es:di+0x28] + + mov ax, 0x4f02 + mov bx, 0x4114 + int 0x10 + +vesa_out: + ret + +vga_println: + ret + +.code32 + +vga_map_frame_buffer: + mov eax, 0xFD000000 + or eax, (1 | 2 | (1 << 7)) + mov ecx, 500 +vga_map_frame_buffer_loop: + mov [_p2 + ecx * 8], eax + + add eax, 4096 * 512 + add ecx, 1 + cmp eax, 0xFD000000 + 800 * 600 + jl vga_map_frame_buffer_loop + + ret + +VESAfb: + .word 0 + +VESAInfo: + .space 256, 0