From 4c4fe4b4904a83047b43d41b85a2c418bdeac782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Thu, 6 Jun 2024 17:15:47 +0200 Subject: [PATCH] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Kröning --- Cargo.lock | 68 +++++++++++++++ Cargo.toml | 5 +- src/arch/x86_64/kernel/mod.rs | 9 +- src/arch/x86_64/kernel/vga.rs | 158 ++++++++-------------------------- xtask/src/ci/qemu.rs | 4 +- 5 files changed, 115 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 099d5c16aa..93203f30fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -630,6 +630,7 @@ dependencies = [ "tock-registers 0.9.0", "trapframe", "uart_16550", + "vga-text-mode", "virtio-spec", "volatile 0.6.1", "x86", @@ -714,6 +715,12 @@ dependencies = [ "nix", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" version = "0.3.69" @@ -916,6 +923,16 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "oem_cp" +version = "2.0.0" +dependencies = [ + "phf", + "phf_codegen", + "serde", + "serde_json", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -1186,6 +1203,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "sbi-rt" version = "0.0.3" @@ -1233,6 +1256,37 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7f8592b424e48e4d0d59faf9fb126077542b3f5ceb0fa6468229619d98743df" +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "shell-words" version = "1.1.0" @@ -1505,12 +1559,26 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vga-text-mode" +version = "0.1.0" +dependencies = [ + "oem_cp", + "vcell", +] + [[package]] name = "virtio-spec" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index dacad51b40..5436d7037b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ name = "measure_startup_time" harness = false [features] -default = ["pci", "pci-ids", "acpi", "fsgsbase", "smp", "tcp", "dhcpv4", "fuse"] +default = ["pci", "pci-ids", "acpi", "fsgsbase", "smp", "tcp", "dhcpv4", "fuse", "vga"] acpi = [] dhcpv4 = [ "smoltcp", @@ -64,7 +64,7 @@ tcp = ["smoltcp", "smoltcp/socket-tcp"] udp = ["smoltcp", "smoltcp/socket-udp"] dns = ["smoltcp", "smoltcp/socket-dns"] trace = [] -vga = [] +vga = ["vga-text-mode"] common-os = [] nostd = [] semihosting = ["dep:semihosting"] @@ -133,6 +133,7 @@ features = [ free-list = { version = "0.3", features = ["x86_64"] } multiboot = "0.8" uart_16550 = "0.3" +vga-text-mode = { path = "../../vga-text-mode", optional = true } x86 = { version = "0.52", default-features = false } x86_64 = "0.15" diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index aef2bc5768..dfa6b14aab 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -140,13 +140,14 @@ pub fn message_output_init() { pub fn output_message_buf(buf: &[u8]) { // Output messages to the serial port and VGA screen in unikernel mode. + +use alloc::string::String; COM1.lock().as_mut().unwrap().send(buf); #[cfg(feature = "vga")] - for &byte in buf { - // vga::write_byte() checks if VGA support has been initialized, - // so we don't need any additional if clause around it. - vga::write_byte(byte); + { + let s = String::from_utf8_lossy(buf); + vga::print(&s); } } diff --git a/src/arch/x86_64/kernel/vga.rs b/src/arch/x86_64/kernel/vga.rs index 422e91ce9f..eec8cc374e 100644 --- a/src/arch/x86_64/kernel/vga.rs +++ b/src/arch/x86_64/kernel/vga.rs @@ -1,134 +1,50 @@ -use x86::io::*; +use core::alloc::Layout; + +use core::fmt::Write; +use hermit_sync::{InterruptOnceCell, InterruptSpinMutex}; +use vga_text_mode::{ VgaScreen, FrontBuffer, text_buffer::TextBuffer}; +use x86_64::instructions::port::Port; use crate::arch::x86_64::mm::paging::{BasePageSize, PageTableEntryFlags, PageTableEntryFlagsExt}; use crate::arch::x86_64::mm::{paging, PhysAddr, VirtAddr}; -const CRT_CONTROLLER_ADDRESS_PORT: u16 = 0x3D4; -const CRT_CONTROLLER_DATA_PORT: u16 = 0x3D5; -const CURSOR_START_REGISTER: u8 = 0x0A; -const CURSOR_DISABLE: u8 = 0x20; - -const ATTRIBUTE_BLACK: u8 = 0x00; -const ATTRIBUTE_LIGHTGREY: u8 = 0x07; -const COLS: usize = 80; -const ROWS: usize = 25; -const VGA_BUFFER_ADDRESS: u64 = 0xB8000; - -static mut VGA_SCREEN: VgaScreen = VgaScreen::new(); - -#[derive(Clone, Copy)] -#[repr(C, packed)] -struct VgaCharacter { - character: u8, - attribute: u8, -} - -impl VgaCharacter { - const fn new(character: u8, attribute: u8) -> Self { - Self { - character, - attribute, - } - } -} - -struct VgaScreen { - buffer: *mut [[VgaCharacter; COLS]; ROWS], - current_col: usize, - current_row: usize, - is_initialized: bool, -} - -impl VgaScreen { - const fn new() -> Self { - Self { - buffer: VGA_BUFFER_ADDRESS as *mut _, - current_col: 0, - current_row: 0, - is_initialized: false, - } - } - - fn init(&mut self) { - // Identity map the VGA buffer. We only need the first page. - let mut flags = PageTableEntryFlags::empty(); - flags.device().writable().execute_disable(); - paging::map::( - VirtAddr(VGA_BUFFER_ADDRESS), - PhysAddr(VGA_BUFFER_ADDRESS), - 1, - flags, - ); +static VGA_SCREEN: InterruptOnceCell>> = InterruptOnceCell::new(); - // Disable the cursor. - unsafe { - outb(CRT_CONTROLLER_ADDRESS_PORT, CURSOR_START_REGISTER); - outb(CRT_CONTROLLER_DATA_PORT, CURSOR_DISABLE); - } - - // Clear the screen. - for r in 0..ROWS { - self.clear_row(r); - } - - // Initialization done! - self.is_initialized = true; - } +pub fn init() { + let layout = Layout::new::(); + let virt_addr = FrontBuffer::PHYS_ADDR; + + // Identity map the VGA buffer. We only need the first page. + let mut flags = PageTableEntryFlags::empty(); + flags.device().writable().execute_disable(); + paging::map::( + VirtAddr(virt_addr as _), + PhysAddr(FrontBuffer::PHYS_ADDR as u64), + 1, + flags, + ); + + // Disable the cursor. + unsafe { + const CRT_CONTROLLER_ADDRESS_PORT: u16 = 0x3D4; + const CRT_CONTROLLER_DATA_PORT: u16 = 0x3D5; + const CURSOR_START_REGISTER: u8 = 0x0A; + const CURSOR_DISABLE: u8 = 0x20; - #[inline] - fn clear_row(&mut self, row: usize) { - // Overwrite this row by a bogus character in black. - for c in 0..COLS { - unsafe { - (*self.buffer)[row][c] = VgaCharacter::new(0, ATTRIBUTE_BLACK); - } - } + Port::new(CRT_CONTROLLER_ADDRESS_PORT).write(CURSOR_START_REGISTER); + Port::new(CRT_CONTROLLER_DATA_PORT).write(CURSOR_DISABLE); } - fn write_byte(&mut self, byte: u8) { - if !self.is_initialized { - return; - } - - // Move to the next row if we have a newline character or hit the end of a column. - if byte == b'\n' || self.current_col == COLS { - self.current_col = 0; - self.current_row += 1; - } - - // Check if we have hit the end of the screen rows. - if self.current_row == ROWS { - // Shift all rows up by one line, removing the oldest visible screen row. - for r in 1..ROWS { - for c in 0..COLS { - unsafe { - (*self.buffer)[r - 1][c] = (*self.buffer)[r][c]; - } - } - } + let front_buffer = unsafe { &mut *(virt_addr as *mut TextBuffer) }; + let front_buffer = FrontBuffer::new(front_buffer); - // Clear the last screen row and write to it next time. - self.clear_row(ROWS - 1); - self.current_row = ROWS - 1; - } - - if byte != b'\n' { - // Put our character into the VGA screen buffer and advance the column counter. - unsafe { - (*self.buffer)[self.current_row][self.current_col] = - VgaCharacter::new(byte, ATTRIBUTE_LIGHTGREY); - } - self.current_col += 1; - } - } -} - -pub fn init() { - unsafe { VGA_SCREEN.init() }; + VGA_SCREEN + .set(InterruptSpinMutex::new(VgaScreen::new(front_buffer))) + .unwrap(); } -pub fn write_byte(byte: u8) { - unsafe { - VGA_SCREEN.write_byte(byte); +pub fn print(s: &str) { + if let Some(vga_screen) = VGA_SCREEN.get() { + vga_screen.lock().write_str(s).unwrap(); } } diff --git a/xtask/src/ci/qemu.rs b/xtask/src/ci/qemu.rs index 706866d143..85a53053a4 100644 --- a/xtask/src/ci/qemu.rs +++ b/xtask/src/ci/qemu.rs @@ -77,8 +77,8 @@ impl Qemu { let qemu = env::var_os("QEMU").unwrap_or_else(|| format!("qemu-system-{arch}").into()); let qemu = cmd!(sh, "{qemu}") - .args(&["-display", "none"]) - .args(&["-serial", "stdio"]) + // .args(&["-display", "none"]) + // .args(&["-serial", "stdio"]) .args(&["-kernel", format!("hermit-loader-{arch}").as_ref()]) .args(self.machine_args()) .args(self.cpu_args())