From 92738603ab20a9bb4f73cb58e72b3efb52471463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Tue, 2 Apr 2024 11:58:30 +0200 Subject: [PATCH 1/4] fix: remove static mut multiboot memory management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Kröning --- src/arch/x86_64/fdt.rs | 5 +++-- src/arch/x86_64/mod.rs | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/arch/x86_64/fdt.rs b/src/arch/x86_64/fdt.rs index 0f65e329..54f58fe2 100644 --- a/src/arch/x86_64/fdt.rs +++ b/src/arch/x86_64/fdt.rs @@ -3,14 +3,15 @@ use alloc::format; use multiboot::information::{MemoryType, Multiboot}; use vm_fdt::{Error as FdtError, FdtWriter}; -use super::{mb_info, MEM}; +use super::{mb_info, Mem}; pub struct DeviceTree; impl DeviceTree { #[cfg(all(target_os = "none", not(feature = "fc")))] pub fn create() -> Result<&'static [u8], FdtError> { - let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut MEM).unwrap() }; + let mut mem = Mem; + let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() }; let all_regions = multiboot .memory_regions() diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 0101186b..2d93ae34 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -55,8 +55,6 @@ static mut COM1: SerialPort = unsafe { SerialPort::new(SERIAL_IO_PORT) }; #[cfg(all(target_os = "none", not(feature = "fc")))] struct Mem; -#[cfg(all(target_os = "none", not(feature = "fc")))] -static mut MEM: Mem = Mem; #[cfg(all(target_os = "none", not(feature = "fc")))] impl MemoryManagement for Mem { @@ -213,8 +211,9 @@ pub fn find_kernel() -> &'static [u8] { let page_address = unsafe { mb_info.align_down(Size4KiB::SIZE as usize) }; paging::map::(page_address, page_address, 1, PageTableFlags::empty()); + let mut mem = Mem; // Load the Multiboot information and identity-map the modules information. - let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut MEM).unwrap() }; + let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() }; let modules_address = multiboot .modules() .expect("Could not find a memory map in the Multiboot information") @@ -440,7 +439,8 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { entry_point, } = kernel_info; - let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut MEM).unwrap() }; + let mut mem = Mem; + let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() }; // determine boot stack address let mut new_stack = ptr::addr_of!(kernel_end) From 46bbfd38eae25ce67d92f845538fbfe1dd8e1b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Wed, 3 Apr 2024 14:10:41 +0200 Subject: [PATCH 2/4] fix: put console in one-shot mutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Kröning --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + src/console.rs | 4 +++- src/main.rs | 4 +--- src/none.rs | 2 +- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ce498e5..b093b1c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -295,6 +295,7 @@ dependencies = [ "log", "multiboot", "naked-function", + "one-shot-mutex", "qemu-exit", "riscv", "sbi-rt", @@ -386,6 +387,15 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "one-shot-mutex" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab252a69210b0deb4dc8d8695c257d718b058c69a7c3ac6d83cf78310eb6ece" +dependencies = [ + "lock_api", +] + [[package]] name = "paste" version = "1.0.14" diff --git a/Cargo.toml b/Cargo.toml index 243bfcc3..9248ab38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ edition = "2021" align-address = "0.1" hermit-entry = { version = "0.9", features = ["loader"] } log = "0.4" +one-shot-mutex = "0.1" sptr = "0.3" vm-fdt = { version = "0.3", default-features = false, features = ["alloc"] } diff --git a/src/console.rs b/src/console.rs index 8e66e7c6..61dd3e32 100644 --- a/src/console.rs +++ b/src/console.rs @@ -1,5 +1,7 @@ use core::fmt; +use one_shot_mutex::OneShotMutex; + pub struct Console(()); impl fmt::Write for Console { @@ -11,4 +13,4 @@ impl fmt::Write for Console { } } -pub static mut CONSOLE: Console = Console(()); +pub static CONSOLE: OneShotMutex = OneShotMutex::new(Console(())); diff --git a/src/main.rs b/src/main.rs index 7cdec0ae..e464b188 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,5 @@ extern crate alloc; fn _print(args: core::fmt::Arguments<'_>) { use core::fmt::Write; - unsafe { - console::CONSOLE.write_fmt(args).unwrap(); - } + console::CONSOLE.lock().write_fmt(args).unwrap(); } diff --git a/src/none.rs b/src/none.rs index f7051cd4..405e45ac 100644 --- a/src/none.rs +++ b/src/none.rs @@ -44,7 +44,7 @@ pub(crate) unsafe extern "C" fn loader_main() -> ! { #[panic_handler] fn panic(info: &core::panic::PanicInfo<'_>) -> ! { // We can't use `println!` or related macros, because `_print` unwraps a result and might panic again - writeln!(unsafe { &mut console::CONSOLE }, "[LOADER] {info}").ok(); + writeln!(console::CONSOLE.lock(), "[LOADER] {info}").ok(); loop {} } From 0cc400a9041df02441f717571c5183c92e51bd8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Wed, 3 Apr 2024 14:26:38 +0200 Subject: [PATCH 3/4] fix(extern static): unsafe_op_in_unsafe_fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Kröning --- src/arch/aarch64/mod.rs | 17 +++++++++-------- src/arch/x86_64/mod.rs | 5 +++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs index 25911b50..51e1f7ec 100644 --- a/src/arch/aarch64/mod.rs +++ b/src/arch/aarch64/mod.rs @@ -81,7 +81,7 @@ pub fn output_message_byte(byte: u8) { } pub unsafe fn get_memory(_memory_size: u64) -> u64 { - (ptr::addr_of!(kernel_end).addr() as u64).align_up(LargePageSize::SIZE as u64) + (unsafe { ptr::addr_of!(kernel_end) }.addr() as u64).align_up(LargePageSize::SIZE as u64) } pub fn find_kernel() -> &'static [u8] { @@ -159,21 +159,21 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { for i in pgt_slice.iter_mut() { *i = 0; } - pgt_slice[0] = ptr::addr_of!(l1_pgtable).addr() as u64 + PT_PT; - pgt_slice[511] = ptr::addr_of!(l0_pgtable).addr() as u64 + PT_PT + PT_SELF; + pgt_slice[0] = unsafe { ptr::addr_of!(l1_pgtable) }.addr() as u64 + PT_PT; + pgt_slice[511] = unsafe { ptr::addr_of!(l0_pgtable) }.addr() as u64 + PT_PT + PT_SELF; let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l1_pgtable), 512) }; for i in pgt_slice.iter_mut() { *i = 0; } - pgt_slice[0] = ptr::addr_of!(l2_pgtable).addr() as u64 + PT_PT; - pgt_slice[1] = ptr::addr_of!(l2k_pgtable).addr() as u64 + PT_PT; + pgt_slice[0] = unsafe { ptr::addr_of!(l2_pgtable) }.addr() as u64 + PT_PT; + pgt_slice[1] = unsafe { ptr::addr_of!(l2k_pgtable) }.addr() as u64 + PT_PT; let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l2_pgtable), 512) }; for i in pgt_slice.iter_mut() { *i = 0; } - pgt_slice[0] = ptr::addr_of!(l3_pgtable).addr() as u64 + PT_PT; + pgt_slice[0] = unsafe { ptr::addr_of!(l3_pgtable) }.addr() as u64 + PT_PT; let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l3_pgtable), 512) }; for i in pgt_slice.iter_mut() { @@ -187,8 +187,9 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { *i = 0; } for (i, pgt_slice) in pgt_slice.iter_mut().enumerate().take(10) { - *pgt_slice = - ptr::addr_of!(L0mib_pgtable).addr() as u64 + (i * BasePageSize::SIZE) as u64 + PT_PT; + *pgt_slice = unsafe { ptr::addr_of!(L0mib_pgtable) }.addr() as u64 + + (i * BasePageSize::SIZE) as u64 + + PT_PT; } let pgt_slice = diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 2d93ae34..be54de08 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -284,7 +284,8 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { } = kernel_info; // determine boot stack address - let new_stack = (ptr::addr_of!(kernel_end).addr() + 0x1000).align_up(Size4KiB::SIZE as usize); + let new_stack = + (unsafe { ptr::addr_of!(kernel_end) }.addr() + 0x1000).align_up(Size4KiB::SIZE as usize); let cmdline_ptr = unsafe { *(sptr::from_exposed_addr(boot_params + LINUX_SETUP_HEADER_OFFSET + CMD_LINE_PTR_OFFSET)) @@ -443,7 +444,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() }; // determine boot stack address - let mut new_stack = ptr::addr_of!(kernel_end) + let mut new_stack = unsafe { ptr::addr_of!(kernel_end) } .addr() .align_up(Size4KiB::SIZE as usize); From 8102c3039a6ca10e3707aee1832b7a748f52825e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Thu, 4 Apr 2024 10:16:26 +0200 Subject: [PATCH 4/4] fix: put raw boot info into take-static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Kröning --- Cargo.lock | 16 ++++++++ Cargo.toml | 1 + src/arch/aarch64/mod.rs | 34 ++++++++-------- src/arch/riscv64/mod.rs | 78 ++++++++++++++++++------------------- src/arch/x86_64/mod.rs | 86 +++++++++++++++++++++-------------------- 5 files changed, 117 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b093b1c8..53271c19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,6 +113,12 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +[[package]] +name = "call-once" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a57a50948117a233b27f9bf73ab74709ab90d245216c4707cc16eea067a50bb" + [[package]] name = "cfg-if" version = "1.0.0" @@ -301,6 +307,7 @@ dependencies = [ "sbi-rt", "spinning_top", "sptr", + "take-static", "uart_16550", "uefi", "uefi-services", @@ -588,6 +595,15 @@ dependencies = [ "windows", ] +[[package]] +name = "take-static" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf67eb0a80961fdb5df5e14b75c5b9fc93bdbf88b00d0260b7eec55041c4fe01" +dependencies = [ + "call-once", +] + [[package]] name = "time" version = "0.3.34" diff --git a/Cargo.toml b/Cargo.toml index 9248ab38..39a6199e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ hermit-entry = { version = "0.9", features = ["loader"] } log = "0.4" one-shot-mutex = "0.1" sptr = "0.3" +take-static = "0.1" vm-fdt = { version = "0.3", default-features = false, features = ["alloc"] } [features] diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs index 51e1f7ec..307e5d0f 100644 --- a/src/arch/aarch64/mod.rs +++ b/src/arch/aarch64/mod.rs @@ -228,7 +228,12 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { } let current_stack_address = load_info.kernel_image_addr_range.start - KERNEL_STACK_SIZE as u64; - pub static mut BOOT_INFO: Option = None; + + take_static::take_static! { + static RAW_BOOT_INFO: Option = None; + } + + let raw_boot_info = RAW_BOOT_INFO.take().unwrap(); let dtb = unsafe { Dtb::from_raw(sptr::from_exposed_addr(DEVICE_TREE as usize)) @@ -247,22 +252,19 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { let ram_start = u64::from_be_bytes(start_slice.try_into().unwrap()); let ram_size = u64::from_be_bytes(size_slice.try_into().unwrap()); - let boot_info = { - let boot_info = BootInfo { - hardware_info: HardwareInfo { - phys_addr_range: ram_start..ram_start + ram_size, - serial_port_base: SerialPortBase::new(0x1000), - device_tree: core::num::NonZeroU64::new(DEVICE_TREE), - }, - load_info, - platform_info: PlatformInfo::LinuxBoot, - }; - RawBootInfo::from(boot_info) + let boot_info = BootInfo { + hardware_info: HardwareInfo { + phys_addr_range: ram_start..ram_start + ram_size, + serial_port_base: SerialPortBase::new(0x1000), + device_tree: core::num::NonZeroU64::new(DEVICE_TREE), + }, + load_info, + platform_info: PlatformInfo::LinuxBoot, }; - unsafe { - BOOT_INFO = Some(boot_info); - } + info!("boot_info = {boot_info:#?}"); + let boot_info_ptr = raw_boot_info.insert(RawBootInfo::from(boot_info)); + info!("boot_info at {boot_info_ptr:p}"); // Jump to the kernel entry point and provide the Multiboot information to it. info!( @@ -292,7 +294,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { "br {entry}", stack_address = in(reg) current_stack_address, entry = in(reg) entry_point, - in("x0") BOOT_INFO.as_ref().unwrap(), + in("x0") boot_info_ptr, in("x1") 0, options(noreturn) ) diff --git a/src/arch/riscv64/mod.rs b/src/arch/riscv64/mod.rs index 341de128..4cd5f7e5 100644 --- a/src/arch/riscv64/mod.rs +++ b/src/arch/riscv64/mod.rs @@ -100,47 +100,45 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { info!("hart_id = {}", start::get_hart_id()); - static mut BOOT_INFO: Option = None; - - let boot_info = { - let phys_addr_range = { - let memory = fdt.memory(); - let mut regions = memory.regions(); - - let mem_region = regions.next().unwrap(); - assert!( - regions.next().is_none(), - "hermit-loader can only handle one memory region yet" - ); - - let mem_base = u64::try_from(mem_region.starting_address.addr()).unwrap(); - let mem_size = u64::try_from(mem_region.size.unwrap()).unwrap(); - mem_base..mem_base + mem_size - }; - - let device_tree = { - let fdt_addr = start::get_fdt_ptr().expose_addr(); - DeviceTreeAddress::new(fdt_addr.try_into().unwrap()) - }; - - let boot_info = BootInfo { - hardware_info: HardwareInfo { - phys_addr_range, - serial_port_base: None, - device_tree, - }, - load_info, - platform_info: PlatformInfo::LinuxBoot, - }; - - info!("boot_info = {boot_info:#?}"); - - RawBootInfo::from(boot_info) + take_static::take_static! { + static RAW_BOOT_INFO: Option = None; + } + + let raw_boot_info = RAW_BOOT_INFO.take().unwrap(); + + let phys_addr_range = { + let memory = fdt.memory(); + let mut regions = memory.regions(); + + let mem_region = regions.next().unwrap(); + assert!( + regions.next().is_none(), + "hermit-loader can only handle one memory region yet" + ); + + let mem_base = u64::try_from(mem_region.starting_address.addr()).unwrap(); + let mem_size = u64::try_from(mem_region.size.unwrap()).unwrap(); + mem_base..mem_base + mem_size }; - unsafe { - BOOT_INFO = Some(boot_info); - } + let device_tree = { + let fdt_addr = start::get_fdt_ptr().expose_addr(); + DeviceTreeAddress::new(fdt_addr.try_into().unwrap()) + }; + + let boot_info = BootInfo { + hardware_info: HardwareInfo { + phys_addr_range, + serial_port_base: None, + device_tree, + }, + load_info, + platform_info: PlatformInfo::LinuxBoot, + }; + + info!("boot_info = {boot_info:#?}"); + let boot_info_ptr = raw_boot_info.insert(RawBootInfo::from(boot_info)); + info!("boot_info at {boot_info_ptr:p}"); // Check expected signature of entry function let entry: Entry = { @@ -158,7 +156,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { entry = in(reg) entry, stack = in(reg) start::get_stack_ptr(), in("a0") start::get_hart_id(), - in("a1") BOOT_INFO.as_ref().unwrap(), + in("a1") boot_info_ptr, options(noreturn) ) } diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index be54de08..212fd6cf 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -381,28 +381,29 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { start_address, end_address ); - static mut BOOT_INFO: Option = None; - - let boot_info = { - let boot_info = BootInfo { - hardware_info: HardwareInfo { - phys_addr_range: start_address as u64..end_address as u64, - serial_port_base: SerialPortBase::new(SERIAL_IO_PORT), - device_tree: None, - }, - load_info, - platform_info: PlatformInfo::LinuxBootParams { - command_line, - boot_params_addr: (unsafe { boot_params } as u64).try_into().unwrap(), - }, - }; - RawBootInfo::from(boot_info) - }; - unsafe { - BOOT_INFO = Some(boot_info); - info!("BootInfo located at {:p}", &BOOT_INFO); + take_static::take_static! { + static RAW_BOOT_INFO: Option = None; + } + + let raw_boot_info = RAW_BOOT_INFO.take().unwrap(); + + let boot_info = BootInfo { + hardware_info: HardwareInfo { + phys_addr_range: start_address as u64..end_address as u64, + serial_port_base: SerialPortBase::new(SERIAL_IO_PORT), + device_tree: None, + }, + load_info, + platform_info: PlatformInfo::LinuxBootParams { + command_line, + boot_params_addr: (unsafe { boot_params } as u64).try_into().unwrap(), + }, }; + info!("boot_info = {boot_info:#?}"); + let boot_info_ptr = raw_boot_info.insert(RawBootInfo::from(boot_info)); + info!("boot_info at {boot_info_ptr:p}"); + // Jump to the kernel entry point and provide the Multiboot information to it. info!( "Jumping to HermitCore Application Entry Point at {:#x}", @@ -426,7 +427,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { "jmp {entry}", stack_address = in(reg) current_stack_address, entry = in(reg) entry_point, - in("rdi") BOOT_INFO.as_ref().unwrap(), + in("rdi") boot_info_ptr, in("rsi") 0, options(noreturn) ) @@ -484,28 +485,29 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { let device_tree = DeviceTree::create().expect("Unable to create devicetree!"); - static mut BOOT_INFO: Option = None; - - let boot_info = { - let boot_info = BootInfo { - hardware_info: HardwareInfo { - phys_addr_range: 0..0, - serial_port_base: SerialPortBase::new(SERIAL_IO_PORT), - device_tree: DeviceTreeAddress::new(device_tree.as_ptr() as u64), - }, - load_info, - platform_info: PlatformInfo::Multiboot { - command_line, - multiboot_info_addr: (unsafe { mb_info } as u64).try_into().unwrap(), - }, - }; - RawBootInfo::from(boot_info) - }; - unsafe { - BOOT_INFO = Some(boot_info); - info!("BootInfo located at {:p}", &BOOT_INFO); + take_static::take_static! { + static RAW_BOOT_INFO: Option = None; } + let raw_boot_info = RAW_BOOT_INFO.take().unwrap(); + + let boot_info = BootInfo { + hardware_info: HardwareInfo { + phys_addr_range: 0..0, + serial_port_base: SerialPortBase::new(SERIAL_IO_PORT), + device_tree: DeviceTreeAddress::new(device_tree.as_ptr() as u64), + }, + load_info, + platform_info: PlatformInfo::Multiboot { + command_line, + multiboot_info_addr: (unsafe { mb_info } as u64).try_into().unwrap(), + }, + }; + + info!("boot_info = {boot_info:#?}"); + let boot_info_ptr = raw_boot_info.insert(RawBootInfo::from(boot_info)); + info!("boot_info at {boot_info_ptr:p}"); + // Jump to the kernel entry point and provide the Multiboot information to it. info!( "Jumping to HermitCore Application Entry Point at {:#x}", @@ -529,7 +531,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! { "jmp {entry}", stack_address = in(reg) current_stack_address, entry = in(reg) entry_point, - in("rdi") BOOT_INFO.as_ref().unwrap(), + in("rdi") boot_info_ptr, in("rsi") 0, options(noreturn) )