Skip to content

Commit 7dcc963

Browse files
committed
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.
1 parent ea3f61a commit 7dcc963

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

uefi/src/main.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
144144
let mut frame_allocator =
145145
LegacyFrameAllocator::new(memory_map.entries().copied().map(UefiMemoryDescriptor));
146146

147-
let page_tables = create_page_tables(&mut frame_allocator);
147+
let max_phys_addr = frame_allocator.max_phys_addr();
148+
let page_tables = create_page_tables(&mut frame_allocator, max_phys_addr, framebuffer.as_ref());
148149
let mut ramdisk_len = 0u64;
149150
let ramdisk_addr = if let Some(rd) = ramdisk {
150151
ramdisk_len = rd.len() as u64;
@@ -385,6 +386,8 @@ fn load_file_from_tftp_boot_server(
385386
/// Creates page table abstraction types for both the bootloader and kernel page tables.
386387
fn create_page_tables(
387388
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
389+
max_phys_addr: PhysAddr,
390+
frame_buffer: Option<&RawFrameBufferInfo>,
388391
) -> bootloader_x86_64_common::PageTables {
389392
// UEFI identity-maps all memory, so the offset between physical and virtual addresses is 0
390393
let phys_offset = VirtAddr::new(0);
@@ -410,9 +413,21 @@ fn create_page_tables(
410413
}
411414
};
412415

413-
// copy the first entry (we don't need to access more than 512 GiB; also, some UEFI
414-
// implementations seem to create an level 4 table entry 0 in all slots)
415-
new_table[0] = old_table[0].clone();
416+
// copy the pml4 entries for all identity mapped memory.
417+
let end_addr = VirtAddr::new(max_phys_addr.as_u64() - 1);
418+
for p4 in 0..=usize::from(end_addr.p4_index()) {
419+
new_table[p4] = old_table[p4].clone();
420+
}
421+
422+
// copy the pml4 entry for the frame buffer (the frame buffer is not
423+
// necessarily part of the identity mapping).
424+
if let Some(frame_buffer) = frame_buffer {
425+
let start_addr = VirtAddr::new(frame_buffer.addr.as_u64());
426+
let end_addr = start_addr + frame_buffer.info.byte_len;
427+
for p4 in usize::from(start_addr.p4_index())..=usize::from(end_addr.p4_index()) {
428+
new_table[p4] = old_table[p4].clone();
429+
}
430+
}
416431

417432
// the first level 4 table entry is now identical, so we can just load the new one
418433
unsafe {

0 commit comments

Comments
 (0)