Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's mapped in the lower half? #470

Closed
mrjbom opened this issue Nov 1, 2024 · 3 comments
Closed

What's mapped in the lower half? #470

mrjbom opened this issue Nov 1, 2024 · 3 comments

Comments

@mrjbom
Copy link

mrjbom commented Nov 1, 2024

As the kernel of the upper half, I want nothing to be displayed in the lower half.
But TLB after loading looks like this:

(qemu) info tlb
000000000013b000: 000000000013b000 ----A----
000000000013c000: 000000000013c000 ---------
00000000013ac000: 00000000013ac000 ---------
...
Higher half mapped

I realized that 13ac000 belongs to GDT, I created my GDT and can now unmap that address.
But what is mapped in the first two addresses? Can I safely unmap them?

@Freax13
Copy link
Member

Freax13 commented Nov 1, 2024

That's probably the context switch function of the boot loader:

// identity-map context switch function, so that we don't get an immediate pagefault
// after switching the active page table
let context_switch_function = PhysAddr::new(context_switch as *const () as u64);
let context_switch_function_start_frame: PhysFrame =
PhysFrame::containing_address(context_switch_function);
for frame in PhysFrame::range_inclusive(
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 {
// 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),
}
}

These pages contain a function that switches to the kernel page tables and jumps to its entry point. You can safely unmap it.

See also #240

@mrjbom
Copy link
Author

mrjbom commented Nov 1, 2024

If it turns out not to be context switch function, then I suppose I can safely unmap these addresses anyway? Why does the bootloader leave these things mapped?
For example, GDT could be safely unmapped by bootloader.

@Freax13
Copy link
Member

Freax13 commented Nov 1, 2024

If it turns out not to be context switch function, then I suppose I can safely unmap these addresses anyway?

I'm pretty sure it's the context switch function. If it's not the context switch function, then it depends on the memory for whether it's safe to unmap.

Why does the bootloader leave these things mapped?

The context switch function needs to do two things:

  1. Switch to the kernel's page tables.
  2. Jump to the kernel's entry point.

It needs to do these steps in that order. The problem is that if we don't map the context switch function into the kernel's page tables, we can't do the second step after switching the page tables.

For example, GDT could be safely unmapped by bootloader.

The GDT can't be safely unmapped before switching to a new one. Some instructions like iret read from the GDT and if the GDT is no longer mapped, this causes a page fault.

@mrjbom mrjbom closed this as completed Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants