2019-05-23 17:50:37 +01:00
|
|
|
const multiboot = @import("multiboot.zig");
|
2019-11-02 01:22:10 +00:00
|
|
|
const std = @import("std");
|
|
|
|
const expectEqual = std.testing.expectEqual;
|
2019-11-02 02:00:49 +00:00
|
|
|
const log = @import("log.zig");
|
2019-05-23 17:50:37 +01:00
|
|
|
|
|
|
|
pub const MemProfile = struct {
|
2019-09-09 23:38:06 +01:00
|
|
|
/// The virtual end address of the kernel code.
|
2019-05-23 17:50:37 +01:00
|
|
|
vaddr_end: [*]u8,
|
2019-09-09 23:38:06 +01:00
|
|
|
|
|
|
|
/// The virtual end address of the kernel code.
|
2019-05-23 17:50:37 +01:00
|
|
|
vaddr_start: [*]u8,
|
2019-09-09 23:38:06 +01:00
|
|
|
|
|
|
|
/// The physical end address of the kernel code.
|
2019-05-23 17:50:37 +01:00
|
|
|
physaddr_end: [*]u8,
|
2019-09-09 23:38:06 +01:00
|
|
|
|
|
|
|
/// The physical start address of the kernel code.
|
2019-05-23 17:50:37 +01:00
|
|
|
physaddr_start: [*]u8,
|
2019-09-09 23:38:06 +01:00
|
|
|
|
|
|
|
/// The amount of memory in the system, in kilobytes.
|
2019-05-23 17:50:37 +01:00
|
|
|
mem_kb: u32,
|
2019-09-09 23:38:06 +01:00
|
|
|
|
|
|
|
/// The size of the fixed buffer allocator used as the first memory allocator.
|
2019-09-08 20:48:23 +01:00
|
|
|
fixed_alloc_size: u32,
|
2019-09-09 23:38:06 +01:00
|
|
|
|
|
|
|
/// The boot modules provided by the bootloader.
|
2019-11-02 02:00:49 +00:00
|
|
|
boot_modules: []multiboot.multiboot_module_t,
|
2019-09-09 23:38:06 +01:00
|
|
|
|
|
|
|
/// The memory map provided by the bootloader. Desribes which areas of memory are available and
|
|
|
|
/// which are reserved.
|
|
|
|
mem_map: []multiboot.multiboot_memory_map_t,
|
2019-05-23 17:50:37 +01:00
|
|
|
};
|
|
|
|
|
2019-11-02 01:22:10 +00:00
|
|
|
/// The virtual end of the kernel code
|
2019-05-23 17:50:37 +01:00
|
|
|
extern var KERNEL_VADDR_END: *u32;
|
2019-11-02 01:22:10 +00:00
|
|
|
|
|
|
|
/// The virtual start of the kernel code
|
2019-05-23 17:50:37 +01:00
|
|
|
extern var KERNEL_VADDR_START: *u32;
|
2019-11-02 01:22:10 +00:00
|
|
|
|
|
|
|
/// The physical end of the kernel code
|
2019-05-23 17:50:37 +01:00
|
|
|
extern var KERNEL_PHYSADDR_END: *u32;
|
2019-11-02 01:22:10 +00:00
|
|
|
|
|
|
|
/// The physical start of the kernel code
|
2019-05-23 17:50:37 +01:00
|
|
|
extern var KERNEL_PHYSADDR_START: *u32;
|
|
|
|
|
2019-11-02 01:22:10 +00:00
|
|
|
/// 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.
|
2019-11-02 02:18:02 +00:00
|
|
|
const FIXED_ALLOC_SIZE: usize = 1024 * 1024;
|
2019-05-23 17:50:37 +01:00
|
|
|
|
2019-11-02 01:22:10 +00:00
|
|
|
/// 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.
|
|
|
|
///
|
2019-05-23 17:50:37 +01:00
|
|
|
pub fn init(mb_info: *multiboot.multiboot_info_t) MemProfile {
|
2020-01-01 19:12:36 +00:00
|
|
|
log.logInfo("Init mem\n", .{});
|
2019-09-09 23:38:06 +01:00
|
|
|
defer log.logInfo("Done\n", .{});
|
2019-11-02 02:00:49 +00:00
|
|
|
const mods_count = mb_info.mods_count;
|
2019-11-02 01:22:10 +00:00
|
|
|
ADDR_OFFSET = @ptrToInt(&KERNEL_ADDR_OFFSET);
|
2019-09-09 23:38:06 +01:00
|
|
|
const mmap_addr = mb_info.mmap_addr;
|
|
|
|
const num_mmap_entries = mb_info.mmap_length / @sizeOf(multiboot.multiboot_memory_map_t);
|
2019-11-02 02:00:49 +00:00
|
|
|
const mem_profile = MemProfile{
|
2019-05-23 17:50:37 +01:00
|
|
|
.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),
|
|
|
|
// Total memory available including the initial 1MiB that grub doesn't include
|
|
|
|
.mem_kb = mb_info.mem_upper + mb_info.mem_lower + 1024,
|
|
|
|
.fixed_alloc_size = FIXED_ALLOC_SIZE,
|
2019-11-02 02:00:49 +00:00
|
|
|
.boot_modules = @intToPtr([*]multiboot.multiboot_mod_list, physToVirt(mb_info.mods_addr))[0..mods_count],
|
2019-09-09 23:38:06 +01:00
|
|
|
.mem_map = @intToPtr([*]multiboot.multiboot_memory_map_t, mmap_addr)[0..num_mmap_entries],
|
2019-05-23 17:50:37 +01:00
|
|
|
};
|
2019-11-02 02:00:49 +00:00
|
|
|
return mem_profile;
|
2019-05-23 17:50:37 +01:00
|
|
|
}
|
2019-11-02 01:22:10 +00:00
|
|
|
|
|
|
|
///
|
|
|
|
/// 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.
|
|
|
|
///
|
2020-01-01 19:12:36 +00:00
|
|
|
/// Return: @TypeOf(virt)
|
2019-11-02 01:22:10 +00:00
|
|
|
/// The physical address.
|
|
|
|
///
|
2020-01-01 19:12:36 +00:00
|
|
|
pub inline fn virtToPhys(virt: var) @TypeOf(virt) {
|
|
|
|
const T = @TypeOf(virt);
|
2019-11-02 01:22:10 +00:00
|
|
|
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.
|
|
|
|
///
|
2020-01-01 19:12:36 +00:00
|
|
|
/// Return: @TypeOf(virt)
|
2019-11-02 01:22:10 +00:00
|
|
|
/// The virtual address.
|
|
|
|
///
|
2020-01-01 19:12:36 +00:00
|
|
|
pub inline fn physToVirt(phys: var) @TypeOf(phys) {
|
|
|
|
const T = @TypeOf(phys);
|
2019-11-02 01:22:10 +00:00
|
|
|
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;
|
2019-11-10 12:35:08 +00:00
|
|
|
expectEqual(physToVirt(@as(usize, 0)), offset + 0);
|
|
|
|
expectEqual(physToVirt(@as(usize, 123)), offset + 123);
|
2020-01-01 19:12:36 +00:00
|
|
|
expectEqual(@ptrToInt(physToVirt(@intToPtr(*align(1) usize, 123))), offset + 123);
|
2019-11-02 01:22:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test "virtToPhys" {
|
|
|
|
ADDR_OFFSET = 0xC0000000;
|
|
|
|
const offset: usize = ADDR_OFFSET;
|
|
|
|
expectEqual(virtToPhys(offset + 0), 0);
|
|
|
|
expectEqual(virtToPhys(offset + 123), 123);
|
2020-01-01 19:12:36 +00:00
|
|
|
expectEqual(@ptrToInt(virtToPhys(@intToPtr(*align(1) usize, offset + 123))), 123);
|
2019-11-02 01:22:10 +00:00
|
|
|
}
|