Skip to content

Commit af99f0f

Browse files
authored
Merge pull request #466 from rust-osdev/fix/frame-buffer-not-in-first-pml4
copy more PML4 entries
2 parents 5d318bf + 9726814 commit af99f0f

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

common/src/level_4_entries.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,17 @@ impl UsedLevel4Entries {
3939
rng: config.mappings.aslr.then(entropy::build_rng),
4040
};
4141

42-
used.entry_state[0] = true; // TODO: Can we do this dynamically?
42+
// The bootloader maps of the kernel's memory into its own page tables.
43+
// We need to prevent overlaps, so mark all memory that could already
44+
// be used by the bootload as inaccessible.
45+
46+
// All memory in this range is identity mapped.
47+
used.mark_range_as_used(0, max_phys_addr.as_u64());
48+
49+
// The bootload needs to access the frame buffer.
50+
if let Some(frame_buffer) = framebuffer {
51+
used.mark_range_as_used(frame_buffer.addr.as_u64(), frame_buffer.info.byte_len);
52+
}
4353

4454
// Mark the statically configured ranges from the config as used.
4555

uefi/src/main.rs

+19-4
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)