From b970f7d27cb6cc1801e3dece93d9deb103953cfa Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sat, 4 Mar 2023 23:59:52 -0800 Subject: [PATCH 01/80] kernel image fields --- api/src/info.rs | 9 +++++++++ common/src/lib.rs | 9 ++++++++- common/src/load_kernel.rs | 8 ++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/api/src/info.rs b/api/src/info.rs index cdb48722..23646499 100644 --- a/api/src/info.rs +++ b/api/src/info.rs @@ -56,6 +56,12 @@ pub struct BootInfo { pub ramdisk_addr: Optional, /// Ramdisk image size, set to 0 if addr is None pub ramdisk_len: u64, + /// Kernel image address + pub kernel_addr: u64, + /// Kernel image size + pub kernel_len: u64, + /// Kernel image relocation address + pub kernel_image_offset: u64, #[doc(hidden)] pub _test_sentinel: u64, @@ -76,6 +82,9 @@ impl BootInfo { tls_template: Optional::None, ramdisk_addr: Optional::None, ramdisk_len: 0, + kernel_addr: 0, + kernel_len: 0, + kernel_image_offset: 0, _test_sentinel: 0, } } diff --git a/common/src/lib.rs b/common/src/lib.rs index ecd0d9cc..a765e76a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -198,7 +198,7 @@ where let kernel_slice_start = kernel.start_address as u64; let kernel_slice_len = u64::try_from(kernel.len).unwrap(); - let (entry_point, tls_template) = load_kernel::load_kernel( + let (kernel_image_offset, entry_point, tls_template) = load_kernel::load_kernel( kernel, kernel_page_table, frame_allocator, @@ -402,6 +402,8 @@ where kernel_slice_start, kernel_slice_len, + kernel_image_offset: kernel_image_offset.as_u64(), + ramdisk_slice_start, ramdisk_slice_len, } @@ -429,6 +431,8 @@ pub struct Mappings { pub kernel_slice_start: u64, /// Size of the kernel slice allocation in memory. pub kernel_slice_len: u64, + /// Start address of the kernel image relocated in memory. + pub kernel_image_offset: u64, pub ramdisk_slice_start: Option, pub ramdisk_slice_len: u64, } @@ -543,6 +547,9 @@ where .map(|addr| addr.as_u64()) .into(); info.ramdisk_len = mappings.ramdisk_slice_len; + info.kernel_addr = mappings.kernel_slice_start as _; + info.kernel_len = mappings.kernel_slice_len as _; + info.kernel_image_offset = mappings.kernel_image_offset; info._test_sentinel = boot_config._test_sentinel; info }); diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs index a79a404a..68ad9778 100644 --- a/common/src/load_kernel.rs +++ b/common/src/load_kernel.rs @@ -721,11 +721,15 @@ pub fn load_kernel( page_table: &mut (impl MapperAllSizes + Translate), frame_allocator: &mut impl FrameAllocator, used_entries: &mut UsedLevel4Entries, -) -> Result<(VirtAddr, Option), &'static str> { +) -> Result<(VirtAddr, VirtAddr, Option), &'static str> { let mut loader = Loader::new(kernel, page_table, frame_allocator, used_entries)?; let tls_template = loader.load_segments()?; - Ok((loader.entry_point(), tls_template)) + Ok(( + VirtAddr::new(loader.inner.virtual_address_offset.virtual_address_offset() as u64), + loader.entry_point(), + tls_template, + )) } /// A helper type used to offset virtual addresses for position independent From 4f27700f22103f442cc8846f4cde8532626394b5 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sun, 5 Mar 2023 01:03:11 -0800 Subject: [PATCH 02/80] zero rbp --- common/src/lib.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index a765e76a..65a06b82 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -39,7 +39,7 @@ pub mod serial; const PAGE_SIZE: u64 = 4096; -/// Initialize a text-based logger using the given pixel-based framebuffer as output. +/// Initialize a text-based logger using the given pixel-based framebuffer as output. pub fn init_logger( framebuffer: &'static mut [u8], info: FrameBufferInfo, @@ -594,7 +594,7 @@ pub struct PageTables { /// /// Must be the page table that the `kernel` field of this struct refers to. /// - /// This frame is loaded into the `CR3` register on the final context switch to the kernel. + /// This frame is loaded into the `CR3` register on the final context switch to the kernel. pub kernel_level_4_frame: PhysFrame, } @@ -602,7 +602,13 @@ pub struct PageTables { unsafe fn context_switch(addresses: Addresses) -> ! { unsafe { asm!( - "mov cr3, {}; mov rsp, {}; push 0; jmp {}", + r#" + xor rbp, rbp + mov cr3, {} + mov rsp, {} + push 0 + jmp {} + "#, in(reg) addresses.page_table.start_address().as_u64(), in(reg) addresses.stack_top.as_u64(), in(reg) addresses.entry_point.as_u64(), From a65533a4deb86afe13f4dcc79209b344fee34f4f Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Wed, 5 Apr 2023 21:40:11 -0700 Subject: [PATCH 03/80] review --- api/src/info.rs | 6 +++--- common/src/legacy_memory_region.rs | 3 ++- common/src/lib.rs | 14 +++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/api/src/info.rs b/api/src/info.rs index 23646499..965fcf40 100644 --- a/api/src/info.rs +++ b/api/src/info.rs @@ -56,11 +56,11 @@ pub struct BootInfo { pub ramdisk_addr: Optional, /// Ramdisk image size, set to 0 if addr is None pub ramdisk_len: u64, - /// Kernel image address + /// Physical address of the kernel ELF in memory. pub kernel_addr: u64, - /// Kernel image size + /// Size of the kernel ELF in memory. pub kernel_len: u64, - /// Kernel image relocation address + /// Virtual address of the loaded kernel image. pub kernel_image_offset: u64, #[doc(hidden)] diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index bf804e9c..6f4b1741 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -110,10 +110,11 @@ where pub fn construct_memory_map( self, regions: &mut [MaybeUninit], - kernel_slice_start: u64, + kernel_slice_start: PhysAddr, kernel_slice_len: u64, ) -> &mut [MemoryRegion] { let mut next_index = 0; + let kernel_slice_start = kernel_slice_start.as_u64(); for descriptor in self.original { let mut start = descriptor.start(); diff --git a/common/src/lib.rs b/common/src/lib.rs index 65a06b82..3c407644 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -195,7 +195,7 @@ where enable_write_protect_bit(); let config = kernel.config; - let kernel_slice_start = kernel.start_address as u64; + let kernel_slice_start = PhysAddr::new(kernel.start_address as _); let kernel_slice_len = u64::try_from(kernel.len).unwrap(); let (kernel_image_offset, entry_point, tls_template) = load_kernel::load_kernel( @@ -402,7 +402,7 @@ where kernel_slice_start, kernel_slice_len, - kernel_image_offset: kernel_image_offset.as_u64(), + kernel_image_offset, ramdisk_slice_start, ramdisk_slice_len, @@ -428,11 +428,11 @@ pub struct Mappings { pub tls_template: Option, /// Start address of the kernel slice allocation in memory. - pub kernel_slice_start: u64, + pub kernel_slice_start: PhysAddr, /// Size of the kernel slice allocation in memory. pub kernel_slice_len: u64, - /// Start address of the kernel image relocated in memory. - pub kernel_image_offset: u64, + /// Relocation offset of the kernel image in virtual memory. + pub kernel_image_offset: VirtAddr, pub ramdisk_slice_start: Option, pub ramdisk_slice_len: u64, } @@ -547,9 +547,9 @@ where .map(|addr| addr.as_u64()) .into(); info.ramdisk_len = mappings.ramdisk_slice_len; - info.kernel_addr = mappings.kernel_slice_start as _; + info.kernel_addr = mappings.kernel_slice_start.as_u64(); info.kernel_len = mappings.kernel_slice_len as _; - info.kernel_image_offset = mappings.kernel_image_offset; + info.kernel_image_offset = mappings.kernel_image_offset.as_u64(); info._test_sentinel = boot_config._test_sentinel; info }); From 3cec1488a58915b8c588b31a73715d676fa4e693 Mon Sep 17 00:00:00 2001 From: kuzeyardabulut <54737933+kuzeyardabulut@users.noreply.github.com> Date: Thu, 3 Aug 2023 19:14:18 +0300 Subject: [PATCH 04/80] Update racy_cell.rs --- bios/common/src/racy_cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bios/common/src/racy_cell.rs b/bios/common/src/racy_cell.rs index d2797f7b..439d1b18 100644 --- a/bios/common/src/racy_cell.rs +++ b/bios/common/src/racy_cell.rs @@ -18,4 +18,4 @@ impl RacyCell { } unsafe impl Send for RacyCell where T: Send {} -unsafe impl Sync for RacyCell {} +unsafe impl Sync for RacyCell {} From 98e4d39d2380fc9ac5f5f826fba75e676a1d4f3d Mon Sep 17 00:00:00 2001 From: Andrea Frigido Date: Sun, 13 Aug 2023 15:07:25 +0100 Subject: [PATCH 05/80] chore: Update license field following SPDX 2.1 license expression standard --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b6ab32f2..49dfb111 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ exclude = ["examples/basic", "examples/test_framework"] [workspace.package] # don't forget to update `workspace.dependencies` below version = "0.11.4" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/rust-osdev/bootloader" [workspace.dependencies] From 166be1b8e1e90d6214bfd14490ff8f90f626eeb2 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 24 Oct 2023 10:24:01 +0200 Subject: [PATCH 06/80] Update `rustix` dependency --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5023a397..70862902 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -851,9 +851,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.22" +version = "0.37.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" +checksum = "84f3f8f960ed3b5a59055428714943298bf3fa2d4a1d53135084e0544829d995" dependencies = [ "bitflags 1.3.2", "errno", From 52c8338fcdbef569c5d4d2ad589dc2c999b16a41 Mon Sep 17 00:00:00 2001 From: Kenny Strawn Date: Tue, 24 Oct 2023 05:13:08 -0700 Subject: [PATCH 07/80] Add an additional MB of space to the generated FAT partition --- src/fat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fat.rs b/src/fat.rs index aa2a450b..c81033b5 100644 --- a/src/fat.rs +++ b/src/fat.rs @@ -26,7 +26,7 @@ pub fn create_fat_filesystem( .truncate(true) .open(out_fat_path) .unwrap(); - let fat_size_padded_and_rounded = ((needed_size + 1024 * 64 - 1) / MB + 1) * MB; + let fat_size_padded_and_rounded = ((needed_size + 1024 * 64 - 1) / MB + 1) * MB + MB; fat_file.set_len(fat_size_padded_and_rounded).unwrap(); // choose a file system label From 7b018e22cb5a38402ed789bca205844194fce7d2 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Dec 2023 17:03:50 +0100 Subject: [PATCH 08/80] Fix: Enable test runner again The test runner was accidentally disabled in #351, in an attempt to fix the publish errors introduced by #304 (caused by a bug in cargo: https://github.com/rust-lang/cargo/issues/12225). As a result, the test runner became a no-op as neither the bios nor the uefi features were enabled. This commit fixes the issue by enabling both features by default. Once the cargo bug is fixed, we might want to switch back to the feature configuration added of #304. Fixes #405 --- tests/runner/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/runner/Cargo.toml b/tests/runner/Cargo.toml index 127184a6..796ffb01 100644 --- a/tests/runner/Cargo.toml +++ b/tests/runner/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] +default = ["bios", "uefi"] bios = ["bootloader/bios"] uefi = ["bootloader/uefi", "dep:ovmf-prebuilt"] From 6b237324c85f66b19d0136e62a8c7f9b0c770ec2 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 28 Dec 2023 14:21:01 +0100 Subject: [PATCH 09/80] Fix: Mark `ramdisk` frames as used in memory map --- common/src/legacy_memory_region.rs | 47 +++++++++++++++++++++++++++++- common/src/lib.rs | 8 +++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index 6f4b1741..e57c74cd 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -112,9 +112,12 @@ where regions: &mut [MaybeUninit], kernel_slice_start: PhysAddr, kernel_slice_len: u64, + ramdisk_slice_start: Option, + ramdisk_slice_len: u64, ) -> &mut [MemoryRegion] { let mut next_index = 0; let kernel_slice_start = kernel_slice_start.as_u64(); + let ramdisk_slice_start = ramdisk_slice_start.map(|a| a.as_u64()); for descriptor in self.original { let mut start = descriptor.start(); @@ -157,8 +160,9 @@ where kind, }; - // check if region overlaps with kernel + // check if region overlaps with kernel or ramdisk let kernel_slice_end = kernel_slice_start + kernel_slice_len; + let ramdisk_slice_end = ramdisk_slice_start.map(|s| s + ramdisk_slice_len); if region.kind == MemoryRegionKind::Usable && kernel_slice_start < region.end && kernel_slice_end > region.start @@ -198,6 +202,47 @@ where Self::add_region(before_kernel, regions, &mut next_index); Self::add_region(kernel, regions, &mut next_index); Self::add_region(after_kernel, regions, &mut next_index); + } else if region.kind == MemoryRegionKind::Usable + && ramdisk_slice_start.map(|s| s < region.end).unwrap_or(false) + && ramdisk_slice_end.map(|e| e > region.start).unwrap_or(false) + { + // region overlaps with ramdisk -> we might need to split it + let ramdisk_slice_start = ramdisk_slice_start.unwrap(); + let ramdisk_slice_end = ramdisk_slice_end.unwrap(); + + // ensure that the ramdisk allocation does not span multiple regions + assert!( + ramdisk_slice_start >= region.start, + "region overlaps with ramdisk, but ramdisk begins before region \ + (ramdisk_start: {ramdisk_slice_start:#x}, region_start: {:#x})", + region.start + ); + assert!( + ramdisk_slice_end <= region.end, + "region overlaps with ramdisk, but region ends before ramdisk \ + (ramdisk_end: {ramdisk_slice_end:#x}, region_end: {:#x})", + region.end, + ); + + // split the region into three parts + let before_ramdisk = MemoryRegion { + end: ramdisk_slice_start, + ..region + }; + let ramdisk = MemoryRegion { + start: ramdisk_slice_start, + end: ramdisk_slice_end, + kind: MemoryRegionKind::Bootloader, + }; + let after_ramdisk = MemoryRegion { + start: ramdisk_slice_end, + ..region + }; + + // add the three regions (empty regions are ignored in `add_region`) + Self::add_region(before_ramdisk, regions, &mut next_index); + Self::add_region(ramdisk, regions, &mut next_index); + Self::add_region(after_ramdisk, regions, &mut next_index); } else { // add the region normally Self::add_region(region, regions, &mut next_index); diff --git a/common/src/lib.rs b/common/src/lib.rs index 3c407644..2c5aaba4 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -293,14 +293,14 @@ where None }; let ramdisk_slice_len = system_info.ramdisk_len; - let ramdisk_slice_start = if let Some(ramdisk_address) = system_info.ramdisk_addr { + let ramdisk_slice_phys_start = system_info.ramdisk_addr.map(PhysAddr::new); + let ramdisk_slice_start = if let Some(physical_address) = ramdisk_slice_phys_start { let start_page = mapping_addr_page_aligned( config.mappings.ramdisk_memory, system_info.ramdisk_len, &mut used_entries, "ramdisk start", ); - let physical_address = PhysAddr::new(ramdisk_address); let ramdisk_physical_start_page: PhysFrame = PhysFrame::containing_address(physical_address); let ramdisk_page_count = (system_info.ramdisk_len - 1) / Size4KiB::SIZE; @@ -404,6 +404,7 @@ where kernel_slice_len, kernel_image_offset, + ramdisk_slice_phys_start, ramdisk_slice_start, ramdisk_slice_len, } @@ -433,6 +434,7 @@ pub struct Mappings { pub kernel_slice_len: u64, /// Relocation offset of the kernel image in virtual memory. pub kernel_image_offset: VirtAddr, + pub ramdisk_slice_phys_start: Option, pub ramdisk_slice_start: Option, pub ramdisk_slice_len: u64, } @@ -516,6 +518,8 @@ where memory_regions, mappings.kernel_slice_start, mappings.kernel_slice_len, + mappings.ramdisk_slice_phys_start, + mappings.ramdisk_slice_len, ); log::info!("Create bootinfo"); From 7c7462777c276c1c09701f5bc076777c54ef4bb1 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 28 Dec 2023 14:22:33 +0100 Subject: [PATCH 10/80] Add a test to verify that ramdisk is marked as used in memory map --- tests/ramdisk.rs | 8 ++ .../ramdisk/src/bin/memory_map.rs | 88 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 tests/test_kernels/ramdisk/src/bin/memory_map.rs diff --git a/tests/ramdisk.rs b/tests/ramdisk.rs index bdd7f9db..08c86f9b 100644 --- a/tests/ramdisk.rs +++ b/tests/ramdisk.rs @@ -18,3 +18,11 @@ fn check_ramdisk() { Some(Path::new(RAMDISK_PATH)), ); } + +#[test] +fn memory_map() { + run_test_kernel_with_ramdisk( + env!("CARGO_BIN_FILE_TEST_KERNEL_RAMDISK_memory_map"), + Some(Path::new(RAMDISK_PATH)), + ); +} diff --git a/tests/test_kernels/ramdisk/src/bin/memory_map.rs b/tests/test_kernels/ramdisk/src/bin/memory_map.rs new file mode 100644 index 00000000..b939a420 --- /dev/null +++ b/tests/test_kernels/ramdisk/src/bin/memory_map.rs @@ -0,0 +1,88 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{ + config::Mapping, entry_point, info::MemoryRegionKind, BootInfo, BootloaderConfig, +}; +use core::{fmt::Write, ptr::slice_from_raw_parts}; +use test_kernel_ramdisk::{exit_qemu, serial, QemuExitCode, RAMDISK_CONTENTS}; +use x86_64::{ + structures::paging::{OffsetPageTable, PageTable, PageTableFlags, Translate}, + VirtAddr, +}; + +pub const BOOTLOADER_CONFIG: BootloaderConfig = { + let mut config = BootloaderConfig::new_default(); + config.mappings.physical_memory = Some(Mapping::FixedAddress(0x0000_6000_0000_0000)); + config +}; + +entry_point!(kernel_main, config = &BOOTLOADER_CONFIG); + +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { + writeln!(serial(), "Boot info: {boot_info:?}").unwrap(); + + let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset.into_option().unwrap()); + let level_4_table = unsafe { active_level_4_table(phys_mem_offset) }; + let page_table = unsafe { OffsetPageTable::new(level_4_table, phys_mem_offset) }; + + let ramdisk_start_addr = VirtAddr::new(boot_info.ramdisk_addr.into_option().unwrap()); + assert_eq!(boot_info.ramdisk_len as usize, RAMDISK_CONTENTS.len()); + let ramdisk_end_addr = ramdisk_start_addr + boot_info.ramdisk_len; + + let mut next_addr = ramdisk_start_addr; + while next_addr < ramdisk_end_addr { + let phys_addr = match page_table.translate(next_addr) { + x86_64::structures::paging::mapper::TranslateResult::Mapped { + frame, + offset: _, + flags, + } => { + assert!(flags.contains(PageTableFlags::PRESENT)); + assert!(flags.contains(PageTableFlags::WRITABLE)); + + next_addr += frame.size(); + + frame.start_address() + } + other => panic!("invalid result: {other:?}"), + }; + let region = boot_info + .memory_regions + .iter() + .find(|r| r.start <= phys_addr.as_u64() && r.end > phys_addr.as_u64()) + .unwrap(); + assert_eq!(region.kind, MemoryRegionKind::Bootloader); + } + + let actual_ramdisk = unsafe { + &*slice_from_raw_parts( + boot_info.ramdisk_addr.into_option().unwrap() as *const u8, + boot_info.ramdisk_len as usize, + ) + }; + writeln!(serial(), "Actual contents: {actual_ramdisk:?}").unwrap(); + assert_eq!(RAMDISK_CONTENTS, actual_ramdisk); + + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + let _ = writeln!(test_kernel_ramdisk::serial(), "PANIC: {info}"); + exit_qemu(QemuExitCode::Failed); +} + +pub unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable { + use x86_64::registers::control::Cr3; + + let (level_4_table_frame, _) = Cr3::read(); + + let phys = level_4_table_frame.start_address(); + let virt = physical_memory_offset + phys.as_u64(); + let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); + + &mut *page_table_ptr // unsafe +} From e27698fd51ac8ba1129295344018288992e0868b Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 28 Dec 2023 14:31:35 +0100 Subject: [PATCH 11/80] Set `NO_EXECUTE` flag for all writable memory regions Including the kernel stack, the ramdisk, and the physical memory mapping. --- bios/stage-4/src/main.rs | 4 +++- common/src/lib.rs | 15 +++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 260dd622..9ade45f8 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -78,7 +78,9 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { bootloader_page_table .identity_map( frame, - PageTableFlags::PRESENT | PageTableFlags::WRITABLE, + PageTableFlags::PRESENT + | PageTableFlags::WRITABLE + | PageTableFlags::NO_EXECUTE, &mut frame_allocator, ) .unwrap() diff --git a/common/src/lib.rs b/common/src/lib.rs index 3c407644..8370bd08 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -225,7 +225,7 @@ where let frame = frame_allocator .allocate_frame() .expect("frame allocation failed when mapping a kernel stack"); - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE; match unsafe { kernel_page_table.map_to(page, frame, flags, frame_allocator) } { Ok(tlb) => tlb.flush(), Err(err) => panic!("failed to map page {:?}: {:?}", page, err), @@ -278,7 +278,8 @@ where PhysFrame::range_inclusive(framebuffer_start_frame, framebuffer_end_frame).enumerate() { let page = start_page + u64::from_usize(i); - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + let flags = + PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE; match unsafe { kernel_page_table.map_to(page, frame, flags, frame_allocator) } { Ok(tlb) => tlb.flush(), Err(err) => panic!( @@ -306,7 +307,7 @@ where let ramdisk_page_count = (system_info.ramdisk_len - 1) / Size4KiB::SIZE; let ramdisk_physical_end_page = ramdisk_physical_start_page + ramdisk_page_count; - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE; for (i, frame) in PhysFrame::range_inclusive(ramdisk_physical_start_page, ramdisk_physical_end_page) .enumerate() @@ -339,7 +340,8 @@ where for frame in PhysFrame::range_inclusive(start_frame, end_frame) { let page = Page::containing_address(offset + frame.start_address().as_u64()); - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + let flags = + PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE; match unsafe { kernel_page_table.map_to(page, frame, flags, frame_allocator) } { Ok(tlb) => tlb.ignore(), Err(err) => panic!( @@ -380,7 +382,7 @@ where u16::from(index) ); } - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE; entry.set_frame(page_tables.kernel_level_4_frame, flags); Some(index) @@ -479,7 +481,8 @@ where let start_page = Page::containing_address(boot_info_addr); let end_page = Page::containing_address(memory_map_regions_end - 1u64); for page in Page::range_inclusive(start_page, end_page) { - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + let flags = + PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE; let frame = frame_allocator .allocate_frame() .expect("frame allocation for boot info failed"); From 6ea5e5f07b447ad27ea32c52e657793ad5dbb0db Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 28 Dec 2023 14:47:07 +0100 Subject: [PATCH 12/80] Release `v0.11.5` --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 10 +++++----- Changelog.md | 12 ++++++++++++ 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70862902..97352a1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,7 +155,7 @@ dependencies = [ [[package]] name = "bootloader" -version = "0.11.4" +version = "0.11.5" dependencies = [ "anyhow", "async-process", @@ -180,22 +180,22 @@ dependencies = [ [[package]] name = "bootloader-boot-config" -version = "0.11.4" +version = "0.11.5" dependencies = [ "serde", ] [[package]] name = "bootloader-x86_64-bios-boot-sector" -version = "0.11.4" +version = "0.11.5" [[package]] name = "bootloader-x86_64-bios-common" -version = "0.11.4" +version = "0.11.5" [[package]] name = "bootloader-x86_64-bios-stage-2" -version = "0.11.4" +version = "0.11.5" dependencies = [ "bootloader-x86_64-bios-common", "byteorder", @@ -204,7 +204,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-3" -version = "0.11.4" +version = "0.11.5" dependencies = [ "bootloader-x86_64-bios-common", "noto-sans-mono-bitmap 0.1.6", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-4" -version = "0.11.4" +version = "0.11.5" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-bios-common", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-common" -version = "0.11.4" +version = "0.11.5" dependencies = [ "bootloader-boot-config", "bootloader_api", @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-uefi" -version = "0.11.4" +version = "0.11.5" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-common", @@ -259,7 +259,7 @@ dependencies = [ [[package]] name = "bootloader_api" -version = "0.11.4" +version = "0.11.5" dependencies = [ "rand", ] diff --git a/Cargo.toml b/Cargo.toml index 49dfb111..4378584c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,15 +31,15 @@ exclude = ["examples/basic", "examples/test_framework"] [workspace.package] # don't forget to update `workspace.dependencies` below -version = "0.11.4" +version = "0.11.5" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-osdev/bootloader" [workspace.dependencies] -bootloader_api = { version = "0.11.4", path = "api" } -bootloader-x86_64-common = { version = "0.11.4", path = "common" } -bootloader-boot-config = { version = "0.11.4", path = "common/config" } -bootloader-x86_64-bios-common = { version = "0.11.4", path = "bios/common" } +bootloader_api = { version = "0.11.5", path = "api" } +bootloader-x86_64-common = { version = "0.11.5", path = "common" } +bootloader-boot-config = { version = "0.11.5", path = "common/config" } +bootloader-x86_64-bios-common = { version = "0.11.5", path = "bios/common" } [features] default = ["bios", "uefi"] diff --git a/Changelog.md b/Changelog.md index b8ecf0b8..bd39899e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,17 @@ # Unreleased +# 0.11.5 – 2023-12-28 + +* [RacyCell: Data race allowed on `T`](https://github.com/rust-osdev/bootloader/pull/390) +* [Update license field following SPDX 2.1 license expression standard](https://github.com/rust-osdev/bootloader/pull/391) +* [kernel image fields & zero out rbp](https://github.com/rust-osdev/bootloader/pull/346) +* [Update `rustix` dependency](https://github.com/rust-osdev/bootloader/pull/398) +* [Add an additional MB of space to the generated FAT partition](https://github.com/rust-osdev/bootloader/pull/397) +* [Fix: Enable test runner again](https://github.com/rust-osdev/bootloader/pull/407) +* [Fix: Mark `ramdisk` as used in memory map](https://github.com/rust-osdev/bootloader/pull/408) + +**Full Changelog**: https://github.com/rust-osdev/bootloader/compare/v0.11.4...v0.11.5 + # 0.11.4 – 2023-07-05 - [Fix bug stemming from treating an exclusive range as an inclusive ranges](https://github.com/rust-osdev/bootloader/pull/362) From 7d2a579adb0ed6c60ba850099c20fae3a73e361d Mon Sep 17 00:00:00 2001 From: Will Schroeder <61419567+mysteriouslyseeing@users.noreply.github.com> Date: Fri, 29 Dec 2023 02:26:23 +1100 Subject: [PATCH 13/80] Embed bios and uefi binaries (#395) --- build.rs | 113 +++++++++++++++++++++++++++++++++++----- src/file_data_source.rs | 9 ++++ src/lib.rs | 49 ++++++++--------- src/mbr.rs | 17 +++--- 4 files changed, 140 insertions(+), 48 deletions(-) diff --git a/build.rs b/build.rs index d40373d4..3f543d3f 100644 --- a/build.rs +++ b/build.rs @@ -21,7 +21,6 @@ async fn bios_main() { // BIOS crates don't have enough dependencies to utilize all cores on modern // CPUs. So by running the build commands in parallel, we increase the number // of utilized cores.) - #[cfg(not(docsrs_dummy_build))] let (bios_boot_sector_path, bios_stage_2_path, bios_stage_3_path, bios_stage_4_path) = ( build_bios_boot_sector(&out_dir), build_bios_stage_2(&out_dir), @@ -30,14 +29,6 @@ async fn bios_main() { ) .join() .await; - // dummy implementations because docsrs builds have no network access - #[cfg(docsrs_dummy_build)] - let (bios_boot_sector_path, bios_stage_2_path, bios_stage_3_path, bios_stage_4_path) = ( - PathBuf::new(), - PathBuf::new(), - PathBuf::new(), - PathBuf::new(), - ); println!( "cargo:rustc-env=BIOS_BOOT_SECTOR_PATH={}", bios_boot_sector_path.display() @@ -60,11 +51,7 @@ async fn bios_main() { async fn uefi_main() { let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); - #[cfg(not(docsrs_dummy_build))] let uefi_path = build_uefi_bootloader(&out_dir).await; - // dummy implementation because docsrs builds have no network access - #[cfg(docsrs_dummy_build)] - let uefi_path = PathBuf::new(); println!( "cargo:rustc-env=UEFI_BOOTLOADER_PATH={}", @@ -109,6 +96,26 @@ async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { } } +// dummy implementation because docsrs builds have no network access. +// This will put an empty file in out_dir and return its path. +#[cfg(docsrs_dummy_build)] +#[cfg(feature = "uefi")] +async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { + use std::fs::File; + + let path = out_dir.join("bootloader-dummy-bootloader-uefi"); + + if File::create(&path).is_err() { + panic!("Failed to create dummy uefi bootloader"); + } + assert!( + path.exists(), + "uefi bootloader dummy file does not exist after file creation" + ); + + path +} + #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { @@ -153,6 +160,26 @@ async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { convert_elf_to_bin(elf_path).await } +// dummy implementation because docsrs builds have no network access. +// This will put an empty file in out_dir and return its path. +#[cfg(docsrs_dummy_build)] +#[cfg(feature = "bios")] +async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { + use std::fs::File; + + let path = out_dir.join("bootloader-dummy-bios-boot-sector"); + + if File::create(&path).is_err() { + panic!("Failed to create dummy bios boot sector"); + } + assert!( + path.exists(), + "bios boot sector dummy file does not exist after file creation" + ); + + path +} + #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] async fn build_bios_stage_2(out_dir: &Path) -> PathBuf { @@ -199,6 +226,26 @@ async fn build_bios_stage_2(out_dir: &Path) -> PathBuf { convert_elf_to_bin(elf_path).await } +// dummy implementation because docsrs builds have no network access. +// This will put an empty file in out_dir and return its path. +#[cfg(docsrs_dummy_build)] +#[cfg(feature = "bios")] +async fn build_bios_stage_2(out_dir: &Path) -> PathBuf { + use std::fs::File; + + let path = out_dir.join("bootloader-dummy-bios-stage-2"); + + if File::create(&path).is_err() { + panic!("Failed to create dummy bios second stage"); + } + assert!( + path.exists(), + "bios second stage dummy file does not exist after file creation" + ); + + path +} + #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] async fn build_bios_stage_3(out_dir: &Path) -> PathBuf { @@ -241,6 +288,26 @@ async fn build_bios_stage_3(out_dir: &Path) -> PathBuf { convert_elf_to_bin(elf_path).await } +// dummy implementation because docsrs builds have no network access. +// This will put an empty file in out_dir and return its path. +#[cfg(docsrs_dummy_build)] +#[cfg(feature = "bios")] +async fn build_bios_stage_3(out_dir: &Path) -> PathBuf { + use std::fs::File; + + let path = out_dir.join("bootloader-dummy-bios-stage-3"); + + if File::create(&path).is_err() { + panic!("Failed to create dummy bios stage-3"); + } + assert!( + path.exists(), + "bios stage-3 dummy file does not exist after file creation" + ); + + path +} + #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] async fn build_bios_stage_4(out_dir: &Path) -> PathBuf { @@ -284,6 +351,26 @@ async fn build_bios_stage_4(out_dir: &Path) -> PathBuf { convert_elf_to_bin(elf_path).await } +// dummy implementation because docsrs builds have no network access. +// This will put an empty file in out_dir and return its path. +#[cfg(docsrs_dummy_build)] +#[cfg(feature = "bios")] +async fn build_bios_stage_4(out_dir: &Path) -> PathBuf { + use std::fs::File; + + let path = out_dir.join("bootloader-dummy-bios-stage-4"); + + if File::create(&path).is_err() { + panic!("Failed to create dummy bios stage-4"); + } + assert!( + path.exists(), + "bios stage-4 dummy file does not exist after file creation" + ); + + path +} + #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] async fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf { diff --git a/src/file_data_source.rs b/src/file_data_source.rs index 3e1128b3..5724d96f 100644 --- a/src/file_data_source.rs +++ b/src/file_data_source.rs @@ -11,6 +11,7 @@ use std::{fs, io}; pub enum FileDataSource { File(PathBuf), Data(Vec), + Bytes(&'static [u8]), } impl Debug for FileDataSource { @@ -22,6 +23,9 @@ impl Debug for FileDataSource { FileDataSource::Data(d) => { f.write_fmt(format_args!("data source: {} raw bytes ", d.len())) } + FileDataSource::Bytes(b) => { + f.write_fmt(format_args!("data source: {} raw bytes ", b.len())) + } } } } @@ -34,6 +38,7 @@ impl FileDataSource { .with_context(|| format!("failed to read metadata of file `{}`", path.display()))? .len(), FileDataSource::Data(v) => v.len() as u64, + FileDataSource::Bytes(s) => s.len() as u64, }) } /// Copy this data source to the specified target that implements io::Write @@ -51,6 +56,10 @@ impl FileDataSource { let mut cursor = Cursor::new(contents); io::copy(&mut cursor, target)?; } + FileDataSource::Bytes(contents) => { + let mut cursor = Cursor::new(contents); + io::copy(&mut cursor, target)?; + } }; Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 179f1d10..cb3805e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,17 @@ const KERNEL_FILE_NAME: &str = "kernel-x86_64"; const RAMDISK_FILE_NAME: &str = "ramdisk"; const CONFIG_FILE_NAME: &str = "boot.json"; +#[cfg(feature = "uefi")] +const UEFI_BOOTLOADER: &[u8] = include_bytes!(env!("UEFI_BOOTLOADER_PATH")); +#[cfg(feature = "bios")] +const BIOS_BOOT_SECTOR: &[u8] = include_bytes!(env!("BIOS_BOOT_SECTOR_PATH")); +#[cfg(feature = "bios")] +const BIOS_STAGE_2: &[u8] = include_bytes!(env!("BIOS_STAGE_2_PATH")); +#[cfg(feature = "bios")] +const BIOS_STAGE_3: &[u8] = include_bytes!(env!("BIOS_STAGE_3_PATH")); +#[cfg(feature = "bios")] +const BIOS_STAGE_4: &[u8] = include_bytes!(env!("BIOS_STAGE_4_PATH")); + /// Allows creating disk images for a specified set of files. /// /// It can currently create `MBR` (BIOS), `GPT` (UEFI), and `TFTP` (UEFI) images. @@ -98,28 +109,19 @@ impl DiskImageBuilder { #[cfg(feature = "bios")] /// Create an MBR disk image for booting on BIOS systems. pub fn create_bios_image(&self, image_path: &Path) -> anyhow::Result<()> { - const BIOS_STAGE_3: &str = "boot-stage-3"; - const BIOS_STAGE_4: &str = "boot-stage-4"; - let bootsector_path = Path::new(env!("BIOS_BOOT_SECTOR_PATH")); - let stage_2_path = Path::new(env!("BIOS_STAGE_2_PATH")); - let stage_3_path = Path::new(env!("BIOS_STAGE_3_PATH")); - let stage_4_path = Path::new(env!("BIOS_STAGE_4_PATH")); + const BIOS_STAGE_3_NAME: &str = "boot-stage-3"; + const BIOS_STAGE_4_NAME: &str = "boot-stage-4"; + let stage_3 = FileDataSource::Bytes(BIOS_STAGE_3); + let stage_4 = FileDataSource::Bytes(BIOS_STAGE_4); let mut internal_files = BTreeMap::new(); - internal_files.insert( - BIOS_STAGE_3, - FileDataSource::File(stage_3_path.to_path_buf()), - ); - internal_files.insert( - BIOS_STAGE_4, - FileDataSource::File(stage_4_path.to_path_buf()), - ); - + internal_files.insert(BIOS_STAGE_3_NAME, stage_3); + internal_files.insert(BIOS_STAGE_4_NAME, stage_4); let fat_partition = self .create_fat_filesystem_image(internal_files) .context("failed to create FAT partition")?; mbr::create_mbr_disk( - bootsector_path, - stage_2_path, + BIOS_BOOT_SECTOR, + BIOS_STAGE_2, fat_partition.path(), image_path, ) @@ -135,12 +137,9 @@ impl DiskImageBuilder { /// Create a GPT disk image for booting on UEFI systems. pub fn create_uefi_image(&self, image_path: &Path) -> anyhow::Result<()> { const UEFI_BOOT_FILENAME: &str = "efi/boot/bootx64.efi"; - let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH")); + let mut internal_files = BTreeMap::new(); - internal_files.insert( - UEFI_BOOT_FILENAME, - FileDataSource::File(bootloader_path.to_path_buf()), - ); + internal_files.insert(UEFI_BOOT_FILENAME, FileDataSource::Bytes(UEFI_BOOTLOADER)); let fat_partition = self .create_fat_filesystem_image(internal_files) .context("failed to create FAT partition")?; @@ -159,15 +158,13 @@ impl DiskImageBuilder { use std::{fs, ops::Deref}; const UEFI_TFTP_BOOT_FILENAME: &str = "bootloader"; - let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH")); fs::create_dir_all(tftp_path) .with_context(|| format!("failed to create out dir at {}", tftp_path.display()))?; let to = tftp_path.join(UEFI_TFTP_BOOT_FILENAME); - fs::copy(bootloader_path, &to).with_context(|| { + fs::write(&to, UEFI_BOOTLOADER).with_context(|| { format!( - "failed to copy bootloader from {} to {}", - bootloader_path.display(), + "failed to copy bootloader from the embedded binary to {}", to.display() ) })?; diff --git a/src/mbr.rs b/src/mbr.rs index 6c7a9f0d..3328a07f 100644 --- a/src/mbr.rs +++ b/src/mbr.rs @@ -5,15 +5,17 @@ use std::{ io::{self, Seek, SeekFrom}, path::Path, }; + const SECTOR_SIZE: u32 = 512; pub fn create_mbr_disk( - bootsector_path: &Path, - second_stage_path: &Path, + bootsector_binary: &[u8], + second_stage_binary: &[u8], boot_partition_path: &Path, out_mbr_path: &Path, ) -> anyhow::Result<()> { - let mut boot_sector = File::open(bootsector_path).context("failed to open boot sector")?; + use std::io::Cursor; + let mut boot_sector = Cursor::new(bootsector_binary); let mut mbr = mbrman::MBR::read_from(&mut boot_sector, SECTOR_SIZE).context("failed to read MBR")?; @@ -23,12 +25,9 @@ pub fn create_mbr_disk( } } - let mut second_stage = - File::open(second_stage_path).context("failed to open second stage binary")?; - let second_stage_size = second_stage - .metadata() - .context("failed to read file metadata of second stage")? - .len(); + let mut second_stage = Cursor::new(second_stage_binary); + let second_stage_size = second_stage_binary.len() as u64; + let second_stage_start_sector = 1; let second_stage_sectors = ((second_stage_size - 1) / u64::from(SECTOR_SIZE) + 1) .try_into() From 2db7ae29d110ccef4f4feef7cb3603722662e4a4 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 29 Dec 2023 20:15:35 +0100 Subject: [PATCH 14/80] Add a `take` method to `Optional` This makes it easier to take ownership of optional values inside the `&'static mut BootInfo`. --- api/src/info.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/src/info.rs b/api/src/info.rs index 965fcf40..81c849d8 100644 --- a/api/src/info.rs +++ b/api/src/info.rs @@ -341,6 +341,11 @@ impl Optional { Self::None => None, } } + + /// Takes the value out of the `Optional`, leaving a `None` in its place. + pub fn take(&mut self) -> Option { + core::mem::replace(self, Optional::None).into_option() + } } impl From> for Optional { From 0dce7e0b7d4738714e77a3aa700d0de4449a42c8 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sun, 28 Jan 2024 10:55:47 +0100 Subject: [PATCH 15/80] Fix data layout for stage 3 target --- i686-stage-3.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i686-stage-3.json b/i686-stage-3.json index b444faec..10e6d4b5 100644 --- a/i686-stage-3.json +++ b/i686-stage-3.json @@ -1,7 +1,7 @@ { "arch": "x86", "cpu": "i386", - "data-layout": "e-m:e-i32:32-f80:128-n8:16:32-S128-p:32:32", + "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128", "dynamic-linking": false, "executables": true, "linker-flavor": "ld.lld", From cac796ecac22b952bc90b5994103fdd6debaac90 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sun, 28 Jan 2024 11:09:07 +0100 Subject: [PATCH 16/80] Release `v0.11.6` --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 10 +++++----- Changelog.md | 8 ++++++++ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97352a1a..2fd29ff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,7 +155,7 @@ dependencies = [ [[package]] name = "bootloader" -version = "0.11.5" +version = "0.11.6" dependencies = [ "anyhow", "async-process", @@ -180,22 +180,22 @@ dependencies = [ [[package]] name = "bootloader-boot-config" -version = "0.11.5" +version = "0.11.6" dependencies = [ "serde", ] [[package]] name = "bootloader-x86_64-bios-boot-sector" -version = "0.11.5" +version = "0.11.6" [[package]] name = "bootloader-x86_64-bios-common" -version = "0.11.5" +version = "0.11.6" [[package]] name = "bootloader-x86_64-bios-stage-2" -version = "0.11.5" +version = "0.11.6" dependencies = [ "bootloader-x86_64-bios-common", "byteorder", @@ -204,7 +204,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-3" -version = "0.11.5" +version = "0.11.6" dependencies = [ "bootloader-x86_64-bios-common", "noto-sans-mono-bitmap 0.1.6", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-4" -version = "0.11.5" +version = "0.11.6" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-bios-common", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-common" -version = "0.11.5" +version = "0.11.6" dependencies = [ "bootloader-boot-config", "bootloader_api", @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-uefi" -version = "0.11.5" +version = "0.11.6" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-common", @@ -259,7 +259,7 @@ dependencies = [ [[package]] name = "bootloader_api" -version = "0.11.5" +version = "0.11.6" dependencies = [ "rand", ] diff --git a/Cargo.toml b/Cargo.toml index 4378584c..820017e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,15 +31,15 @@ exclude = ["examples/basic", "examples/test_framework"] [workspace.package] # don't forget to update `workspace.dependencies` below -version = "0.11.5" +version = "0.11.6" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-osdev/bootloader" [workspace.dependencies] -bootloader_api = { version = "0.11.5", path = "api" } -bootloader-x86_64-common = { version = "0.11.5", path = "common" } -bootloader-boot-config = { version = "0.11.5", path = "common/config" } -bootloader-x86_64-bios-common = { version = "0.11.5", path = "bios/common" } +bootloader_api = { version = "0.11.6", path = "api" } +bootloader-x86_64-common = { version = "0.11.6", path = "common" } +bootloader-boot-config = { version = "0.11.6", path = "common/config" } +bootloader-x86_64-bios-common = { version = "0.11.6", path = "bios/common" } [features] default = ["bios", "uefi"] diff --git a/Changelog.md b/Changelog.md index bd39899e..5200a49a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,13 @@ # Unreleased +# 0.11.6 – 2024-01-28 + +* [Embed bios and uefi binaries](https://github.com/rust-osdev/bootloader/pull/395) +* [Add a `take` method to `Optional`](https://github.com/rust-osdev/bootloader/pull/411) +* [Fix data layout for stage 3 target](https://github.com/rust-osdev/bootloader/pull/413) + +**Full Changelog**: https://github.com/rust-osdev/bootloader/compare/v0.11.5...v0.11.6 + # 0.11.5 – 2023-12-28 * [RacyCell: Data race allowed on `T`](https://github.com/rust-osdev/bootloader/pull/390) From 09b2569c83112dd121b50c7b45a30f338eb39f22 Mon Sep 17 00:00:00 2001 From: Tim Satke <48135919+tsatke@users.noreply.github.com> Date: Wed, 14 Feb 2024 08:47:00 +0100 Subject: [PATCH 17/80] Update i686-stage-3.json adapt data-layout to match LLVM's --- i686-stage-3.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i686-stage-3.json b/i686-stage-3.json index 10e6d4b5..c89fac10 100644 --- a/i686-stage-3.json +++ b/i686-stage-3.json @@ -1,7 +1,7 @@ { "arch": "x86", "cpu": "i386", - "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128", + "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", "dynamic-linking": false, "executables": true, "linker-flavor": "ld.lld", From d7d3ef1caec84f18be98f9fe60d3ab5c0fbb29be Mon Sep 17 00:00:00 2001 From: Tim Satke <48135919+tsatke@users.noreply.github.com> Date: Wed, 14 Feb 2024 08:48:46 +0100 Subject: [PATCH 18/80] Update i386-code16-boot-sector.json --- i386-code16-boot-sector.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i386-code16-boot-sector.json b/i386-code16-boot-sector.json index f5ed774e..3a51b364 100644 --- a/i386-code16-boot-sector.json +++ b/i386-code16-boot-sector.json @@ -1,7 +1,7 @@ { "arch": "x86", "cpu": "i386", - "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128", + "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", "dynamic-linking": false, "executables": true, "linker-flavor": "ld.lld", From a2427a5252d536d487f54e27b72f6ee79b1e1455 Mon Sep 17 00:00:00 2001 From: Tim Satke <48135919+tsatke@users.noreply.github.com> Date: Wed, 14 Feb 2024 08:49:23 +0100 Subject: [PATCH 19/80] Update i386-code16-stage-2.json --- i386-code16-stage-2.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i386-code16-stage-2.json b/i386-code16-stage-2.json index f5ed774e..3a51b364 100644 --- a/i386-code16-stage-2.json +++ b/i386-code16-stage-2.json @@ -1,7 +1,7 @@ { "arch": "x86", "cpu": "i386", - "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128", + "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", "dynamic-linking": false, "executables": true, "linker-flavor": "ld.lld", From 090f0309fb41c2ff19b1a79b5567cecc3ca084df Mon Sep 17 00:00:00 2001 From: tsatke Date: Wed, 14 Feb 2024 08:55:51 +0100 Subject: [PATCH 20/80] update data-layout for stage 4 --- x86_64-stage-4.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x86_64-stage-4.json b/x86_64-stage-4.json index 976fd56d..026d23f9 100644 --- a/x86_64-stage-4.json +++ b/x86_64-stage-4.json @@ -2,7 +2,7 @@ "arch": "x86_64", "code-model": "kernel", "cpu": "x86-64", - "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "disable-redzone": true, "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float", "linker": "rust-lld", From 8f5bd4e91ad54f6ebc2c55219eaeeb56f57b9e71 Mon Sep 17 00:00:00 2001 From: tsatke Date: Thu, 15 Feb 2024 16:28:33 +0100 Subject: [PATCH 21/80] attempt workaround by Freax13 --- bios/stage-4/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 9ade45f8..439b1fec 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -262,6 +262,7 @@ fn detect_rsdp() -> Option { #[derive(Clone)] struct IdentityMapped; impl AcpiHandler for IdentityMapped { + #[inline(never)] unsafe fn map_physical_region( &self, physical_address: usize, From 2ebe7899eb0e6e565c49840d8d2c5e66a7cfacee Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 16 Feb 2024 16:22:03 +0100 Subject: [PATCH 22/80] Add a FIXME comment to the `inline(never)` and link to the GitHub issue --- bios/stage-4/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 439b1fec..cf159a61 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -262,6 +262,9 @@ fn detect_rsdp() -> Option { #[derive(Clone)] struct IdentityMapped; impl AcpiHandler for IdentityMapped { + // TODO FIXME: This inline(never) annotation is required. Without it, + // LLVM replaces the `search_for_on_bios` call below with a `ud2` + // instruction. See https://github.com/rust-osdev/bootloader/issues/425 #[inline(never)] unsafe fn map_physical_region( &self, From 0f8493f0b13f573f972a2877478b89400c719a30 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 16 Feb 2024 17:08:51 +0100 Subject: [PATCH 23/80] Release `v0.11.7` --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 10 +++++----- Changelog.md | 7 +++++++ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2fd29ff4..28cb9d7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,7 +155,7 @@ dependencies = [ [[package]] name = "bootloader" -version = "0.11.6" +version = "0.11.7" dependencies = [ "anyhow", "async-process", @@ -180,22 +180,22 @@ dependencies = [ [[package]] name = "bootloader-boot-config" -version = "0.11.6" +version = "0.11.7" dependencies = [ "serde", ] [[package]] name = "bootloader-x86_64-bios-boot-sector" -version = "0.11.6" +version = "0.11.7" [[package]] name = "bootloader-x86_64-bios-common" -version = "0.11.6" +version = "0.11.7" [[package]] name = "bootloader-x86_64-bios-stage-2" -version = "0.11.6" +version = "0.11.7" dependencies = [ "bootloader-x86_64-bios-common", "byteorder", @@ -204,7 +204,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-3" -version = "0.11.6" +version = "0.11.7" dependencies = [ "bootloader-x86_64-bios-common", "noto-sans-mono-bitmap 0.1.6", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-4" -version = "0.11.6" +version = "0.11.7" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-bios-common", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-common" -version = "0.11.6" +version = "0.11.7" dependencies = [ "bootloader-boot-config", "bootloader_api", @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-uefi" -version = "0.11.6" +version = "0.11.7" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-common", @@ -259,7 +259,7 @@ dependencies = [ [[package]] name = "bootloader_api" -version = "0.11.6" +version = "0.11.7" dependencies = [ "rand", ] diff --git a/Cargo.toml b/Cargo.toml index 820017e2..94d582c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,15 +31,15 @@ exclude = ["examples/basic", "examples/test_framework"] [workspace.package] # don't forget to update `workspace.dependencies` below -version = "0.11.6" +version = "0.11.7" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-osdev/bootloader" [workspace.dependencies] -bootloader_api = { version = "0.11.6", path = "api" } -bootloader-x86_64-common = { version = "0.11.6", path = "common" } -bootloader-boot-config = { version = "0.11.6", path = "common/config" } -bootloader-x86_64-bios-common = { version = "0.11.6", path = "bios/common" } +bootloader_api = { version = "0.11.7", path = "api" } +bootloader-x86_64-common = { version = "0.11.7", path = "common" } +bootloader-boot-config = { version = "0.11.7", path = "common/config" } +bootloader-x86_64-bios-common = { version = "0.11.7", path = "bios/common" } [features] default = ["bios", "uefi"] diff --git a/Changelog.md b/Changelog.md index 5200a49a..3ae96afd 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,12 @@ # Unreleased +# 0.11.7 – 2024-02-16 + +* Set `NO_EXECUTE` flag for all writable memory regions by @phil-opp in https://github.com/rust-osdev/bootloader/pull/409 +* adapt data layout to match LLVM's by @tsatke in https://github.com/rust-osdev/bootloader/pull/420 + +**Full Changelog**: https://github.com/rust-osdev/bootloader/compare/v0.11.6...v0.11.7 + # 0.11.6 – 2024-01-28 * [Embed bios and uefi binaries](https://github.com/rust-osdev/bootloader/pull/395) From 66520102e8cbff1596a5b4465ad374e3b1fdfb62 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Wed, 21 Feb 2024 18:37:04 +0100 Subject: [PATCH 24/80] avoid 32-bit relocation to __BOOTLOADER_CONFIG As explained in my comment in #427, the compiler seems to have trouble emitting relocations for references to global variables in custom sections. For custom sections, it always emits 32-bit relocations even when a 64-bit relocation would be required. This patch works around that by never referencing the global in the custom section directly from code, but only through a pointer from another global variable in the non-custom .data section. The relocation used for the pointer in the global variable will always use a 64-bit relocation. --- api/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index 4ada525f..047e3cec 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -120,13 +120,17 @@ macro_rules! entry_point { config.serialize() }; + // Workaround for https://github.com/rust-osdev/bootloader/issues/427 + static __BOOTLOADER_CONFIG_REF: &[u8; $crate::BootloaderConfig::SERIALIZED_LEN] = + &__BOOTLOADER_CONFIG; + #[export_name = "_start"] pub extern "C" fn __impl_start(boot_info: &'static mut $crate::BootInfo) -> ! { // validate the signature of the program entry point let f: fn(&'static mut $crate::BootInfo) -> ! = $path; // ensure that the config is used so that the linker keeps it - $crate::__force_use(&__BOOTLOADER_CONFIG); + $crate::__force_use(__BOOTLOADER_CONFIG_REF); f(boot_info) } From b785b6d4f059c5b08a7a1a9cfa95a5ffaa35af9d Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 23 Feb 2024 20:17:38 +0100 Subject: [PATCH 25/80] add another level of indirection This prevents the compiler from optimzing out __BOOTLOADER_CONFIG_REF in favor of accessing __BOOTLOADER_CONFIG directly. --- api/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index 047e3cec..2075256a 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -130,7 +130,7 @@ macro_rules! entry_point { let f: fn(&'static mut $crate::BootInfo) -> ! = $path; // ensure that the config is used so that the linker keeps it - $crate::__force_use(__BOOTLOADER_CONFIG_REF); + $crate::__force_use(&__BOOTLOADER_CONFIG_REF); f(boot_info) } @@ -139,7 +139,7 @@ macro_rules! entry_point { } #[doc(hidden)] -pub fn __force_use(slice: &[u8]) { +pub fn __force_use(slice: &&[u8; BootloaderConfig::SERIALIZED_LEN]) { let force_use = slice.as_ptr() as usize; unsafe { core::arch::asm!("add {0}, 0", in(reg) force_use, options(nomem, nostack)) }; } From d0d10feec87e591ded71d66995e6a4752b62036b Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 7 Mar 2024 19:02:38 +0100 Subject: [PATCH 26/80] don't call slice::as_ptr We want to avoid directly accessing the data in the .bootloader-config section and slice::as_ptr gets a pointer to that data. Instead we cast a reference to a reference to the data in .bootloader-config to an address and pass that to the asm! block. The problem with as_ptr was that it's a method on the slice and not the reference and so by calling slice::as_ptr, we once again directly accessed the slice when we only meant to access the reference to the reference to the data. --- api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index 2075256a..e1fb0fb3 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -140,6 +140,6 @@ macro_rules! entry_point { #[doc(hidden)] pub fn __force_use(slice: &&[u8; BootloaderConfig::SERIALIZED_LEN]) { - let force_use = slice.as_ptr() as usize; + let force_use = slice as *const _ as usize; unsafe { core::arch::asm!("add {0}, 0", in(reg) force_use, options(nomem, nostack)) }; } From 571e75b37cfb2735c75aaee9bda09e2f4599305a Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 9 Mar 2024 21:45:28 -0500 Subject: [PATCH 27/80] Change gitter badge to zulip badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 202a1984..e8f4ef01 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Docs](https://docs.rs/bootloader/badge.svg)](https://docs.rs/bootloader) [![Build Status](https://github.com/rust-osdev/bootloader/actions/workflows/build.yml/badge.svg)](https://github.com/rust-osdev/bootloader/actions/workflows/build.yml) -[![Join the chat at https://gitter.im/rust-osdev/bootloader](https://badges.gitter.im/rust-osdev/bootloader.svg)](https://gitter.im/rust-osdev/bootloader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat at https://rust-osdev.zulipchat.com](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://rust-osdev.zulipchat.com) An experimental x86_64 bootloader that works on both BIOS and UEFI systems. Written in Rust and some inline assembly, buildable on all platforms without additional build-time dependencies (just some `rustup` components). From 074e17abe2ef726c63ba45e4b386d423b220c770 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 26 Apr 2024 08:33:29 +0200 Subject: [PATCH 28/80] CI: Also test on x86_64-based `macos-12` The `macos-latest` runner is ARM-based now. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a397f5fd..ec90853d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-12, windows-latest, macos-latest] runs-on: ${{ matrix.os }} timeout-minutes: 30 From a2633589e25c47fd8be3db617346309e65af030d Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 26 Apr 2024 08:35:25 +0200 Subject: [PATCH 29/80] Make the `entry_point` macro only available on `x86_64` Inline assembly causes build errors on other architectures. We can still run the config tests on other architectures, so we don't want to set the `target_arch` for the entire crate. --- api/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/src/lib.rs b/api/src/lib.rs index e1fb0fb3..586ae1d0 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -106,6 +106,7 @@ mod version_info { /// `#[link_section = ".bootloader-config"]`, which instructs the Rust compiler to store it /// in a special section of the resulting ELF executable. From there, the bootloader will /// automatically read it when loading the kernel. +#[cfg(target_arch = "x86_64")] #[macro_export] macro_rules! entry_point { ($path:path) => { @@ -139,6 +140,7 @@ macro_rules! entry_point { } #[doc(hidden)] +#[cfg(target_arch = "x86_64")] pub fn __force_use(slice: &&[u8; BootloaderConfig::SERIALIZED_LEN]) { let force_use = slice as *const _ as usize; unsafe { core::arch::asm!("add {0}, 0", in(reg) force_use, options(nomem, nostack)) }; From 63a01e03e8c6a338c8b17a24242d2a924d4d592d Mon Sep 17 00:00:00 2001 From: Ferdia McKeogh Date: Tue, 30 Apr 2024 16:05:35 +0100 Subject: [PATCH 30/80] Fix doc comment and error message only referencing the BIOS but used for UEFI --- src/lib.rs | 2 +- src/uefi/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cb3805e8..db5f32e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -216,7 +216,7 @@ impl DiskImageBuilder { let out_file = NamedTempFile::new().context("failed to create temp file")?; fat::create_fat_filesystem(local_map, out_file.path()) - .context("failed to create BIOS FAT filesystem")?; + .context("failed to create FAT filesystem")?; Ok(out_file) } diff --git a/src/uefi/mod.rs b/src/uefi/mod.rs index 7a27e728..34c63527 100644 --- a/src/uefi/mod.rs +++ b/src/uefi/mod.rs @@ -4,7 +4,7 @@ use bootloader_boot_config::BootConfig; use crate::DiskImageBuilder; -/// Create disk images for booting on legacy BIOS systems. +/// Create disk images for booting on UEFI systems. pub struct UefiBoot { image_builder: DiskImageBuilder, } From f8a629cce69fdd31be2dd427da04727f60817269 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Fri, 24 May 2024 13:28:44 +0200 Subject: [PATCH 31/80] Ensure all page table frames are mapped as writable --- Changelog.md | 2 ++ common/src/lib.rs | 23 +++++++++++++++++++++-- common/src/load_kernel.rs | 22 ++++++++++++++++++++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Changelog.md b/Changelog.md index 3ae96afd..6ac95ddc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,7 @@ # Unreleased +* Fix bug leading to page table frames that are not mapped as writable + # 0.11.7 – 2024-02-16 * Set `NO_EXECUTE` flag for all writable memory regions by @phil-opp in https://github.com/rust-osdev/bootloader/pull/409 diff --git a/common/src/lib.rs b/common/src/lib.rs index 3533e0fe..c17f68fc 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -241,8 +241,18 @@ where context_switch_function_start_frame, context_switch_function_start_frame + 1, ) { + let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64())); match unsafe { - kernel_page_table.identity_map(frame, PageTableFlags::PRESENT, frame_allocator) + // The parent table flags need to be both readable and writable to + // support recursive page tables. + // See https://github.com/rust-osdev/bootloader/issues/443#issuecomment-2130010621 + kernel_page_table.map_to_with_table_flags( + page, + frame, + PageTableFlags::PRESENT, + PageTableFlags::PRESENT | PageTableFlags::WRITABLE, + frame_allocator, + ) } { Ok(tlb) => tlb.flush(), Err(err) => panic!("failed to identity map frame {:?}: {:?}", frame, err), @@ -254,8 +264,17 @@ where .allocate_frame() .expect("failed to allocate GDT frame"); gdt::create_and_load(gdt_frame); + let gdt_page = Page::containing_address(VirtAddr::new(gdt_frame.start_address().as_u64())); match unsafe { - kernel_page_table.identity_map(gdt_frame, PageTableFlags::PRESENT, frame_allocator) + // The parent table flags need to be both readable and writable to + // support recursive page tables. + kernel_page_table.map_to_with_table_flags( + gdt_page, + gdt_frame, + PageTableFlags::PRESENT, + PageTableFlags::PRESENT | PageTableFlags::WRITABLE, + frame_allocator, + ) } { Ok(tlb) => tlb.flush(), Err(err) => panic!("failed to identity map frame {:?}: {:?}", gdt_frame, err), diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs index 68ad9778..6cc24fed 100644 --- a/common/src/load_kernel.rs +++ b/common/src/load_kernel.rs @@ -185,8 +185,17 @@ where let offset = frame - start_frame; let page = start_page + offset; let flusher = unsafe { + // The parent table flags need to be both readable and writable to + // support recursive page tables. + // See https://github.com/rust-osdev/bootloader/issues/443#issuecomment-2130010621 self.page_table - .map_to(page, frame, segment_flags, self.frame_allocator) + .map_to_with_table_flags( + page, + frame, + segment_flags, + Flags::PRESENT | Flags::WRITABLE, + self.frame_allocator, + ) .map_err(|_err| "map_to failed")? }; // we operate on an inactive page table, so there's no need to flush anything @@ -280,8 +289,17 @@ where // map frame let flusher = unsafe { + // The parent table flags need to be both readable and writable to + // support recursive page tables. + // See https://github.com/rust-osdev/bootloader/issues/443#issuecomment-2130010621 self.page_table - .map_to(page, frame, segment_flags, self.frame_allocator) + .map_to_with_table_flags( + page, + frame, + segment_flags, + Flags::PRESENT | Flags::WRITABLE, + self.frame_allocator, + ) .map_err(|_err| "Failed to map new frame for bss memory")? }; // we operate on an inactive page table, so we don't need to flush our changes From 1e52e4c5e7c4c38c49bad53dac579331e5dbaaa8 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Mon, 17 Jun 2024 01:06:06 +0200 Subject: [PATCH 32/80] Fix warning: unecessary import for alloc::Vec --- src/file_data_source.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/file_data_source.rs b/src/file_data_source.rs index 5724d96f..47656ff8 100644 --- a/src/file_data_source.rs +++ b/src/file_data_source.rs @@ -1,4 +1,3 @@ -use alloc::vec::Vec; use anyhow::Context; use core::fmt::{Debug, Formatter}; From 25551270a856091b43a3f84b038c628f7eab186f Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sun, 9 Jun 2024 00:19:34 +0200 Subject: [PATCH 33/80] Guard the lower 1MB of memory This commit fixes the review changes in #317. Most of the credit should go to Jason Couture Co-authored-by: Jason Couture --- Cargo.lock | 10 +++ Cargo.toml | 2 + common/src/legacy_memory_region.rs | 49 ++++++++++++-- tests/lower_memory_free.rs | 7 ++ .../test_kernels/lower_memory_free/Cargo.toml | 12 ++++ .../src/bin/lower_memory_free.rs | 65 +++++++++++++++++++ .../test_kernels/lower_memory_free/src/lib.rs | 27 ++++++++ 7 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 tests/lower_memory_free.rs create mode 100644 tests/test_kernels/lower_memory_free/Cargo.toml create mode 100644 tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs create mode 100644 tests/test_kernels/lower_memory_free/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 28cb9d7a..f257994d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,7 @@ dependencies = [ "test_kernel_config_file", "test_kernel_default_settings", "test_kernel_higher_half", + "test_kernel_lower_memory_free", "test_kernel_map_phys_mem", "test_kernel_min_stack", "test_kernel_pie", @@ -1078,6 +1079,15 @@ dependencies = [ "x86_64", ] +[[package]] +name = "test_kernel_lower_memory_free" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + [[package]] name = "test_kernel_lto" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 94d582c2..4de19416 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ members = [ "tests/test_kernels/lto", "tests/test_kernels/ramdisk", "tests/test_kernels/min_stack", + "tests/test_kernels/lower_memory_free", ] exclude = ["examples/basic", "examples/test_framework"] @@ -67,6 +68,7 @@ test_kernel_pie = { path = "tests/test_kernels/pie", artifact = "bin", target = test_kernel_ramdisk = { path = "tests/test_kernels/ramdisk", artifact = "bin", target = "x86_64-unknown-none" } test_kernel_config_file = { path = "tests/test_kernels/config_file", artifact = "bin", target = "x86_64-unknown-none" } test_kernel_min_stack = { path = "tests/test_kernels/min_stack", artifact = "bin", target = "x86_64-unknown-none" } +test_kernel_lower_memory_free = { path = "tests/test_kernels/lower_memory_free", artifact = "bin", target = "x86_64-unknown-none" } [profile.dev] panic = "abort" diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index e57c74cd..1fbf1cfb 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -28,8 +28,12 @@ pub struct LegacyFrameAllocator { memory_map: I, current_descriptor: Option, next_frame: PhysFrame, + min_frame: PhysFrame, } +/// Start address of the first frame that is not part of the lower 1MB of frames +const LOWER_MEMORY_END_PAGE: u64 = 0x100_000; + impl LegacyFrameAllocator where I: ExactSizeIterator + Clone, @@ -40,20 +44,26 @@ where /// Skips the frame at physical address zero to avoid potential problems. For example /// identity-mapping the frame at address zero is not valid in Rust, because Rust's `core` /// library assumes that references can never point to virtual address `0`. + /// Also skips the lower 1MB of frames, there are use cases that require lower conventional memory access (Such as SMP SIPI). pub fn new(memory_map: I) -> Self { // skip frame 0 because the rust core library does not see 0 as a valid address - let start_frame = PhysFrame::containing_address(PhysAddr::new(0x1000)); + // Also skip at least the lower 1MB of frames, there are use cases that require lower conventional memory access (Such as SMP SIPI). + let start_frame = PhysFrame::containing_address(PhysAddr::new(LOWER_MEMORY_END_PAGE)); Self::new_starting_at(start_frame, memory_map) } /// Creates a new frame allocator based on the given legacy memory regions. Skips any frames - /// before the given `frame`. + /// before the given `frame` or `0x10000`(1MB) whichever is higher, there are use cases that require + /// lower conventional memory access (Such as SMP SIPI). pub fn new_starting_at(frame: PhysFrame, memory_map: I) -> Self { + let lower_mem_end = PhysFrame::containing_address(PhysAddr::new(LOWER_MEMORY_END_PAGE)); + let frame = core::cmp::max(frame, lower_mem_end); Self { original: memory_map.clone(), memory_map, current_descriptor: None, next_frame: frame, + min_frame: frame, } } @@ -71,6 +81,7 @@ where if self.next_frame <= end_frame { let ret = self.next_frame; self.next_frame += 1; + Some(ret) } else { None @@ -125,14 +136,44 @@ where let next_free = self.next_frame.start_address(); let kind = match descriptor.kind() { MemoryRegionKind::Usable => { - if end <= next_free { + if end <= next_free && start >= self.min_frame.start_address() { MemoryRegionKind::Bootloader } else if descriptor.start() >= next_free { MemoryRegionKind::Usable + } else if end <= self.min_frame.start_address() { + // treat regions before min_frame as usable + // this allows for access to the lower 1MB of frames + MemoryRegionKind::Usable + } else if end <= next_free { + // part of the region is used -> add it separately + // first part of the region is in lower 1MB, later part is used + let free_region = MemoryRegion { + start: descriptor.start().as_u64(), + end: self.min_frame.start_address().as_u64(), + kind: MemoryRegionKind::Usable, + }; + Self::add_region(free_region, regions, &mut next_index); + + // add bootloader part normally + start = self.min_frame.start_address(); + MemoryRegionKind::Bootloader } else { + if start < self.min_frame.start_address() { + // part of the region is in lower memory + let lower_region = MemoryRegion { + start: start.as_u64(), + end: self.min_frame.start_address().as_u64(), + kind: MemoryRegionKind::Usable, + }; + Self::add_region(lower_region, regions, &mut next_index); + + start = self.min_frame.start_address(); + } + // part of the region is used -> add it separately + // first part of the region is used, later part is free let used_region = MemoryRegion { - start: descriptor.start().as_u64(), + start: start.as_u64(), end: next_free.as_u64(), kind: MemoryRegionKind::Bootloader, }; diff --git a/tests/lower_memory_free.rs b/tests/lower_memory_free.rs new file mode 100644 index 00000000..aedaf061 --- /dev/null +++ b/tests/lower_memory_free.rs @@ -0,0 +1,7 @@ +use bootloader_test_runner::run_test_kernel; +#[test] +fn lower_memory_free() { + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_LOWER_MEMORY_FREE_lower_memory_free" + )); +} diff --git a/tests/test_kernels/lower_memory_free/Cargo.toml b/tests/test_kernels/lower_memory_free/Cargo.toml new file mode 100644 index 00000000..65b06da2 --- /dev/null +++ b/tests/test_kernels/lower_memory_free/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "test_kernel_lower_memory_free" +version = "0.1.0" +edition = "2021" + +[dependencies] +bootloader_api = { path = "../../../api" } +x86_64 = { version = "0.14.7", default-features = false, features = [ + "instructions", + "inline_asm", +] } +uart_16550 = "0.2.10" diff --git a/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs b/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs new file mode 100644 index 00000000..1bc91aef --- /dev/null +++ b/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs @@ -0,0 +1,65 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{ + config::Mapping, entry_point, info::MemoryRegionKind, BootInfo, BootloaderConfig, +}; +use test_kernel_lower_memory_free::{exit_qemu, QemuExitCode}; + +const LOWER_MEMORY_END_PAGE: u64 = 0x0010_0000; +const WRITE_TEST_UNTIL: u64 = 0x4000_0000; + +pub const BOOTLOADER_CONFIG: BootloaderConfig = { + let mut config = BootloaderConfig::new_default(); + config.mappings.physical_memory = Some(Mapping::FixedAddress(0x0000_4000_0000_0000)); + config +}; + +entry_point!(kernel_main, config = &BOOTLOADER_CONFIG); + +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { + use core::fmt::Write; + use test_kernel_lower_memory_free::serial; + + let phys_mem_offset = boot_info.physical_memory_offset.into_option().unwrap(); + + let mut count = 0; + for region in boot_info.memory_regions.iter() { + writeln!( + serial(), + "Region: {:016x}-{:016x} - {:?}", + region.start, + region.end, + region.kind + ) + .unwrap(); + if region.kind == MemoryRegionKind::Usable && region.start < LOWER_MEMORY_END_PAGE { + let end = core::cmp::min(region.end, LOWER_MEMORY_END_PAGE); + let pages = (end - region.start) / 4096; + count += pages; + } + if region.kind == MemoryRegionKind::Usable && region.start < WRITE_TEST_UNTIL { + let end = core::cmp::min(region.end, WRITE_TEST_UNTIL); + // ensure region is actually writable + let addr = phys_mem_offset + region.start; + let size = end - region.start; + unsafe { + core::ptr::write_bytes(addr as *mut u8, 0xff, size as usize); + } + } + } + + writeln!(serial(), "Free lower memory page count: {}", count).unwrap(); + assert!(count > 0x10); // 0x10 chosen arbirarily, we need _some_ free conventional memory, but not all of it. Some, especially on BIOS, may be reserved for hardware. + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[panic_handler] +#[cfg(not(test))] +fn panic(info: &core::panic::PanicInfo) -> ! { + use core::fmt::Write; + + let _ = writeln!(test_kernel_lower_memory_free::serial(), "PANIC: {}", info); + exit_qemu(QemuExitCode::Failed); +} diff --git a/tests/test_kernels/lower_memory_free/src/lib.rs b/tests/test_kernels/lower_memory_free/src/lib.rs new file mode 100644 index 00000000..4e46fdb6 --- /dev/null +++ b/tests/test_kernels/lower_memory_free/src/lib.rs @@ -0,0 +1,27 @@ +#![no_std] + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum QemuExitCode { + Success = 0x10, + Failed = 0x11, +} + +pub fn exit_qemu(exit_code: QemuExitCode) -> ! { + use x86_64::instructions::{nop, port::Port}; + + unsafe { + let mut port = Port::new(0xf4); + port.write(exit_code as u32); + } + + loop { + nop(); + } +} + +pub fn serial() -> uart_16550::SerialPort { + let mut port = unsafe { uart_16550::SerialPort::new(0x3F8) }; + port.init(); + port +} From e09e68a9081d3c50414b58997fbe6af942e8a91b Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Mon, 17 Jun 2024 01:26:33 +0200 Subject: [PATCH 34/80] Rework: LegacyFrameAllocator::construct_memory_map The new implementation takes in a list of slices that are used by the bootloader. It then goes through all regions and checks if they overlap any of those slices. If so, the region is split and this process is started recursively until none of the usable regions overlap the memory used by the bootloader. --- bios/common/src/lib.rs | 1 + bios/stage-2/src/main.rs | 4 + bios/stage-4/src/main.rs | 17 +- common/src/legacy_memory_region.rs | 351 +++++++++++++++++------------ common/src/lib.rs | 20 +- 5 files changed, 238 insertions(+), 155 deletions(-) diff --git a/bios/common/src/lib.rs b/bios/common/src/lib.rs index 166e12df..de20d0e6 100644 --- a/bios/common/src/lib.rs +++ b/bios/common/src/lib.rs @@ -5,6 +5,7 @@ pub mod racy_cell; #[cfg_attr(feature = "debug", derive(Debug))] #[repr(C)] pub struct BiosInfo { + pub stage_3: Region, pub stage_4: Region, pub kernel: Region, pub ramdisk: Region, diff --git a/bios/stage-2/src/main.rs b/bios/stage-2/src/main.rs index b5b07d65..95ec8c79 100644 --- a/bios/stage-2/src/main.rs +++ b/bios/stage-2/src/main.rs @@ -145,6 +145,10 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! { vesa_mode.enable().unwrap(); let mut info = BiosInfo { + stage_3: Region { + start: STAGE_3_DST as u64, + len: stage_3_len, + }, stage_4: Region { start: stage_4_dst as u64, len: stage_4_len, diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index cf159a61..028ec9ae 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -4,7 +4,8 @@ use crate::memory_descriptor::MemoryRegion; use bootloader_api::info::{FrameBufferInfo, PixelFormat}; use bootloader_boot_config::{BootConfig, LevelFilter}; -use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion}; +use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion, Region}; +use bootloader_x86_64_common::legacy_memory_region::UsedMemorySlice; use bootloader_x86_64_common::RawFrameBufferInfo; use bootloader_x86_64_common::{ legacy_memory_region::LegacyFrameAllocator, load_and_switch_to_kernel, Kernel, PageTables, @@ -55,9 +56,10 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { }; let kernel_size = info.kernel.len; let next_free_frame = PhysFrame::containing_address(PhysAddr::new(info.last_used_addr)) + 1; - let mut frame_allocator = LegacyFrameAllocator::new_starting_at( + let mut frame_allocator = LegacyFrameAllocator::new_with_used_slices( next_free_frame, memory_map.iter().copied().map(MemoryRegion), + used_memory_slices(info), ); // We identity-mapped all memory, so the offset between physical and virtual addresses is 0 @@ -216,6 +218,17 @@ fn init_logger( framebuffer_info } +fn used_memory_slices(info: &BiosInfo) -> impl Iterator + Clone { + // skip kernel and ramdisk because they are handled individually by the + // uefi/bios common code + [info.stage_3, info.stage_4, info.config_file] + .into_iter() + .map(|region| UsedMemorySlice { + start: PhysAddr::new(region.start).as_u64(), + len: region.len, + }) +} + /// Creates page table abstraction types for both the bootloader and kernel page tables. fn create_page_tables(frame_allocator: &mut impl FrameAllocator) -> PageTables { // We identity-mapped all memory, so the offset between physical and virtual addresses is 0 diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index 1fbf1cfb..8a74c268 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -1,10 +1,23 @@ use bootloader_api::info::{MemoryRegion, MemoryRegionKind}; -use core::mem::MaybeUninit; +use core::{ + iter::{empty, Empty}, + mem::MaybeUninit, +}; use x86_64::{ structures::paging::{FrameAllocator, PhysFrame, Size4KiB}, PhysAddr, }; +/// A slice of memory that is used by the bootloader and needs to be reserved +/// in the kernel +#[derive(Clone, Copy, Debug)] +pub struct UsedMemorySlice { + /// the physical start of the slice + pub start: u64, + /// the length of the slice + pub len: u64, +} + /// Abstraction trait for a memory region returned by the UEFI or BIOS firmware. pub trait LegacyMemoryRegion: Copy + core::fmt::Debug { /// Returns the physical start address of the region. @@ -23,18 +36,19 @@ pub trait LegacyMemoryRegion: Copy + core::fmt::Debug { } /// A physical frame allocator based on a BIOS or UEFI provided memory map. -pub struct LegacyFrameAllocator { +pub struct LegacyFrameAllocator { original: I, memory_map: I, current_descriptor: Option, next_frame: PhysFrame, min_frame: PhysFrame, + used_slices: S, } /// Start address of the first frame that is not part of the lower 1MB of frames const LOWER_MEMORY_END_PAGE: u64 = 0x100_000; -impl LegacyFrameAllocator +impl LegacyFrameAllocator> where I: ExactSizeIterator + Clone, I::Item: LegacyMemoryRegion, @@ -56,14 +70,28 @@ where /// before the given `frame` or `0x10000`(1MB) whichever is higher, there are use cases that require /// lower conventional memory access (Such as SMP SIPI). pub fn new_starting_at(frame: PhysFrame, memory_map: I) -> Self { + Self::new_with_used_slices(frame, memory_map, empty()) + } +} + +impl LegacyFrameAllocator +where + I: ExactSizeIterator + Clone, + I::Item: LegacyMemoryRegion, + S: Iterator + Clone, +{ + pub fn new_with_used_slices(start_frame: PhysFrame, memory_map: I, used_slices: S) -> Self { + // skip frame 0 because the rust core library does not see 0 as a valid address + // Also skip at least the lower 1MB of frames, there are use cases that require lower conventional memory access (Such as SMP SIPI). let lower_mem_end = PhysFrame::containing_address(PhysAddr::new(LOWER_MEMORY_END_PAGE)); - let frame = core::cmp::max(frame, lower_mem_end); + let frame = core::cmp::max(start_frame, lower_mem_end); Self { original: memory_map.clone(), memory_map, current_descriptor: None, next_frame: frame, min_frame: frame, + used_slices, } } @@ -126,64 +154,19 @@ where ramdisk_slice_start: Option, ramdisk_slice_len: u64, ) -> &mut [MemoryRegion] { - let mut next_index = 0; - let kernel_slice_start = kernel_slice_start.as_u64(); - let ramdisk_slice_start = ramdisk_slice_start.map(|a| a.as_u64()); + let used_slices = Self::used_regions_iter( + self.min_frame, + self.next_frame, + kernel_slice_start, + kernel_slice_len, + ramdisk_slice_start, + ramdisk_slice_len, + self.used_slices, + ); + let mut next_index = 0; for descriptor in self.original { - let mut start = descriptor.start(); - let end = start + descriptor.len(); - let next_free = self.next_frame.start_address(); let kind = match descriptor.kind() { - MemoryRegionKind::Usable => { - if end <= next_free && start >= self.min_frame.start_address() { - MemoryRegionKind::Bootloader - } else if descriptor.start() >= next_free { - MemoryRegionKind::Usable - } else if end <= self.min_frame.start_address() { - // treat regions before min_frame as usable - // this allows for access to the lower 1MB of frames - MemoryRegionKind::Usable - } else if end <= next_free { - // part of the region is used -> add it separately - // first part of the region is in lower 1MB, later part is used - let free_region = MemoryRegion { - start: descriptor.start().as_u64(), - end: self.min_frame.start_address().as_u64(), - kind: MemoryRegionKind::Usable, - }; - Self::add_region(free_region, regions, &mut next_index); - - // add bootloader part normally - start = self.min_frame.start_address(); - MemoryRegionKind::Bootloader - } else { - if start < self.min_frame.start_address() { - // part of the region is in lower memory - let lower_region = MemoryRegion { - start: start.as_u64(), - end: self.min_frame.start_address().as_u64(), - kind: MemoryRegionKind::Usable, - }; - Self::add_region(lower_region, regions, &mut next_index); - - start = self.min_frame.start_address(); - } - - // part of the region is used -> add it separately - // first part of the region is used, later part is free - let used_region = MemoryRegion { - start: start.as_u64(), - end: next_free.as_u64(), - kind: MemoryRegionKind::Bootloader, - }; - Self::add_region(used_region, regions, &mut next_index); - - // add unused part normally - start = next_free; - MemoryRegionKind::Usable - } - } _ if descriptor.usable_after_bootloader_exit() => { // Region was not usable before, but it will be as soon as // the bootloader passes control to the kernel. We don't @@ -195,97 +178,15 @@ where other => other, }; + let end = descriptor.start() + descriptor.len(); let region = MemoryRegion { - start: start.as_u64(), + start: descriptor.start().as_u64(), end: end.as_u64(), kind, }; - - // check if region overlaps with kernel or ramdisk - let kernel_slice_end = kernel_slice_start + kernel_slice_len; - let ramdisk_slice_end = ramdisk_slice_start.map(|s| s + ramdisk_slice_len); - if region.kind == MemoryRegionKind::Usable - && kernel_slice_start < region.end - && kernel_slice_end > region.start - { - // region overlaps with kernel -> we might need to split it - - // ensure that the kernel allocation does not span multiple regions - assert!( - kernel_slice_start >= region.start, - "region overlaps with kernel, but kernel begins before region \ - (kernel_slice_start: {kernel_slice_start:#x}, region_start: {:#x})", - region.start - ); - assert!( - kernel_slice_end <= region.end, - "region overlaps with kernel, but region ends before kernel \ - (kernel_slice_end: {kernel_slice_end:#x}, region_end: {:#x})", - region.end, - ); - - // split the region into three parts - let before_kernel = MemoryRegion { - end: kernel_slice_start, - ..region - }; - let kernel = MemoryRegion { - start: kernel_slice_start, - end: kernel_slice_end, - kind: MemoryRegionKind::Bootloader, - }; - let after_kernel = MemoryRegion { - start: kernel_slice_end, - ..region - }; - - // add the three regions (empty regions are ignored in `add_region`) - Self::add_region(before_kernel, regions, &mut next_index); - Self::add_region(kernel, regions, &mut next_index); - Self::add_region(after_kernel, regions, &mut next_index); - } else if region.kind == MemoryRegionKind::Usable - && ramdisk_slice_start.map(|s| s < region.end).unwrap_or(false) - && ramdisk_slice_end.map(|e| e > region.start).unwrap_or(false) - { - // region overlaps with ramdisk -> we might need to split it - let ramdisk_slice_start = ramdisk_slice_start.unwrap(); - let ramdisk_slice_end = ramdisk_slice_end.unwrap(); - - // ensure that the ramdisk allocation does not span multiple regions - assert!( - ramdisk_slice_start >= region.start, - "region overlaps with ramdisk, but ramdisk begins before region \ - (ramdisk_start: {ramdisk_slice_start:#x}, region_start: {:#x})", - region.start - ); - assert!( - ramdisk_slice_end <= region.end, - "region overlaps with ramdisk, but region ends before ramdisk \ - (ramdisk_end: {ramdisk_slice_end:#x}, region_end: {:#x})", - region.end, - ); - - // split the region into three parts - let before_ramdisk = MemoryRegion { - end: ramdisk_slice_start, - ..region - }; - let ramdisk = MemoryRegion { - start: ramdisk_slice_start, - end: ramdisk_slice_end, - kind: MemoryRegionKind::Bootloader, - }; - let after_ramdisk = MemoryRegion { - start: ramdisk_slice_end, - ..region - }; - - // add the three regions (empty regions are ignored in `add_region`) - Self::add_region(before_ramdisk, regions, &mut next_index); - Self::add_region(ramdisk, regions, &mut next_index); - Self::add_region(after_ramdisk, regions, &mut next_index); + if region.kind == MemoryRegionKind::Usable { + Self::split_and_add_region(region, regions, &mut next_index, used_slices.clone()); } else { - // add the region normally Self::add_region(region, regions, &mut next_index); } } @@ -298,6 +199,125 @@ where } } + fn used_regions_iter( + min_frame: PhysFrame, + next_free: PhysFrame, + kernel_slice_start: PhysAddr, + kernel_slice_len: u64, + ramdisk_slice_start: Option, + ramdisk_slice_len: u64, + used_slices: S, + ) -> impl Iterator + Clone { + BootloaderUsedMemorySliceIter { + bootloader: UsedMemorySlice { + start: min_frame.start_address().as_u64(), + // TODO: unit test that this is not an off by 1 + len: next_free.start_address() - min_frame.start_address(), + }, + kernel: UsedMemorySlice { + start: kernel_slice_start.as_u64(), + len: kernel_slice_len, + }, + ramdisk: ramdisk_slice_start.map(|start| UsedMemorySlice { + start: start.as_u64(), + len: ramdisk_slice_len, + }), + state: KernelRamIterState::Bootloader, + } + .chain(used_slices) + } + + // TODO unit test + fn split_and_add_region<'a, U>( + region: MemoryRegion, + regions: &mut [MaybeUninit], + next_index: &mut usize, + used_slices: U, + ) where + U: Iterator + Clone, + { + assert!(region.kind == MemoryRegionKind::Usable); + if region.start == region.end { + // skip zero sized regions + return; + } + + for slice in used_slices.clone() { + let slice_end = slice.start + slice.len; + if region.end <= slice.start || region.start >= slice_end { + // region and slice don't overlap + continue; + } + + if region.start >= slice.start && region.end <= slice_end { + // region is completly covered by slice + let bootloader = MemoryRegion { + start: region.start, + end: region.end, + kind: MemoryRegionKind::Bootloader, + }; + Self::add_region(bootloader, regions, next_index); + return; + } + if region.start < slice.start && region.end <= slice_end { + // there is a usable region before the bootloader slice + let before = MemoryRegion { + start: region.start, + end: slice.start, + kind: MemoryRegionKind::Usable, + }; + + let bootloader = MemoryRegion { + start: slice.start, + end: region.end, + kind: MemoryRegionKind::Bootloader, + }; + Self::split_and_add_region(before, regions, next_index, used_slices); + Self::add_region(bootloader, regions, next_index); + return; + } else if region.start < slice.start && region.end > slice_end { + // there is usable region before and after the bootloader slice + let before = MemoryRegion { + start: region.start, + end: slice.start, + kind: MemoryRegionKind::Usable, + }; + let bootloader = MemoryRegion { + start: slice.start, + end: slice_end, + kind: MemoryRegionKind::Bootloader, + }; + let after = MemoryRegion { + start: slice_end, + end: region.end, + kind: MemoryRegionKind::Usable, + }; + Self::split_and_add_region(before, regions, next_index, used_slices.clone()); + Self::add_region(bootloader, regions, next_index); + Self::split_and_add_region(after, regions, next_index, used_slices.clone()); + return; + } + if region.start >= slice.start && region.end > slice_end { + // there is a usable region after the bootloader slice + let bootloader = MemoryRegion { + start: region.start, + end: slice_end, + kind: MemoryRegionKind::Bootloader, + }; + let after = MemoryRegion { + start: slice_end, + end: region.end, + kind: MemoryRegionKind::Usable, + }; + Self::add_region(bootloader, regions, next_index); + Self::split_and_add_region(after, regions, next_index, used_slices); + return; + } + } + // region is not coverd by any slice + Self::add_region(region, regions, next_index); + } + fn add_region( region: MemoryRegion, regions: &mut [MaybeUninit], @@ -318,10 +338,11 @@ where } } -unsafe impl FrameAllocator for LegacyFrameAllocator +unsafe impl FrameAllocator for LegacyFrameAllocator where I: ExactSizeIterator + Clone, I::Item: LegacyMemoryRegion, + S: Iterator + Clone, { fn allocate_frame(&mut self) -> Option> { if let Some(current_descriptor) = self.current_descriptor { @@ -347,3 +368,41 @@ where None } } + +#[derive(Clone)] +struct BootloaderUsedMemorySliceIter { + bootloader: UsedMemorySlice, + kernel: UsedMemorySlice, + ramdisk: Option, + state: KernelRamIterState, +} + +#[derive(Clone)] +enum KernelRamIterState { + Bootloader, + Kernel, + Ramdisk, + Done, +} + +impl Iterator for BootloaderUsedMemorySliceIter { + type Item = UsedMemorySlice; + + fn next(&mut self) -> Option { + match self.state { + KernelRamIterState::Bootloader => { + self.state = KernelRamIterState::Kernel; + Some(self.bootloader) + } + KernelRamIterState::Kernel => { + self.state = KernelRamIterState::Ramdisk; + Some(self.kernel) + } + KernelRamIterState::Ramdisk => { + self.state = KernelRamIterState::Done; + self.ramdisk + } + KernelRamIterState::Done => None, + } + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index c17f68fc..9eae870d 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -10,6 +10,7 @@ use bootloader_api::{ }; use bootloader_boot_config::{BootConfig, LevelFilter}; use core::{alloc::Layout, arch::asm, mem::MaybeUninit, slice}; +use legacy_memory_region::UsedMemorySlice; use level_4_entries::UsedLevel4Entries; use usize_conversions::FromUsize; use x86_64::{ @@ -123,16 +124,17 @@ impl<'a> Kernel<'a> { /// This function is a convenience function that first calls [`set_up_mappings`], then /// [`create_boot_info`], and finally [`switch_to_kernel`]. The given arguments are passed /// directly to these functions, so see their docs for more info. -pub fn load_and_switch_to_kernel( +pub fn load_and_switch_to_kernel( kernel: Kernel, boot_config: BootConfig, - mut frame_allocator: LegacyFrameAllocator, + mut frame_allocator: LegacyFrameAllocator, mut page_tables: PageTables, system_info: SystemInfo, ) -> ! where I: ExactSizeIterator + Clone, D: LegacyMemoryRegion, + S: Iterator + Clone, { let config = kernel.config; let mut mappings = set_up_mappings( @@ -168,9 +170,9 @@ where /// /// This function reacts to unexpected situations (e.g. invalid kernel ELF file) with a panic, so /// errors are not recoverable. -pub fn set_up_mappings( +pub fn set_up_mappings( kernel: Kernel, - frame_allocator: &mut LegacyFrameAllocator, + frame_allocator: &mut LegacyFrameAllocator, page_tables: &mut PageTables, framebuffer: Option<&RawFrameBufferInfo>, config: &BootloaderConfig, @@ -179,6 +181,7 @@ pub fn set_up_mappings( where I: ExactSizeIterator + Clone, D: LegacyMemoryRegion, + S: Iterator + Clone, { let kernel_page_table = &mut page_tables.kernel; @@ -466,10 +469,10 @@ pub struct Mappings { /// address space at the same address. This makes it possible to return a Rust /// reference that is valid in both address spaces. The necessary physical frames /// are taken from the given `frame_allocator`. -pub fn create_boot_info( +pub fn create_boot_info( config: &BootloaderConfig, boot_config: &BootConfig, - mut frame_allocator: LegacyFrameAllocator, + mut frame_allocator: LegacyFrameAllocator, page_tables: &mut PageTables, mappings: &mut Mappings, system_info: SystemInfo, @@ -477,13 +480,16 @@ pub fn create_boot_info( where I: ExactSizeIterator + Clone, D: LegacyMemoryRegion, + S: Iterator + Clone, { log::info!("Allocate bootinfo"); // allocate and map space for the boot info let (boot_info, memory_regions) = { let boot_info_layout = Layout::new::(); - let regions = frame_allocator.len() + 4; // up to 4 regions might be split into used/unused + // TODO the assumption here about the regions is wrong + // figure out what the correct region count should be + let regions = frame_allocator.len() + 4 + 30; // up to 4 regions might be split into used/unused let memory_regions_layout = Layout::array::(regions).unwrap(); let (combined, memory_regions_offset) = boot_info_layout.extend(memory_regions_layout).unwrap(); From 444627888ca174e83232443aa5911f24c61383ba Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sat, 22 Jun 2024 17:34:32 +0200 Subject: [PATCH 35/80] Trivial PR changes --- bios/stage-4/src/main.rs | 4 ++-- common/src/legacy_memory_region.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 028ec9ae..446a33a0 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -224,8 +224,8 @@ fn used_memory_slices(info: &BiosInfo) -> impl Iterator [info.stage_3, info.stage_4, info.config_file] .into_iter() .map(|region| UsedMemorySlice { - start: PhysAddr::new(region.start).as_u64(), - len: region.len, + start: region.start, + end: region.start + region.len, }) } diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index 8a74c268..fd32f548 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -14,8 +14,8 @@ use x86_64::{ pub struct UsedMemorySlice { /// the physical start of the slice pub start: u64, - /// the length of the slice - pub len: u64, + /// The physical end address (exclusive) of the region. + pub end: u64, } /// Abstraction trait for a memory region returned by the UEFI or BIOS firmware. @@ -46,7 +46,7 @@ pub struct LegacyFrameAllocator { } /// Start address of the first frame that is not part of the lower 1MB of frames -const LOWER_MEMORY_END_PAGE: u64 = 0x100_000; +const LOWER_MEMORY_END_PAGE: u64 = 0x10_0000; impl LegacyFrameAllocator> where @@ -212,15 +212,15 @@ where bootloader: UsedMemorySlice { start: min_frame.start_address().as_u64(), // TODO: unit test that this is not an off by 1 - len: next_free.start_address() - min_frame.start_address(), + end: next_free.start_address() - min_frame.start_address(), }, kernel: UsedMemorySlice { start: kernel_slice_start.as_u64(), - len: kernel_slice_len, + end: kernel_slice_len, }, ramdisk: ramdisk_slice_start.map(|start| UsedMemorySlice { start: start.as_u64(), - len: ramdisk_slice_len, + end: ramdisk_slice_len, }), state: KernelRamIterState::Bootloader, } @@ -243,7 +243,7 @@ where } for slice in used_slices.clone() { - let slice_end = slice.start + slice.len; + let slice_end = slice.start + slice.end; if region.end <= slice.start || region.start >= slice_end { // region and slice don't overlap continue; From f3d383e1be77318a2ee6abf8e84f2b07816424f1 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sat, 22 Jun 2024 17:51:47 +0200 Subject: [PATCH 36/80] New test to check usable memory is writable split out the write check from the lower_memory_free test. Those 2 aren't really related --- Cargo.lock | 10 +++++ Cargo.toml | 2 + .../src/bin/lower_memory_free.rs | 12 ------ .../write_usable_memory/Cargo.toml | 12 ++++++ .../src/bin/write_usable_memory.rs | 42 +++++++++++++++++++ .../write_usable_memory/src/lib.rs | 27 ++++++++++++ tests/write_usable_memory.rs | 7 ++++ 7 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 tests/test_kernels/write_usable_memory/Cargo.toml create mode 100644 tests/test_kernels/write_usable_memory/src/bin/write_usable_memory.rs create mode 100644 tests/test_kernels/write_usable_memory/src/lib.rs create mode 100644 tests/write_usable_memory.rs diff --git a/Cargo.lock b/Cargo.lock index f257994d..34decae3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,6 +177,7 @@ dependencies = [ "test_kernel_min_stack", "test_kernel_pie", "test_kernel_ramdisk", + "test_kernel_write_usable_memory", ] [[package]] @@ -1133,6 +1134,15 @@ dependencies = [ "x86_64", ] +[[package]] +name = "test_kernel_write_usable_memory" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + [[package]] name = "thiserror" version = "1.0.41" diff --git a/Cargo.toml b/Cargo.toml index 4de19416..4ff329fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ members = [ "tests/test_kernels/ramdisk", "tests/test_kernels/min_stack", "tests/test_kernels/lower_memory_free", + "tests/test_kernels/write_usable_memory", ] exclude = ["examples/basic", "examples/test_framework"] @@ -69,6 +70,7 @@ test_kernel_ramdisk = { path = "tests/test_kernels/ramdisk", artifact = "bin", t test_kernel_config_file = { path = "tests/test_kernels/config_file", artifact = "bin", target = "x86_64-unknown-none" } test_kernel_min_stack = { path = "tests/test_kernels/min_stack", artifact = "bin", target = "x86_64-unknown-none" } test_kernel_lower_memory_free = { path = "tests/test_kernels/lower_memory_free", artifact = "bin", target = "x86_64-unknown-none" } +test_kernel_write_usable_memory = { path = "tests/test_kernels/write_usable_memory", artifact = "bin", target = "x86_64-unknown-none" } [profile.dev] panic = "abort" diff --git a/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs b/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs index 1bc91aef..ff337ec2 100644 --- a/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs +++ b/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs @@ -7,7 +7,6 @@ use bootloader_api::{ use test_kernel_lower_memory_free::{exit_qemu, QemuExitCode}; const LOWER_MEMORY_END_PAGE: u64 = 0x0010_0000; -const WRITE_TEST_UNTIL: u64 = 0x4000_0000; pub const BOOTLOADER_CONFIG: BootloaderConfig = { let mut config = BootloaderConfig::new_default(); @@ -21,8 +20,6 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! { use core::fmt::Write; use test_kernel_lower_memory_free::serial; - let phys_mem_offset = boot_info.physical_memory_offset.into_option().unwrap(); - let mut count = 0; for region in boot_info.memory_regions.iter() { writeln!( @@ -38,15 +35,6 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! { let pages = (end - region.start) / 4096; count += pages; } - if region.kind == MemoryRegionKind::Usable && region.start < WRITE_TEST_UNTIL { - let end = core::cmp::min(region.end, WRITE_TEST_UNTIL); - // ensure region is actually writable - let addr = phys_mem_offset + region.start; - let size = end - region.start; - unsafe { - core::ptr::write_bytes(addr as *mut u8, 0xff, size as usize); - } - } } writeln!(serial(), "Free lower memory page count: {}", count).unwrap(); diff --git a/tests/test_kernels/write_usable_memory/Cargo.toml b/tests/test_kernels/write_usable_memory/Cargo.toml new file mode 100644 index 00000000..88cf640f --- /dev/null +++ b/tests/test_kernels/write_usable_memory/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "test_kernel_write_usable_memory" +version = "0.1.0" +edition = "2021" + +[dependencies] +bootloader_api = { path = "../../../api" } +x86_64 = { version = "0.14.7", default-features = false, features = [ + "instructions", + "inline_asm", +] } +uart_16550 = "0.2.10" diff --git a/tests/test_kernels/write_usable_memory/src/bin/write_usable_memory.rs b/tests/test_kernels/write_usable_memory/src/bin/write_usable_memory.rs new file mode 100644 index 00000000..95a27d37 --- /dev/null +++ b/tests/test_kernels/write_usable_memory/src/bin/write_usable_memory.rs @@ -0,0 +1,42 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{ + config::Mapping, entry_point, info::MemoryRegionKind, BootInfo, BootloaderConfig, +}; +use test_kernel_write_usable_memory::{exit_qemu, QemuExitCode}; + +pub const BOOTLOADER_CONFIG: BootloaderConfig = { + let mut config = BootloaderConfig::new_default(); + config.mappings.physical_memory = Some(Mapping::FixedAddress(0x0000_4000_0000_0000)); + config +}; + +entry_point!(kernel_main, config = &BOOTLOADER_CONFIG); + +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { + let phys_mem_offset = boot_info.physical_memory_offset.into_option().unwrap(); + + for region in boot_info.memory_regions.iter() { + if region.kind == MemoryRegionKind::Usable { + // ensure region is actually writable + let addr = phys_mem_offset + region.start; + let size = region.end - region.start; + unsafe { + core::ptr::write_bytes(addr as *mut u8, 0xff, size as usize); + } + } + } + + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[panic_handler] +#[cfg(not(test))] +fn panic(info: &core::panic::PanicInfo) -> ! { + use core::fmt::Write; + + let _ = writeln!(test_kernel_write_usable_memory::serial(), "PANIC: {}", info); + exit_qemu(QemuExitCode::Failed); +} diff --git a/tests/test_kernels/write_usable_memory/src/lib.rs b/tests/test_kernels/write_usable_memory/src/lib.rs new file mode 100644 index 00000000..4e46fdb6 --- /dev/null +++ b/tests/test_kernels/write_usable_memory/src/lib.rs @@ -0,0 +1,27 @@ +#![no_std] + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum QemuExitCode { + Success = 0x10, + Failed = 0x11, +} + +pub fn exit_qemu(exit_code: QemuExitCode) -> ! { + use x86_64::instructions::{nop, port::Port}; + + unsafe { + let mut port = Port::new(0xf4); + port.write(exit_code as u32); + } + + loop { + nop(); + } +} + +pub fn serial() -> uart_16550::SerialPort { + let mut port = unsafe { uart_16550::SerialPort::new(0x3F8) }; + port.init(); + port +} diff --git a/tests/write_usable_memory.rs b/tests/write_usable_memory.rs new file mode 100644 index 00000000..a2c7b11a --- /dev/null +++ b/tests/write_usable_memory.rs @@ -0,0 +1,7 @@ +use bootloader_test_runner::run_test_kernel; +#[test] +fn lower_memory_free() { + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_WRITE_USABLE_MEMORY_write_usable_memory" + )); +} From 3326e7ae10f3e78526fd3c7c3d4529d00614e786 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sat, 22 Jun 2024 18:17:20 +0200 Subject: [PATCH 37/80] Remove BootloaderUsedMemorySliceIter --- bios/stage-4/src/main.rs | 5 +-- common/src/legacy_memory_region.rs | 72 +++++++++--------------------- 2 files changed, 21 insertions(+), 56 deletions(-) diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 446a33a0..cb52d6dc 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -223,10 +223,7 @@ fn used_memory_slices(info: &BiosInfo) -> impl Iterator // uefi/bios common code [info.stage_3, info.stage_4, info.config_file] .into_iter() - .map(|region| UsedMemorySlice { - start: region.start, - end: region.start + region.len, - }) + .map(|region| UsedMemorySlice::new_from_len(region.start, region.len)) } /// Creates page table abstraction types for both the bootloader and kernel page tables. diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index fd32f548..57a8bdc6 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -18,6 +18,16 @@ pub struct UsedMemorySlice { pub end: u64, } +impl UsedMemorySlice { + /// Creates a new slice + pub fn new_from_len(start: u64, len: u64) -> Self { + Self { + start, + end: start + len, + } + } +} + /// Abstraction trait for a memory region returned by the UEFI or BIOS firmware. pub trait LegacyMemoryRegion: Copy + core::fmt::Debug { /// Returns the physical start address of the region. @@ -208,22 +218,18 @@ where ramdisk_slice_len: u64, used_slices: S, ) -> impl Iterator + Clone { - BootloaderUsedMemorySliceIter { - bootloader: UsedMemorySlice { + [ + UsedMemorySlice { start: min_frame.start_address().as_u64(), - // TODO: unit test that this is not an off by 1 - end: next_free.start_address() - min_frame.start_address(), + end: next_free.start_address().as_u64(), }, - kernel: UsedMemorySlice { - start: kernel_slice_start.as_u64(), - end: kernel_slice_len, - }, - ramdisk: ramdisk_slice_start.map(|start| UsedMemorySlice { - start: start.as_u64(), - end: ramdisk_slice_len, - }), - state: KernelRamIterState::Bootloader, - } + UsedMemorySlice::new_from_len(kernel_slice_start.as_u64(), kernel_slice_len), + ] + .into_iter() + .chain( + ramdisk_slice_start + .map(|start| UsedMemorySlice::new_from_len(start.as_u64(), ramdisk_slice_len)), + ) .chain(used_slices) } @@ -368,41 +374,3 @@ where None } } - -#[derive(Clone)] -struct BootloaderUsedMemorySliceIter { - bootloader: UsedMemorySlice, - kernel: UsedMemorySlice, - ramdisk: Option, - state: KernelRamIterState, -} - -#[derive(Clone)] -enum KernelRamIterState { - Bootloader, - Kernel, - Ramdisk, - Done, -} - -impl Iterator for BootloaderUsedMemorySliceIter { - type Item = UsedMemorySlice; - - fn next(&mut self) -> Option { - match self.state { - KernelRamIterState::Bootloader => { - self.state = KernelRamIterState::Kernel; - Some(self.bootloader) - } - KernelRamIterState::Kernel => { - self.state = KernelRamIterState::Ramdisk; - Some(self.kernel) - } - KernelRamIterState::Ramdisk => { - self.state = KernelRamIterState::Done; - self.ramdisk - } - KernelRamIterState::Done => None, - } - } -} From 57632044b881913e5d5e8cf758ced3b97a507efe Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sat, 22 Jun 2024 19:03:27 +0200 Subject: [PATCH 38/80] Improve construct_memory_map implementation simplify the overlap check into single if condition and move to interative implementation --- common/src/legacy_memory_region.rs | 111 +++++++++++------------------ 1 file changed, 40 insertions(+), 71 deletions(-) diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index 57a8bdc6..4b51c3fe 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -1,5 +1,6 @@ use bootloader_api::info::{MemoryRegion, MemoryRegionKind}; use core::{ + cmp, iter::{empty, Empty}, mem::MaybeUninit, }; @@ -235,7 +236,7 @@ where // TODO unit test fn split_and_add_region<'a, U>( - region: MemoryRegion, + mut region: MemoryRegion, regions: &mut [MaybeUninit], next_index: &mut usize, used_slices: U, @@ -243,85 +244,53 @@ where U: Iterator + Clone, { assert!(region.kind == MemoryRegionKind::Usable); - if region.start == region.end { - // skip zero sized regions - return; - } - - for slice in used_slices.clone() { - let slice_end = slice.start + slice.end; - if region.end <= slice.start || region.start >= slice_end { - // region and slice don't overlap - continue; - } - - if region.start >= slice.start && region.end <= slice_end { - // region is completly covered by slice - let bootloader = MemoryRegion { - start: region.start, - end: region.end, - kind: MemoryRegionKind::Bootloader, - }; - Self::add_region(bootloader, regions, next_index); - return; - } - if region.start < slice.start && region.end <= slice_end { - // there is a usable region before the bootloader slice - let before = MemoryRegion { - start: region.start, - end: slice.start, - kind: MemoryRegionKind::Usable, - }; - - let bootloader = MemoryRegion { - start: slice.start, - end: region.end, - kind: MemoryRegionKind::Bootloader, - }; - Self::split_and_add_region(before, regions, next_index, used_slices); - Self::add_region(bootloader, regions, next_index); - return; - } else if region.start < slice.start && region.end > slice_end { - // there is usable region before and after the bootloader slice - let before = MemoryRegion { + // Each loop iteration takes a chunk of `region` and adds it to + // `regions`. Do this until `region` is empty. + while region.start != region.end { + // Check if there is overlap between `region` and `used_slices`. + if let Some((overlap_start, overlap_end)) = used_slices + .clone() + .map(|slice| { + // Calculate the start and end points of the overlap + // between `slice` and `region`. If `slice` and `region` + // don't overlap, the range will be ill-formed + // (overlap_start > overlap_end). + let overlap_start = cmp::max(region.start, slice.start); + let overlap_end = cmp::min(region.end, slice.end); + (overlap_start, overlap_end) + }) + .filter(|(overlap_start, overlap_end)| { + // Only consider non-empty overlap. + overlap_start < overlap_end + }) + .min_by_key(|&(overlap_start, _)| { + // Find the earliest overlap. + overlap_start + }) + { + // There's no overlapping used slice before `overlap_start`, so + // we know that memory between `region.start` and + // `overlap_start` is usable. + let usable = MemoryRegion { start: region.start, - end: slice.start, + end: overlap_start, kind: MemoryRegionKind::Usable, }; let bootloader = MemoryRegion { - start: slice.start, - end: slice_end, + start: overlap_start, + end: overlap_end, kind: MemoryRegionKind::Bootloader, }; - let after = MemoryRegion { - start: slice_end, - end: region.end, - kind: MemoryRegionKind::Usable, - }; - Self::split_and_add_region(before, regions, next_index, used_slices.clone()); + Self::add_region(usable, regions, next_index); Self::add_region(bootloader, regions, next_index); - Self::split_and_add_region(after, regions, next_index, used_slices.clone()); - return; - } - if region.start >= slice.start && region.end > slice_end { - // there is a usable region after the bootloader slice - let bootloader = MemoryRegion { - start: region.start, - end: slice_end, - kind: MemoryRegionKind::Bootloader, - }; - let after = MemoryRegion { - start: slice_end, - end: region.end, - kind: MemoryRegionKind::Usable, - }; - Self::add_region(bootloader, regions, next_index); - Self::split_and_add_region(after, regions, next_index, used_slices); - return; + // Continue after the overlapped region. + region.start = overlap_end; + } else { + // There's no overlap. We can add the whole region. + Self::add_region(region, regions, next_index); + break; } } - // region is not coverd by any slice - Self::add_region(region, regions, next_index); } fn add_region( From 0c2103204140c65ad7560e6a9afedd2dabefc57c Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sat, 22 Jun 2024 19:06:45 +0200 Subject: [PATCH 39/80] tests for LegacyFrameAllocator::construct_memory_map This test also covers #445 --- .github/workflows/ci.yml | 2 + common/src/legacy_memory_region.rs | 246 +++++++++++++++++++++++++++++ common/src/lib.rs | 2 +- 3 files changed, 249 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec90853d..09170a46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,6 +68,8 @@ jobs: - uses: r7kamura/rust-problem-matchers@v1.1.0 - name: Run api tests run: cargo test -p bootloader_api + - name: Run bootloader common tests + run: cargo test -p bootloader-x86_64-common - name: Run integration tests run: cargo test -- --test-threads 1 diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index 4b51c3fe..c2c5c238 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -343,3 +343,249 @@ where None } } + +#[cfg(test)] +mod tests { + use super::*; + use bootloader_api::info::MemoryRegionKind; + + #[derive(Copy, Clone, Debug)] + struct TestMemoryRegion { + start: PhysAddr, + len: u64, + kind: MemoryRegionKind, + } + + impl LegacyMemoryRegion for TestMemoryRegion { + fn start(&self) -> PhysAddr { + self.start + } + + fn len(&self) -> u64 { + assert!(self.len % 4096 == 0); + self.len + } + + fn kind(&self) -> MemoryRegionKind { + self.kind + } + + fn usable_after_bootloader_exit(&self) -> bool { + match self.kind { + MemoryRegionKind::Usable => true, + _ => false, + } + } + } + + // we need some kind of max phys memory, 4GB seems reasonable + const MAX_PHYS_ADDR: u64 = 0x4000_0000; + + fn create_single_test_region() -> Vec { + vec![TestMemoryRegion { + start: PhysAddr::new(0), + len: MAX_PHYS_ADDR, + kind: MemoryRegionKind::Usable, + }] + } + + #[test] + fn test_kernel_and_ram_in_same_region() { + let regions = create_single_test_region(); + let mut allocator = LegacyFrameAllocator::new(regions.into_iter()); + // allocate at least 1 frame + allocator.allocate_frame(); + + let mut regions = [MaybeUninit::uninit(); 10]; + let kernel_slice_start = PhysAddr::new(0x50000); + let kernel_slice_len = 0x1000; + let ramdisk_slice_start = Some(PhysAddr::new(0x60000)); + let ramdisk_slice_len = 0x2000; + + let kernel_regions = allocator.construct_memory_map( + &mut regions, + kernel_slice_start, + kernel_slice_len, + ramdisk_slice_start, + ramdisk_slice_len, + ); + let mut kernel_regions = kernel_regions.iter(); + // usable memory before the kernel + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x0000, + end: 0x50000, + kind: MemoryRegionKind::Usable + }) + ); + // kernel + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x50000, + end: 0x51000, + kind: MemoryRegionKind::Bootloader + }) + ); + // usabel memory between kernel and ramdisk + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x51000, + end: 0x60000, + kind: MemoryRegionKind::Usable + }) + ); + // ramdisk + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x60000, + end: 0x62000, + kind: MemoryRegionKind::Bootloader + }) + ); + // usabele memory after ramdisk, up until bootloader allocated memory + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x62000, + end: 0x10_0000, + kind: MemoryRegionKind::Usable + }) + ); + // bootloader allocated memory + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x10_0000, + end: 0x10_1000, + kind: MemoryRegionKind::Bootloader + }) + ); + // rest is free + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x10_1000, + end: MAX_PHYS_ADDR, + kind: MemoryRegionKind::Usable + }) + ); + assert_eq!(kernel_regions.next(), None); + } + + #[test] + fn test_multiple_regions() { + let regions = vec![ + TestMemoryRegion { + start: PhysAddr::new(0), + len: 0x10_0000, + kind: MemoryRegionKind::Usable, + }, + TestMemoryRegion { + start: PhysAddr::new(0x10_0000), + len: 0x5000, + kind: MemoryRegionKind::UnknownBios(0), + }, + TestMemoryRegion { + start: PhysAddr::new(0x10_5000), + len: MAX_PHYS_ADDR - 0x10_5000, + kind: MemoryRegionKind::Usable, + }, + ]; + let mut allocator = LegacyFrameAllocator::new(regions.into_iter()); + // allocate at least 1 frame + allocator.allocate_frame(); + + let mut regions = [MaybeUninit::uninit(); 10]; + let kernel_slice_start = PhysAddr::new(0x50000); + let kernel_slice_len = 0x1000; + let ramdisk_slice_start = Some(PhysAddr::new(0x60000)); + let ramdisk_slice_len = 0x2000; + + let kernel_regions = allocator.construct_memory_map( + &mut regions, + kernel_slice_start, + kernel_slice_len, + ramdisk_slice_start, + ramdisk_slice_len, + ); + let mut kernel_regions = kernel_regions.iter(); + + // usable memory before the kernel + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x0000, + end: 0x50000, + kind: MemoryRegionKind::Usable + }) + ); + // kernel + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x50000, + end: 0x51000, + kind: MemoryRegionKind::Bootloader + }) + ); + // usabel memory between kernel and ramdisk + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x51000, + end: 0x60000, + kind: MemoryRegionKind::Usable + }) + ); + // ramdisk + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x60000, + end: 0x62000, + kind: MemoryRegionKind::Bootloader + }) + ); + // usabele memory after ramdisk, up until bootloader allocated memory + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x62000, + end: 0x10_0000, + kind: MemoryRegionKind::Usable + }) + ); + // the unknown bios region + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x10_0000, + end: 0x10_5000, + kind: MemoryRegionKind::UnknownBios(0) + }) + ); + // bootloader allocated memory, this gets pushed back by the bios region + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x10_5000, + end: 0x10_6000, + kind: MemoryRegionKind::Bootloader + }) + ); + // rest is free + assert_eq!( + kernel_regions.next(), + Some(&MemoryRegion { + start: 0x10_6000, + end: MAX_PHYS_ADDR, + kind: MemoryRegionKind::Usable + }) + ); + assert_eq!(kernel_regions.next(), None); + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 9eae870d..4a880188 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,4 +1,4 @@ -#![no_std] +#![cfg_attr(not(test), no_std)] #![feature(step_trait)] #![deny(unsafe_op_in_unsafe_fn)] From 0f4dd1f074dc239c7f332d214d22a99980d912fe Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sat, 22 Jun 2024 19:24:11 +0200 Subject: [PATCH 40/80] Test to ensure MemoryRegions are always frame aligned --- .github/workflows/ci.yml | 1 + common/src/legacy_memory_region.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09170a46..6cd687ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,7 @@ jobs: - name: Run api tests run: cargo test -p bootloader_api - name: Run bootloader common tests + if: runner.os == 'Linux' run: cargo test -p bootloader-x86_64-common - name: Run integration tests run: cargo test -- --test-threads 1 diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index c2c5c238..f76ccb9a 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -389,6 +389,33 @@ mod tests { }] } + #[test] + fn test_all_regions_frame_alligned() { + let regions = create_single_test_region(); + let mut allocator = LegacyFrameAllocator::new(regions.into_iter()); + // allocate at least 1 frame + allocator.allocate_frame(); + + let mut regions = [MaybeUninit::uninit(); 10]; + let kernel_slice_start = PhysAddr::new(0x50000); + let kernel_slice_len = 0x0500; + let ramdisk_slice_start = None; + let ramdisk_slice_len = 0; + + let kernel_regions = allocator.construct_memory_map( + &mut regions, + kernel_slice_start, + kernel_slice_len, + ramdisk_slice_start, + ramdisk_slice_len, + ); + + for region in kernel_regions.iter() { + assert!(region.start % 0x1000 == 0); + assert!(region.end % 0x1000 == 0); + } + } + #[test] fn test_kernel_and_ram_in_same_region() { let regions = create_single_test_region(); From 9b3efcbef5bf1c060d1c96c33ab3cd14ab148130 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sun, 23 Jun 2024 12:30:55 +0200 Subject: [PATCH 41/80] fixup workflow condition --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6cd687ec..e2d9e796 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: - name: Run api tests run: cargo test -p bootloader_api - name: Run bootloader common tests - if: runner.os == 'Linux' + if: runner.arch == 'x86' run: cargo test -p bootloader-x86_64-common - name: Run integration tests run: cargo test -- --test-threads 1 From b0cae120fd6b5c2047c9b93293b4475ee60c10c9 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sun, 23 Jun 2024 13:02:27 +0200 Subject: [PATCH 42/80] Ensure MemoryRegions are aligned to 4096 --- common/src/legacy_memory_region.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index f76ccb9a..bdd9a63f 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -5,6 +5,7 @@ use core::{ mem::MaybeUninit, }; use x86_64::{ + align_down, align_up, structures::paging::{FrameAllocator, PhysFrame, Size4KiB}, PhysAddr, }; @@ -232,9 +233,12 @@ where .map(|start| UsedMemorySlice::new_from_len(start.as_u64(), ramdisk_slice_len)), ) .chain(used_slices) + .map(|slice| UsedMemorySlice { + start: align_down(slice.start, 0x1000), + end: align_up(slice.end, 0x1000), + }) } - // TODO unit test fn split_and_add_region<'a, U>( mut region: MemoryRegion, regions: &mut [MaybeUninit], @@ -347,7 +351,6 @@ where #[cfg(test)] mod tests { use super::*; - use bootloader_api::info::MemoryRegionKind; #[derive(Copy, Clone, Debug)] struct TestMemoryRegion { From b36417fd091932557e4556f09dea3816de28ac59 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sun, 23 Jun 2024 13:24:57 +0200 Subject: [PATCH 43/80] fix max memory region calculation --- common/src/legacy_memory_region.rs | 8 ++++++++ common/src/lib.rs | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index bdd9a63f..2a0eee3e 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -152,6 +152,14 @@ where .unwrap() } + /// Calculate the maximum number of regions produced by [Self::construct_memory_map] + pub fn memory_map_max_region_count(&self) -> usize { + // every used slice can split an original region into 3 new regions, + // this means we need to reserve 2 extra spaces for each slice. + // There are 3 additional slices (kernel, ramdisk and the bootloader heap) + self.len() + (3 + self.used_slices.clone().count()) * 2 + } + /// Converts this type to a boot info memory map. /// /// The memory map is placed in the given `regions` slice. The length of the given slice diff --git a/common/src/lib.rs b/common/src/lib.rs index 4a880188..9280eb14 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -487,9 +487,7 @@ where // allocate and map space for the boot info let (boot_info, memory_regions) = { let boot_info_layout = Layout::new::(); - // TODO the assumption here about the regions is wrong - // figure out what the correct region count should be - let regions = frame_allocator.len() + 4 + 30; // up to 4 regions might be split into used/unused + let regions = frame_allocator.memory_map_max_region_count(); let memory_regions_layout = Layout::array::(regions).unwrap(); let (combined, memory_regions_offset) = boot_info_layout.extend(memory_regions_layout).unwrap(); From 3b07272dba12fb877f5679ffe07820ce53edccd8 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sun, 23 Jun 2024 16:55:50 +0200 Subject: [PATCH 44/80] fix spelling mistake Co-authored-by: Tom Dohrmann --- .../test_kernels/lower_memory_free/src/bin/lower_memory_free.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs b/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs index ff337ec2..9620d1ca 100644 --- a/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs +++ b/tests/test_kernels/lower_memory_free/src/bin/lower_memory_free.rs @@ -38,7 +38,7 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! { } writeln!(serial(), "Free lower memory page count: {}", count).unwrap(); - assert!(count > 0x10); // 0x10 chosen arbirarily, we need _some_ free conventional memory, but not all of it. Some, especially on BIOS, may be reserved for hardware. + assert!(count > 0x10); // 0x10 chosen arbitrarily, we need _some_ free conventional memory, but not all of it. Some, especially on BIOS, may be reserved for hardware. exit_qemu(QemuExitCode::Success); } From 25f48f7e65600ff3acabeb1f7fcc1bae61fb7f83 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sun, 23 Jun 2024 22:35:45 +0200 Subject: [PATCH 45/80] Remove used_slice concept from LegacyFrameAllocator --- bios/common/src/lib.rs | 1 - bios/stage-2/src/main.rs | 4 -- bios/stage-4/src/main.rs | 14 +---- common/src/legacy_memory_region.rs | 83 +++++++++--------------------- common/src/lib.rs | 16 +++--- 5 files changed, 32 insertions(+), 86 deletions(-) diff --git a/bios/common/src/lib.rs b/bios/common/src/lib.rs index de20d0e6..166e12df 100644 --- a/bios/common/src/lib.rs +++ b/bios/common/src/lib.rs @@ -5,7 +5,6 @@ pub mod racy_cell; #[cfg_attr(feature = "debug", derive(Debug))] #[repr(C)] pub struct BiosInfo { - pub stage_3: Region, pub stage_4: Region, pub kernel: Region, pub ramdisk: Region, diff --git a/bios/stage-2/src/main.rs b/bios/stage-2/src/main.rs index 95ec8c79..b5b07d65 100644 --- a/bios/stage-2/src/main.rs +++ b/bios/stage-2/src/main.rs @@ -145,10 +145,6 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! { vesa_mode.enable().unwrap(); let mut info = BiosInfo { - stage_3: Region { - start: STAGE_3_DST as u64, - len: stage_3_len, - }, stage_4: Region { start: stage_4_dst as u64, len: stage_4_len, diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index cb52d6dc..cf159a61 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -4,8 +4,7 @@ use crate::memory_descriptor::MemoryRegion; use bootloader_api::info::{FrameBufferInfo, PixelFormat}; use bootloader_boot_config::{BootConfig, LevelFilter}; -use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion, Region}; -use bootloader_x86_64_common::legacy_memory_region::UsedMemorySlice; +use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion}; use bootloader_x86_64_common::RawFrameBufferInfo; use bootloader_x86_64_common::{ legacy_memory_region::LegacyFrameAllocator, load_and_switch_to_kernel, Kernel, PageTables, @@ -56,10 +55,9 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { }; let kernel_size = info.kernel.len; let next_free_frame = PhysFrame::containing_address(PhysAddr::new(info.last_used_addr)) + 1; - let mut frame_allocator = LegacyFrameAllocator::new_with_used_slices( + let mut frame_allocator = LegacyFrameAllocator::new_starting_at( next_free_frame, memory_map.iter().copied().map(MemoryRegion), - used_memory_slices(info), ); // We identity-mapped all memory, so the offset between physical and virtual addresses is 0 @@ -218,14 +216,6 @@ fn init_logger( framebuffer_info } -fn used_memory_slices(info: &BiosInfo) -> impl Iterator + Clone { - // skip kernel and ramdisk because they are handled individually by the - // uefi/bios common code - [info.stage_3, info.stage_4, info.config_file] - .into_iter() - .map(|region| UsedMemorySlice::new_from_len(region.start, region.len)) -} - /// Creates page table abstraction types for both the bootloader and kernel page tables. fn create_page_tables(frame_allocator: &mut impl FrameAllocator) -> PageTables { // We identity-mapped all memory, so the offset between physical and virtual addresses is 0 diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index 2a0eee3e..ccff22fb 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -48,19 +48,18 @@ pub trait LegacyMemoryRegion: Copy + core::fmt::Debug { } /// A physical frame allocator based on a BIOS or UEFI provided memory map. -pub struct LegacyFrameAllocator { +pub struct LegacyFrameAllocator { original: I, memory_map: I, current_descriptor: Option, next_frame: PhysFrame, min_frame: PhysFrame, - used_slices: S, } /// Start address of the first frame that is not part of the lower 1MB of frames const LOWER_MEMORY_END_PAGE: u64 = 0x10_0000; -impl LegacyFrameAllocator> +impl LegacyFrameAllocator where I: ExactSizeIterator + Clone, I::Item: LegacyMemoryRegion, @@ -82,28 +81,16 @@ where /// before the given `frame` or `0x10000`(1MB) whichever is higher, there are use cases that require /// lower conventional memory access (Such as SMP SIPI). pub fn new_starting_at(frame: PhysFrame, memory_map: I) -> Self { - Self::new_with_used_slices(frame, memory_map, empty()) - } -} - -impl LegacyFrameAllocator -where - I: ExactSizeIterator + Clone, - I::Item: LegacyMemoryRegion, - S: Iterator + Clone, -{ - pub fn new_with_used_slices(start_frame: PhysFrame, memory_map: I, used_slices: S) -> Self { // skip frame 0 because the rust core library does not see 0 as a valid address // Also skip at least the lower 1MB of frames, there are use cases that require lower conventional memory access (Such as SMP SIPI). let lower_mem_end = PhysFrame::containing_address(PhysAddr::new(LOWER_MEMORY_END_PAGE)); - let frame = core::cmp::max(start_frame, lower_mem_end); + let frame = core::cmp::max(frame, lower_mem_end); Self { original: memory_map.clone(), memory_map, current_descriptor: None, next_frame: frame, min_frame: frame, - used_slices, } } @@ -154,10 +141,10 @@ where /// Calculate the maximum number of regions produced by [Self::construct_memory_map] pub fn memory_map_max_region_count(&self) -> usize { - // every used slice can split an original region into 3 new regions, - // this means we need to reserve 2 extra spaces for each slice. - // There are 3 additional slices (kernel, ramdisk and the bootloader heap) - self.len() + (3 + self.used_slices.clone().count()) * 2 + // every used region can split an original region into 3 new regions, + // this means we need to reserve 2 extra spaces for each region. + // There are 3 used regions: kernel, ramdisk and the bootloader heap + self.len() + 6 } /// Converts this type to a boot info memory map. @@ -174,15 +161,22 @@ where ramdisk_slice_start: Option, ramdisk_slice_len: u64, ) -> &mut [MemoryRegion] { - let used_slices = Self::used_regions_iter( - self.min_frame, - self.next_frame, - kernel_slice_start, - kernel_slice_len, - ramdisk_slice_start, - ramdisk_slice_len, - self.used_slices, - ); + let used_slices = [ + UsedMemorySlice { + start: self.min_frame.start_address().as_u64(), + end: self.next_frame.start_address().as_u64(), + }, + UsedMemorySlice::new_from_len(kernel_slice_start.as_u64(), kernel_slice_len), + ] + .into_iter() + .chain( + ramdisk_slice_start + .map(|start| UsedMemorySlice::new_from_len(start.as_u64(), ramdisk_slice_len)), + ) + .map(|slice| UsedMemorySlice { + start: align_down(slice.start, 0x1000), + end: align_up(slice.end, 0x1000), + }); let mut next_index = 0; for descriptor in self.original { @@ -219,34 +213,6 @@ where } } - fn used_regions_iter( - min_frame: PhysFrame, - next_free: PhysFrame, - kernel_slice_start: PhysAddr, - kernel_slice_len: u64, - ramdisk_slice_start: Option, - ramdisk_slice_len: u64, - used_slices: S, - ) -> impl Iterator + Clone { - [ - UsedMemorySlice { - start: min_frame.start_address().as_u64(), - end: next_free.start_address().as_u64(), - }, - UsedMemorySlice::new_from_len(kernel_slice_start.as_u64(), kernel_slice_len), - ] - .into_iter() - .chain( - ramdisk_slice_start - .map(|start| UsedMemorySlice::new_from_len(start.as_u64(), ramdisk_slice_len)), - ) - .chain(used_slices) - .map(|slice| UsedMemorySlice { - start: align_down(slice.start, 0x1000), - end: align_up(slice.end, 0x1000), - }) - } - fn split_and_add_region<'a, U>( mut region: MemoryRegion, regions: &mut [MaybeUninit], @@ -325,11 +291,10 @@ where } } -unsafe impl FrameAllocator for LegacyFrameAllocator +unsafe impl FrameAllocator for LegacyFrameAllocator where I: ExactSizeIterator + Clone, I::Item: LegacyMemoryRegion, - S: Iterator + Clone, { fn allocate_frame(&mut self) -> Option> { if let Some(current_descriptor) = self.current_descriptor { diff --git a/common/src/lib.rs b/common/src/lib.rs index 9280eb14..1c8b1efe 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -10,7 +10,6 @@ use bootloader_api::{ }; use bootloader_boot_config::{BootConfig, LevelFilter}; use core::{alloc::Layout, arch::asm, mem::MaybeUninit, slice}; -use legacy_memory_region::UsedMemorySlice; use level_4_entries::UsedLevel4Entries; use usize_conversions::FromUsize; use x86_64::{ @@ -124,17 +123,16 @@ impl<'a> Kernel<'a> { /// This function is a convenience function that first calls [`set_up_mappings`], then /// [`create_boot_info`], and finally [`switch_to_kernel`]. The given arguments are passed /// directly to these functions, so see their docs for more info. -pub fn load_and_switch_to_kernel( +pub fn load_and_switch_to_kernel( kernel: Kernel, boot_config: BootConfig, - mut frame_allocator: LegacyFrameAllocator, + mut frame_allocator: LegacyFrameAllocator, mut page_tables: PageTables, system_info: SystemInfo, ) -> ! where I: ExactSizeIterator + Clone, D: LegacyMemoryRegion, - S: Iterator + Clone, { let config = kernel.config; let mut mappings = set_up_mappings( @@ -170,9 +168,9 @@ where /// /// This function reacts to unexpected situations (e.g. invalid kernel ELF file) with a panic, so /// errors are not recoverable. -pub fn set_up_mappings( +pub fn set_up_mappings( kernel: Kernel, - frame_allocator: &mut LegacyFrameAllocator, + frame_allocator: &mut LegacyFrameAllocator, page_tables: &mut PageTables, framebuffer: Option<&RawFrameBufferInfo>, config: &BootloaderConfig, @@ -181,7 +179,6 @@ pub fn set_up_mappings( where I: ExactSizeIterator + Clone, D: LegacyMemoryRegion, - S: Iterator + Clone, { let kernel_page_table = &mut page_tables.kernel; @@ -469,10 +466,10 @@ pub struct Mappings { /// address space at the same address. This makes it possible to return a Rust /// reference that is valid in both address spaces. The necessary physical frames /// are taken from the given `frame_allocator`. -pub fn create_boot_info( +pub fn create_boot_info( config: &BootloaderConfig, boot_config: &BootConfig, - mut frame_allocator: LegacyFrameAllocator, + mut frame_allocator: LegacyFrameAllocator, page_tables: &mut PageTables, mappings: &mut Mappings, system_info: SystemInfo, @@ -480,7 +477,6 @@ pub fn create_boot_info( where I: ExactSizeIterator + Clone, D: LegacyMemoryRegion, - S: Iterator + Clone, { log::info!("Allocate bootinfo"); From bf104bd13e323ef2c5bec6c17a3fc38414fcf7a7 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Wed, 10 Jul 2024 19:36:17 +0200 Subject: [PATCH 46/80] always cover at least the first 4 GiB of physical memory --- common/src/legacy_memory_region.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index ccff22fb..baa7d0b9 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -132,11 +132,17 @@ where /// /// Useful for creating a mapping for all physical memory. pub fn max_phys_addr(&self) -> PhysAddr { - self.original + let max = self + .original .clone() .map(|r| r.start() + r.len()) .max() - .unwrap() + .unwrap(); + + // Always cover at least the first 4 GiB of physical memory. That area + // contains useful MMIO regions (local APIC, I/O APIC, PCI bars) that + // we want to make accessible to the kernel even if no DRAM exists >4GiB. + cmp::max(max, PhysAddr::new(0x1_0000_0000)) } /// Calculate the maximum number of regions produced by [Self::construct_memory_map] From ea3f61a57ccd57b7ed37eeed1e53ee6cb2cfdd81 Mon Sep 17 00:00:00 2001 From: spencer3035 <43581946+spencer3035@users.noreply.github.com> Date: Sun, 25 Aug 2024 12:10:06 -0600 Subject: [PATCH 47/80] Fixed "jc fail" instructions not working properly and updated README.md (#453) * Fixed "jc fail" instructions not working properly and updated README.md * Fixed stage 2 fail calls and removed additional asm label --- bios/boot_sector/README.md | 8 ++++---- bios/boot_sector/src/boot.s | 7 ++++++- bios/boot_sector/src/dap.rs | 6 ++++-- bios/boot_sector/src/mbr.rs | 4 ++-- bios/stage-2/src/dap.rs | 6 ++++-- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/bios/boot_sector/README.md b/bios/boot_sector/README.md index 5c9cf4e6..a783d80e 100644 --- a/bios/boot_sector/README.md +++ b/bios/boot_sector/README.md @@ -4,13 +4,13 @@ This executable needs to fit into the 512-byte boot sector, so we need to use al ## Build Commands -1. `cargo build --release -Zbuild-std=core --target x86-16bit.json -Zbuild-std-features=compiler-builtins-mem` -2. `objcopy -I elf32-i386 -O binary target/x86-16bit/release/first_stage target/disk_image.bin +1. `cargo build --profile=stage-1 -Zbuild-std=core --target ../../i386-code16-boot-sector.json -Zbuild-std-features=compiler-builtins-mem` +2. `objcopy -I elf32-i386 -O binary ../../target/i386-code16-boot-sector/stage-1/bootloader-x86_64-bios-boot-sector ../../target/disk_image.img` To run in QEMU: -- `qemu-system-x86_64 -drive format=raw,file=target/disk_image.bin` +- `qemu-system-x86_64 -drive format=raw,file=../../target/disk_image.img` To print the contents of the ELF file, e.g. for trying to bring the size down: -- `objdump -xsdS -M i8086,intel target/x86-16bit/release/first_stage` +- `objdump -xsdS -M i8086,intel ../../target/i386-code16-boot-sector/stage-1/bootloader-x86_64-bios-boot-sector` diff --git a/bios/boot_sector/src/boot.s b/bios/boot_sector/src/boot.s index 992ce693..1544cac2 100644 --- a/bios/boot_sector/src/boot.s +++ b/bios/boot_sector/src/boot.s @@ -36,13 +36,18 @@ check_int13h_extensions: mov bx, 0x55aa # dl contains drive number int 0x13 - jc fail + jnc .int13_pass + call fail +.int13_pass: pop ax # pop error code again rust: # push arguments push dx # disk number call first_stage + # Fail code if first stage returns + push 'x' + call fail spin: hlt diff --git a/bios/boot_sector/src/dap.rs b/bios/boot_sector/src/dap.rs index da72b777..11e8a853 100644 --- a/bios/boot_sector/src/dap.rs +++ b/bios/boot_sector/src/dap.rs @@ -38,11 +38,13 @@ impl DiskAddressPacket { let self_addr = self as *const Self as u16; unsafe { asm!( - "push 0x7a", // error code `z`, passed to `fail` on error + "push 'z'", // error code `z`, passed to `fail` on error "mov {1:x}, si", // backup the `si` register, whose contents are required by LLVM "mov si, {0:x}", "int 0x13", - "jc fail", + "jnc 2f", // carry is set on fail + "call fail", + "2:", "pop si", // remove error code again "mov si, {1:x}", // restore the `si` register to its prior state in(reg) self_addr, diff --git a/bios/boot_sector/src/mbr.rs b/bios/boot_sector/src/mbr.rs index 1f7eed52..05382d28 100644 --- a/bios/boot_sector/src/mbr.rs +++ b/bios/boot_sector/src/mbr.rs @@ -16,14 +16,14 @@ pub(crate) fn get_partition(partitions_raw: &[u8], index: usize) -> PartitionTab .get(8..) .and_then(|s| s.get(..4)) .and_then(|s| s.try_into().ok()) - .unwrap_or_fail(b'e'), + .unwrap_or_fail(b'f'), ); let len = u32::from_le_bytes( buffer .get(12..) .and_then(|s| s.get(..4)) .and_then(|s| s.try_into().ok()) - .unwrap_or_fail(b'f'), + .unwrap_or_fail(b'g'), ); PartitionTableEntry::new(bootable, partition_type, lba, len) } diff --git a/bios/stage-2/src/dap.rs b/bios/stage-2/src/dap.rs index 00bd1268..f94b7fde 100644 --- a/bios/stage-2/src/dap.rs +++ b/bios/stage-2/src/dap.rs @@ -38,11 +38,13 @@ impl DiskAddressPacket { pub unsafe fn perform_load(&self, disk_number: u16) { let self_addr = self as *const Self as u16; asm!( - "push 0x7a", // error code `z`, passed to `fail` on error + "push 'z'", // error code `z`, passed to `fail` on error "mov {1:x}, si", "mov si, {0:x}", "int 0x13", - "jc fail", + "jnc 2f", // carry is set on fail + "call fail", + "2:", "pop si", // remove error code again "mov si, {1:x}", in(reg) self_addr, From ccac2cec732848ec7abd098582b2129a0f538893 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sat, 12 Oct 2024 08:51:34 +0200 Subject: [PATCH 48/80] mention E820 in docs for UnknownBios This wasn't entirely obvious previously, let's be explicit. --- api/src/info.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/src/info.rs b/api/src/info.rs index 81c849d8..d8962d62 100644 --- a/api/src/info.rs +++ b/api/src/info.rs @@ -173,6 +173,8 @@ pub enum MemoryRegionKind { /// Contains the UEFI memory type tag. UnknownUefi(u32), /// An unknown memory region reported by the BIOS firmware. + /// + /// Contains the E820 memory type. UnknownBios(u32), } From 7dcc96318dc23268ed926b1750db7bbd44075980 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sat, 26 Oct 2024 13:27:29 +0200 Subject: [PATCH 49/80] copy more PML4 entries If there is more than 512 GiB of memory, we need to copy more than the first PML4 entry to access it. Similarly if the frame buffer is not in the address range covered by the first PML4 entry, we need to copy more entries in order to access it. --- uefi/src/main.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/uefi/src/main.rs b/uefi/src/main.rs index 93dfb6c7..4eaef2b5 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -144,7 +144,8 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { let mut frame_allocator = LegacyFrameAllocator::new(memory_map.entries().copied().map(UefiMemoryDescriptor)); - let page_tables = create_page_tables(&mut frame_allocator); + let max_phys_addr = frame_allocator.max_phys_addr(); + let page_tables = create_page_tables(&mut frame_allocator, max_phys_addr, framebuffer.as_ref()); let mut ramdisk_len = 0u64; let ramdisk_addr = if let Some(rd) = ramdisk { ramdisk_len = rd.len() as u64; @@ -385,6 +386,8 @@ fn load_file_from_tftp_boot_server( /// Creates page table abstraction types for both the bootloader and kernel page tables. fn create_page_tables( frame_allocator: &mut impl FrameAllocator, + max_phys_addr: PhysAddr, + frame_buffer: Option<&RawFrameBufferInfo>, ) -> bootloader_x86_64_common::PageTables { // UEFI identity-maps all memory, so the offset between physical and virtual addresses is 0 let phys_offset = VirtAddr::new(0); @@ -410,9 +413,21 @@ fn create_page_tables( } }; - // copy the first entry (we don't need to access more than 512 GiB; also, some UEFI - // implementations seem to create an level 4 table entry 0 in all slots) - new_table[0] = old_table[0].clone(); + // copy the pml4 entries for all identity mapped memory. + let end_addr = VirtAddr::new(max_phys_addr.as_u64() - 1); + for p4 in 0..=usize::from(end_addr.p4_index()) { + new_table[p4] = old_table[p4].clone(); + } + + // copy the pml4 entry for the frame buffer (the frame buffer is not + // necessarily part of the identity mapping). + if let Some(frame_buffer) = frame_buffer { + let start_addr = VirtAddr::new(frame_buffer.addr.as_u64()); + let end_addr = start_addr + frame_buffer.info.byte_len; + for p4 in usize::from(start_addr.p4_index())..=usize::from(end_addr.p4_index()) { + new_table[p4] = old_table[p4].clone(); + } + } // the first level 4 table entry is now identical, so we can just load the new one unsafe { From 97268147ecf5bb247d93da4be4681399e9f30a2f Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sat, 26 Oct 2024 13:29:01 +0200 Subject: [PATCH 50/80] mark more entries as used The bootloader maps some of the memory used by the kernel into its own address space as well. In order for that to work we must ensure that the bootloader doesn't already have memory mapped there. Mark regions that are likely to be used by the bootloader as unusable. --- common/src/level_4_entries.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/common/src/level_4_entries.rs b/common/src/level_4_entries.rs index 6e6ad9d3..c894d0b5 100644 --- a/common/src/level_4_entries.rs +++ b/common/src/level_4_entries.rs @@ -39,7 +39,17 @@ impl UsedLevel4Entries { rng: config.mappings.aslr.then(entropy::build_rng), }; - used.entry_state[0] = true; // TODO: Can we do this dynamically? + // The bootloader maps of the kernel's memory into its own page tables. + // We need to prevent overlaps, so mark all memory that could already + // be used by the bootload as inaccessible. + + // All memory in this range is identity mapped. + used.mark_range_as_used(0, max_phys_addr.as_u64()); + + // The bootload needs to access the frame buffer. + if let Some(frame_buffer) = framebuffer { + used.mark_range_as_used(frame_buffer.addr.as_u64(), frame_buffer.info.byte_len); + } // Mark the statically configured ranges from the config as used. From 8234bf92f36baa74b18fca441a11aa0737e06669 Mon Sep 17 00:00:00 2001 From: Ollrogge Date: Fri, 1 Nov 2024 13:20:32 +0100 Subject: [PATCH 51/80] Remove 3dnow features from stage4 target --- x86_64-stage-4.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x86_64-stage-4.json b/x86_64-stage-4.json index 026d23f9..40102494 100644 --- a/x86_64-stage-4.json +++ b/x86_64-stage-4.json @@ -4,7 +4,7 @@ "cpu": "x86-64", "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "disable-redzone": true, - "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float", + "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float", "linker": "rust-lld", "linker-flavor": "ld.lld", "llvm-target": "x86_64-unknown-none-elf", From 8a9d8a9a84133ad12ef84c1b3d866b6de5809b55 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 1 Nov 2024 08:32:36 +0100 Subject: [PATCH 52/80] release v0.11.8 --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 10 +++++----- Changelog.md | 13 ++++++++++++- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34decae3..9846e70e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,7 +155,7 @@ dependencies = [ [[package]] name = "bootloader" -version = "0.11.7" +version = "0.11.8" dependencies = [ "anyhow", "async-process", @@ -182,22 +182,22 @@ dependencies = [ [[package]] name = "bootloader-boot-config" -version = "0.11.7" +version = "0.11.8" dependencies = [ "serde", ] [[package]] name = "bootloader-x86_64-bios-boot-sector" -version = "0.11.7" +version = "0.11.8" [[package]] name = "bootloader-x86_64-bios-common" -version = "0.11.7" +version = "0.11.8" [[package]] name = "bootloader-x86_64-bios-stage-2" -version = "0.11.7" +version = "0.11.8" dependencies = [ "bootloader-x86_64-bios-common", "byteorder", @@ -206,7 +206,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-3" -version = "0.11.7" +version = "0.11.8" dependencies = [ "bootloader-x86_64-bios-common", "noto-sans-mono-bitmap 0.1.6", @@ -214,7 +214,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-4" -version = "0.11.7" +version = "0.11.8" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-bios-common", @@ -229,7 +229,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-common" -version = "0.11.7" +version = "0.11.8" dependencies = [ "bootloader-boot-config", "bootloader_api", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-uefi" -version = "0.11.7" +version = "0.11.8" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-common", @@ -261,7 +261,7 @@ dependencies = [ [[package]] name = "bootloader_api" -version = "0.11.7" +version = "0.11.8" dependencies = [ "rand", ] diff --git a/Cargo.toml b/Cargo.toml index 4ff329fe..452cdca7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,15 +33,15 @@ exclude = ["examples/basic", "examples/test_framework"] [workspace.package] # don't forget to update `workspace.dependencies` below -version = "0.11.7" +version = "0.11.8" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-osdev/bootloader" [workspace.dependencies] -bootloader_api = { version = "0.11.7", path = "api" } -bootloader-x86_64-common = { version = "0.11.7", path = "common" } -bootloader-boot-config = { version = "0.11.7", path = "common/config" } -bootloader-x86_64-bios-common = { version = "0.11.7", path = "bios/common" } +bootloader_api = { version = "0.11.8", path = "api" } +bootloader-x86_64-common = { version = "0.11.8", path = "common" } +bootloader-boot-config = { version = "0.11.8", path = "common/config" } +bootloader-x86_64-bios-common = { version = "0.11.8", path = "bios/common" } [features] default = ["bios", "uefi"] diff --git a/Changelog.md b/Changelog.md index 6ac95ddc..acc412af 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,17 @@ # Unreleased -* Fix bug leading to page table frames that are not mapped as writable +# 0.11.8 – 2024-11-02 + +* [avoid 32-bit relocation to __BOOTLOADER_CONFIG](https://github.com/rust-osdev/bootloader/pull/428) +* [Fix doc comment and error message only referencing the BIOS but used for UEFI](https://github.com/rust-osdev/bootloader/pull/439) +* [Ensure all page table frames are mapped as writable](https://github.com/rust-osdev/bootloader/pull/444) +* [Guard the lower 1MB of memory](https://github.com/rust-osdev/bootloader/pull/446) +* [always cover at least the first 4 GiB of physical memory](https://github.com/rust-osdev/bootloader/pull/448) +* [Fixed "jc fail" instructions not working properly and updated README.md](https://github.com/rust-osdev/bootloader/pull/453) +* [Remove 3dnow features from stage4 target](https://github.com/rust-osdev/bootloader/pull/471) +* [mention E820 in docs for UnknownBios](https://github.com/rust-osdev/bootloader/pull/461) + +**Full Changelog**: https://github.com/rust-osdev/bootloader/compare/v0.11.7...v0.11.8 # 0.11.7 – 2024-02-16 From 0688aeeadcc8b98a6a5765f4f1b126588aedffb9 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sun, 17 Nov 2024 11:25:40 -0800 Subject: [PATCH 53/80] Convert LF to CRLF when writing to serial port --- common/src/serial.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/src/serial.rs b/common/src/serial.rs index 1882e366..8435c8e1 100644 --- a/common/src/serial.rs +++ b/common/src/serial.rs @@ -17,7 +17,12 @@ impl SerialPort { impl fmt::Write for SerialPort { fn write_str(&mut self, s: &str) -> fmt::Result { - self.port.write_str(s).unwrap(); + for char in s.bytes() { + match char { + b'\n' => self.port.write_str("\r\n").unwrap(), + byte => self.port.send(byte), + } + } Ok(()) } } From 9acc2a902e5b65583f2560615adfa17067a35511 Mon Sep 17 00:00:00 2001 From: Mako <61922615+Makonede@users.noreply.github.com> Date: Sat, 30 Nov 2024 01:55:08 -0800 Subject: [PATCH 54/80] Update x86_64 (#478) * Update x86_64 (actually) Signed-off-by: Mako <61922615+Makonede@users.noreply.github.com> --- Cargo.lock | 8 ++++---- common/src/load_kernel.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9846e70e..704cb6a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "anyhow" @@ -1372,12 +1372,12 @@ dependencies = [ [[package]] name = "x86_64" -version = "0.14.10" +version = "0.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" +checksum = "c101112411baafbb4bf8d33e4c4a80ab5b02d74d2612331c61e8192fc9710491" dependencies = [ "bit_field", - "bitflags 1.3.2", + "bitflags 2.3.3", "rustversion", "volatile", ] diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs index 6cc24fed..0eab3a24 100644 --- a/common/src/load_kernel.rs +++ b/common/src/load_kernel.rs @@ -353,7 +353,7 @@ where // These are the offsets from the start address. These correspond // to the destination indices in `buf`. - let start_offset_in_buf = Step::steps_between(&addr, &start_copy_address).unwrap(); + let start_offset_in_buf = Step::steps_between(&addr, &start_copy_address).1.unwrap(); // Calculate the source slice. // Utilize that frames are identity mapped. @@ -420,7 +420,7 @@ where // These are the offsets from the start address. These correspond // to the destination indices in `buf`. - let start_offset_in_buf = Step::steps_between(&addr, &start_copy_address).unwrap(); + let start_offset_in_buf = Step::steps_between(&addr, &start_copy_address).1.unwrap(); // Calculate the source slice. // Utilize that frames are identity mapped. From 9fd392d9b92f1106a4e2697c4112f41523783cb8 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sat, 30 Nov 2024 11:01:39 +0100 Subject: [PATCH 55/80] update changelog --- Changelog.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Changelog.md b/Changelog.md index acc412af..4348f47e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,15 @@ # Unreleased +# 0.11.9 – 2024-11-30 + +This release is compatible with Rust nightlies starting with `nightly-2024-11-23`. + +* [copy more PML4 entries](https://github.com/rust-osdev/bootloader/pull/466) +* [Convert LF to CRLF when writing to serial port](https://github.com/rust-osdev/bootloader/pull/474) +* [Update x86_64 & fix build on latest nightly](https://github.com/rust-osdev/bootloader/pull/478) + +**Full Changelog**: https://github.com/rust-osdev/bootloader/compare/v0.11.8...v0.11.9 + # 0.11.8 – 2024-11-02 * [avoid 32-bit relocation to __BOOTLOADER_CONFIG](https://github.com/rust-osdev/bootloader/pull/428) From f8b5445c1be2a21ce469173e4d1855d0f090002d Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sat, 30 Nov 2024 11:02:17 +0100 Subject: [PATCH 56/80] release v0.11.9 --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 704cb6a7..0cbe73c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,7 +155,7 @@ dependencies = [ [[package]] name = "bootloader" -version = "0.11.8" +version = "0.11.9" dependencies = [ "anyhow", "async-process", @@ -182,22 +182,22 @@ dependencies = [ [[package]] name = "bootloader-boot-config" -version = "0.11.8" +version = "0.11.9" dependencies = [ "serde", ] [[package]] name = "bootloader-x86_64-bios-boot-sector" -version = "0.11.8" +version = "0.11.9" [[package]] name = "bootloader-x86_64-bios-common" -version = "0.11.8" +version = "0.11.9" [[package]] name = "bootloader-x86_64-bios-stage-2" -version = "0.11.8" +version = "0.11.9" dependencies = [ "bootloader-x86_64-bios-common", "byteorder", @@ -206,7 +206,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-3" -version = "0.11.8" +version = "0.11.9" dependencies = [ "bootloader-x86_64-bios-common", "noto-sans-mono-bitmap 0.1.6", @@ -214,7 +214,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-4" -version = "0.11.8" +version = "0.11.9" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-bios-common", @@ -229,7 +229,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-common" -version = "0.11.8" +version = "0.11.9" dependencies = [ "bootloader-boot-config", "bootloader_api", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-uefi" -version = "0.11.8" +version = "0.11.9" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-common", @@ -261,7 +261,7 @@ dependencies = [ [[package]] name = "bootloader_api" -version = "0.11.8" +version = "0.11.9" dependencies = [ "rand", ] diff --git a/Cargo.toml b/Cargo.toml index 452cdca7..c5fdc211 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ exclude = ["examples/basic", "examples/test_framework"] [workspace.package] # don't forget to update `workspace.dependencies` below -version = "0.11.8" +version = "0.11.9" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-osdev/bootloader" From 198af0734158bd8ba7060ae7cc9bb378a6e50e1f Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe Date: Sat, 23 Nov 2024 11:14:27 -0800 Subject: [PATCH 57/80] Remove "UEFI boot" log message --- uefi/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/uefi/src/main.rs b/uefi/src/main.rs index 4eaef2b5..0ad26557 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -531,8 +531,6 @@ fn init_logger( stride: mode_info.stride(), }; - log::info!("UEFI boot"); - bootloader_x86_64_common::init_logger( slice, info, From 8d9104b221de41be23c5b2633af221d9407fe33a Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 19 Jan 2025 11:01:06 +0100 Subject: [PATCH 58/80] use threads instead of futures in build.rs There's no inherent reason why we should use future-based concurrency in build.rs. We don't spawn many futures and we don't make use of any of the nice patterns made possible by structured concurrency. The downside of using futures is that we have to pull in a bunch of dependencies. Switching to sync code and removing the dependencies resulted in a nice performance improvement (35s -> 30s). Also, it's just good practice to reduce the number of unneeded dependencies especially if some of them are unmaintained. --- Cargo.lock | 353 ----------------------------------------------------- Cargo.toml | 3 - build.rs | 101 ++++++++------- 3 files changed, 54 insertions(+), 403 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0cbe73c9..78bc7d77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,70 +14,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" -[[package]] -name = "async-channel" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite", - "log", - "parking", - "polling", - "rustix", - "slab", - "socket2", - "waker-fn", -] - -[[package]] -name = "async-lock" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-process" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" -dependencies = [ - "async-io", - "async-lock", - "autocfg", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix", - "signal-hook", - "windows-sys", -] - -[[package]] -name = "async-task" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" - [[package]] name = "atomic-polyfill" version = "0.1.11" @@ -87,12 +23,6 @@ dependencies = [ "critical-section", ] -[[package]] -name = "atomic-waker" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" - [[package]] name = "autocfg" version = "1.1.0" @@ -138,32 +68,14 @@ dependencies = [ "wyz", ] -[[package]] -name = "blocking" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" -dependencies = [ - "async-channel", - "async-lock", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "log", -] - [[package]] name = "bootloader" version = "0.11.9" dependencies = [ "anyhow", - "async-process", "bootloader-boot-config", "bootloader_test_runner", "fatfs", - "futures", - "futures-concurrency", "gpt", "llvm-tools", "mbrman", @@ -293,15 +205,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "concurrent-queue" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "conquer-once" version = "0.3.2" @@ -338,15 +241,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" -[[package]] -name = "crossbeam-utils" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] - [[package]] name = "errno" version = "0.3.1" @@ -368,12 +262,6 @@ dependencies = [ "libc", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "fastrand" version = "1.9.0" @@ -400,121 +288,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-concurrency" -version = "7.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b726119e6cd29cf120724495b2085e1ed3d17821ea17b86de54576d1aa565f5e" -dependencies = [ - "bitvec", - "futures-core", - "pin-project", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.23", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - [[package]] name = "getrandom" version = "0.2.10" @@ -648,12 +421,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - [[package]] name = "noto-sans-mono-bitmap" version = "0.1.6" @@ -672,60 +439,6 @@ version = "0.1.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa50141d081512ab30fd9e7e7692476866df5098b028536ad6680212e717fa8d" -[[package]] -name = "parking" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" - -[[package]] -name = "pin-project" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.23", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys", -] - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -940,44 +653,6 @@ dependencies = [ "serde", ] -[[package]] -name = "signal-hook" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "spin" version = "0.9.8" @@ -1261,40 +936,12 @@ dependencies = [ "quote", ] -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index c5fdc211..a854ef63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -129,9 +129,6 @@ opt-level = 2 [build-dependencies] llvm-tools = "0.1.1" -async-process = "1.6.0" -futures = "0.3.25" -futures-concurrency = "7.0.0" [package.metadata.docs.rs] rustc-args = ["--cfg", "docsrs_dummy_build"] diff --git a/build.rs b/build.rs index 3f543d3f..c83c6145 100644 --- a/build.rs +++ b/build.rs @@ -1,34 +1,40 @@ -use async_process::Command; -use futures::executor::block_on; -use futures_concurrency::future::Join; use std::path::{Path, PathBuf}; +use std::process::Command; const BOOTLOADER_VERSION: &str = env!("CARGO_PKG_VERSION"); fn main() { #[cfg(not(feature = "uefi"))] - async fn uefi_main() {} + fn uefi_main() {} #[cfg(not(feature = "bios"))] - async fn bios_main() {} + fn bios_main() {} - block_on((uefi_main(), bios_main()).join()); + // Spawn two threads to build the uefi and bios code concurrently. + let uefi_main_handle = std::thread::spawn(uefi_main); + let bios_main_handle = std::thread::spawn(bios_main); + + // Wait for the threads to finish. + uefi_main_handle.join().unwrap(); + bios_main_handle.join().unwrap(); } #[cfg(feature = "bios")] -async fn bios_main() { - let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); +fn bios_main() { // Run the bios build commands concurrently. // (Cargo already uses multiple threads for building dependencies, but these // BIOS crates don't have enough dependencies to utilize all cores on modern // CPUs. So by running the build commands in parallel, we increase the number // of utilized cores.) - let (bios_boot_sector_path, bios_stage_2_path, bios_stage_3_path, bios_stage_4_path) = ( - build_bios_boot_sector(&out_dir), - build_bios_stage_2(&out_dir), - build_bios_stage_3(&out_dir), - build_bios_stage_4(&out_dir), - ) - .join() - .await; + let bios_boot_sector_path_handle = std::thread::spawn(build_bios_boot_sector); + let bios_stage_2_path_handle = std::thread::spawn(build_bios_stage_2); + let bios_stage_3_path_handle = std::thread::spawn(build_bios_stage_3); + let bios_stage_4_path_handle = std::thread::spawn(build_bios_stage_4); + + // Wait for the commands to finish. + let bios_boot_sector_path = bios_boot_sector_path_handle.join().unwrap(); + let bios_stage_2_path = bios_stage_2_path_handle.join().unwrap(); + let bios_stage_3_path = bios_stage_3_path_handle.join().unwrap(); + let bios_stage_4_path = bios_stage_4_path_handle.join().unwrap(); + println!( "cargo:rustc-env=BIOS_BOOT_SECTOR_PATH={}", bios_boot_sector_path.display() @@ -48,11 +54,8 @@ async fn bios_main() { } #[cfg(feature = "uefi")] -async fn uefi_main() { - let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); - - let uefi_path = build_uefi_bootloader(&out_dir).await; - +fn uefi_main() { + let uefi_path = build_uefi_bootloader(); println!( "cargo:rustc-env=UEFI_BOOTLOADER_PATH={}", uefi_path.display() @@ -61,7 +64,8 @@ async fn uefi_main() { #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "uefi")] -async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { +fn build_uefi_bootloader() -> PathBuf { + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); cmd.arg("install").arg("bootloader-x86_64-uefi"); @@ -77,12 +81,11 @@ async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { cmd.arg("--target").arg("x86_64-unknown-uefi"); cmd.arg("-Zbuild-std=core") .arg("-Zbuild-std-features=compiler-builtins-mem"); - cmd.arg("--root").arg(out_dir); + cmd.arg("--root").arg(&out_dir); cmd.env_remove("RUSTFLAGS"); cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); let status = cmd .status() - .await .expect("failed to run cargo install for uefi bootloader"); if status.success() { let path = out_dir.join("bin").join("bootloader-x86_64-uefi.efi"); @@ -100,9 +103,10 @@ async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { // This will put an empty file in out_dir and return its path. #[cfg(docsrs_dummy_build)] #[cfg(feature = "uefi")] -async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { +fn build_uefi_bootloader() -> PathBuf { use std::fs::File; + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let path = out_dir.join("bootloader-dummy-bootloader-uefi"); if File::create(&path).is_err() { @@ -118,7 +122,8 @@ async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] -async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { +fn build_bios_boot_sector() -> PathBuf { + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); cmd.arg("install").arg("bootloader-x86_64-bios-boot-sector"); @@ -137,13 +142,12 @@ async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { cmd.arg("--profile").arg("stage-1"); cmd.arg("-Zbuild-std=core") .arg("-Zbuild-std-features=compiler-builtins-mem"); - cmd.arg("--root").arg(out_dir); + cmd.arg("--root").arg(&out_dir); cmd.env_remove("RUSTFLAGS"); cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); cmd.env_remove("RUSTC_WORKSPACE_WRAPPER"); // used by clippy let status = cmd .status() - .await .expect("failed to run cargo install for bios bootsector"); let elf_path = if status.success() { let path = out_dir @@ -157,16 +161,17 @@ async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { } else { panic!("failed to build bios boot sector"); }; - convert_elf_to_bin(elf_path).await + convert_elf_to_bin(elf_path) } // dummy implementation because docsrs builds have no network access. // This will put an empty file in out_dir and return its path. #[cfg(docsrs_dummy_build)] #[cfg(feature = "bios")] -async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { +fn build_bios_boot_sector() -> PathBuf { use std::fs::File; + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let path = out_dir.join("bootloader-dummy-bios-boot-sector"); if File::create(&path).is_err() { @@ -182,7 +187,8 @@ async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] -async fn build_bios_stage_2(out_dir: &Path) -> PathBuf { +fn build_bios_stage_2() -> PathBuf { + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); cmd.arg("install").arg("bootloader-x86_64-bios-stage-2"); @@ -205,13 +211,12 @@ async fn build_bios_stage_2(out_dir: &Path) -> PathBuf { cmd.arg("--profile").arg("stage-2"); cmd.arg("-Zbuild-std=core") .arg("-Zbuild-std-features=compiler-builtins-mem"); - cmd.arg("--root").arg(out_dir); + cmd.arg("--root").arg(&out_dir); cmd.env_remove("RUSTFLAGS"); cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); cmd.env_remove("RUSTC_WORKSPACE_WRAPPER"); // used by clippy let status = cmd .status() - .await .expect("failed to run cargo install for bios second stage"); let elf_path = if status.success() { let path = out_dir.join("bin").join("bootloader-x86_64-bios-stage-2"); @@ -223,16 +228,17 @@ async fn build_bios_stage_2(out_dir: &Path) -> PathBuf { } else { panic!("failed to build bios second stage"); }; - convert_elf_to_bin(elf_path).await + convert_elf_to_bin(elf_path) } // dummy implementation because docsrs builds have no network access. // This will put an empty file in out_dir and return its path. #[cfg(docsrs_dummy_build)] #[cfg(feature = "bios")] -async fn build_bios_stage_2(out_dir: &Path) -> PathBuf { +fn build_bios_stage_2() -> PathBuf { use std::fs::File; + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let path = out_dir.join("bootloader-dummy-bios-stage-2"); if File::create(&path).is_err() { @@ -248,7 +254,8 @@ async fn build_bios_stage_2(out_dir: &Path) -> PathBuf { #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] -async fn build_bios_stage_3(out_dir: &Path) -> PathBuf { +fn build_bios_stage_3() -> PathBuf { + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); cmd.arg("install").arg("bootloader-x86_64-bios-stage-3"); @@ -267,13 +274,12 @@ async fn build_bios_stage_3(out_dir: &Path) -> PathBuf { cmd.arg("--profile").arg("stage-3"); cmd.arg("-Zbuild-std=core") .arg("-Zbuild-std-features=compiler-builtins-mem"); - cmd.arg("--root").arg(out_dir); + cmd.arg("--root").arg(&out_dir); cmd.env_remove("RUSTFLAGS"); cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); cmd.env_remove("RUSTC_WORKSPACE_WRAPPER"); // used by clippy let status = cmd .status() - .await .expect("failed to run cargo install for bios stage-3"); let elf_path = if status.success() { let path = out_dir.join("bin").join("bootloader-x86_64-bios-stage-3"); @@ -285,16 +291,17 @@ async fn build_bios_stage_3(out_dir: &Path) -> PathBuf { } else { panic!("failed to build bios stage-3"); }; - convert_elf_to_bin(elf_path).await + convert_elf_to_bin(elf_path) } // dummy implementation because docsrs builds have no network access. // This will put an empty file in out_dir and return its path. #[cfg(docsrs_dummy_build)] #[cfg(feature = "bios")] -async fn build_bios_stage_3(out_dir: &Path) -> PathBuf { +fn build_bios_stage_3() -> PathBuf { use std::fs::File; + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let path = out_dir.join("bootloader-dummy-bios-stage-3"); if File::create(&path).is_err() { @@ -310,7 +317,8 @@ async fn build_bios_stage_3(out_dir: &Path) -> PathBuf { #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] -async fn build_bios_stage_4(out_dir: &Path) -> PathBuf { +fn build_bios_stage_4() -> PathBuf { + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); cmd.arg("install").arg("bootloader-x86_64-bios-stage-4"); @@ -329,13 +337,12 @@ async fn build_bios_stage_4(out_dir: &Path) -> PathBuf { cmd.arg("--profile").arg("stage-4"); cmd.arg("-Zbuild-std=core") .arg("-Zbuild-std-features=compiler-builtins-mem"); - cmd.arg("--root").arg(out_dir); + cmd.arg("--root").arg(&out_dir); cmd.env_remove("RUSTFLAGS"); cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); cmd.env_remove("RUSTC_WORKSPACE_WRAPPER"); // used by clippy let status = cmd .status() - .await .expect("failed to run cargo install for bios stage-4"); let elf_path = if status.success() { let path = out_dir.join("bin").join("bootloader-x86_64-bios-stage-4"); @@ -348,16 +355,17 @@ async fn build_bios_stage_4(out_dir: &Path) -> PathBuf { panic!("failed to build bios stage-4"); }; - convert_elf_to_bin(elf_path).await + convert_elf_to_bin(elf_path) } // dummy implementation because docsrs builds have no network access. // This will put an empty file in out_dir and return its path. #[cfg(docsrs_dummy_build)] #[cfg(feature = "bios")] -async fn build_bios_stage_4(out_dir: &Path) -> PathBuf { +fn build_bios_stage_4() -> PathBuf { use std::fs::File; + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let path = out_dir.join("bootloader-dummy-bios-stage-4"); if File::create(&path).is_err() { @@ -373,7 +381,7 @@ async fn build_bios_stage_4(out_dir: &Path) -> PathBuf { #[cfg(not(docsrs_dummy_build))] #[cfg(feature = "bios")] -async fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf { +fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf { let flat_binary_path = elf_path.with_extension("bin"); let llvm_tools = llvm_tools::LlvmTools::new().expect("failed to get llvm tools"); @@ -390,7 +398,6 @@ async fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf { cmd.arg(&flat_binary_path); let output = cmd .output() - .await .expect("failed to execute llvm-objcopy command"); if !output.status.success() { panic!( From 51576e30553315710f934e5dfa67a0caeaf97553 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 19 Jan 2025 11:09:08 +0100 Subject: [PATCH 59/80] remove macos-12 from CI test matrix macos-12 has been removed from GitHub actions. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2d9e796..981deef6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-12, windows-latest, macos-latest] + os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} timeout-minutes: 30 From 80e1905a6c38593144f325441ce6fe6f699f4c11 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 21 Jan 2025 12:55:09 +0100 Subject: [PATCH 60/80] Move test kernels to a separate workspace The test kernels need to be built for a different target and we don't want to unify dependency features with the main packages (as this can lead to enabled `std` features). --- .github/workflows/ci.yml | 7 ++ Cargo.lock | 9 -- Cargo.toml | 11 +- tests/test_kernels/.cargo/config.toml | 1 + tests/test_kernels/Cargo.lock | 141 ++++++++++++++++++++++++++ tests/test_kernels/Cargo.toml | 13 +++ 6 files changed, 163 insertions(+), 19 deletions(-) create mode 100644 tests/test_kernels/Cargo.lock create mode 100644 tests/test_kernels/Cargo.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 981deef6..c4e66bbb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,9 @@ jobs: - uses: r7kamura/rust-problem-matchers@v1.1.0 - name: "Run `cargo check`" run: cargo check --all-targets --all + - name: "Check test kernels" + run: cargo check --all + working-directory: tests/test_kernels - name: "Check docs.rs build" run: cargo check env: @@ -89,6 +92,8 @@ jobs: - uses: actions/checkout@v3 - uses: r7kamura/rust-problem-matchers@v1.1.0 - run: cargo fmt --all -- --check + - run: cargo fmt --all -- --check + working-directory: tests/test_kernels clippy: name: Clippy @@ -99,6 +104,8 @@ jobs: - uses: Swatinem/rust-cache@v2 - uses: r7kamura/rust-problem-matchers@v1.1.0 - run: cargo clippy --all --all-targets + - run: cargo clippy --all + working-directory: tests/test_kernels semver-checks: name: Semver Checks diff --git a/Cargo.lock b/Cargo.lock index 78bc7d77..632880e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -764,15 +764,6 @@ dependencies = [ "x86_64", ] -[[package]] -name = "test_kernel_lto" -version = "0.1.0" -dependencies = [ - "bootloader_api", - "uart_16550", - "x86_64", -] - [[package]] name = "test_kernel_map_phys_mem" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a854ef63..9a6cf690 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,17 +19,8 @@ members = [ "bios/stage-*", "bios/common", "tests/runner", - "tests/test_kernels/default_settings", - "tests/test_kernels/map_phys_mem", - "tests/test_kernels/higher_half", - "tests/test_kernels/pie", - "tests/test_kernels/lto", - "tests/test_kernels/ramdisk", - "tests/test_kernels/min_stack", - "tests/test_kernels/lower_memory_free", - "tests/test_kernels/write_usable_memory", ] -exclude = ["examples/basic", "examples/test_framework"] +exclude = ["examples/basic", "examples/test_framework", "tests/test_kernels"] [workspace.package] # don't forget to update `workspace.dependencies` below diff --git a/tests/test_kernels/.cargo/config.toml b/tests/test_kernels/.cargo/config.toml index 9766b811..412c4a33 100644 --- a/tests/test_kernels/.cargo/config.toml +++ b/tests/test_kernels/.cargo/config.toml @@ -1,2 +1,3 @@ [build] target-dir = "../../target" +target = "x86_64-unknown-none" diff --git a/tests/test_kernels/Cargo.lock b/tests/test_kernels/Cargo.lock new file mode 100644 index 00000000..408c7bb2 --- /dev/null +++ b/tests/test_kernels/Cargo.lock @@ -0,0 +1,141 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" + +[[package]] +name = "bootloader_api" +version = "0.11.9" + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "test_kernel_default_settings" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "test_kernel_higher_half" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "test_kernel_lower_memory_free" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "test_kernel_lto" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "test_kernel_map_phys_mem" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "test_kernel_min_stack" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "test_kernel_pie" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "test_kernel_ramdisk" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "test_kernel_write_usable_memory" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + +[[package]] +name = "uart_16550" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614ff2a87880d4bd4374722268598a970bbad05ced8bf630439417347254ab2e" +dependencies = [ + "bitflags 1.3.2", + "rustversion", + "x86_64", +] + +[[package]] +name = "volatile" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" + +[[package]] +name = "x86_64" +version = "0.14.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c101112411baafbb4bf8d33e4c4a80ab5b02d74d2612331c61e8192fc9710491" +dependencies = [ + "bit_field", + "bitflags 2.8.0", + "rustversion", + "volatile", +] diff --git a/tests/test_kernels/Cargo.toml b/tests/test_kernels/Cargo.toml new file mode 100644 index 00000000..ce5a6f0a --- /dev/null +++ b/tests/test_kernels/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +resolver = "2" +members = [ + "default_settings", + "map_phys_mem", + "higher_half", + "pie", + "lto", + "ramdisk", + "min_stack", + "lower_memory_free", + "write_usable_memory", +] From c45fed1521877800b65c2c907d8c9d1370c788be Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 21 Jan 2025 13:14:59 +0100 Subject: [PATCH 61/80] Move test kernel profiles to test kernel workspace --- Cargo.toml | 19 ------------------- tests/test_kernels/Cargo.toml | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9a6cf690..3bd001d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,3 @@ -cargo-features = ["profile-rustflags"] - [package] name = "bootloader" description = "An experimental x86_64 bootloader that works on both BIOS and UEFI systems." @@ -101,23 +99,6 @@ inherits = "release" debug = true overflow-checks = true -[profile.lto] -inherits = "release" -lto = true - -[profile.test.package.test_kernel_higher_half] -rustflags = [ - "-C", - "link-args=--image-base 0xFFFF800000000000", - "-C", - "relocation-model=pic", - "-C", - "code-model=large", -] - -[profile.test.package.test_kernel_min_stack] -opt-level = 2 - [build-dependencies] llvm-tools = "0.1.1" diff --git a/tests/test_kernels/Cargo.toml b/tests/test_kernels/Cargo.toml index ce5a6f0a..f9216bf8 100644 --- a/tests/test_kernels/Cargo.toml +++ b/tests/test_kernels/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["profile-rustflags"] + [workspace] resolver = "2" members = [ @@ -11,3 +13,26 @@ members = [ "lower_memory_free", "write_usable_memory", ] + +[profile.release] +panic = "abort" +lto = false +debug = true +overflow-checks = true + +[profile.lto] +inherits = "release" +lto = true + +[profile.test.package.test_kernel_higher_half] +rustflags = [ + "-C", + "link-args=--image-base 0xFFFF800000000000", + "-C", + "relocation-model=pic", + "-C", + "code-model=large", +] + +[profile.test.package.test_kernel_min_stack] +opt-level = 2 From 704d609bb27a66fe0b713269c2fb59b81e75ac46 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 21 Jan 2025 13:16:43 +0100 Subject: [PATCH 62/80] Fix `test_kernel_lto` build --- tests/lto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lto.rs b/tests/lto.rs index 00cfe60f..5c259236 100644 --- a/tests/lto.rs +++ b/tests/lto.rs @@ -6,9 +6,9 @@ use bootloader_test_runner::run_test_kernel; fn basic_boot() { // build test kernel manually to force-enable link-time optimization let mut cmd = Command::new(std::env::var("CARGO").unwrap_or_else(|_| "cargo".into())); + cmd.current_dir("tests/test_kernels"); cmd.arg("build"); cmd.arg("-p").arg("test_kernel_lto"); - cmd.arg("--target").arg("x86_64-unknown-none"); cmd.arg("--profile").arg("lto"); let status = cmd.status().unwrap(); assert!(status.success()); From 72637a66cba627175a3954bf4fdf27613782ef77 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 21 Jan 2025 13:25:25 +0100 Subject: [PATCH 63/80] Fix: Use wildcard exclude for in workspace list --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3bd001d5..3b0c9a4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ members = [ "bios/common", "tests/runner", ] -exclude = ["examples/basic", "examples/test_framework", "tests/test_kernels"] +exclude = ["examples/basic", "examples/test_framework", "tests/test_kernels/*"] [workspace.package] # don't forget to update `workspace.dependencies` below From ec3d39249cab6c872a3284cd23f98ec6164c001f Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 21 Jan 2025 16:48:23 +0100 Subject: [PATCH 64/80] fix condition for running bootloader common tests There's no 'x86' arch. There is 'X86', but we currently don't any CI job on a 32-bit target, so this still wouldn't work. Let's just use X64. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c4e66bbb..f136dc79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,7 +72,7 @@ jobs: - name: Run api tests run: cargo test -p bootloader_api - name: Run bootloader common tests - if: runner.arch == 'x86' + if: runner.arch == 'X64' run: cargo test -p bootloader-x86_64-common - name: Run integration tests run: cargo test -- --test-threads 1 From 7323271b6adc93e31894ecaf2efda2cf1eb698ef Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sat, 1 Feb 2025 20:58:37 -0800 Subject: [PATCH 65/80] Update `x86_64` to `0.15.2` --- Cargo.lock | 38 ++++++++++++------- bios/stage-4/Cargo.toml | 2 +- common/Cargo.toml | 2 +- common/src/gdt.rs | 4 +- common/src/level_4_entries.rs | 20 +++++----- common/src/lib.rs | 11 +++--- common/src/load_kernel.rs | 4 +- tests/test_kernels/Cargo.lock | 32 +++++++++++----- tests/test_kernels/config_file/Cargo.toml | 3 +- .../test_kernels/default_settings/Cargo.toml | 3 +- tests/test_kernels/higher_half/Cargo.toml | 3 +- .../test_kernels/lower_memory_free/Cargo.toml | 3 +- tests/test_kernels/lto/Cargo.toml | 3 +- tests/test_kernels/map_phys_mem/Cargo.toml | 3 +- tests/test_kernels/min_stack/Cargo.toml | 3 +- tests/test_kernels/pie/Cargo.toml | 3 +- tests/test_kernels/ramdisk/Cargo.toml | 3 +- .../write_usable_memory/Cargo.toml | 3 +- uefi/Cargo.toml | 2 +- uefi/src/main.rs | 2 +- 20 files changed, 80 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 632880e8..cbdac28a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,7 +136,7 @@ dependencies = [ "rsdp", "serde-json-core", "usize_conversions", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -154,7 +154,7 @@ dependencies = [ "spinning_top", "uart_16550", "usize_conversions", - "x86_64", + "x86_64 0.15.2", "xmas-elf", ] @@ -168,7 +168,7 @@ dependencies = [ "log", "serde-json-core", "uefi", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -734,7 +734,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -743,7 +743,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -752,7 +752,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -761,7 +761,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -770,7 +770,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -779,7 +779,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -788,7 +788,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -797,7 +797,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -806,7 +806,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -837,7 +837,7 @@ checksum = "b074eb9300ad949edd74c529c0e8d451625af71bb948e6b65fe69f72dc1363d9" dependencies = [ "bitflags 1.3.2", "rustversion", - "x86_64", + "x86_64 0.14.13", ] [[package]] @@ -1020,6 +1020,18 @@ dependencies = [ "volatile", ] +[[package]] +name = "x86_64" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f042214de98141e9c8706e8192b73f56494087cc55ebec28ce10f26c5c364ae" +dependencies = [ + "bit_field", + "bitflags 2.3.3", + "rustversion", + "volatile", +] + [[package]] name = "xmas-elf" version = "0.8.0" diff --git a/bios/stage-4/Cargo.toml b/bios/stage-4/Cargo.toml index 769ca657..2afb8654 100644 --- a/bios/stage-4/Cargo.toml +++ b/bios/stage-4/Cargo.toml @@ -14,7 +14,7 @@ bootloader-x86_64-common = { workspace = true } bootloader-x86_64-bios-common = { workspace = true } bootloader-boot-config = { workspace = true } log = "0.4.14" -x86_64 = "0.14.8" +x86_64 = "0.15.2" rsdp = "2.0.0" usize_conversions = "0.2.0" serde-json-core = "0.5.0" diff --git a/common/Cargo.toml b/common/Cargo.toml index afc8ed7d..7375b940 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -14,7 +14,7 @@ bootloader-boot-config = { workspace = true } conquer-once = { version = "0.3.2", default-features = false } spinning_top = "0.2.4" usize_conversions = "0.2.0" -x86_64 = { version = "0.14.8" } +x86_64 = { version = "0.15.2" } xmas-elf = "0.8.0" raw-cpuid = "10.2.0" rand = { version = "0.8.4", default-features = false } diff --git a/common/src/gdt.rs b/common/src/gdt.rs index 9ac45ade..5ba16c5b 100644 --- a/common/src/gdt.rs +++ b/common/src/gdt.rs @@ -15,8 +15,8 @@ pub fn create_and_load(frame: PhysFrame) { let ptr: *mut GlobalDescriptorTable = virt_addr.as_mut_ptr(); let mut gdt = GlobalDescriptorTable::new(); - let code_selector = gdt.add_entry(Descriptor::kernel_code_segment()); - let data_selector = gdt.add_entry(Descriptor::kernel_data_segment()); + let code_selector = gdt.append(Descriptor::kernel_code_segment()); + let data_selector = gdt.append(Descriptor::kernel_data_segment()); let gdt = unsafe { ptr.write(gdt); &*ptr diff --git a/common/src/level_4_entries.rs b/common/src/level_4_entries.rs index c894d0b5..9757374f 100644 --- a/common/src/level_4_entries.rs +++ b/common/src/level_4_entries.rs @@ -48,7 +48,10 @@ impl UsedLevel4Entries { // The bootload needs to access the frame buffer. if let Some(frame_buffer) = framebuffer { - used.mark_range_as_used(frame_buffer.addr.as_u64(), frame_buffer.info.byte_len); + used.mark_range_as_used( + frame_buffer.addr.as_u64(), + frame_buffer.info.byte_len as u64, + ); } // Mark the statically configured ranges from the config as used. @@ -56,7 +59,7 @@ impl UsedLevel4Entries { if let Some(config::Mapping::FixedAddress(physical_memory_offset)) = config.mappings.physical_memory { - used.mark_range_as_used(physical_memory_offset, max_phys_addr.as_u64().into_usize()); + used.mark_range_as_used(physical_memory_offset, max_phys_addr.as_u64()); } if let Some(config::Mapping::FixedAddress(recursive_address)) = @@ -76,12 +79,12 @@ impl UsedLevel4Entries { let memory_regions_layout = Layout::array::(regions).unwrap(); let (combined, _) = boot_info_layout.extend(memory_regions_layout).unwrap(); - used.mark_range_as_used(boot_info_address, combined.size()); + used.mark_range_as_used(boot_info_address, combined.size() as u64); } if let config::Mapping::FixedAddress(framebuffer_address) = config.mappings.framebuffer { if let Some(framebuffer) = framebuffer { - used.mark_range_as_used(framebuffer_address, framebuffer.info.byte_len); + used.mark_range_as_used(framebuffer_address, framebuffer.info.byte_len as u64); } } @@ -111,14 +114,9 @@ impl UsedLevel4Entries { } /// Marks all p4 entries in the range `[address..address+size)` as used. - /// - /// `size` can be a `u64` or `usize`. - fn mark_range_as_used(&mut self, address: u64, size: S) - where - VirtAddr: core::ops::Add, - { + fn mark_range_as_used(&mut self, address: u64, size: u64) { let start = VirtAddr::new(address); - let end_inclusive = (start + size) - 1usize; + let end_inclusive = (start + size) - 1; let start_page = Page::::containing_address(start); let end_page_inclusive = Page::::containing_address(end_inclusive); diff --git a/common/src/lib.rs b/common/src/lib.rs index 1c8b1efe..475ab22e 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -285,8 +285,9 @@ where log::info!("Map framebuffer"); let framebuffer_start_frame: PhysFrame = PhysFrame::containing_address(framebuffer.addr); - let framebuffer_end_frame = - PhysFrame::containing_address(framebuffer.addr + framebuffer.info.byte_len - 1u64); + let framebuffer_end_frame = PhysFrame::containing_address( + framebuffer.addr + framebuffer.info.byte_len as u64 - 1u64, + ); let start_page = mapping_addr_page_aligned( config.mappings.framebuffer, u64::from_usize(framebuffer.info.byte_len), @@ -394,7 +395,7 @@ where } }; - let entry = &mut kernel_page_table.level_4_table()[index]; + let entry = &mut kernel_page_table.level_4_table_mut()[index]; if !entry.is_unused() { panic!( "Could not set up recursive mapping: index {} already in use", @@ -496,8 +497,8 @@ where ) .expect("boot info addr is not properly aligned"); - let memory_map_regions_addr = boot_info_addr + memory_regions_offset; - let memory_map_regions_end = boot_info_addr + combined.size(); + let memory_map_regions_addr = boot_info_addr + memory_regions_offset as u64; + let memory_map_regions_end = boot_info_addr + combined.size() as u64; let start_page = Page::containing_address(boot_info_addr); let end_page = Page::containing_address(memory_map_regions_end - 1u64); diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs index 0eab3a24..073f69ef 100644 --- a/common/src/load_kernel.rs +++ b/common/src/load_kernel.rs @@ -349,7 +349,7 @@ where let copy_len = end_inclusive_offset_in_frame - start_offset_in_frame + 1; // Calculate the physical addresses. - let start_phys_addr = phys_addr.start_address() + start_offset_in_frame; + let start_phys_addr = phys_addr.start_address() + start_offset_in_frame as u64; // These are the offsets from the start address. These correspond // to the destination indices in `buf`. @@ -416,7 +416,7 @@ where let copy_len = end_inclusive_offset_in_frame - start_offset_in_frame + 1; // Calculate the physical addresses. - let start_phys_addr = phys_addr.start_address() + start_offset_in_frame; + let start_phys_addr = phys_addr.start_address() + start_offset_in_frame as u64; // These are the offsets from the start address. These correspond // to the destination indices in `buf`. diff --git a/tests/test_kernels/Cargo.lock b/tests/test_kernels/Cargo.lock index 408c7bb2..00964519 100644 --- a/tests/test_kernels/Cargo.lock +++ b/tests/test_kernels/Cargo.lock @@ -36,7 +36,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -45,7 +45,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -54,7 +54,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -63,7 +63,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -72,7 +72,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -81,7 +81,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -90,7 +90,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -99,7 +99,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -108,7 +108,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.15.2", ] [[package]] @@ -119,7 +119,7 @@ checksum = "614ff2a87880d4bd4374722268598a970bbad05ced8bf630439417347254ab2e" dependencies = [ "bitflags 1.3.2", "rustversion", - "x86_64", + "x86_64 0.14.13", ] [[package]] @@ -139,3 +139,15 @@ dependencies = [ "rustversion", "volatile", ] + +[[package]] +name = "x86_64" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f042214de98141e9c8706e8192b73f56494087cc55ebec28ce10f26c5c364ae" +dependencies = [ + "bit_field", + "bitflags 2.8.0", + "rustversion", + "volatile", +] diff --git a/tests/test_kernels/config_file/Cargo.toml b/tests/test_kernels/config_file/Cargo.toml index 990b9508..86a90cf7 100644 --- a/tests/test_kernels/config_file/Cargo.toml +++ b/tests/test_kernels/config_file/Cargo.toml @@ -6,8 +6,7 @@ edition = "2021" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/default_settings/Cargo.toml b/tests/test_kernels/default_settings/Cargo.toml index 81e1be2f..8d643cdd 100644 --- a/tests/test_kernels/default_settings/Cargo.toml +++ b/tests/test_kernels/default_settings/Cargo.toml @@ -6,8 +6,7 @@ edition = "2021" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/higher_half/Cargo.toml b/tests/test_kernels/higher_half/Cargo.toml index aedecae0..b7d7f2c7 100644 --- a/tests/test_kernels/higher_half/Cargo.toml +++ b/tests/test_kernels/higher_half/Cargo.toml @@ -8,9 +8,8 @@ edition = "2021" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/lower_memory_free/Cargo.toml b/tests/test_kernels/lower_memory_free/Cargo.toml index 65b06da2..be0249c7 100644 --- a/tests/test_kernels/lower_memory_free/Cargo.toml +++ b/tests/test_kernels/lower_memory_free/Cargo.toml @@ -5,8 +5,7 @@ edition = "2021" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/lto/Cargo.toml b/tests/test_kernels/lto/Cargo.toml index 030625c1..0f8e4e3c 100644 --- a/tests/test_kernels/lto/Cargo.toml +++ b/tests/test_kernels/lto/Cargo.toml @@ -6,8 +6,7 @@ edition = "2018" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/map_phys_mem/Cargo.toml b/tests/test_kernels/map_phys_mem/Cargo.toml index 51233f1c..5dcb5b16 100644 --- a/tests/test_kernels/map_phys_mem/Cargo.toml +++ b/tests/test_kernels/map_phys_mem/Cargo.toml @@ -6,8 +6,7 @@ edition = "2021" [target.'cfg(target_arch = "x86_64")'.dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/min_stack/Cargo.toml b/tests/test_kernels/min_stack/Cargo.toml index afc7c2d6..82aae6d3 100644 --- a/tests/test_kernels/min_stack/Cargo.toml +++ b/tests/test_kernels/min_stack/Cargo.toml @@ -6,8 +6,7 @@ edition = "2021" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/pie/Cargo.toml b/tests/test_kernels/pie/Cargo.toml index c6ee298a..93f71abd 100644 --- a/tests/test_kernels/pie/Cargo.toml +++ b/tests/test_kernels/pie/Cargo.toml @@ -6,8 +6,7 @@ edition = "2018" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/ramdisk/Cargo.toml b/tests/test_kernels/ramdisk/Cargo.toml index 4258b0a5..0ca537e7 100644 --- a/tests/test_kernels/ramdisk/Cargo.toml +++ b/tests/test_kernels/ramdisk/Cargo.toml @@ -6,8 +6,7 @@ edition = "2021" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/tests/test_kernels/write_usable_memory/Cargo.toml b/tests/test_kernels/write_usable_memory/Cargo.toml index 88cf640f..200abc9d 100644 --- a/tests/test_kernels/write_usable_memory/Cargo.toml +++ b/tests/test_kernels/write_usable_memory/Cargo.toml @@ -5,8 +5,7 @@ edition = "2021" [dependencies] bootloader_api = { path = "../../../api" } -x86_64 = { version = "0.14.7", default-features = false, features = [ +x86_64 = { version = "0.15.2", default-features = false, features = [ "instructions", - "inline_asm", ] } uart_16550 = "0.2.10" diff --git a/uefi/Cargo.toml b/uefi/Cargo.toml index 80168be5..9e96ce64 100644 --- a/uefi/Cargo.toml +++ b/uefi/Cargo.toml @@ -13,6 +13,6 @@ bootloader_api = { workspace = true } bootloader-x86_64-common = { workspace = true } bootloader-boot-config = { workspace = true } log = "0.4.14" -x86_64 = "0.14.8" +x86_64 = "0.15.2" serde-json-core = "0.5.0" uefi = "0.20.0" diff --git a/uefi/src/main.rs b/uefi/src/main.rs index 0ad26557..1ee17c0d 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -423,7 +423,7 @@ fn create_page_tables( // necessarily part of the identity mapping). if let Some(frame_buffer) = frame_buffer { let start_addr = VirtAddr::new(frame_buffer.addr.as_u64()); - let end_addr = start_addr + frame_buffer.info.byte_len; + let end_addr = start_addr + frame_buffer.info.byte_len as u64; for p4 in usize::from(start_addr.p4_index())..=usize::from(end_addr.p4_index()) { new_table[p4] = old_table[p4].clone(); } From 42f095fc52ba59150595764e98e381329e16b5da Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sun, 2 Feb 2025 09:09:36 -0800 Subject: [PATCH 66/80] Remove cast in common/src/load_kernel.rs:412 --- common/src/load_kernel.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs index 073f69ef..3c79bd0c 100644 --- a/common/src/load_kernel.rs +++ b/common/src/load_kernel.rs @@ -409,14 +409,14 @@ where let end_inclusive_copy_address = cmp::min(end_inclusive_addr, page_end_inclusive); // These are the offsets into the frame we want to copy from. - let start_offset_in_frame = (start_copy_address - page_start) as usize; - let end_inclusive_offset_in_frame = (end_inclusive_copy_address - page_start) as usize; + let start_offset_in_frame = start_copy_address - page_start; + let end_inclusive_offset_in_frame = end_inclusive_copy_address - page_start; // Calculate how many bytes we want to copy from this frame. let copy_len = end_inclusive_offset_in_frame - start_offset_in_frame + 1; // Calculate the physical addresses. - let start_phys_addr = phys_addr.start_address() + start_offset_in_frame as u64; + let start_phys_addr = phys_addr.start_address() + start_offset_in_frame; // These are the offsets from the start address. These correspond // to the destination indices in `buf`. @@ -429,11 +429,11 @@ where // SAFETY: We know that this memory is valid because we got it // as a result from a translation. There are not other // references to it. - &mut *core::ptr::slice_from_raw_parts_mut(dest_ptr, copy_len) + &mut *core::ptr::slice_from_raw_parts_mut(dest_ptr, copy_len as usize) }; // Calculate the destination pointer. - let src = &buf[start_offset_in_buf..][..copy_len]; + let src = &buf[start_offset_in_buf..][..copy_len as usize]; // Do the actual copy. dest.copy_from_slice(src); From 449d31e3004514790c723e2f8e70da6d1dcf9740 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sun, 2 Feb 2025 09:30:25 -0800 Subject: [PATCH 67/80] Remove more casts in load_kernel.rs --- common/src/load_kernel.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs index 3c79bd0c..b1c35560 100644 --- a/common/src/load_kernel.rs +++ b/common/src/load_kernel.rs @@ -342,14 +342,14 @@ where let end_inclusive_copy_address = cmp::min(end_inclusive_addr, page_end_inclusive); // These are the offsets into the frame we want to copy from. - let start_offset_in_frame = (start_copy_address - page_start) as usize; - let end_inclusive_offset_in_frame = (end_inclusive_copy_address - page_start) as usize; + let start_offset_in_frame = start_copy_address - page_start; + let end_inclusive_offset_in_frame = end_inclusive_copy_address - page_start; // Calculate how many bytes we want to copy from this frame. let copy_len = end_inclusive_offset_in_frame - start_offset_in_frame + 1; // Calculate the physical addresses. - let start_phys_addr = phys_addr.start_address() + start_offset_in_frame as u64; + let start_phys_addr = phys_addr.start_address() + start_offset_in_frame; // These are the offsets from the start address. These correspond // to the destination indices in `buf`. @@ -362,11 +362,11 @@ where // SAFETY: We know that this memory is valid because we got it // as a result from a translation. There are not other // references to it. - &*core::ptr::slice_from_raw_parts(src_ptr, copy_len) + &*core::ptr::slice_from_raw_parts(src_ptr, copy_len as usize) }; // Calculate the destination pointer. - let dest = &mut buf[start_offset_in_buf..][..copy_len]; + let dest = &mut buf[start_offset_in_buf..][..copy_len as usize]; // Do the actual copy. dest.copy_from_slice(src); From 704b2c3ce985c0d30218085d11f9016dab100f6f Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 4 Feb 2025 06:44:11 +0100 Subject: [PATCH 68/80] change rustc-abi in custom targets to x86-softfloat With the latest nightly, setting "+soft-float" in "features" is only allowed if "rustc-abi" is set to "x86-softfloat". --- i686-stage-3.json | 3 ++- x86_64-stage-4.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/i686-stage-3.json b/i686-stage-3.json index c89fac10..227250d4 100644 --- a/i686-stage-3.json +++ b/i686-stage-3.json @@ -17,5 +17,6 @@ "os": "none", "vendor": "unknown", "relocation-model": "static", - "features": "+soft-float,-sse,-mmx" + "features": "+soft-float,-sse,-mmx", + "rustc-abi": "x86-softfloat" } diff --git a/x86_64-stage-4.json b/x86_64-stage-4.json index 40102494..b2e7e997 100644 --- a/x86_64-stage-4.json +++ b/x86_64-stage-4.json @@ -18,5 +18,6 @@ "static-position-independent-executables": true, "target-pointer-width": "64", "relocation-model": "static", - "os": "none" + "os": "none", + "rustc-abi": "x86-softfloat" } From d60e374f49ea8e310b6cca6c8358178f28410490 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 10 Feb 2025 10:55:47 +0100 Subject: [PATCH 69/80] Release `v0.11.10` --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 10 +++++----- Changelog.md | 7 +++++++ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbdac28a..885893a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,7 +70,7 @@ dependencies = [ [[package]] name = "bootloader" -version = "0.11.9" +version = "0.11.10" dependencies = [ "anyhow", "bootloader-boot-config", @@ -94,22 +94,22 @@ dependencies = [ [[package]] name = "bootloader-boot-config" -version = "0.11.9" +version = "0.11.10" dependencies = [ "serde", ] [[package]] name = "bootloader-x86_64-bios-boot-sector" -version = "0.11.9" +version = "0.11.10" [[package]] name = "bootloader-x86_64-bios-common" -version = "0.11.9" +version = "0.11.10" [[package]] name = "bootloader-x86_64-bios-stage-2" -version = "0.11.9" +version = "0.11.10" dependencies = [ "bootloader-x86_64-bios-common", "byteorder", @@ -118,7 +118,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-3" -version = "0.11.9" +version = "0.11.10" dependencies = [ "bootloader-x86_64-bios-common", "noto-sans-mono-bitmap 0.1.6", @@ -126,7 +126,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-4" -version = "0.11.9" +version = "0.11.10" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-bios-common", @@ -141,7 +141,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-common" -version = "0.11.9" +version = "0.11.10" dependencies = [ "bootloader-boot-config", "bootloader_api", @@ -160,7 +160,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-uefi" -version = "0.11.9" +version = "0.11.10" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-common", @@ -173,7 +173,7 @@ dependencies = [ [[package]] name = "bootloader_api" -version = "0.11.9" +version = "0.11.10" dependencies = [ "rand", ] diff --git a/Cargo.toml b/Cargo.toml index 3b0c9a4d..b4ca4946 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,15 +22,15 @@ exclude = ["examples/basic", "examples/test_framework", "tests/test_kernels/*"] [workspace.package] # don't forget to update `workspace.dependencies` below -version = "0.11.9" +version = "0.11.10" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-osdev/bootloader" [workspace.dependencies] -bootloader_api = { version = "0.11.8", path = "api" } -bootloader-x86_64-common = { version = "0.11.8", path = "common" } -bootloader-boot-config = { version = "0.11.8", path = "common/config" } -bootloader-x86_64-bios-common = { version = "0.11.8", path = "bios/common" } +bootloader_api = { version = "0.11.10", path = "api" } +bootloader-x86_64-common = { version = "0.11.10", path = "common" } +bootloader-boot-config = { version = "0.11.10", path = "common/config" } +bootloader-x86_64-bios-common = { version = "0.11.10", path = "bios/common" } [features] default = ["bios", "uefi"] diff --git a/Changelog.md b/Changelog.md index 4348f47e..30e1e0ce 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,12 @@ # Unreleased +* [Remove "UEFI boot" log message](https://github.com/rust-osdev/bootloader/pull/476) +* [use threads instead of futures in build.rs](https://github.com/rust-osdev/bootloader/pull/484) +* [Move test kernels to a separate workspace](https://github.com/rust-osdev/bootloader/pull/486) +* [fix condition for running bootloader common tests](https://github.com/rust-osdev/bootloader/pull/487) +* [Update `x86_64` to `0.15.2`](https://github.com/rust-osdev/bootloader/pull/490) +* [change rustc-abi in custom targets to x86-softfloat](https://github.com/rust-osdev/bootloader/pull/491) + # 0.11.9 – 2024-11-30 This release is compatible with Rust nightlies starting with `nightly-2024-11-23`. From 3d81486dd05632daf6680aba1364c2d49e334543 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 10 Feb 2025 13:31:32 +0100 Subject: [PATCH 70/80] Add section header and link to full changelog --- Changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changelog.md b/Changelog.md index 30e1e0ce..8fbde67c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,7 @@ # Unreleased +# 0.11.10 – 2025-02-10 + * [Remove "UEFI boot" log message](https://github.com/rust-osdev/bootloader/pull/476) * [use threads instead of futures in build.rs](https://github.com/rust-osdev/bootloader/pull/484) * [Move test kernels to a separate workspace](https://github.com/rust-osdev/bootloader/pull/486) @@ -7,6 +9,8 @@ * [Update `x86_64` to `0.15.2`](https://github.com/rust-osdev/bootloader/pull/490) * [change rustc-abi in custom targets to x86-softfloat](https://github.com/rust-osdev/bootloader/pull/491) +**Full Changelog**: https://github.com/rust-osdev/bootloader/compare/v0.11.9...v0.11.10 + # 0.11.9 – 2024-11-30 This release is compatible with Rust nightlies starting with `nightly-2024-11-23`. From 2d22245f14eb1513cd9e106ed609f27b0c0cb122 Mon Sep 17 00:00:00 2001 From: Justus Flerlage Date: Fri, 14 Feb 2025 17:04:11 +0100 Subject: [PATCH 71/80] Update uart_16550 to 0.3.2 --- common/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/Cargo.toml b/common/Cargo.toml index 7375b940..7f9531c6 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -19,7 +19,7 @@ xmas-elf = "0.8.0" raw-cpuid = "10.2.0" rand = { version = "0.8.4", default-features = false } rand_hc = "0.3.1" -uart_16550 = "0.2.18" +uart_16550 = "0.3.2" log = "0.4.17" [dependencies.noto-sans-mono-bitmap] From fa4be39490b9939e60721f9e468f0306f831b919 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Mon, 10 Feb 2025 14:19:05 +0100 Subject: [PATCH 72/80] Specify kernel-base virt addr in BootloaderConfig --- Cargo.lock | 10 +++ Cargo.toml | 1 + Changelog.md | 6 ++ api/build.rs | 9 ++- api/src/config.rs | 35 +++++--- common/src/legacy_memory_region.rs | 6 +- common/src/level_4_entries.rs | 30 ++++++- common/src/lib.rs | 4 +- common/src/load_kernel.rs | 80 ++++++++++++++----- tests/fixed_kernel_address.rs | 29 +++++++ tests/test_kernels/Cargo.lock | 11 ++- tests/test_kernels/Cargo.toml | 1 + .../fixed_kernel_address/Cargo.toml | 11 +++ .../src/bin/basic_boot.rs | 18 +++++ .../src/bin/check_boot_info.rs | 23 ++++++ .../src/bin/should_panic.rs | 20 +++++ .../src/bin/verify_kernel_address.rs | 29 +++++++ .../fixed_kernel_address/src/lib.rs | 37 +++++++++ 18 files changed, 313 insertions(+), 47 deletions(-) create mode 100644 tests/fixed_kernel_address.rs create mode 100644 tests/test_kernels/fixed_kernel_address/Cargo.toml create mode 100644 tests/test_kernels/fixed_kernel_address/src/bin/basic_boot.rs create mode 100644 tests/test_kernels/fixed_kernel_address/src/bin/check_boot_info.rs create mode 100644 tests/test_kernels/fixed_kernel_address/src/bin/should_panic.rs create mode 100644 tests/test_kernels/fixed_kernel_address/src/bin/verify_kernel_address.rs create mode 100644 tests/test_kernels/fixed_kernel_address/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 885893a3..2efbcb2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,6 +83,7 @@ dependencies = [ "tempfile", "test_kernel_config_file", "test_kernel_default_settings", + "test_kernel_fixed_kernel_address", "test_kernel_higher_half", "test_kernel_lower_memory_free", "test_kernel_map_phys_mem", @@ -746,6 +747,15 @@ dependencies = [ "x86_64 0.15.2", ] +[[package]] +name = "test_kernel_fixed_kernel_address" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64 0.15.2", +] + [[package]] name = "test_kernel_higher_half" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index b4ca4946..4edbbc78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ test_kernel_config_file = { path = "tests/test_kernels/config_file", artifact = test_kernel_min_stack = { path = "tests/test_kernels/min_stack", artifact = "bin", target = "x86_64-unknown-none" } test_kernel_lower_memory_free = { path = "tests/test_kernels/lower_memory_free", artifact = "bin", target = "x86_64-unknown-none" } test_kernel_write_usable_memory = { path = "tests/test_kernels/write_usable_memory", artifact = "bin", target = "x86_64-unknown-none" } +test_kernel_fixed_kernel_address = { path = "tests/test_kernels/fixed_kernel_address", artifact = "bin", target = "x86_64-unknown-none" } [profile.dev] panic = "abort" diff --git a/Changelog.md b/Changelog.md index 8fbde67c..4ec903fa 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,11 @@ # Unreleased +## Features + +* add `kernel_base` mapping to the BootloaderConfig to specify the virtual address + at which position-independent kernels are loaded. + + # 0.11.10 – 2025-02-10 * [Remove "UEFI boot" log message](https://github.com/rust-osdev/bootloader/pull/476) diff --git a/api/build.rs b/api/build.rs index e0b1437d..75754523 100644 --- a/api/build.rs +++ b/api/build.rs @@ -15,14 +15,15 @@ fn main() { (31, 9), (40, 9), (49, 9), - (58, 10), - (68, 10), - (78, 1), - (79, 9), + (58, 9), + (67, 10), + (77, 10), + (87, 1), (88, 9), (97, 9), (106, 9), (115, 9), + (124, 9), ]; let mut code = String::new(); diff --git a/api/src/config.rs b/api/src/config.rs index 9def2a5f..5de0db3e 100644 --- a/api/src/config.rs +++ b/api/src/config.rs @@ -43,7 +43,7 @@ impl BootloaderConfig { 0x3D, ]; #[doc(hidden)] - pub const SERIALIZED_LEN: usize = 124; + pub const SERIALIZED_LEN: usize = 133; /// Creates a new default configuration with the following values: /// @@ -77,6 +77,7 @@ impl BootloaderConfig { } = version; let Mappings { kernel_stack, + kernel_base, boot_info, framebuffer, physical_memory, @@ -97,35 +98,38 @@ impl BootloaderConfig { concat_4_3(one, two) }; let buf = concat_16_7(Self::UUID, version); + let buf = concat_23_8(buf, kernel_stack_size.to_le_bytes()); let buf = concat_31_9(buf, kernel_stack.serialize()); - let buf = concat_40_9(buf, boot_info.serialize()); - let buf = concat_49_9(buf, framebuffer.serialize()); + let buf = concat_40_9(buf, kernel_base.serialize()); + + let buf = concat_49_9(buf, boot_info.serialize()); + let buf = concat_58_9(buf, framebuffer.serialize()); - let buf = concat_58_10( + let buf = concat_67_10( buf, match physical_memory { Option::None => [0; 10], Option::Some(m) => concat_1_9([1], m.serialize()), }, ); - let buf = concat_68_10( + let buf = concat_77_10( buf, match page_table_recursive { Option::None => [0; 10], Option::Some(m) => concat_1_9([1], m.serialize()), }, ); - let buf = concat_78_1(buf, [(*aslr) as u8]); - let buf = concat_79_9( + let buf = concat_87_1(buf, [(*aslr) as u8]); + let buf = concat_88_9( buf, match dynamic_range_start { Option::None => [0; 9], Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()), }, ); - let buf = concat_88_9( + let buf = concat_97_9( buf, match dynamic_range_end { Option::None => [0; 9], @@ -133,9 +137,9 @@ impl BootloaderConfig { }, ); - let buf = concat_97_9(buf, ramdisk_memory.serialize()); + let buf = concat_106_9(buf, ramdisk_memory.serialize()); - let buf = concat_106_9( + let buf = concat_115_9( buf, match minimum_framebuffer_height { Option::None => [0; 9], @@ -143,7 +147,7 @@ impl BootloaderConfig { }, ); - concat_115_9( + concat_124_9( buf, match minimum_framebuffer_width { Option::None => [0; 9], @@ -196,6 +200,7 @@ impl BootloaderConfig { let (mappings, s) = { let (&kernel_stack, s) = split_array_ref(s); + let (&kernel_base, s) = split_array_ref(s); let (&boot_info, s) = split_array_ref(s); let (&framebuffer, s) = split_array_ref(s); let (&physical_memory_some, s) = split_array_ref(s); @@ -211,6 +216,7 @@ impl BootloaderConfig { let mappings = Mappings { kernel_stack: Mapping::deserialize(&kernel_stack)?, + kernel_base: Mapping::deserialize(&kernel_base)?, boot_info: Mapping::deserialize(&boot_info)?, framebuffer: Mapping::deserialize(&framebuffer)?, physical_memory: match physical_memory_some { @@ -371,6 +377,11 @@ pub struct Mappings { /// `FixedAddress(0xf_0000_0000)` will result in a guard page at address /// `0xf_0000_0000` and the kernel stack starting at address `0xf_0000_1000`. pub kernel_stack: Mapping, + /// Configures the base address of the kernel. + /// + /// If a fixed address is set, it must be paged aligned and the kernel must be + /// a position-independent exectuable. + pub kernel_base: Mapping, /// Specifies where the [`crate::BootInfo`] struct should be placed in virtual memory. pub boot_info: Mapping, /// Specifies the mapping of the frame buffer memory region. @@ -413,6 +424,7 @@ impl Mappings { pub const fn new_default() -> Self { Self { kernel_stack: Mapping::new_default(), + kernel_base: Mapping::new_default(), boot_info: Mapping::new_default(), framebuffer: Mapping::new_default(), physical_memory: Option::None, @@ -430,6 +442,7 @@ impl Mappings { let recursive = rand::random(); Self { kernel_stack: Mapping::random(), + kernel_base: Mapping::random(), boot_info: Mapping::random(), framebuffer: Mapping::random(), physical_memory: if phys { diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs index baa7d0b9..0c613392 100644 --- a/common/src/legacy_memory_region.rs +++ b/common/src/legacy_memory_region.rs @@ -1,9 +1,5 @@ use bootloader_api::info::{MemoryRegion, MemoryRegionKind}; -use core::{ - cmp, - iter::{empty, Empty}, - mem::MaybeUninit, -}; +use core::{cmp, mem::MaybeUninit}; use x86_64::{ align_down, align_up, structures::paging::{FrameAllocator, PhysFrame, Size4KiB}, diff --git a/common/src/level_4_entries.rs b/common/src/level_4_entries.rs index 9757374f..926dd541 100644 --- a/common/src/level_4_entries.rs +++ b/common/src/level_4_entries.rs @@ -1,4 +1,8 @@ -use crate::{entropy, load_kernel::VirtualAddressOffset, BootInfo, RawFrameBufferInfo}; +use crate::{ + entropy, + load_kernel::{calc_elf_memory_requirements, ElfMemoryRequirements, VirtualAddressOffset}, + BootInfo, RawFrameBufferInfo, +}; use bootloader_api::{config, info::MemoryRegion, BootloaderConfig}; use core::{alloc::Layout, iter::Step}; use rand::{ @@ -11,7 +15,7 @@ use x86_64::{ structures::paging::{Page, PageTableIndex, Size4KiB}, PhysAddr, VirtAddr, }; -use xmas_elf::program::ProgramHeader; +use xmas_elf::{header, program::ProgramHeader, ElfFile}; /// Keeps track of used entries in a level 4 page table. /// @@ -33,7 +37,8 @@ impl UsedLevel4Entries { regions_len: usize, framebuffer: Option<&RawFrameBufferInfo>, config: &BootloaderConfig, - ) -> Self { + kernel_elf: &ElfFile<'_>, + ) -> Result { let mut used = UsedLevel4Entries { entry_state: [false; 512], rng: config.mappings.aslr.then(entropy::build_rng), @@ -73,6 +78,23 @@ impl UsedLevel4Entries { used.mark_range_as_used(kernel_stack_address, config.kernel_stack_size); } + if let config::Mapping::FixedAddress(kernel_base) = config.mappings.kernel_base { + let ElfMemoryRequirements { size, align, .. } = + calc_elf_memory_requirements(kernel_elf); + + if !VirtAddr::new(kernel_base).is_aligned(align) { + return Err("kernel_code mapping alignment does not match elf file"); + } + + used.mark_range_as_used(kernel_base, size); + } + if kernel_elf.header.pt2.type_().as_type() == header::Type::Executable { + let ElfMemoryRequirements { size, min_addr, .. } = + calc_elf_memory_requirements(kernel_elf); + + used.mark_range_as_used(min_addr, size); + } + if let config::Mapping::FixedAddress(boot_info_address) = config.mappings.boot_info { let boot_info_layout = Layout::new::(); let regions = regions_len + 1; // one region might be split into used/unused @@ -110,7 +132,7 @@ impl UsedLevel4Entries { } } - used + Ok(used) } /// Marks all p4 entries in the range `[address..address+size)` as used. diff --git a/common/src/lib.rs b/common/src/lib.rs index 475ab22e..0a4f729d 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -187,7 +187,9 @@ where frame_allocator.len(), framebuffer, config, - ); + &kernel.elf, + ) + .expect("Failed to mark level 4 entries as used"); // Enable support for the no-execute bit in page tables. enable_nxe_bit(); diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs index b1c35560..b54bd246 100644 --- a/common/src/load_kernel.rs +++ b/common/src/load_kernel.rs @@ -1,5 +1,5 @@ use crate::{level_4_entries::UsedLevel4Entries, PAGE_SIZE}; -use bootloader_api::info::TlsTemplate; +use bootloader_api::{config::Mapping, info::TlsTemplate}; use core::{cmp, iter::Step, mem::size_of, ops::Add}; use x86_64::{ @@ -59,27 +59,30 @@ where let virtual_address_offset = match elf_file.header.pt2.type_().as_type() { header::Type::None => unimplemented!(), header::Type::Relocatable => unimplemented!(), - header::Type::Executable => VirtualAddressOffset::zero(), + header::Type::Executable => match kernel.config.mappings.kernel_base { + Mapping::Dynamic => VirtualAddressOffset::zero(), + _ => { + return Err(concat!( + "Invalid kernel_code mapping. ", + "Executable can only be mapped at virtual_address_offset 0." + )) + } + }, header::Type::SharedObject => { - // Find the highest virtual memory address and the biggest alignment. - let load_program_headers = elf_file - .program_iter() - .filter(|h| matches!(h.get_type(), Ok(Type::Load))); - let max_addr = load_program_headers - .clone() - .map(|h| h.virtual_addr() + h.mem_size()) - .max() - .unwrap_or(0); - let min_addr = load_program_headers - .clone() - .map(|h| h.virtual_addr()) - .min() - .unwrap_or(0); - let size = max_addr - min_addr; - let align = load_program_headers.map(|h| h.align()).max().unwrap_or(1); - - let offset = used_entries.get_free_address(size, align).as_u64(); - VirtualAddressOffset::new(i128::from(offset) - i128::from(min_addr)) + let ElfMemoryRequirements { + size, + align, + min_addr, + } = calc_elf_memory_requirements(&elf_file); + match kernel.config.mappings.kernel_base { + Mapping::Dynamic => { + let offset = used_entries.get_free_address(size, align).as_u64(); + VirtualAddressOffset::new(i128::from(offset) - i128::from(min_addr)) + } + Mapping::FixedAddress(address) => { + VirtualAddressOffset::new(i128::from(address)) + } + } } header::Type::Core => unimplemented!(), header::Type::ProcessorSpecific(_) => unimplemented!(), @@ -750,6 +753,41 @@ pub fn load_kernel( )) } +/// Basic information about the memory segments of an elf file. +pub struct ElfMemoryRequirements { + /// total size needed for all segments + pub size: u64, + /// memory alignment for the elf file + pub align: u64, + /// the smallest virtual address used by the elf file + pub min_addr: u64, +} + +/// Calculates basic requirements needed to allocate memory for an elf file. +pub fn calc_elf_memory_requirements(elf_file: &ElfFile) -> ElfMemoryRequirements { + // Find the highest virtual memory address and the biggest alignment. + let load_program_headers = elf_file + .program_iter() + .filter(|h| matches!(h.get_type(), Ok(Type::Load))); + let max_addr = load_program_headers + .clone() + .map(|h| h.virtual_addr() + h.mem_size()) + .max() + .unwrap_or(0); + let min_addr = load_program_headers + .clone() + .map(|h| h.virtual_addr()) + .min() + .unwrap_or(0); + let size = max_addr - min_addr; + let align = load_program_headers.map(|h| h.align()).max().unwrap_or(1); + ElfMemoryRequirements { + size, + align, + min_addr, + } +} + /// A helper type used to offset virtual addresses for position independent /// executables. #[derive(Clone, Copy)] diff --git a/tests/fixed_kernel_address.rs b/tests/fixed_kernel_address.rs new file mode 100644 index 00000000..25e15d67 --- /dev/null +++ b/tests/fixed_kernel_address.rs @@ -0,0 +1,29 @@ +use bootloader_test_runner::run_test_kernel; + +#[test] +fn basic_boot() { + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_FIXED_KERNEL_ADDRESS_basic_boot" + )); +} + +#[test] +fn should_panic() { + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_FIXED_KERNEL_ADDRESS_should_panic" + )); +} + +#[test] +fn check_boot_info() { + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_FIXED_KERNEL_ADDRESS_check_boot_info" + )); +} + +#[test] +fn verify_kernel_address() { + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_FIXED_KERNEL_ADDRESS_verify_kernel_address" + )); +} diff --git a/tests/test_kernels/Cargo.lock b/tests/test_kernels/Cargo.lock index 00964519..110fc16d 100644 --- a/tests/test_kernels/Cargo.lock +++ b/tests/test_kernels/Cargo.lock @@ -22,7 +22,7 @@ checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bootloader_api" -version = "0.11.9" +version = "0.11.10" [[package]] name = "rustversion" @@ -39,6 +39,15 @@ dependencies = [ "x86_64 0.15.2", ] +[[package]] +name = "test_kernel_fixed_kernel_address" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64 0.15.2", +] + [[package]] name = "test_kernel_higher_half" version = "0.1.0" diff --git a/tests/test_kernels/Cargo.toml b/tests/test_kernels/Cargo.toml index f9216bf8..80daa869 100644 --- a/tests/test_kernels/Cargo.toml +++ b/tests/test_kernels/Cargo.toml @@ -12,6 +12,7 @@ members = [ "min_stack", "lower_memory_free", "write_usable_memory", + "fixed_kernel_address", ] [profile.release] diff --git a/tests/test_kernels/fixed_kernel_address/Cargo.toml b/tests/test_kernels/fixed_kernel_address/Cargo.toml new file mode 100644 index 00000000..8a402dca --- /dev/null +++ b/tests/test_kernels/fixed_kernel_address/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "test_kernel_fixed_kernel_address" +version = "0.1.0" +edition = "2021" + +[target.'cfg(target_arch = "x86_64")'.dependencies] +bootloader_api = { path = "../../../api" } +x86_64 = { version = "0.15.2", default-features = false, features = [ + "instructions", +] } +uart_16550 = "0.2.10" diff --git a/tests/test_kernels/fixed_kernel_address/src/bin/basic_boot.rs b/tests/test_kernels/fixed_kernel_address/src/bin/basic_boot.rs new file mode 100644 index 00000000..6d8f696c --- /dev/null +++ b/tests/test_kernels/fixed_kernel_address/src/bin/basic_boot.rs @@ -0,0 +1,18 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{entry_point, BootInfo}; +use test_kernel_fixed_kernel_address::{exit_qemu, QemuExitCode, BOOTLOADER_CONFIG}; + +entry_point!(kernel_main, config = &BOOTLOADER_CONFIG); + +fn kernel_main(_boot_info: &'static mut BootInfo) -> ! { + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + exit_qemu(QemuExitCode::Failed); +} diff --git a/tests/test_kernels/fixed_kernel_address/src/bin/check_boot_info.rs b/tests/test_kernels/fixed_kernel_address/src/bin/check_boot_info.rs new file mode 100644 index 00000000..24267c7a --- /dev/null +++ b/tests/test_kernels/fixed_kernel_address/src/bin/check_boot_info.rs @@ -0,0 +1,23 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{entry_point, BootInfo}; +use test_kernel_fixed_kernel_address::{exit_qemu, QemuExitCode, BOOTLOADER_CONFIG, KERNEL_ADDR}; + +entry_point!(kernel_main, config = &BOOTLOADER_CONFIG); + +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { + assert_eq!(boot_info.kernel_image_offset, KERNEL_ADDR); + + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + use core::fmt::Write; + + let _ = writeln!(test_kernel_fixed_kernel_address::serial(), "PANIC: {info}"); + exit_qemu(QemuExitCode::Failed); +} diff --git a/tests/test_kernels/fixed_kernel_address/src/bin/should_panic.rs b/tests/test_kernels/fixed_kernel_address/src/bin/should_panic.rs new file mode 100644 index 00000000..a005c051 --- /dev/null +++ b/tests/test_kernels/fixed_kernel_address/src/bin/should_panic.rs @@ -0,0 +1,20 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{entry_point, BootInfo}; +use test_kernel_fixed_kernel_address::BOOTLOADER_CONFIG; + +entry_point!(kernel_main, config = &BOOTLOADER_CONFIG); + +fn kernel_main(_boot_info: &'static mut BootInfo) -> ! { + panic!(); +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + use test_kernel_fixed_kernel_address::{exit_qemu, QemuExitCode}; + + exit_qemu(QemuExitCode::Success); +} diff --git a/tests/test_kernels/fixed_kernel_address/src/bin/verify_kernel_address.rs b/tests/test_kernels/fixed_kernel_address/src/bin/verify_kernel_address.rs new file mode 100644 index 00000000..13944bd1 --- /dev/null +++ b/tests/test_kernels/fixed_kernel_address/src/bin/verify_kernel_address.rs @@ -0,0 +1,29 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{entry_point, BootInfo}; +use test_kernel_fixed_kernel_address::{exit_qemu, QemuExitCode, BOOTLOADER_CONFIG, KERNEL_ADDR}; + +entry_point!(kernel_main, config = &BOOTLOADER_CONFIG); + +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { + // verify that kernel is loaded at the specified base address. + let rip = x86_64::registers::read_rip().as_u64(); + let kernel_start = KERNEL_ADDR; + let kernel_end = kernel_start + boot_info.kernel_len; + let kernel_range = kernel_start..kernel_end; + + assert!(kernel_range.contains(&rip)); + + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + use core::fmt::Write; + + let _ = writeln!(test_kernel_fixed_kernel_address::serial(), "PANIC: {info}"); + exit_qemu(QemuExitCode::Failed); +} diff --git a/tests/test_kernels/fixed_kernel_address/src/lib.rs b/tests/test_kernels/fixed_kernel_address/src/lib.rs new file mode 100644 index 00000000..1231418a --- /dev/null +++ b/tests/test_kernels/fixed_kernel_address/src/lib.rs @@ -0,0 +1,37 @@ +#![no_std] + +use bootloader_api::{config::Mapping, BootloaderConfig}; + +pub const KERNEL_ADDR: u64 = 0x1987_6543_0000; + +pub const BOOTLOADER_CONFIG: BootloaderConfig = { + let mut config = BootloaderConfig::new_default(); + config.mappings.kernel_base = Mapping::FixedAddress(KERNEL_ADDR); + config +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum QemuExitCode { + Success = 0x10, + Failed = 0x11, +} + +pub fn exit_qemu(exit_code: QemuExitCode) -> ! { + use x86_64::instructions::{nop, port::Port}; + + unsafe { + let mut port = Port::new(0xf4); + port.write(exit_code as u32); + } + + loop { + nop(); + } +} + +pub fn serial() -> uart_16550::SerialPort { + let mut port = unsafe { uart_16550::SerialPort::new(0x3F8) }; + port.init(); + port +} From 3cb6e6f6291ab4fcb63286e15aeca2ac0a0d3e70 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe Date: Tue, 25 Feb 2025 13:35:58 -0800 Subject: [PATCH 73/80] Use `Result::ok` (#496) * Use `Result::ok` * Update uefi/src/main.rs --------- Co-authored-by: Tom Dohrmann --- uefi/src/main.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/uefi/src/main.rs b/uefi/src/main.rs index 1ee17c0d..99a4821c 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -313,10 +313,7 @@ fn load_file_from_disk( let file_handle_result = root.open(filename, FileMode::Read, FileAttribute::empty()); - let file_handle = match file_handle_result { - Err(_) => return None, - Ok(handle) => handle, - }; + let file_handle = file_handle_result.ok()?; let mut file = match file_handle.into_type().unwrap() { uefi::proto::media::file::FileType::Regular(f) => f, From fe2d2b936e41b8fe6ab5d8d650a82a9e2bd37b60 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 1 Apr 2025 19:56:43 +0200 Subject: [PATCH 74/80] implement Send+Sync for MemoryRegions This also makes BootInfo Send+Sync. It's now possible to store BootInfo in a static without resorting to unsafe code. --- api/src/info.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/src/info.rs b/api/src/info.rs index d8962d62..d934c532 100644 --- a/api/src/info.rs +++ b/api/src/info.rs @@ -132,6 +132,9 @@ impl From for &'static mut [MemoryRegion] { } } +unsafe impl Send for MemoryRegions {} +unsafe impl Sync for MemoryRegions {} + /// Represent a physical memory region. #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[repr(C)] From 23f0b60b755c2f4458b14747edfd49176e0e4f50 Mon Sep 17 00:00:00 2001 From: Aaron P <19561067+aaronzper@users.noreply.github.com> Date: Wed, 4 Jun 2025 21:56:13 -0400 Subject: [PATCH 75/80] Document physical memory mapping size --- api/src/config.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/api/src/config.rs b/api/src/config.rs index 5de0db3e..a5434351 100644 --- a/api/src/config.rs +++ b/api/src/config.rs @@ -386,10 +386,16 @@ pub struct Mappings { pub boot_info: Mapping, /// Specifies the mapping of the frame buffer memory region. pub framebuffer: Mapping, - /// The bootloader supports to map the whole physical memory into the virtual address + /// The bootloader supports mapping the whole physical memory into the virtual address /// space at some offset. This is useful for accessing and modifying the page tables set /// up by the bootloader. /// + /// This mapping will go from physical address `0x0` to whichever is larger: + /// - The end of the last region in the BIOS/UEFI memory map + /// - The address `0x1_0000_0000` (such that at least 4 GiB of physical memory are always mapped). + /// This is to ensure that useful MMIO regions (local APIC, I/O APIC, PCI bars) are + /// accessible to the kernel even if less physical memory than that is on the system. + /// /// Defaults to `None`, i.e. no mapping of the physical memory. pub physical_memory: Option, /// As an alternative to mapping the whole physical memory (see [`Self::physical_memory`]), From aee3504410eb3da2091fbe824d58bb50af6ff2a2 Mon Sep 17 00:00:00 2001 From: Aaron <19561067+aaronzper@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:07:45 -0400 Subject: [PATCH 76/80] Update api/src/config.rs with Clippy formatting Co-authored-by: Tom Dohrmann --- api/src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/config.rs b/api/src/config.rs index a5434351..c0f574bd 100644 --- a/api/src/config.rs +++ b/api/src/config.rs @@ -393,8 +393,8 @@ pub struct Mappings { /// This mapping will go from physical address `0x0` to whichever is larger: /// - The end of the last region in the BIOS/UEFI memory map /// - The address `0x1_0000_0000` (such that at least 4 GiB of physical memory are always mapped). - /// This is to ensure that useful MMIO regions (local APIC, I/O APIC, PCI bars) are - /// accessible to the kernel even if less physical memory than that is on the system. + /// This is to ensure that useful MMIO regions (local APIC, I/O APIC, PCI bars) are + /// accessible to the kernel even if less physical memory than that is on the system. /// /// Defaults to `None`, i.e. no mapping of the physical memory. pub physical_memory: Option, From 0c1125a7dcec8f727a76be67ca98363f6ff11b5e Mon Sep 17 00:00:00 2001 From: Mattie Nash Date: Wed, 30 Jul 2025 22:34:48 -0500 Subject: [PATCH 77/80] Fixes the type of target-c-int-width in target jsons. In https://github.com/rust-lang/rust/pull/144218, the type of target-c-int-width was changed to an Option, when previously it could be parsed from a string. That change caused an error "error: error loading target specification: target-c-int-width: invalid type: string "32", expected u16 at line 13 column 27" This pr is meant to fix that. --- i386-code16-boot-sector.json | 2 +- i386-code16-stage-2.json | 2 +- i686-stage-3.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/i386-code16-boot-sector.json b/i386-code16-boot-sector.json index 3a51b364..9cf5c514 100644 --- a/i386-code16-boot-sector.json +++ b/i386-code16-boot-sector.json @@ -10,7 +10,7 @@ "max-atomic-width": 64, "position-independent-executables": false, "disable-redzone": true, - "target-c-int-width": "32", + "target-c-int-width": 32, "target-pointer-width": "32", "target-endian": "little", "panic-strategy": "abort", diff --git a/i386-code16-stage-2.json b/i386-code16-stage-2.json index 3a51b364..9cf5c514 100644 --- a/i386-code16-stage-2.json +++ b/i386-code16-stage-2.json @@ -10,7 +10,7 @@ "max-atomic-width": 64, "position-independent-executables": false, "disable-redzone": true, - "target-c-int-width": "32", + "target-c-int-width": 32, "target-pointer-width": "32", "target-endian": "little", "panic-strategy": "abort", diff --git a/i686-stage-3.json b/i686-stage-3.json index 227250d4..82fc22c6 100644 --- a/i686-stage-3.json +++ b/i686-stage-3.json @@ -10,7 +10,7 @@ "max-atomic-width": 64, "position-independent-executables": false, "disable-redzone": true, - "target-c-int-width": "32", + "target-c-int-width": 32, "target-pointer-width": "32", "target-endian": "little", "panic-strategy": "abort", From f541a8203a6bac49e8c31a1c165abcde2bbcc9ec Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 31 Jul 2025 21:00:37 +0200 Subject: [PATCH 78/80] fix Cargo.lock This shouldn't have been updated in #495. --- Cargo.lock | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2efbcb2d..a9f3a34c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,7 +153,7 @@ dependencies = [ "rand_hc", "raw-cpuid", "spinning_top", - "uart_16550", + "uart_16550 0.3.2", "usize_conversions", "x86_64 0.15.2", "xmas-elf", @@ -734,7 +734,7 @@ name = "test_kernel_config_file" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -743,7 +743,7 @@ name = "test_kernel_default_settings" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -752,7 +752,7 @@ name = "test_kernel_fixed_kernel_address" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -761,7 +761,7 @@ name = "test_kernel_higher_half" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -770,7 +770,7 @@ name = "test_kernel_lower_memory_free" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -779,7 +779,7 @@ name = "test_kernel_map_phys_mem" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -788,7 +788,7 @@ name = "test_kernel_min_stack" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -797,7 +797,7 @@ name = "test_kernel_pie" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -806,7 +806,7 @@ name = "test_kernel_ramdisk" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -815,7 +815,7 @@ name = "test_kernel_write_usable_memory" version = "0.1.0" dependencies = [ "bootloader_api", - "uart_16550", + "uart_16550 0.2.18", "x86_64 0.15.2", ] @@ -850,6 +850,17 @@ dependencies = [ "x86_64 0.14.13", ] +[[package]] +name = "uart_16550" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e492212ac378a5e00da953718dafb1340d9fbaf4f27d6f3c5cab03d931d1c049" +dependencies = [ + "bitflags 2.3.3", + "rustversion", + "x86", +] + [[package]] name = "ucs2" version = "0.3.2" @@ -1018,6 +1029,17 @@ dependencies = [ "tap", ] +[[package]] +name = "x86" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" +dependencies = [ + "bit_field", + "bitflags 1.3.2", + "raw-cpuid", +] + [[package]] name = "x86_64" version = "0.14.13" From 3082b55e82301abebca33b3bfd13650bd91d5d30 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 31 Jul 2025 20:59:38 +0200 Subject: [PATCH 79/80] update changelog --- Changelog.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 4ec903fa..7daa1cdf 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,10 +1,17 @@ # Unreleased -## Features +# 0.11.11 – 2025-07-31 + +This release is compatible with Rust nightlies starting with `nightly-2025-07-24`. -* add `kernel_base` mapping to the BootloaderConfig to specify the virtual address - at which position-independent kernels are loaded. +* [Update uart_16550 to 0.3.2](https://github.com/rust-osdev/bootloader/pull/495) +* [add `kernel_base` mapping to the BootloaderConfig](https://github.com/rust-osdev/bootloader/pull/494) +* [Use Result::ok](https://github.com/rust-osdev/bootloader/pull/496) +* [implement Send+Sync for MemoryRegions](https://github.com/rust-osdev/bootloader/pull/502) +* [Document physical memory mapping size](https://github.com/rust-osdev/bootloader/pull/506) +* [Fixes the type of target-c-int-width in target jsons. #](https://github.com/rust-osdev/bootloader/pull/509) +**Full Changelog**: https://github.com/rust-osdev/bootloader/compare/v0.11.10...v0.11.11 # 0.11.10 – 2025-02-10 From 1e34b4378541a60c8f8962d62ed4067e819267ec Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 31 Jul 2025 21:02:04 +0200 Subject: [PATCH 80/80] release v0.11.11 --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9f3a34c..c97f6a54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,7 +70,7 @@ dependencies = [ [[package]] name = "bootloader" -version = "0.11.10" +version = "0.11.11" dependencies = [ "anyhow", "bootloader-boot-config", @@ -95,22 +95,22 @@ dependencies = [ [[package]] name = "bootloader-boot-config" -version = "0.11.10" +version = "0.11.11" dependencies = [ "serde", ] [[package]] name = "bootloader-x86_64-bios-boot-sector" -version = "0.11.10" +version = "0.11.11" [[package]] name = "bootloader-x86_64-bios-common" -version = "0.11.10" +version = "0.11.11" [[package]] name = "bootloader-x86_64-bios-stage-2" -version = "0.11.10" +version = "0.11.11" dependencies = [ "bootloader-x86_64-bios-common", "byteorder", @@ -119,7 +119,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-3" -version = "0.11.10" +version = "0.11.11" dependencies = [ "bootloader-x86_64-bios-common", "noto-sans-mono-bitmap 0.1.6", @@ -127,7 +127,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-bios-stage-4" -version = "0.11.10" +version = "0.11.11" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-bios-common", @@ -142,7 +142,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-common" -version = "0.11.10" +version = "0.11.11" dependencies = [ "bootloader-boot-config", "bootloader_api", @@ -161,7 +161,7 @@ dependencies = [ [[package]] name = "bootloader-x86_64-uefi" -version = "0.11.10" +version = "0.11.11" dependencies = [ "bootloader-boot-config", "bootloader-x86_64-common", @@ -174,7 +174,7 @@ dependencies = [ [[package]] name = "bootloader_api" -version = "0.11.10" +version = "0.11.11" dependencies = [ "rand", ] diff --git a/Cargo.toml b/Cargo.toml index 4edbbc78..eec8eb7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,15 +22,15 @@ exclude = ["examples/basic", "examples/test_framework", "tests/test_kernels/*"] [workspace.package] # don't forget to update `workspace.dependencies` below -version = "0.11.10" +version = "0.11.11" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-osdev/bootloader" [workspace.dependencies] -bootloader_api = { version = "0.11.10", path = "api" } -bootloader-x86_64-common = { version = "0.11.10", path = "common" } -bootloader-boot-config = { version = "0.11.10", path = "common/config" } -bootloader-x86_64-bios-common = { version = "0.11.10", path = "bios/common" } +bootloader_api = { version = "0.11.11", path = "api" } +bootloader-x86_64-common = { version = "0.11.11", path = "common" } +bootloader-boot-config = { version = "0.11.11", path = "common/config" } +bootloader-x86_64-bios-common = { version = "0.11.11", path = "bios/common" } [features] default = ["bios", "uefi"]