From 14c63aa98a0901f9e915d0658144a45a61814c45 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 23 Sep 2022 11:14:30 -0700 Subject: [PATCH] Only perform a single TLB flush after identity mapping This commit changes the BIOS bootloader to only flush the TLB once, after it has identity-mapped every physical memory frame. This should be a bit more efficient, as we don't perform a separate `invlpg` for every page table entry we create, and instead only flush the entire thing by reloading `CR3` when we're actually ready to use it. This is based on a suggestion by @phil-opp, here: https://github.com/rust-osdev/bootloader/pull/260#issuecomment-1255418145 This change doesn't actually seem to make all that big an impact in boot times on QEMU v7.1 on its own, relative to PR #260, but it might make an additional improvement on top of that PR. --- src/bin/bios.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/bin/bios.rs b/src/bin/bios.rs index 153f339a..3b1fd571 100644 --- a/src/bin/bios.rs +++ b/src/bin/bios.rs @@ -109,7 +109,7 @@ fn bootloader_main( PhysFrame::containing_address(PhysAddr::new(4096 * 512 * 512)); let end_frame = PhysFrame::containing_address(PhysAddr::new(max_phys_addr - 1)); for frame in PhysFrame::range_inclusive(start_frame, end_frame) { - unsafe { + let flusher = unsafe { bootloader_page_table .identity_map( frame, @@ -117,11 +117,20 @@ fn bootloader_main( &mut frame_allocator, ) .unwrap() - .flush() }; + // skip flushing the entry from the TLB for now, as we will + // flush the entire TLB at the end of the loop. + flusher.ignore(); } } + // once all the physical memory is mapped, flush the TLB by reloading the + // CR3 register. + // + // we perform a single flush here rather than flushing each individual entry as + // it's mapped using `invlpg`, for efficiency. + x86_64::instructions::tlb::flush_all(); + let framebuffer_addr = PhysAddr::new(unsafe { VBEModeInfo_physbaseptr }.into()); let mut error = None; let framebuffer_info = unsafe {