Use the new MapperAllSizes::translate_addr function in Post 10

This commit is contained in:
Philipp Oppermann
2019-03-09 13:46:55 +01:00
parent 4c68f8a541
commit 9011a8a123

View File

@@ -270,13 +270,18 @@ pub extern "C" fn _start() -> ! {
use blog_os::memory::translate_addr; use blog_os::memory::translate_addr;
// the identity-mapped vga buffer page let addresses = [
println!("0xb8000 -> {:?}", translate_addr(0xb8000)); // the identity-mapped vga buffer page
// some code page 0xb8000,
println!("0x20010a -> {:?}", translate_addr(0x20010a)); // some code page
// some stack page 0x20010a,
println!("0x57ac_001f_fe48 -> {:?}", translate_addr(0x57ac_001f_fe48)); // some stack page
0x57ac_001f_fe48,
];
for &address in &addresses {
println!("{:?} -> {:?}", address, translate_addr(address));
}
println!("It did not crash!"); println!("It did not crash!");
blog_os::hlt_loop(); blog_os::hlt_loop();
@@ -291,9 +296,10 @@ As expected, the identity-mapped address `0xb8000` translates to the same physic
#### The `RecursivePageTable` Type #### The `RecursivePageTable` Type
The `x86_64` provides a [`RecursivePageTable`] type that implements safe abstractions for various page table operations. By using this type, we can reimplement our `translate_addr` function in a much cleaner way: The `x86_64` provides a [`RecursivePageTable`] type that implements safe abstractions for various page table operations. The type implements the [`MapperAllSizes`] trait, which already contains a `translate_addr` function that we can use instead of hand-rolling our own. To create a new `RecursivePageTable`, we create a `memory::init` function:
[`RecursivePageTable`]: https://docs.rs/x86_64/0.5.0/x86_64/structures/paging/struct.RecursivePageTable.html [`RecursivePageTable`]: https://docs.rs/x86_64/0.5.0/x86_64/structures/paging/struct.RecursivePageTable.html
[`MapperAllSizes`]: https://docs.rs/x86_64/0.5.0/x86_64/structures/paging/mapper/trait.MapperAllSizes.html
```rust ```rust
// in src/memory.rs // in src/memory.rs
@@ -310,24 +316,11 @@ pub unsafe fn init(level_4_table_addr: usize) -> RecursivePageTable<'static> {
let level_4_table = &mut *level_4_table_ptr; let level_4_table = &mut *level_4_table_ptr;
RecursivePageTable::new(level_4_table).unwrap() RecursivePageTable::new(level_4_table).unwrap()
} }
/// Returns the physical address for the given virtual address, or `None` if
/// the virtual address is not mapped.
pub fn translate_addr(addr: u64, recursive_page_table: &RecursivePageTable)
-> Option<PhysAddr>
{
let addr = VirtAddr::new(addr);
let page: Page = Page::containing_address(addr);
// perform the translation
let frame = recursive_page_table.translate_page(page);
frame.map(|frame| frame.start_address() + u64::from(addr.page_offset()))
}
``` ```
The `RecursivePageTable` type encapsulates the unsafety of the page table walk completely so that we no longer need `unsafe` in our `translate_addr` function. The `init` function needs to be unsafe because the caller has to guarantee that the passed `level_4_table_addr` is valid. The `RecursivePageTable` type encapsulates the unsafety of the page table walk completely so that we no longer need `unsafe` to implement our own `translate_addr` function. The `init` function needs to be unsafe because the caller has to guarantee that the passed `level_4_table_addr` is valid.
Our `_start` function needs to be updated for the new function signature in the following way: We can now use the `MapperAllSizes::translate_addr` function in our `_start` function:
```rust ```rust
// in src/main.rs // in src/main.rs
@@ -337,25 +330,33 @@ Our `_start` function needs to be updated for the new function signature in the
pub extern "C" fn _start() -> ! { pub extern "C" fn _start() -> ! {
[] // initialize GDT, IDT, PICS [] // initialize GDT, IDT, PICS
use blog_os::memory::{self, translate_addr}; use blog_os::memory;
use x86_64::{
structures::paging::MapperAllSizes,
VirtAddr,
};
const LEVEL_4_TABLE_ADDR: usize = 0o_177777_777_777_777_777_0000; const LEVEL_4_TABLE_ADDR: usize = 0o_177777_777_777_777_777_0000;
let recursive_page_table = unsafe { memory::init(LEVEL_4_TABLE_ADDR) }; let recursive_page_table = unsafe { memory::init(LEVEL_4_TABLE_ADDR) };
// the identity-mapped vga buffer page let addresses = []; // as before
println!("0xb8000 -> {:?}", translate_addr(0xb8000, &recursive_page_table)); for &address in &addresses {
// some code page let virt_addr = VirtAddr::new(address);
println!("0x20010a -> {:?}", translate_addr(0x20010a, &recursive_page_table)); let phys_addr = recursive_page_table.translate_addr(virt_addr);
// some stack page println!("{:?} -> {:?}", virt_addr, phys_addr);
println!("0x57ac_001f_fe48 -> {:?}", translate_addr(0x57ac_001f_fe48, }
&recursive_page_table));
println!("It did not crash!"); println!("It did not crash!");
blog_os::hlt_loop(); blog_os::hlt_loop();
} }
``` ```
Instead of passing the `LEVEL_4_TABLE_ADDR` to `translate_addr` and accessing the page tables through unsafe raw pointers, we now pass references to a `RecursivePageTable` type. By doing this, we now have a safe abstraction and clear ownership semantics. This ensures that we can't accidentally modify the page table concurrently, because an exclusive borrow of the `RecursivePageTable` is needed in order to modify it. Instead of using `u64` for all addresses we now use the [`VirtAddr`] and [`PhysAddr`] wrapper types to differentiate the two kinds of addresses. In order to be able to call the `translate_addr` method, we need to import the `MapperAllSizes` trait.
[`VirtAddr`]: https://docs.rs/x86_64/0.5.0/x86_64/struct.VirtAddr.html
[`PhysAddr`]: https://docs.rs/x86_64/0.5.0/x86_64/struct.PhysAddr.html
By using the `RecursivePageTable` type, we now have a safe abstraction and clear ownership semantics. This ensures that we can't accidentally modify the page table concurrently, because an exclusive borrow of the `RecursivePageTable` is needed in order to modify it.
When we run it, we see the same result as with our handcrafted translation function. When we run it, we see the same result as with our handcrafted translation function.