Merge pull request #105 from SamTebbs33/feature/virtToPhys-and-physToVirt

Move virtToPhys to mem.zig and add physToVirt
This commit is contained in:
Sam Tebbs 2019-11-08 22:05:12 +00:00 committed by GitHub
commit 762ddc3a63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 39 deletions

View file

@ -8,6 +8,7 @@ const isr = @import("isr.zig");
const MemProfile = @import("../../mem.zig").MemProfile; const MemProfile = @import("../../mem.zig").MemProfile;
const tty = @import("../../tty.zig"); const tty = @import("../../tty.zig");
const log = @import("../../log.zig"); const log = @import("../../log.zig");
const mem = @import("../../mem.zig");
const options = @import("build_options"); const options = @import("build_options");
const testing = std.testing; const testing = std.testing;
@ -119,31 +120,6 @@ const TENTRY_GLOBAL: u32 = 0x100;
const TENTRY_AVAILABLE: u32 = 0xE00; const TENTRY_AVAILABLE: u32 = 0xE00;
const TENTRY_PAGE_ADDR: u32 = 0xFFFFF000; const TENTRY_PAGE_ADDR: u32 = 0xFFFFF000;
/// The kernel's virtual address offset. It's assigned in the init function and the virtToPhys test.
/// We can't just use KERNEL_ADDR_OFFSET since using externs in the virtToPhys test is broken in
/// release-safe. This is a workaround until that is fixed.
var ADDR_OFFSET: usize = undefined;
extern var KERNEL_ADDR_OFFSET: *u32;
///
/// Convert a virtual address to its physical counterpart by subtracting the kernel virtual offset from the virtual address.
///
/// Arguments:
/// IN virt: var - The virtual address to covert. Either an integer or pointer.
///
/// Return: @typeOf(virt)
/// The physical address.
///
inline fn virtToPhys(virt: var) @typeOf(virt) {
const offset = ADDR_OFFSET;
const T = @typeOf(virt);
return switch (@typeId(T)) {
.Pointer => @intToPtr(T, @ptrToInt(virt) - offset),
.Int => virt - offset,
else => @compileError("Only pointers and integers are supported"),
};
}
/// ///
/// Convert a virtual address to an index within an array of directory entries. /// Convert a virtual address to an index within an array of directory entries.
/// ///
@ -227,7 +203,7 @@ fn mapDirEntry(dir: *Directory, virt_start: usize, virt_end: usize, phys_start:
// Create a table and put the physical address in the dir entry // Create a table and put the physical address in the dir entry
table = &(try allocator.alignedAlloc(Table, @truncate(u29, PAGE_SIZE_4KB), 1))[0]; table = &(try allocator.alignedAlloc(Table, @truncate(u29, PAGE_SIZE_4KB), 1))[0];
@memset(@ptrCast([*]u8, table), 0, @sizeOf(Table)); @memset(@ptrCast([*]u8, table), 0, @sizeOf(Table));
const table_phys_addr = @ptrToInt(virtToPhys(table)); const table_phys_addr = @ptrToInt(mem.virtToPhys(table));
dir_entry.* |= @intCast(u32, DENTRY_PAGE_ADDR & table_phys_addr); dir_entry.* |= @intCast(u32, DENTRY_PAGE_ADDR & table_phys_addr);
dir.tables[entry] = table; dir.tables[entry] = table;
} }
@ -316,7 +292,6 @@ fn pageFault(state: *arch.InterruptContext) void {
/// ///
pub fn init(mem_profile: *const MemProfile, allocator: *std.mem.Allocator) void { pub fn init(mem_profile: *const MemProfile, allocator: *std.mem.Allocator) void {
log.logInfo("Init paging\n"); log.logInfo("Init paging\n");
ADDR_OFFSET = @ptrToInt(&KERNEL_ADDR_OFFSET);
// Calculate start and end of mapping // Calculate start and end of mapping
const v_start = std.mem.alignBackward(@ptrToInt(mem_profile.vaddr_start), PAGE_SIZE_4KB); const v_start = std.mem.alignBackward(@ptrToInt(mem_profile.vaddr_start), PAGE_SIZE_4KB);
const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end) + mem_profile.fixed_alloc_size, PAGE_SIZE_4KB); const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end) + mem_profile.fixed_alloc_size, PAGE_SIZE_4KB);
@ -336,14 +311,14 @@ pub fn init(mem_profile: *const MemProfile, allocator: *std.mem.Allocator) void
const tty_addr = tty.getVideoBufferAddress(); const tty_addr = tty.getVideoBufferAddress();
// If the previous mapping space didn't cover the tty buffer, do so now // If the previous mapping space didn't cover the tty buffer, do so now
if (v_start > tty_addr or v_end <= tty_addr) { if (v_start > tty_addr or v_end <= tty_addr) {
const tty_phys = virtToPhys(tty_addr); const tty_phys = mem.virtToPhys(tty_addr);
const tty_buff_size = 32 * 1024; const tty_buff_size = 32 * 1024;
mapDir(kernel_directory, tty_addr, tty_addr + tty_buff_size, tty_phys, tty_phys + tty_buff_size, allocator) catch |e| { mapDir(kernel_directory, tty_addr, tty_addr + tty_buff_size, tty_phys, tty_phys + tty_buff_size, allocator) catch |e| {
panic(@errorReturnTrace(), "Failed to map vga buffer in kernel directory: {}\n", e); panic(@errorReturnTrace(), "Failed to map vga buffer in kernel directory: {}\n", e);
}; };
} }
const dir_physaddr = @ptrToInt(virtToPhys(kernel_directory)); const dir_physaddr = @ptrToInt(mem.virtToPhys(kernel_directory));
asm volatile ("mov %[addr], %%cr3" asm volatile ("mov %[addr], %%cr3"
: :
: [addr] "{eax}" (dir_physaddr) : [addr] "{eax}" (dir_physaddr)
@ -388,14 +363,6 @@ fn checkTableEntry(entry: TableEntry, page_phys: usize) void {
expectEqual(entry & TENTRY_PAGE_ADDR, @intCast(u32, page_phys)); expectEqual(entry & TENTRY_PAGE_ADDR, @intCast(u32, page_phys));
} }
test "virtToPhys" {
ADDR_OFFSET = 0xC0000000;
const offset: usize = ADDR_OFFSET;
expectEqual(virtToPhys(offset + 0), 0);
expectEqual(virtToPhys(offset + 123), 123);
expectEqual(virtToPhys(@intToPtr(*usize, offset + 123)), @intToPtr(*usize, 123));
}
test "virtToDirEntryIdx" { test "virtToDirEntryIdx" {
expectEqual(virtToDirEntryIdx(0), 0); expectEqual(virtToDirEntryIdx(0), 0);
expectEqual(virtToDirEntryIdx(123), 0); expectEqual(virtToDirEntryIdx(123), 0);

View file

@ -1,4 +1,6 @@
const multiboot = @import("multiboot.zig"); const multiboot = @import("multiboot.zig");
const std = @import("std");
const expectEqual = std.testing.expectEqual;
pub const MemProfile = struct { pub const MemProfile = struct {
vaddr_end: [*]u8, vaddr_end: [*]u8,
@ -9,16 +11,40 @@ pub const MemProfile = struct {
fixed_alloc_size: u32, fixed_alloc_size: u32,
}; };
// The virtual/physical start/end of the kernel code /// The virtual end of the kernel code
extern var KERNEL_VADDR_END: *u32; extern var KERNEL_VADDR_END: *u32;
/// The virtual start of the kernel code
extern var KERNEL_VADDR_START: *u32; extern var KERNEL_VADDR_START: *u32;
/// The physical end of the kernel code
extern var KERNEL_PHYSADDR_END: *u32; extern var KERNEL_PHYSADDR_END: *u32;
/// The physical start of the kernel code
extern var KERNEL_PHYSADDR_START: *u32; extern var KERNEL_PHYSADDR_START: *u32;
// The size of the fixed allocator used before the heap is set up. Set to 1MiB. /// The boot-time offset that the virtual addresses are from the physical addresses
extern var KERNEL_ADDR_OFFSET: *u32;
/// The size of the fixed allocator used before the heap is set up. Set to 1MiB.
const FIXED_ALLOC_SIZE = 1024 * 1024; const FIXED_ALLOC_SIZE = 1024 * 1024;
/// The kernel's virtual address offset. It's assigned in the init function and this file's tests.
/// We can't just use KERNEL_ADDR_OFFSET since using externs in the virtToPhys test is broken in
/// release-safe. This is a workaround until that is fixed.
var ADDR_OFFSET: usize = undefined;
///
/// Initialise the system's memory profile based on linker symbols and the multiboot info struct.
///
/// Arguments:
/// IN mb_info: *multiboot.multiboot_info_t - The multiboot info passed by the bootloader.
///
/// Return: MemProfile
/// The memory profile constructed from the exported linker symbols and the relevant multiboot info.
///
pub fn init(mb_info: *multiboot.multiboot_info_t) MemProfile { pub fn init(mb_info: *multiboot.multiboot_info_t) MemProfile {
ADDR_OFFSET = @ptrToInt(&KERNEL_ADDR_OFFSET);
return MemProfile{ return MemProfile{
.vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END), .vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END),
.vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START), .vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START),
@ -29,3 +55,55 @@ pub fn init(mb_info: *multiboot.multiboot_info_t) MemProfile {
.fixed_alloc_size = FIXED_ALLOC_SIZE, .fixed_alloc_size = FIXED_ALLOC_SIZE,
}; };
} }
///
/// Convert a virtual address to its physical counterpart by subtracting the kernel virtual offset from the virtual address.
///
/// Arguments:
/// IN virt: var - The virtual address to covert. Either an integer or pointer.
///
/// Return: @typeOf(virt)
/// The physical address.
///
pub fn virtToPhys(virt: var) @typeOf(virt) {
const T = @typeOf(virt);
return switch (@typeId(T)) {
.Pointer => @intToPtr(T, @ptrToInt(virt) - ADDR_OFFSET),
.Int => virt - ADDR_OFFSET,
else => @compileError("Only pointers and integers are supported"),
};
}
///
/// Convert a physical address to its virtual counterpart by adding the kernel virtual offset to the physical address.
///
/// Arguments:
/// IN phys: var - The physical address to covert. Either an integer or pointer.
///
/// Return: @typeOf(virt)
/// The virtual address.
///
pub fn physToVirt(phys: var) @typeOf(phys) {
const T = @typeOf(phys);
return switch (@typeId(T)) {
.Pointer => @intToPtr(T, @ptrToInt(phys) + ADDR_OFFSET),
.Int => phys + ADDR_OFFSET,
else => @compileError("Only pointers and integers are supported"),
};
}
test "physToVirt" {
ADDR_OFFSET = 0xC0000000;
const offset: usize = ADDR_OFFSET;
expectEqual(physToVirt(usize(0)), offset + 0);
expectEqual(physToVirt(usize(123)), offset + 123);
expectEqual(@ptrToInt(physToVirt(@intToPtr(*usize, 123))), offset + 123);
}
test "virtToPhys" {
ADDR_OFFSET = 0xC0000000;
const offset: usize = ADDR_OFFSET;
expectEqual(virtToPhys(offset + 0), 0);
expectEqual(virtToPhys(offset + 123), 123);
expectEqual(@ptrToInt(virtToPhys(@intToPtr(*usize, offset + 123))), 123);
}