Merge pull request #206 from ZystemOS/bugfix/vmm-map-correctly
Bugfix/vmm map correctly
This commit is contained in:
commit
7b4a5e97aa
12 changed files with 348 additions and 263 deletions
|
@ -339,11 +339,10 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
|
|||
mem.ADDR_OFFSET = @ptrToInt(&KERNEL_ADDR_OFFSET);
|
||||
const mmap_addr = mb_info.mmap_addr;
|
||||
const num_mmap_entries = mb_info.mmap_length / @sizeOf(multiboot.multiboot_memory_map_t);
|
||||
const vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END);
|
||||
|
||||
var allocator = std.heap.FixedBufferAllocator.init(vaddr_end[0..mem.FIXED_ALLOC_SIZE]);
|
||||
var reserved_physical_mem = std.ArrayList(mem.Range).init(&allocator.allocator);
|
||||
var reserved_virtual_mem = std.ArrayList(mem.Map).init(&allocator.allocator);
|
||||
const allocator = &mem.fixed_buffer_allocator.allocator;
|
||||
var reserved_physical_mem = std.ArrayList(mem.Range).init(allocator);
|
||||
var reserved_virtual_mem = std.ArrayList(mem.Map).init(allocator);
|
||||
const mem_map = @intToPtr([*]multiboot.multiboot_memory_map_t, mmap_addr)[0..num_mmap_entries];
|
||||
|
||||
// Reserve the unavailable sections from the multiboot memory map
|
||||
|
@ -351,7 +350,10 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
|
|||
if (entry.@"type" != multiboot.MULTIBOOT_MEMORY_AVAILABLE) {
|
||||
// If addr + len is greater than maxInt(usize) just ignore whatever comes after maxInt(usize) since it can't be addressed anyway
|
||||
const end: usize = if (entry.addr > std.math.maxInt(usize) - entry.len) std.math.maxInt(usize) else @intCast(usize, entry.addr + entry.len);
|
||||
try reserved_physical_mem.append(.{ .start = @intCast(usize, entry.addr), .end = end });
|
||||
try reserved_physical_mem.append(.{
|
||||
.start = @intCast(usize, entry.addr),
|
||||
.end = end,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,8 +362,14 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
|
|||
.start = @ptrToInt(mb_info),
|
||||
.end = @ptrToInt(mb_info) + @sizeOf(multiboot.multiboot_info_t),
|
||||
};
|
||||
const mb_physical = mem.Range{ .start = mem.virtToPhys(mb_region.start), .end = mem.virtToPhys(mb_region.end) };
|
||||
try reserved_virtual_mem.append(.{ .virtual = mb_region, .physical = mb_physical });
|
||||
const mb_physical = mem.Range{
|
||||
.start = mem.virtToPhys(mb_region.start),
|
||||
.end = mem.virtToPhys(mb_region.end),
|
||||
};
|
||||
try reserved_virtual_mem.append(.{
|
||||
.virtual = mb_region,
|
||||
.physical = mb_physical,
|
||||
});
|
||||
|
||||
// Map the tty buffer
|
||||
const tty_addr = mem.virtToPhys(tty.getVideoBufferAddress());
|
||||
|
@ -379,16 +387,56 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
|
|||
|
||||
// Map the boot modules
|
||||
const boot_modules = @intToPtr([*]multiboot.multiboot_mod_list, mem.physToVirt(mb_info.mods_addr))[0..mods_count];
|
||||
var modules = std.ArrayList(mem.Module).init(&allocator.allocator);
|
||||
var modules = std.ArrayList(mem.Module).init(allocator);
|
||||
for (boot_modules) |module| {
|
||||
const virtual = mem.Range{ .start = mem.physToVirt(module.mod_start), .end = mem.physToVirt(module.mod_end) };
|
||||
const physical = mem.Range{ .start = module.mod_start, .end = module.mod_end };
|
||||
try modules.append(.{ .region = virtual, .name = std.mem.span(mem.physToVirt(@intToPtr([*:0]u8, module.cmdline))) });
|
||||
try reserved_virtual_mem.append(.{ .physical = physical, .virtual = virtual });
|
||||
const virtual = mem.Range{
|
||||
.start = mem.physToVirt(module.mod_start),
|
||||
.end = mem.physToVirt(module.mod_end),
|
||||
};
|
||||
const physical = mem.Range{
|
||||
.start = module.mod_start,
|
||||
.end = module.mod_end,
|
||||
};
|
||||
try modules.append(.{
|
||||
.region = virtual,
|
||||
.name = std.mem.span(mem.physToVirt(@intToPtr([*:0]u8, module.cmdline))),
|
||||
});
|
||||
try reserved_virtual_mem.append(.{
|
||||
.physical = physical,
|
||||
.virtual = virtual,
|
||||
});
|
||||
}
|
||||
|
||||
// Map the kernel stack
|
||||
const kernel_stack_virt = mem.Range{
|
||||
.start = @ptrToInt(&KERNEL_STACK_START),
|
||||
.end = @ptrToInt(&KERNEL_STACK_END),
|
||||
};
|
||||
const kernel_stack_phy = mem.Range{
|
||||
.start = mem.virtToPhys(kernel_stack_virt.start),
|
||||
.end = mem.virtToPhys(kernel_stack_virt.end),
|
||||
};
|
||||
try reserved_virtual_mem.append(.{
|
||||
.virtual = kernel_stack_virt,
|
||||
.physical = kernel_stack_phy,
|
||||
});
|
||||
|
||||
// Map the rest of the kernel
|
||||
const kernel_virt = mem.Range{
|
||||
.start = @ptrToInt(&KERNEL_VADDR_START),
|
||||
.end = @ptrToInt(&KERNEL_STACK_START),
|
||||
};
|
||||
const kernel_phy = mem.Range{
|
||||
.start = mem.virtToPhys(kernel_virt.start),
|
||||
.end = mem.virtToPhys(kernel_virt.end),
|
||||
};
|
||||
try reserved_virtual_mem.append(.{
|
||||
.virtual = kernel_virt,
|
||||
.physical = kernel_phy,
|
||||
});
|
||||
|
||||
return MemProfile{
|
||||
.vaddr_end = vaddr_end,
|
||||
.vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END),
|
||||
.vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START),
|
||||
.physaddr_end = @ptrCast([*]u8, &KERNEL_PHYSADDR_END),
|
||||
.physaddr_start = @ptrCast([*]u8, &KERNEL_PHYSADDR_START),
|
||||
|
@ -397,7 +445,7 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
|
|||
.modules = modules.items,
|
||||
.physical_reserved = reserved_physical_mem.items,
|
||||
.virtual_reserved = reserved_virtual_mem.items,
|
||||
.fixed_allocator = allocator,
|
||||
.fixed_allocator = mem.fixed_buffer_allocator,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -452,12 +500,10 @@ pub fn initTaskStack(entry_point: usize, allocator: *Allocator) Allocator.Error!
|
|||
/// Initialise the architecture
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN boot_payload: BootPayload - The multiboot information from the GRUB bootloader.
|
||||
/// IN mem_profile: *const MemProfile - The memory profile of the computer. Used to set up
|
||||
/// paging.
|
||||
/// IN allocator: *Allocator - The allocator use to handle memory.
|
||||
///
|
||||
pub fn init(boot_payload: BootPayload, mem_profile: *const MemProfile, allocator: *Allocator) void {
|
||||
pub fn init(mem_profile: *const MemProfile) void {
|
||||
gdt.init();
|
||||
idt.init();
|
||||
|
||||
|
@ -465,7 +511,7 @@ pub fn init(boot_payload: BootPayload, mem_profile: *const MemProfile, allocator
|
|||
isr.init();
|
||||
irq.init();
|
||||
|
||||
paging.init(boot_payload, mem_profile, allocator);
|
||||
paging.init(mem_profile);
|
||||
|
||||
pit.init();
|
||||
rtc.init();
|
||||
|
|
|
@ -101,6 +101,7 @@ export fn start_higher_half() callconv(.Naked) noreturn {
|
|||
asm volatile (
|
||||
\\.extern KERNEL_STACK_END
|
||||
\\mov $KERNEL_STACK_END, %%esp
|
||||
\\sub $32, %%esp
|
||||
\\mov %%esp, %%ebp
|
||||
);
|
||||
|
||||
|
|
|
@ -387,9 +387,8 @@ fn pageFault(state: *arch.CpuState) u32 {
|
|||
///
|
||||
/// Arguments:
|
||||
/// IN mem_profile: *const MemProfile - The memory profile of the system and kernel
|
||||
/// IN allocator: *std.mem.Allocator - The allocator to use
|
||||
///
|
||||
pub fn init(mb_info: *multiboot.multiboot_info_t, mem_profile: *const MemProfile, allocator: *std.mem.Allocator) void {
|
||||
pub fn init(mem_profile: *const MemProfile) void {
|
||||
std.log.info(.paging, "Init\n", .{});
|
||||
defer std.log.info(.paging, "Done\n", .{});
|
||||
|
||||
|
@ -401,7 +400,7 @@ pub fn init(mb_info: *multiboot.multiboot_info_t, mem_profile: *const MemProfile
|
|||
:
|
||||
: [addr] "{eax}" (dir_physaddr)
|
||||
);
|
||||
const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end) + mem.FIXED_ALLOC_SIZE, PAGE_SIZE_4KB);
|
||||
const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end), PAGE_SIZE_4KB);
|
||||
switch (build_options.test_mode) {
|
||||
.Initialisation => runtimeTests(v_end),
|
||||
else => {},
|
||||
|
|
|
@ -414,6 +414,8 @@ const FreeListAllocator = struct {
|
|||
var free_list = &(try FreeListAllocator.init(start, size));
|
||||
var allocator = &free_list.allocator;
|
||||
|
||||
std.debug.warn("", .{});
|
||||
|
||||
const alloc0 = try alloc(allocator, 64, 0, 0);
|
||||
const alloc0_addr = @ptrToInt(alloc0.ptr);
|
||||
// Should be at the start of the heap
|
||||
|
@ -424,6 +426,8 @@ const FreeListAllocator = struct {
|
|||
testing.expectEqual(header.next_free, null);
|
||||
testing.expectEqual(free_list.first_free, header);
|
||||
|
||||
std.debug.warn("", .{});
|
||||
|
||||
// 64 bytes aligned to 4 bytes
|
||||
const alloc1 = try alloc(allocator, 64, 4, 0);
|
||||
const alloc1_addr = @ptrToInt(alloc1.ptr);
|
||||
|
|
|
@ -61,7 +61,9 @@ export fn kmain(boot_payload: arch.BootPayload) void {
|
|||
|
||||
log_root.init(serial_stream);
|
||||
|
||||
const mem_profile = arch.initMem(boot_payload) catch |e| panic_root.panic(@errorReturnTrace(), "Failed to initialise memory profile: {}", .{e});
|
||||
const mem_profile = arch.initMem(boot_payload) catch |e| {
|
||||
panic_root.panic(@errorReturnTrace(), "Failed to initialise memory profile: {}", .{e});
|
||||
};
|
||||
var fixed_allocator = mem_profile.fixed_allocator;
|
||||
|
||||
panic_root.init(&mem_profile, &fixed_allocator.allocator) catch |e| {
|
||||
|
@ -69,10 +71,12 @@ export fn kmain(boot_payload: arch.BootPayload) void {
|
|||
};
|
||||
|
||||
pmm.init(&mem_profile, &fixed_allocator.allocator);
|
||||
kernel_vmm = vmm.init(&mem_profile, &fixed_allocator.allocator) catch |e| panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel VMM: {}", .{e});
|
||||
kernel_vmm = vmm.init(&mem_profile, &fixed_allocator.allocator) catch |e| {
|
||||
panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel VMM: {}", .{e});
|
||||
};
|
||||
|
||||
std.log.info(.kmain, "Init arch " ++ @tagName(builtin.arch) ++ "\n", .{});
|
||||
arch.init(boot_payload, &mem_profile, &fixed_allocator.allocator);
|
||||
arch.init(&mem_profile);
|
||||
std.log.info(.kmain, "Arch init done\n", .{});
|
||||
|
||||
// Give the kernel heap 10% of the available memory. This can be fine-tuned as time goes on.
|
||||
|
|
|
@ -53,7 +53,10 @@ pub const MemProfile = struct {
|
|||
};
|
||||
|
||||
/// The size of the fixed allocator used before the heap is set up. Set to 1MiB.
|
||||
pub const FIXED_ALLOC_SIZE: usize = 1024 * 1024;
|
||||
pub var fixed_buffer: [1024 * 1024]u8 = undefined;
|
||||
|
||||
/// The fixed allocator used before the heap is set up.
|
||||
pub var fixed_buffer_allocator: std.heap.FixedBufferAllocator = std.heap.FixedBufferAllocator.init(fixed_buffer[0..]);
|
||||
|
||||
/// 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
|
||||
|
|
|
@ -6,6 +6,7 @@ const multiboot = @import("multiboot.zig");
|
|||
const mem = @import("mem.zig");
|
||||
const build_options = @import("build_options");
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const testing = std.testing;
|
||||
|
||||
/// The possible errors from panic code
|
||||
|
@ -31,12 +32,12 @@ const SymbolMap = struct {
|
|||
/// Initialise an empty symbol map.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN allocator: *std.mem.Allocator - The allocator to use to initialise the array list.
|
||||
/// IN allocator: *Allocator - The allocator to use to initialise the array list.
|
||||
///
|
||||
/// Return: SymbolMap
|
||||
/// The symbol map.
|
||||
///
|
||||
pub fn init(allocator: *std.mem.Allocator) SymbolMap {
|
||||
pub fn init(allocator: *Allocator) SymbolMap {
|
||||
return SymbolMap{
|
||||
.symbols = ArrayList(MapEntry).init(allocator),
|
||||
};
|
||||
|
@ -56,14 +57,23 @@ const SymbolMap = struct {
|
|||
/// IN name: []const u8 - The name of the entry.
|
||||
/// IN addr: usize - The address for the entry.
|
||||
///
|
||||
/// Error: std.mem.Allocator.Error
|
||||
/// * - See ArrayList.append
|
||||
/// Error: Allocator.Error
|
||||
/// error.OutOfMemory - If there isn't enough memory to append a map entry.
|
||||
///
|
||||
pub fn add(self: *SymbolMap, name: []const u8, addr: usize) !void {
|
||||
pub fn add(self: *SymbolMap, name: []const u8, addr: usize) Allocator.Error!void {
|
||||
try self.addEntry(MapEntry{ .addr = addr, .func_name = name });
|
||||
}
|
||||
|
||||
pub fn addEntry(self: *SymbolMap, entry: MapEntry) !void {
|
||||
///
|
||||
/// Add a symbol map entry.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN entry: MapEntry - The entry.
|
||||
///
|
||||
/// Error: Allocator.Error
|
||||
/// error.OutOfMemory - If there isn't enough memory to append a map entry.
|
||||
///
|
||||
pub fn addEntry(self: *SymbolMap, entry: MapEntry) Allocator.Error!void {
|
||||
try self.symbols.append(entry);
|
||||
}
|
||||
|
||||
|
@ -104,6 +114,168 @@ fn logTraceAddress(addr: usize) void {
|
|||
std.log.emerg(.panic, "{x}: {}\n", .{ addr, str });
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a hexadecimal address from the pointer up until the end pointer. Must be terminated by a
|
||||
/// whitespace character.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN/OUT ptr: *[*]const u8 - The address at which to start looking, updated after all
|
||||
/// characters have been consumed.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A whitespace character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: usize
|
||||
/// The address parsed.
|
||||
///
|
||||
/// Error: PanicError || std.fmt.ParseIntError
|
||||
/// PanicError.InvalidSymbolFile - A terminating whitespace wasn't found before the end address.
|
||||
/// std.fmt.ParseIntError - See std.fmt.parseInt
|
||||
///
|
||||
fn parseAddr(ptr: *[*]const u8, end: *const u8) (PanicError || std.fmt.ParseIntError)!usize {
|
||||
const addr_start = ptr.*;
|
||||
ptr.* = try parseNonWhitespace(ptr.*, end);
|
||||
const len = @ptrToInt(ptr.*) - @ptrToInt(addr_start);
|
||||
const addr_str = addr_start[0..len];
|
||||
return std.fmt.parseInt(usize, addr_str, 16);
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a single character. The address given cannot be greater than or equal to the end address
|
||||
/// given.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN ptr: [*]const u8 - The address at which to get the character from.
|
||||
/// IN end: *const u8 - The end address at which to start looking. ptr cannot be greater than or
|
||||
/// equal to this.
|
||||
///
|
||||
/// Return: u8
|
||||
/// The character parsed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile - The address given is greater than or equal to the end address.
|
||||
///
|
||||
fn parseChar(ptr: [*]const u8, end: *const u8) PanicError!u8 {
|
||||
if (@ptrToInt(ptr) >= @ptrToInt(end)) {
|
||||
return PanicError.InvalidSymbolFile;
|
||||
}
|
||||
return ptr[0];
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse until a non-whitespace character. Must be terminated by a non-whitespace character before
|
||||
/// the end address.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN ptr: [*]const u8 - The address at which to start looking.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A non-whitespace character
|
||||
/// must be found before this.
|
||||
///
|
||||
/// Return: [*]const u8
|
||||
/// ptr plus the number of whitespace characters consumed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile - A terminating non-whitespace character wasn't found before
|
||||
/// the end address.
|
||||
///
|
||||
fn parseWhitespace(ptr: [*]const u8, end: *const u8) PanicError![*]const u8 {
|
||||
var i: u32 = 0;
|
||||
while (std.fmt.isWhiteSpace(try parseChar(ptr + i, end))) : (i += 1) {}
|
||||
return ptr + i;
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse until a whitespace character. Must be terminated by a whitespace character before the end
|
||||
/// address.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN ptr: [*]const u8 - The address at which to start looking.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A whitespace character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: [*]const u8
|
||||
/// ptr plus the number of non-whitespace characters consumed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile - A terminating whitespace character wasn't found before the
|
||||
/// end address.
|
||||
///
|
||||
fn parseNonWhitespace(ptr: [*]const u8, end: *const u8) PanicError![*]const u8 {
|
||||
var i: u32 = 0;
|
||||
while (!std.fmt.isWhiteSpace(try parseChar(ptr + i, end))) : (i += 1) {}
|
||||
return ptr + i;
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse until a newline character. Must be terminated by a newline character before the end
|
||||
/// address.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN ptr: [*]const u8 - The address at which to start looking.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A newline character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: [*]const u8
|
||||
/// ptr plus the number of non-newline characters consumed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile - A terminating newline character wasn't found before the
|
||||
/// end address.
|
||||
///
|
||||
fn parseNonNewLine(ptr: [*]const u8, end: *const u8) PanicError![*]const u8 {
|
||||
var i: u32 = 0;
|
||||
while ((try parseChar(ptr + i, end)) != '\n') : (i += 1) {}
|
||||
return ptr + i;
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a name from the pointer up until the end pointer. Must be terminated by a whitespace
|
||||
/// character.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN/OUT ptr: *[*]const u8 - The address at which to start looking, updated after all
|
||||
/// characters have been consumed.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A whitespace character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: []const u8
|
||||
/// The name parsed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile - A terminating whitespace wasn't found before the end address.
|
||||
///
|
||||
fn parseName(ptr: *[*]const u8, end: *const u8) PanicError![]const u8 {
|
||||
const name_start = ptr.*;
|
||||
ptr.* = try parseNonNewLine(ptr.*, end);
|
||||
const len = @ptrToInt(ptr.*) - @ptrToInt(name_start);
|
||||
return name_start[0..len];
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a symbol map entry from the pointer up until the end pointer,
|
||||
/// in the format of '\d+\w+[a-zA-Z0-9]+'. Must be terminated by a whitespace character.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN/OUT ptr: *[*]const u8 - The address at which to start looking, updated once after the
|
||||
/// address has been consumed and once again after the name has been consumed.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A whitespace character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: MapEntry
|
||||
/// The entry parsed.
|
||||
///
|
||||
/// Error: PanicError || std.fmt.ParseIntError
|
||||
/// PanicError.InvalidSymbolFile - A terminating whitespace wasn't found before the end address.
|
||||
/// std.fmt.ParseIntError - See parseAddr.
|
||||
///
|
||||
fn parseMapEntry(start: *[*]const u8, end: *const u8) (PanicError || std.fmt.ParseIntError)!MapEntry {
|
||||
var ptr = try parseWhitespace(start.*, end);
|
||||
defer start.* = ptr;
|
||||
const addr = try parseAddr(&ptr, end);
|
||||
ptr = try parseWhitespace(ptr, end);
|
||||
const name = try parseName(&ptr, end);
|
||||
return MapEntry{ .addr = addr, .func_name = name };
|
||||
}
|
||||
|
||||
pub fn panic(trace: ?*builtin.StackTrace, comptime format: []const u8, args: anytype) noreturn {
|
||||
@setCold(true);
|
||||
std.log.emerg(.panic, "Kernel panic: " ++ format ++ "\n", args);
|
||||
|
@ -125,168 +297,6 @@ pub fn panic(trace: ?*builtin.StackTrace, comptime format: []const u8, args: any
|
|||
arch.haltNoInterrupts();
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a hexadecimal address from the pointer up until the end pointer. Must be terminated by a
|
||||
/// whitespace character.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN/OUT ptr: *[*]const u8 - The address at which to start looking, updated after all
|
||||
/// characters have been consumed.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A whitespace character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: usize
|
||||
/// The address parsed.
|
||||
///
|
||||
/// Error: PanicError || std.fmt.ParseUnsignedError
|
||||
/// PanicError.InvalidSymbolFile: A terminating whitespace wasn't found before the end address.
|
||||
/// std.fmt.ParseUnsignedError: See std.fmt.parseInt
|
||||
///
|
||||
fn parseAddr(ptr: *[*]const u8, end: *const u8) !usize {
|
||||
const addr_start = ptr.*;
|
||||
ptr.* = try parseNonWhitespace(ptr.*, end);
|
||||
const len = @ptrToInt(ptr.*) - @ptrToInt(addr_start);
|
||||
const addr_str = addr_start[0..len];
|
||||
return try std.fmt.parseInt(usize, addr_str, 16);
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a single character. The address given cannot be greater than or equal to the end address
|
||||
/// given.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN ptr: [*]const u8 - The address at which to get the character from.
|
||||
/// IN end: *const u8 - The end address at which to start looking. ptr cannot be greater than or
|
||||
/// equal to this.
|
||||
///
|
||||
/// Return: u8
|
||||
/// The character parsed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile: The address given is greater than or equal to the end address.
|
||||
///
|
||||
fn parseChar(ptr: [*]const u8, end: *const u8) PanicError!u8 {
|
||||
if (@ptrToInt(ptr) >= @ptrToInt(end)) {
|
||||
return PanicError.InvalidSymbolFile;
|
||||
}
|
||||
return ptr[0];
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse until a non-whitespace character. Must be terminated by a non-whitespace character before
|
||||
/// the end address.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN ptr: [*]const u8 - The address at which to start looking.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A non-whitespace character
|
||||
/// must be found before this.
|
||||
///
|
||||
/// Return: [*]const u8
|
||||
/// ptr plus the number of whitespace characters consumed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile: A terminating non-whitespace character wasn't found before the
|
||||
/// end address.
|
||||
///
|
||||
fn parseWhitespace(ptr: [*]const u8, end: *const u8) PanicError![*]const u8 {
|
||||
var i: u32 = 0;
|
||||
while (std.fmt.isWhiteSpace(try parseChar(ptr + i, end))) : (i += 1) {}
|
||||
return ptr + i;
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse until a whitespace character. Must be terminated by a whitespace character before the end
|
||||
/// address.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN ptr: [*]const u8 - The address at which to start looking.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A whitespace character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: [*]const u8
|
||||
/// ptr plus the number of non-whitespace characters consumed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile: A terminating whitespace character wasn't found before the end
|
||||
/// address.
|
||||
///
|
||||
fn parseNonWhitespace(ptr: [*]const u8, end: *const u8) PanicError![*]const u8 {
|
||||
var i: u32 = 0;
|
||||
while (!std.fmt.isWhiteSpace(try parseChar(ptr + i, end))) : (i += 1) {}
|
||||
return ptr + i;
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse until a newline character. Must be terminated by a newline character before the end
|
||||
/// address.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN ptr: [*]const u8 - The address at which to start looking.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A newline character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: [*]const u8
|
||||
/// ptr plus the number of non-newline characters consumed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile: A terminating newline character wasn't found before the end
|
||||
/// address.
|
||||
///
|
||||
fn parseNonNewLine(ptr: [*]const u8, end: *const u8) PanicError![*]const u8 {
|
||||
var i: u32 = 0;
|
||||
while ((try parseChar(ptr + i, end)) != '\n') : (i += 1) {}
|
||||
return ptr + i;
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a name from the pointer up until the end pointer. Must be terminated by a whitespace
|
||||
/// character.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN/OUT ptr: *[*]const u8 - The address at which to start looking, updated after all
|
||||
/// characters have been consumed.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A whitespace character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: []const u8
|
||||
/// The name parsed.
|
||||
///
|
||||
/// Error: PanicError
|
||||
/// PanicError.InvalidSymbolFile: A terminating whitespace wasn't found before the end address.
|
||||
///
|
||||
fn parseName(ptr: *[*]const u8, end: *const u8) PanicError![]const u8 {
|
||||
const name_start = ptr.*;
|
||||
ptr.* = try parseNonNewLine(ptr.*, end);
|
||||
const len = @ptrToInt(ptr.*) - @ptrToInt(name_start);
|
||||
return name_start[0..len];
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse a symbol map entry from the pointer up until the end pointer,
|
||||
/// in the format of '\d+\w+[a-zA-Z0-9]+'. Must be terminated by a whitespace character.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN/OUT ptr: *[*]const u8 - The address at which to start looking, updated once after the
|
||||
/// address has been consumed and once again after the name has been consumed.
|
||||
/// IN end: *const u8 - The end address at which to start looking. A whitespace character must
|
||||
/// be found before this.
|
||||
///
|
||||
/// Return: MapEntry
|
||||
/// The entry parsed.
|
||||
///
|
||||
/// Error: PanicError || std.fmt.ParseUnsignedError
|
||||
/// PanicError.InvalidSymbolFile: A terminating whitespace wasn't found before the end address.
|
||||
/// std.fmt.ParseUnsignedError: See parseAddr.
|
||||
///
|
||||
fn parseMapEntry(start: *[*]const u8, end: *const u8) !MapEntry {
|
||||
var ptr = try parseWhitespace(start.*, end);
|
||||
defer start.* = ptr;
|
||||
const addr = try parseAddr(&ptr, end);
|
||||
ptr = try parseWhitespace(ptr, end);
|
||||
const name = try parseName(&ptr, end);
|
||||
return MapEntry{ .addr = addr, .func_name = name };
|
||||
}
|
||||
|
||||
///
|
||||
/// Initialise the panic subsystem by looking for a boot module called "kernel.map" and loading the
|
||||
/// symbols from it. Exits early if no such module was found.
|
||||
|
@ -294,13 +304,14 @@ fn parseMapEntry(start: *[*]const u8, end: *const u8) !MapEntry {
|
|||
/// Arguments:
|
||||
/// IN mem_profile: *const mem.MemProfile - The memory profile from which to get the loaded boot
|
||||
/// modules.
|
||||
/// IN allocator: *std.mem.Allocator - The allocator to use to store the symbol map.
|
||||
/// IN allocator: *Allocator - The allocator to use to store the symbol map.
|
||||
///
|
||||
/// Error: PanicError || std.fmt.ParseUnsignedError
|
||||
/// PanicError.InvalidSymbolFile: A terminating whitespace wasn't found before the end address.
|
||||
/// std.fmt.ParseUnsignedError: See parseMapEntry.
|
||||
/// Error: PanicError || Allocator.Error || std.fmt.ParseIntError
|
||||
/// PanicError.InvalidSymbolFile - A terminating whitespace wasn't found before the end address.
|
||||
/// Allocator.Error.OutOfMemory - If there wasn't enough memory.
|
||||
/// std.fmt.ParseIntError - See parseMapEntry.
|
||||
///
|
||||
pub fn init(mem_profile: *const mem.MemProfile, allocator: *std.mem.Allocator) !void {
|
||||
pub fn init(mem_profile: *const mem.MemProfile, allocator: *Allocator) (PanicError || Allocator.Error || std.fmt.ParseIntError)!void {
|
||||
std.log.info(.panic, "Init\n", .{});
|
||||
defer std.log.info(.panic, "Done\n", .{});
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ const MemProfile = (if (is_test) @import(mock_path ++ "mem_mock.zig") else @impo
|
|||
const testing = std.testing;
|
||||
const panic = @import("panic.zig").panic;
|
||||
const Bitmap = @import("bitmap.zig").Bitmap;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const PmmBitmap = Bitmap(u32);
|
||||
|
||||
|
@ -94,16 +95,18 @@ pub fn blocksFree() usize {
|
|||
///
|
||||
/// Arguments:
|
||||
/// IN mem: *const MemProfile - The system's memory profile.
|
||||
/// IN allocator: *std.mem.Allocator - The allocator to use to allocate the bitmaps.
|
||||
/// IN allocator: *Allocator - The allocator to use to allocate the bitmaps.
|
||||
///
|
||||
pub fn init(mem: *const MemProfile, allocator: *std.mem.Allocator) void {
|
||||
pub fn init(mem_profile: *const MemProfile, allocator: *Allocator) void {
|
||||
std.log.info(.pmm, "Init\n", .{});
|
||||
defer std.log.info(.pmm, "Done\n", .{});
|
||||
|
||||
bitmap = PmmBitmap.init(mem.mem_kb * 1024 / BLOCK_SIZE, allocator) catch @panic("Bitmap allocation failed");
|
||||
bitmap = PmmBitmap.init(mem_profile.mem_kb * 1024 / BLOCK_SIZE, allocator) catch |e| {
|
||||
panic(@errorReturnTrace(), "Bitmap allocation failed: {}\n", .{e});
|
||||
};
|
||||
|
||||
// Occupy the regions of memory that the memory map describes as reserved
|
||||
for (mem.physical_reserved) |entry| {
|
||||
for (mem_profile.physical_reserved) |entry| {
|
||||
var addr = std.mem.alignBackward(entry.start, BLOCK_SIZE);
|
||||
var end = entry.end - 1;
|
||||
// If the end address can be aligned without overflowing then align it
|
||||
|
@ -120,7 +123,7 @@ pub fn init(mem: *const MemProfile, allocator: *std.mem.Allocator) void {
|
|||
}
|
||||
|
||||
switch (build_options.test_mode) {
|
||||
.Initialisation => runtimeTests(mem, allocator),
|
||||
.Initialisation => runtimeTests(mem_profile, allocator),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
@ -200,10 +203,10 @@ test "setAddr and isSet" {
|
|||
/// Allocate all blocks and make sure they don't overlap with any reserved addresses.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN mem: *const MemProfile - The memory profile to check for reserved memory regions.
|
||||
/// IN/OUT allocator: *std.mem.Allocator - The allocator to use when needing to create intermediate structures used for testing
|
||||
/// IN mem_profile: *const MemProfile - The memory profile to check for reserved memory regions.
|
||||
/// IN/OUT allocator: *Allocator - The allocator to use when needing to create intermediate structures used for testing
|
||||
///
|
||||
fn runtimeTests(mem: *const MemProfile, allocator: *std.mem.Allocator) void {
|
||||
fn runtimeTests(mem_profile: *const MemProfile, allocator: *Allocator) void {
|
||||
// Make sure that occupied memory can't be allocated
|
||||
var prev_alloc: usize = std.math.maxInt(usize);
|
||||
var alloc_list = std.ArrayList(usize).init(allocator);
|
||||
|
@ -213,17 +216,21 @@ fn runtimeTests(mem: *const MemProfile, allocator: *std.mem.Allocator) void {
|
|||
panic(null, "FAILURE: PMM allocated the same address twice: 0x{x}", .{alloced});
|
||||
}
|
||||
prev_alloc = alloced;
|
||||
for (mem.physical_reserved) |entry| {
|
||||
for (mem_profile.physical_reserved) |entry| {
|
||||
var addr = std.mem.alignBackward(@intCast(usize, entry.start), BLOCK_SIZE);
|
||||
if (addr == alloced) {
|
||||
panic(null, "FAILURE: PMM allocated an address that should be reserved by the memory map: 0x{x}", .{addr});
|
||||
}
|
||||
}
|
||||
alloc_list.append(alloced) catch |e| panic(@errorReturnTrace(), "FAILURE: Failed to add PMM allocation to list: {}", .{e});
|
||||
alloc_list.append(alloced) catch |e| {
|
||||
panic(@errorReturnTrace(), "FAILURE: Failed to add PMM allocation to list: {}", .{e});
|
||||
};
|
||||
}
|
||||
// Clean up
|
||||
for (alloc_list.items) |alloced| {
|
||||
free(alloced) catch |e| panic(@errorReturnTrace(), "FAILURE: Failed freeing allocation in PMM rt test: {}", .{e});
|
||||
free(alloced) catch |e| {
|
||||
panic(@errorReturnTrace(), "FAILURE: Failed freeing allocation in PMM rt test: {}", .{e});
|
||||
};
|
||||
}
|
||||
std.log.info(.pmm, "Tested allocation\n", .{});
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ const mem = if (is_test) @import(mock_path ++ "mem_mock.zig") else @import("mem.
|
|||
const tty = @import("tty.zig");
|
||||
const panic = @import("panic.zig").panic;
|
||||
const arch = @import("arch.zig").internals;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
/// Attributes for a virtual memory allocation
|
||||
pub const Attributes = struct {
|
||||
|
@ -63,13 +64,13 @@ pub fn Mapper(comptime Payload: type) type {
|
|||
/// IN physical_start: usize - The start of the physical memory to map to
|
||||
/// IN physical_end: usize - The end of the physical memory to map to
|
||||
/// IN attrs: Attributes - The attributes to apply to this region of memory
|
||||
/// IN/OUT allocator: std.mem.Allocator - The allocator to use when mapping, if required
|
||||
/// IN/OUT allocator: Allocator - The allocator to use when mapping, if required
|
||||
/// IN spec: Payload - The payload to pass to the mapper
|
||||
///
|
||||
/// Error: std.mem.AllocatorError || MapperError
|
||||
/// Error: AllocatorError || MapperError
|
||||
/// The causes depend on the mapper used
|
||||
///
|
||||
mapFn: fn (virtual_start: usize, virtual_end: usize, physical_start: usize, physical_end: usize, attrs: Attributes, allocator: *std.mem.Allocator, spec: Payload) (std.mem.Allocator.Error || MapperError)!void,
|
||||
mapFn: fn (virtual_start: usize, virtual_end: usize, physical_start: usize, physical_end: usize, attrs: Attributes, allocator: *Allocator, spec: Payload) (Allocator.Error || MapperError)!void,
|
||||
|
||||
///
|
||||
/// Unmap a region (can span more than one block) of virtual memory from its physical memory. After a call to this function, the memory should not be accessible without error.
|
||||
|
@ -79,10 +80,10 @@ pub fn Mapper(comptime Payload: type) type {
|
|||
/// IN virtual_end: usize - The end of the virtual region to unmap
|
||||
/// IN spec: Payload - The payload to pass to the mapper
|
||||
///
|
||||
/// Error: std.mem.AllocatorError || MapperError
|
||||
/// Error: AllocatorError || MapperError
|
||||
/// The causes depend on the mapper used
|
||||
///
|
||||
unmapFn: fn (virtual_start: usize, virtual_end: usize, spec: Payload) (std.mem.Allocator.Error || MapperError)!void,
|
||||
unmapFn: fn (virtual_start: usize, virtual_end: usize, spec: Payload) (Allocator.Error || MapperError)!void,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -132,7 +133,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
end: usize,
|
||||
|
||||
/// The allocator to use when allocating and freeing regions
|
||||
allocator: *std.mem.Allocator,
|
||||
allocator: *Allocator,
|
||||
|
||||
/// All allocations that have been made with this manager
|
||||
allocations: std.hash_map.AutoHashMap(usize, Allocation),
|
||||
|
@ -151,17 +152,17 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
/// Arguments:
|
||||
/// IN start: usize - The start of the memory region to manage
|
||||
/// IN end: usize - The end of the memory region to manage. Must be greater than the start
|
||||
/// IN/OUT allocator: *std.mem.Allocator - The allocator to use when allocating and freeing regions
|
||||
/// IN/OUT allocator: *Allocator - The allocator to use when allocating and freeing regions
|
||||
/// IN mapper: Mapper - The mapper to use when allocating and freeing regions
|
||||
/// IN payload: Payload - The payload data to be passed to the mapper
|
||||
///
|
||||
/// Return: Self
|
||||
/// The manager constructed
|
||||
///
|
||||
/// Error: std.mem.Allocator.Error
|
||||
/// std.mem.Allocator.Error.OutOfMemory - The allocator cannot allocate the memory required
|
||||
/// Error: Allocator.Error
|
||||
/// error.OutOfMemory - The allocator cannot allocate the memory required
|
||||
///
|
||||
pub fn init(start: usize, end: usize, allocator: *std.mem.Allocator, mapper: Mapper(Payload), payload: Payload) std.mem.Allocator.Error!Self {
|
||||
pub fn init(start: usize, end: usize, allocator: *Allocator, mapper: Mapper(Payload), payload: Payload) Allocator.Error!Self {
|
||||
const size = end - start;
|
||||
var bmp = try bitmap.Bitmap(usize).init(std.mem.alignForward(size, pmm.BLOCK_SIZE) / pmm.BLOCK_SIZE, allocator);
|
||||
return Self{
|
||||
|
@ -189,7 +190,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
/// Bitmap(u32).Error.OutOfBounds - The address given is outside of the memory managed
|
||||
///
|
||||
pub fn isSet(self: *const Self, virt: usize) bitmap.Bitmap(u32).BitmapError!bool {
|
||||
return try self.bmp.isSet((virt - self.start) / BLOCK_SIZE);
|
||||
return self.bmp.isSet((virt - self.start) / BLOCK_SIZE);
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -201,21 +202,22 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
/// IN physical: ?mem.Range - The physical region to map to or null if only the virtual region is to be set
|
||||
/// IN attrs: Attributes - The attributes to apply to the memory regions
|
||||
///
|
||||
/// Error: VmmError || Bitmap(u32).BitmapError || std.mem.Allocator.Error || MapperError
|
||||
/// Error: VmmError || Bitmap(u32).BitmapError || Allocator.Error || MapperError
|
||||
/// VmmError.AlreadyAllocated - The virtual address has already been allocated
|
||||
/// VmmError.PhysicalAlreadyAllocated - The physical address has already been allocated
|
||||
/// VmmError.PhysicalVirtualMismatch - The physical region and virtual region are of different sizes
|
||||
/// VmmError.InvalidVirtAddresses - The start virtual address is greater than the end address
|
||||
/// VmmError.InvalidPhysicalAddresses - The start physical address is greater than the end address
|
||||
/// Bitmap.BitmapError.OutOfBounds - The physical or virtual addresses are out of bounds
|
||||
/// std.mem.Allocator.Error.OutOfMemory - Allocating the required memory failed
|
||||
/// Allocator.Error.OutOfMemory - Allocating the required memory failed
|
||||
/// MapperError.* - The causes depend on the mapper used
|
||||
///
|
||||
pub fn set(self: *Self, virtual: mem.Range, physical: ?mem.Range, attrs: Attributes) (VmmError || bitmap.Bitmap(u32).BitmapError || std.mem.Allocator.Error || MapperError)!void {
|
||||
pub fn set(self: *Self, virtual: mem.Range, physical: ?mem.Range, attrs: Attributes) (VmmError || bitmap.Bitmap(u32).BitmapError || Allocator.Error || MapperError)!void {
|
||||
var virt = virtual.start;
|
||||
while (virt < virtual.end) : (virt += BLOCK_SIZE) {
|
||||
if (try self.isSet(virt))
|
||||
if (try self.isSet(virt)) {
|
||||
return VmmError.AlreadyAllocated;
|
||||
}
|
||||
}
|
||||
if (virtual.start > virtual.end) {
|
||||
return VmmError.InvalidVirtAddresses;
|
||||
|
@ -266,12 +268,13 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
/// Return: ?usize
|
||||
/// The address at the start of the allocated region, or null if no region could be allocated due to a lack of contiguous blocks.
|
||||
///
|
||||
/// Error: std.mem.Allocator.Error
|
||||
/// std.mem.AllocatorError.OutOfMemory: The required amount of memory couldn't be allocated
|
||||
/// Error: Allocator.Error
|
||||
/// error.OutOfMemory: The required amount of memory couldn't be allocated
|
||||
///
|
||||
pub fn alloc(self: *Self, num: usize, attrs: Attributes) std.mem.Allocator.Error!?usize {
|
||||
if (num == 0)
|
||||
pub fn alloc(self: *Self, num: usize, attrs: Attributes) Allocator.Error!?usize {
|
||||
if (num == 0) {
|
||||
return null;
|
||||
}
|
||||
// Ensure that there is both enough physical and virtual address space free
|
||||
if (pmm.blocksFree() >= num and self.bmp.num_free_entries >= num) {
|
||||
// The virtual address space must be contiguous
|
||||
|
@ -312,19 +315,23 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
const entry = (vaddr - self.start) / BLOCK_SIZE;
|
||||
if (try self.bmp.isSet(entry)) {
|
||||
// There will be an allocation associated with this virtual address
|
||||
const allocation = self.allocations.get(vaddr) orelse unreachable;
|
||||
const allocation = self.allocations.get(vaddr).?;
|
||||
const physical = allocation.physical;
|
||||
defer physical.deinit();
|
||||
const num_physical_allocations = physical.items.len;
|
||||
for (physical.items) |block, i| {
|
||||
// Clear the address space entry and free the physical memory
|
||||
try self.bmp.clearEntry(entry + i);
|
||||
pmm.free(block) catch |e| panic(@errorReturnTrace(), "Failed to free PMM reserved memory at 0x{X}: {}\n", .{ block * BLOCK_SIZE, e });
|
||||
pmm.free(block) catch |e| {
|
||||
panic(@errorReturnTrace(), "Failed to free PMM reserved memory at 0x{X}: {}\n", .{ block * BLOCK_SIZE, e });
|
||||
};
|
||||
}
|
||||
// Unmap the entire range
|
||||
const region_start = entry * BLOCK_SIZE;
|
||||
const region_end = (entry + num_physical_allocations) * BLOCK_SIZE;
|
||||
self.mapper.unmapFn(region_start, region_end, self.payload) catch |e| panic(@errorReturnTrace(), "Failed to unmap VMM reserved memory from 0x{X} to 0x{X}: {}\n", .{ region_start, region_end, e });
|
||||
self.mapper.unmapFn(region_start, region_end, self.payload) catch |e| {
|
||||
panic(@errorReturnTrace(), "Failed to unmap VMM reserved memory from 0x{X} to 0x{X}: {}\n", .{ region_start, region_end, e });
|
||||
};
|
||||
// The allocation is freed so remove from the map
|
||||
self.allocations.removeAssertDiscard(vaddr);
|
||||
} else {
|
||||
|
@ -339,31 +346,33 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
///
|
||||
/// Arguments:
|
||||
/// IN mem_profile: *const mem.MemProfile - The system's memory profile. This is used to find the kernel code region and boot modules
|
||||
/// IN/OUT allocator: *std.mem.Allocator - The allocator to use when needing to allocate memory
|
||||
/// IN/OUT allocator: *Allocator - The allocator to use when needing to allocate memory
|
||||
///
|
||||
/// Return: VirtualMemoryManager
|
||||
/// The virtual memory manager created with all reserved virtual regions allocated
|
||||
///
|
||||
/// Error: std.mem.Allocator.Error
|
||||
/// std.mem.Allocator.Error.OutOfMemory - The allocator cannot allocate the memory required
|
||||
/// Error: Allocator.Error
|
||||
/// error.OutOfMemory - The allocator cannot allocate the memory required
|
||||
///
|
||||
pub fn init(mem_profile: *const mem.MemProfile, allocator: *std.mem.Allocator) std.mem.Allocator.Error!VirtualMemoryManager(arch.VmmPayload) {
|
||||
std.log.info(.tty, "Init\n", .{});
|
||||
defer std.log.info(.tty, "Done\n", .{});
|
||||
pub fn init(mem_profile: *const mem.MemProfile, allocator: *Allocator) Allocator.Error!VirtualMemoryManager(arch.VmmPayload) {
|
||||
std.log.info(.vmm, "Init\n", .{});
|
||||
defer std.log.info(.vmm, "Done\n", .{});
|
||||
|
||||
var vmm = try VirtualMemoryManager(arch.VmmPayload).init(@ptrToInt(&KERNEL_ADDR_OFFSET), 0xFFFFFFFF, allocator, arch.VMM_MAPPER, arch.KERNEL_VMM_PAYLOAD);
|
||||
|
||||
// Map in kernel
|
||||
// Calculate start and end of mapping
|
||||
const v_start = std.mem.alignBackward(@ptrToInt(mem_profile.vaddr_start), BLOCK_SIZE);
|
||||
const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end) + mem.FIXED_ALLOC_SIZE, BLOCK_SIZE);
|
||||
const p_start = std.mem.alignBackward(@ptrToInt(mem_profile.physaddr_start), BLOCK_SIZE);
|
||||
const p_end = std.mem.alignForward(@ptrToInt(mem_profile.physaddr_end) + mem.FIXED_ALLOC_SIZE, BLOCK_SIZE);
|
||||
vmm.set(.{ .start = v_start, .end = v_end }, mem.Range{ .start = p_start, .end = p_end }, .{ .kernel = true, .writable = false, .cachable = true }) catch |e| panic(@errorReturnTrace(), "Failed mapping kernel code in VMM: {}", .{e});
|
||||
|
||||
// Map all the reserved virtual addresses.
|
||||
for (mem_profile.virtual_reserved) |entry| {
|
||||
const virtual = mem.Range{ .start = std.mem.alignBackward(entry.virtual.start, BLOCK_SIZE), .end = std.mem.alignForward(entry.virtual.end, BLOCK_SIZE) };
|
||||
const physical: ?mem.Range = if (entry.physical) |phys| mem.Range{ .start = std.mem.alignBackward(phys.start, BLOCK_SIZE), .end = std.mem.alignForward(phys.end, BLOCK_SIZE) } else null;
|
||||
const virtual = mem.Range{
|
||||
.start = std.mem.alignBackward(entry.virtual.start, BLOCK_SIZE),
|
||||
.end = std.mem.alignForward(entry.virtual.end, BLOCK_SIZE),
|
||||
};
|
||||
const physical: ?mem.Range = if (entry.physical) |phys|
|
||||
mem.Range{
|
||||
.start = std.mem.alignBackward(phys.start, BLOCK_SIZE),
|
||||
.end = std.mem.alignForward(phys.end, BLOCK_SIZE),
|
||||
}
|
||||
else
|
||||
null;
|
||||
vmm.set(virtual, physical, .{ .kernel = true, .writable = true, .cachable = true }) catch |e| switch (e) {
|
||||
VmmError.AlreadyAllocated => {},
|
||||
else => panic(@errorReturnTrace(), "Failed mapping region in VMM {}: {}\n", .{ entry, e }),
|
||||
|
@ -380,7 +389,7 @@ pub fn init(mem_profile: *const mem.MemProfile, allocator: *std.mem.Allocator) s
|
|||
test "alloc and free" {
|
||||
const num_entries = 512;
|
||||
var vmm = try testInit(num_entries);
|
||||
var allocations = test_allocations orelse unreachable;
|
||||
var allocations = test_allocations.?;
|
||||
var virtual_allocations = std.ArrayList(usize).init(std.testing.allocator);
|
||||
defer virtual_allocations.deinit();
|
||||
|
||||
|
@ -399,7 +408,7 @@ test "alloc and free" {
|
|||
} else {
|
||||
// Else it should have succeeded and allocated the correct address
|
||||
std.testing.expectEqual(@as(?usize, vmm.start + entry * BLOCK_SIZE), result);
|
||||
try virtual_allocations.append(result orelse unreachable);
|
||||
try virtual_allocations.append(result.?);
|
||||
}
|
||||
|
||||
// Make sure that the entries are set or not depending on the allocation success
|
||||
|
@ -471,7 +480,7 @@ test "set" {
|
|||
// Make sure it put the correct address in the map
|
||||
std.testing.expect(vmm.allocations.get(vstart) != null);
|
||||
|
||||
var allocations = test_allocations orelse unreachable;
|
||||
var allocations = test_allocations.?;
|
||||
// The entries before the virtual start shouldn't be set
|
||||
var vaddr = vmm.start;
|
||||
while (vaddr < vstart) : (vaddr += BLOCK_SIZE) {
|
||||
|
@ -499,10 +508,10 @@ var test_mapper = Mapper(u8){ .mapFn = testMap, .unmapFn = testUnmap };
|
|||
/// Return: VirtualMemoryManager(u8)
|
||||
/// The VMM constructed
|
||||
///
|
||||
/// Error: std.mem.Allocator.Error
|
||||
/// Error: Allocator.Error
|
||||
/// OutOfMemory: The allocator couldn't allocate the structures needed
|
||||
///
|
||||
fn testInit(num_entries: u32) std.mem.Allocator.Error!VirtualMemoryManager(u8) {
|
||||
fn testInit(num_entries: u32) Allocator.Error!VirtualMemoryManager(u8) {
|
||||
if (test_allocations == null) {
|
||||
test_allocations = try bitmap.Bitmap(u64).init(num_entries, std.heap.page_allocator);
|
||||
} else |allocations| {
|
||||
|
@ -524,7 +533,7 @@ fn testInit(num_entries: u32) std.mem.Allocator.Error!VirtualMemoryManager(u8) {
|
|||
.modules = &[_]mem.Module{},
|
||||
};
|
||||
pmm.init(&mem_profile, std.heap.page_allocator);
|
||||
return try VirtualMemoryManager(u8).init(0, num_entries * BLOCK_SIZE, std.heap.page_allocator, test_mapper, 39);
|
||||
return VirtualMemoryManager(u8).init(0, num_entries * BLOCK_SIZE, std.heap.page_allocator, test_mapper, 39);
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -536,14 +545,14 @@ fn testInit(num_entries: u32) std.mem.Allocator.Error!VirtualMemoryManager(u8) {
|
|||
/// IN pstart: usize - The start of the physical region to map
|
||||
/// IN pend: usize - The end of the physical region to map
|
||||
/// IN attrs: Attributes - The attributes to map with
|
||||
/// IN/OUT allocator: *std.mem.Allocator - The allocator to use. Ignored
|
||||
/// IN/OUT allocator: *Allocator - The allocator to use. Ignored
|
||||
/// IN payload: u8 - The payload value. Expected to be 39
|
||||
///
|
||||
fn testMap(vstart: usize, vend: usize, pstart: usize, pend: usize, attrs: Attributes, allocator: *std.mem.Allocator, payload: u8) (std.mem.Allocator.Error || MapperError)!void {
|
||||
fn testMap(vstart: usize, vend: usize, pstart: usize, pend: usize, attrs: Attributes, allocator: *Allocator, payload: u8) (Allocator.Error || MapperError)!void {
|
||||
std.testing.expectEqual(@as(u8, 39), payload);
|
||||
var vaddr = vstart;
|
||||
while (vaddr < vend) : (vaddr += BLOCK_SIZE) {
|
||||
(test_allocations orelse unreachable).setEntry(vaddr / BLOCK_SIZE) catch unreachable;
|
||||
(test_allocations.?).setEntry(vaddr / BLOCK_SIZE) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,11 +564,11 @@ fn testMap(vstart: usize, vend: usize, pstart: usize, pend: usize, attrs: Attrib
|
|||
/// IN vend: usize - The end of the virtual region to unmap
|
||||
/// IN payload: u8 - The payload value. Expected to be 39
|
||||
///
|
||||
fn testUnmap(vstart: usize, vend: usize, payload: u8) (std.mem.Allocator.Error || MapperError)!void {
|
||||
fn testUnmap(vstart: usize, vend: usize, payload: u8) (Allocator.Error || MapperError)!void {
|
||||
std.testing.expectEqual(@as(u8, 39), payload);
|
||||
var vaddr = vstart;
|
||||
while (vaddr < vend) : (vaddr += BLOCK_SIZE) {
|
||||
(test_allocations orelse unreachable).clearEntry(vaddr / BLOCK_SIZE) catch unreachable;
|
||||
(test_allocations.?).clearEntry(vaddr / BLOCK_SIZE) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,7 +583,7 @@ fn testUnmap(vstart: usize, vend: usize, payload: u8) (std.mem.Allocator.Error |
|
|||
///
|
||||
fn runtimeTests(comptime Payload: type, vmm: VirtualMemoryManager(Payload), mem_profile: *const mem.MemProfile) void {
|
||||
const v_start = std.mem.alignBackward(@ptrToInt(mem_profile.vaddr_start), BLOCK_SIZE);
|
||||
const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end) + mem.FIXED_ALLOC_SIZE, BLOCK_SIZE);
|
||||
const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end), BLOCK_SIZE);
|
||||
|
||||
var vaddr = vmm.start;
|
||||
while (vaddr < vmm.end - BLOCK_SIZE) : (vaddr += BLOCK_SIZE) {
|
||||
|
@ -597,5 +606,5 @@ fn runtimeTests(comptime Payload: type, vmm: VirtualMemoryManager(Payload), mem_
|
|||
}
|
||||
}
|
||||
|
||||
std.log.info(.tty, "Tested allocations\n", .{});
|
||||
std.log.info(.vmm, "Tested allocations\n", .{});
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ pub fn initTTY(boot_payload: BootPayload) TTY {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn initMem(payload: BootPayload) std.mem.Allocator.Error!mem.MemProfile {
|
||||
pub fn initMem(payload: BootPayload) Allocator.Error!mem.MemProfile {
|
||||
return MemProfile{
|
||||
.vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END),
|
||||
.vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START),
|
||||
|
@ -142,7 +142,7 @@ pub fn initTaskStack(entry_point: usize, allocator: *Allocator) Allocator.Error!
|
|||
return ret;
|
||||
}
|
||||
|
||||
pub fn init(payload: BootPayload, mem_profile: *const MemProfile, allocator: *Allocator) void {
|
||||
pub fn init(mem_profile: *const MemProfile) void {
|
||||
// I'll get back to this as this doesn't effect the current testing.
|
||||
// When I come on to the mem.zig testing, I'll fix :)
|
||||
//return mock_framework.performAction("init", void, mem_profile, allocator);
|
||||
|
|
|
@ -28,7 +28,6 @@ pub const MemProfile = struct {
|
|||
fixed_allocator: std.heap.FixedBufferAllocator,
|
||||
};
|
||||
|
||||
// The size of the fixed allocator used before the heap is set up. Set to 1MiB.
|
||||
const FIXED_ALLOC_SIZE = 1024 * 1024;
|
||||
|
||||
pub fn virtToPhys(virt: anytype) @TypeOf(virt) {
|
||||
|
|
|
@ -120,6 +120,8 @@ pub const RuntimeStep = struct {
|
|||
std.debug.warn("{}\n", .{msg});
|
||||
if (std.mem.indexOf(u8, msg, "FAILURE")) |_| {
|
||||
return false;
|
||||
} else if (std.mem.indexOf(u8, msg, "Kernel panic")) |_| {
|
||||
return false;
|
||||
} else if (std.mem.eql(u8, msg, "[info] (kmain): SUCCESS")) {
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue