mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 22:37:49 +00:00
Update translate_addr code example
This makes the function safe again because no level 4 address is passed in. It also avoids bit-shifts which only work if the recursive index is 0o777.
This commit is contained in:
@@ -189,41 +189,50 @@ use x86_64::structures::paging::PageTable;
|
|||||||
|
|
||||||
/// Returns the physical address for the given virtual address, or `None` if the
|
/// Returns the physical address for the given virtual address, or `None` if the
|
||||||
/// virtual address is not mapped.
|
/// virtual address is not mapped.
|
||||||
///
|
pub fn translate_addr(addr: usize) -> Option<PhysAddr> {
|
||||||
/// Safety: This requires level_4_table_addr to be the address of a valid
|
// introduce variables for the recursive index and the sign extension bits
|
||||||
/// level-4 PageTable
|
// TODO: Don't hardcode these values
|
||||||
pub unsafe fn translate_addr(addr: usize, level_4_table_addr: usize) -> Option<PhysAddr> {
|
let r = 0o777; // recursive index
|
||||||
|
let sign = 0o177777 << 48; // sign extension
|
||||||
|
|
||||||
// retrieve the page table indices of the address that we want to translate
|
// retrieve the page table indices of the address that we want to translate
|
||||||
let level_4_index = (addr >> 39) & 0o777;
|
let l4_idx = (addr >> 39) & 0o777; // level 4 index
|
||||||
let level_3_index = (addr >> 30) & 0o777;
|
let l3_idx = (addr >> 30) & 0o777; // level 3 index
|
||||||
let level_2_index = (addr >> 21) & 0o777;
|
let l2_idx = (addr >> 21) & 0o777; // level 2 index
|
||||||
let level_1_index = (addr >> 12) & 0o777;
|
let l1_idx = (addr >> 12) & 0o777; // level 1 index
|
||||||
let page_offset = addr & 0o7777;
|
let page_offset = addr & 0o7777;
|
||||||
|
|
||||||
|
// calculate the table addresses
|
||||||
|
let level_4_table_addr =
|
||||||
|
sign | (r << 39) | (r << 30) | (r << 21) | (r << 12);
|
||||||
|
let level_3_table_addr =
|
||||||
|
sign | (r << 39) | (r << 30) | (r << 21) | (l4_idx << 12);
|
||||||
|
let level_2_table_addr =
|
||||||
|
sign | (r << 39) | (r << 30) | (l4_idx << 21) | (l3_idx << 12);
|
||||||
|
let level_1_table_addr =
|
||||||
|
sign | (r << 39) | (l4_idx << 30) | (l3_idx << 21) | (l2_idx << 12);
|
||||||
|
|
||||||
// check that level 4 entry is mapped
|
// check that level 4 entry is mapped
|
||||||
let level_4_table = unsafe {&*(level_4_table_addr as *const PageTable)};
|
let level_4_table = unsafe { &*(level_4_table_addr as *const PageTable) };
|
||||||
if level_4_table[level_4_index].addr().is_null() {
|
if level_4_table[l4_idx].addr().is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let level_3_table_addr = (level_4_table_addr << 9) | (level_4_index << 12);
|
|
||||||
|
|
||||||
// check that level 3 entry is mapped
|
// check that level 3 entry is mapped
|
||||||
let level_3_table = unsafe {&*(level_3_table_addr as *const PageTable)};
|
let level_3_table = unsafe { &*(level_3_table_addr as *const PageTable) };
|
||||||
if level_3_table[level_3_index].addr().is_null() {
|
if level_3_table[l3_idx].addr().is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let level_2_table_addr = (level_3_table_addr << 9) | (level_3_index << 12);
|
|
||||||
|
|
||||||
// check that level 2 entry is mapped
|
// check that level 2 entry is mapped
|
||||||
let level_2_table = unsafe {&*(level_2_table_addr as *const PageTable)};
|
let level_2_table = unsafe { &*(level_2_table_addr as *const PageTable) };
|
||||||
if level_2_table[level_2_index].addr().is_null() {
|
if level_2_table[l2_idx].addr().is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let level_1_table_addr = (level_2_table_addr << 9) | (level_2_index << 12);
|
|
||||||
|
|
||||||
// check that level 1 entry is mapped and retrieve physical address from it
|
// check that level 1 entry is mapped and retrieve physical address from it
|
||||||
let level_1_table = unsafe {&*(level_1_table_addr as *const PageTable)};
|
let level_1_table = unsafe { &*(level_1_table_addr as *const PageTable) };
|
||||||
let phys_addr = level_1_table[level_1_index].addr();
|
let phys_addr = level_1_table[l1_idx].addr();
|
||||||
if phys_addr.is_null() {
|
if phys_addr.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -232,17 +241,16 @@ pub unsafe fn translate_addr(addr: usize, level_4_table_addr: usize) -> Option<P
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
First, we calculate the page table indices and the page offset from the address through bitwise operations as specified in the graphic:
|
First, we introduce variables for the recursive index (511 = `0o777`) and the sign extension bits (which are 1 each). Then we calculate the page table indices and the page offset from the address through bitwise operations as specified in the graphic:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Then we transform the `level_4_table_addr` to a [`PageTable`] reference, which is an `unsafe` operation since the compiler can't know that the address is valid. We use the indexing operator to look at the entry with `level_4_index`. If that entry is null, there is no level 3 table for this level 4 entry, which means that the `addr` is not mapped to any physical memory, so we return `None`.
|
In the next step we calculate the virtual addresses of the four page tables as descripbed in the [address calculation] section. We transform each of these addresses to [`PageTable`] references later in the function. These transformations are `unsafe` operations since the compiler can't know that these addresses are valid.
|
||||||
|
|
||||||
[`PageTable`]: https://docs.rs/x86_64/0.3.5/x86_64/structures/paging/struct.PageTable.html
|
|
||||||
|
|
||||||
If the entry is not `None`, we know that a level 3 table exists. We calculate the virtual address of it by shifting the level 4 address 9 bits to the left and setting the address bits 12–21 to the level 4 index (see the section about [address calculation]). We can do that because the recursive index is `0o777` so that it is also a valid sign extension. We then do the same cast and entry-checking as with the level 4 table.
|
|
||||||
|
|
||||||
[address calculation]: #address-calculation
|
[address calculation]: #address-calculation
|
||||||
|
[`PageTable`]: https://docs.rs/x86_64/0.3.5/x86_64/structures/paging/struct.PageTable.html
|
||||||
|
|
||||||
|
After the address calculation, we use the indexing operator to look at the entry in the level 4 table. If that entry is null, there is no level 3 table for this level 4 entry, which means that the `addr` is not mapped to any physical memory, so we return `None`. If the entry is not `None`, we know that a level 3 table exists. We then do the same cast and entry-checking as with the level 4 table.
|
||||||
|
|
||||||
After we checked the three higher level pages, we can finally read the entry of the level 1 table that tells us the physical frame that the address is mapped to. As the last step, we add the page offset to that address and return it.
|
After we checked the three higher level pages, we can finally read the entry of the level 1 table that tells us the physical frame that the address is mapped to. As the last step, we add the page offset to that address and return it.
|
||||||
|
|
||||||
@@ -262,17 +270,13 @@ pub extern "C" fn _start() -> ! {
|
|||||||
|
|
||||||
use blog_os::memory::translate_addr;
|
use blog_os::memory::translate_addr;
|
||||||
|
|
||||||
const LEVEL_4_TABLE_ADDR: usize = 0o_177777_777_777_777_777_0000;
|
// the identity-mapped vga buffer page
|
||||||
|
println!("0xb8000 -> {:?}", translate_addr(0xb8000));
|
||||||
|
// some code page
|
||||||
|
println!("0x20010a -> {:?}", translate_addr(0x20010a));
|
||||||
|
// some stack page
|
||||||
|
println!("0x57ac001ffe48 -> {:?}", translate_addr(0x57ac001ffe48));
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// the identity-mapped vga buffer page
|
|
||||||
println!("0xb8000 -> {:?}", translate_addr(0xb8000, LEVEL_4_TABLE_ADDR));
|
|
||||||
// some code page
|
|
||||||
println!("0x20010a -> {:?}", translate_addr(0x20010a, LEVEL_4_TABLE_ADDR));
|
|
||||||
// some stack page
|
|
||||||
println!("0x57ac001ffe48 -> {:?}", translate_addr(0x57ac001ffe48,
|
|
||||||
LEVEL_4_TABLE_ADDR));
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("It did not crash!");
|
println!("It did not crash!");
|
||||||
blog_os::hlt_loop();
|
blog_os::hlt_loop();
|
||||||
|
|||||||
Reference in New Issue
Block a user