From cd2761e38d4debfc8147215ea0239cc68a61bba7 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 22 Sep 2022 09:02:27 -0700 Subject: [PATCH 1/2] Limit BIOS bootloader's `max_phys_addr` to 4 GiB When determining the maximum physical address for the BIOS bootloader's identity mapping, we currently use the highest address in the E380 memory map, no matter how high it is. However, the bootloader runs in protected mode, and therefore, it cannot address more than 4 GiB of memory. We can save some time by not identity mapping addresses over 4 GiB, as the bootloader cannot address them anyway. This commit changes the BIOS bootloader to skip addresses over 4 GiB when determining the maximum physical address. This is one of the changes described in issue #259. --- src/bin/bios.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bin/bios.rs b/src/bin/bios.rs index 153f339a..b6b51328 100644 --- a/src/bin/bios.rs +++ b/src/bin/bios.rs @@ -78,6 +78,7 @@ fn bootloader_main( use bootloader::binary::{ bios::memory_descriptor::E820MemoryRegion, legacy_memory_region::LegacyFrameAllocator, }; + const GIGABYTE: u64 = 4096 * 512 * 512; let e820_memory_map = { let ptr = usize_from(memory_map_addr.as_u64()) as *const E820MemoryRegion; @@ -86,6 +87,10 @@ fn bootloader_main( let max_phys_addr = e820_memory_map .iter() .map(|r| r.start_addr + r.len) + // Don't consider addresses > 4GiB when determining the maximum + // physical address for the bootloader, as we are in protected mode and + // cannot address more than 4 GiB of memory anyway. + .filter(|&addr| addr < GIGABYTE * 4) .max() .expect("no physical memory regions found"); @@ -106,7 +111,7 @@ fn bootloader_main( // identity-map remaining physical memory (first gigabyte is already identity-mapped) { let start_frame: PhysFrame = - PhysFrame::containing_address(PhysAddr::new(4096 * 512 * 512)); + PhysFrame::containing_address(PhysAddr::new(GIGABYTE)); let end_frame = PhysFrame::containing_address(PhysAddr::new(max_phys_addr - 1)); for frame in PhysFrame::range_inclusive(start_frame, end_frame) { unsafe { From 4da46e1a72b7279241eabf3f25abfb1f10fc69d7 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 22 Sep 2022 11:00:17 -0700 Subject: [PATCH 2/2] Allow mapping part of a region if it crosses 4 GiB --- src/bin/bios.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/bin/bios.rs b/src/bin/bios.rs index b6b51328..434a4c76 100644 --- a/src/bin/bios.rs +++ b/src/bin/bios.rs @@ -10,6 +10,7 @@ use bootloader::{ }; use core::{ arch::{asm, global_asm}, + cmp, panic::PanicInfo, slice, }; @@ -84,15 +85,17 @@ fn bootloader_main( let ptr = usize_from(memory_map_addr.as_u64()) as *const E820MemoryRegion; unsafe { slice::from_raw_parts(ptr, usize_from(memory_map_entry_count)) } }; - let max_phys_addr = e820_memory_map - .iter() - .map(|r| r.start_addr + r.len) - // Don't consider addresses > 4GiB when determining the maximum - // physical address for the bootloader, as we are in protected mode and - // cannot address more than 4 GiB of memory anyway. - .filter(|&addr| addr < GIGABYTE * 4) - .max() - .expect("no physical memory regions found"); + let max_phys_addr = { + let max = e820_memory_map + .iter() + .map(|r| r.start_addr + r.len) + .max() + .expect("no physical memory regions found"); + // Don't consider addresses > 4GiB when determining the maximum physical + // address for the bootloader, as we are in protected mode and cannot + // address more than 4 GiB of memory anyway. + cmp::min(max, 4 * GIGABYTE) + }; let mut frame_allocator = { let kernel_end = PhysFrame::containing_address(kernel_start + kernel_size - 1u64);