Merge pull request #213 from ZystemOS/feature/vmm-convert-addr
Add physToVirt and virtToPhys to VMM
This commit is contained in:
commit
f9244c63cd
1 changed files with 114 additions and 0 deletions
|
@ -176,6 +176,67 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Find the physical address that a given virtual address is mapped to.
|
||||||
|
///
|
||||||
|
/// Arguments:
|
||||||
|
/// IN self: *const Self - The VMM to check for mappings in
|
||||||
|
/// IN virt: usize - The virtual address to find the physical address for
|
||||||
|
///
|
||||||
|
/// Return: usize
|
||||||
|
/// The physical address that the virtual address is mapped to
|
||||||
|
///
|
||||||
|
/// Error: VmmError
|
||||||
|
/// VmmError.NotAllocated - The virtual address hasn't been mapped within the VMM
|
||||||
|
///
|
||||||
|
pub fn virtToPhys(self: *const Self, virt: usize) VmmError!usize {
|
||||||
|
for (self.allocations.unmanaged.entries.items) |entry| {
|
||||||
|
const vaddr = entry.key;
|
||||||
|
// If we've gone past the address without finding a covering region then it hasn't been mapped
|
||||||
|
if (vaddr > virt) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allocation = entry.value;
|
||||||
|
// If this allocation range covers the virtual address then figure out the corresponding physical block
|
||||||
|
if (vaddr <= virt and vaddr + (allocation.physical.items.len * BLOCK_SIZE) > virt) {
|
||||||
|
const block_number = (virt - vaddr) / BLOCK_SIZE;
|
||||||
|
const block_offset = (virt - vaddr) % BLOCK_SIZE;
|
||||||
|
return allocation.physical.items[block_number] + block_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VmmError.NotAllocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Find the virtual address that a given physical address is mapped to.
|
||||||
|
///
|
||||||
|
/// Arguments:
|
||||||
|
/// IN self: *const Self - The VMM to check for mappings in
|
||||||
|
/// IN phys: usize - The physical address to find the virtual address for
|
||||||
|
///
|
||||||
|
/// Return: usize
|
||||||
|
/// The virtual address that the physical address is mapped to
|
||||||
|
///
|
||||||
|
/// Error: VmmError
|
||||||
|
/// VmmError.NotAllocated - The physical address hasn't been mapped within the VMM
|
||||||
|
///
|
||||||
|
pub fn physToVirt(self: *const Self, phys: usize) VmmError!usize {
|
||||||
|
for (self.allocations.unmanaged.entries.items) |entry| {
|
||||||
|
const vaddr = entry.key;
|
||||||
|
const allocation = entry.value;
|
||||||
|
|
||||||
|
for (allocation.physical.items) |block, i| {
|
||||||
|
if (block <= phys and block + BLOCK_SIZE > phys) {
|
||||||
|
const block_addr = vaddr + i * BLOCK_SIZE;
|
||||||
|
const block_offset = phys % BLOCK_SIZE;
|
||||||
|
return block_addr + block_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VmmError.NotAllocated;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Check if a virtual memory address has been set
|
/// Check if a virtual memory address has been set
|
||||||
///
|
///
|
||||||
|
@ -388,6 +449,50 @@ pub fn init(mem_profile: *const mem.MemProfile, allocator: *Allocator) Allocator
|
||||||
return vmm;
|
return vmm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "virtToPhys" {
|
||||||
|
const num_entries = 512;
|
||||||
|
var vmm = try testInit(num_entries);
|
||||||
|
|
||||||
|
const vstart = test_vaddr_start + BLOCK_SIZE;
|
||||||
|
const vend = vstart + BLOCK_SIZE * 3;
|
||||||
|
const pstart = BLOCK_SIZE * 20;
|
||||||
|
const pend = BLOCK_SIZE * 23;
|
||||||
|
|
||||||
|
// Set the physical and virtual back to front to complicate the mappings a bit
|
||||||
|
try vmm.set(.{ .start = vstart, .end = vstart + BLOCK_SIZE }, mem.Range{ .start = pstart + BLOCK_SIZE * 2, .end = pend }, .{ .kernel = true, .writable = true, .cachable = true });
|
||||||
|
try vmm.set(.{ .start = vstart + BLOCK_SIZE, .end = vend }, mem.Range{ .start = pstart, .end = pstart + BLOCK_SIZE * 2 }, .{ .kernel = true, .writable = true, .cachable = true });
|
||||||
|
|
||||||
|
std.testing.expectEqual(pstart + BLOCK_SIZE * 2, try vmm.virtToPhys(vstart));
|
||||||
|
std.testing.expectEqual(pstart + BLOCK_SIZE * 2 + 29, (try vmm.virtToPhys(vstart + 29)));
|
||||||
|
std.testing.expectEqual(pstart + 29, (try vmm.virtToPhys(vstart + BLOCK_SIZE + 29)));
|
||||||
|
|
||||||
|
std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vstart - 1));
|
||||||
|
std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vend));
|
||||||
|
std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vend + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "physToVirt" {
|
||||||
|
const num_entries = 512;
|
||||||
|
var vmm = try testInit(num_entries);
|
||||||
|
|
||||||
|
const vstart = test_vaddr_start + BLOCK_SIZE;
|
||||||
|
const vend = vstart + BLOCK_SIZE * 3;
|
||||||
|
const pstart = BLOCK_SIZE * 20;
|
||||||
|
const pend = BLOCK_SIZE * 23;
|
||||||
|
|
||||||
|
// Set the physical and virtual back to front to complicate the mappings a bit
|
||||||
|
try vmm.set(.{ .start = vstart, .end = vstart + BLOCK_SIZE }, mem.Range{ .start = pstart + BLOCK_SIZE * 2, .end = pend }, .{ .kernel = true, .writable = true, .cachable = true });
|
||||||
|
try vmm.set(.{ .start = vstart + BLOCK_SIZE, .end = vend }, mem.Range{ .start = pstart, .end = pstart + BLOCK_SIZE * 2 }, .{ .kernel = true, .writable = true, .cachable = true });
|
||||||
|
|
||||||
|
std.testing.expectEqual(vstart, try vmm.physToVirt(pstart + BLOCK_SIZE * 2));
|
||||||
|
std.testing.expectEqual(vstart + 29, (try vmm.physToVirt(pstart + BLOCK_SIZE * 2 + 29)));
|
||||||
|
std.testing.expectEqual(vstart + BLOCK_SIZE + 29, (try vmm.physToVirt(pstart + 29)));
|
||||||
|
|
||||||
|
std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pstart - 1));
|
||||||
|
std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pend));
|
||||||
|
std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pend + 1));
|
||||||
|
}
|
||||||
|
|
||||||
test "alloc and free" {
|
test "alloc and free" {
|
||||||
const num_entries = 512;
|
const num_entries = 512;
|
||||||
var vmm = try testInit(num_entries);
|
var vmm = try testInit(num_entries);
|
||||||
|
@ -601,6 +706,15 @@ fn runtimeTests(comptime Payload: type, vmm: VirtualMemoryManager(Payload), mem_
|
||||||
} else {
|
} else {
|
||||||
for (mem_profile.virtual_reserved) |entry| {
|
for (mem_profile.virtual_reserved) |entry| {
|
||||||
if (vaddr >= std.mem.alignBackward(entry.virtual.start, BLOCK_SIZE) and vaddr < std.mem.alignForward(entry.virtual.end, BLOCK_SIZE)) {
|
if (vaddr >= std.mem.alignBackward(entry.virtual.start, BLOCK_SIZE) and vaddr < std.mem.alignForward(entry.virtual.end, BLOCK_SIZE)) {
|
||||||
|
if (entry.physical) |phys| {
|
||||||
|
const expected_phys = phys.start + (vaddr - entry.virtual.start);
|
||||||
|
if (vmm.virtToPhys(vaddr) catch unreachable != expected_phys) {
|
||||||
|
panic(@errorReturnTrace(), "virtToPhys didn't return the correct physical address for 0x{X} (0x{X})\n", .{ vaddr, vmm.virtToPhys(vaddr) });
|
||||||
|
}
|
||||||
|
if (vmm.physToVirt(expected_phys) catch unreachable != vaddr) {
|
||||||
|
panic(@errorReturnTrace(), "physToVirt didn't return the correct virtual address for 0x{X} (0x{X})\n", .{ expected_phys, vaddr });
|
||||||
|
}
|
||||||
|
}
|
||||||
should_be_set = true;
|
should_be_set = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue