Made the kernel higher half
This commit is contained in:
parent
ed25810927
commit
62fefbc836
8 changed files with 336 additions and 149 deletions
|
|
@ -12,13 +12,15 @@ pub fn build(b: *std.Build) void {
|
||||||
const kernel = b.addExecutable(.{
|
const kernel = b.addExecutable(.{
|
||||||
.name = "kernel",
|
.name = "kernel",
|
||||||
.root_module = b.createModule(.{
|
.root_module = b.createModule(.{
|
||||||
.root_source_file = b.path("src/main.zig"),
|
.root_source_file = b.path("src/kernel.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.code_model = .medium,
|
.code_model = .medium,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
kernel.root_module.addAssemblyFile(b.path("src/boot.S"));
|
||||||
|
|
||||||
kernel.setLinkerScript(b.path("linker.ld"));
|
kernel.setLinkerScript(b.path("linker.ld"));
|
||||||
|
|
||||||
b.installArtifact(kernel);
|
b.installArtifact(kernel);
|
||||||
|
|
|
||||||
95
linker.ld
95
linker.ld
|
|
@ -1,35 +1,86 @@
|
||||||
OUTPUT_ARCH(riscv)
|
OUTPUT_ARCH(riscv)
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
|
||||||
MEMORY
|
KERNEL_PHYS_BASE = 0x80200000;
|
||||||
{
|
KERNEL_VIRT_OFFSET = 0xffffffc000000000;
|
||||||
RAM (rwx) : ORIGIN = 0x80200000, LENGTH = 126M
|
BOOT_STACK_SIZE = 0x10000;
|
||||||
}
|
KERNEL_STACK_SIZE = 0x10000;
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
.text : {
|
. = KERNEL_PHYS_BASE;
|
||||||
*(.text.init)
|
|
||||||
*(.text .text.*)
|
|
||||||
} > RAM
|
|
||||||
|
|
||||||
.rodata : {
|
__boot_phys_start = .;
|
||||||
*(.rodata .rodata.*)
|
|
||||||
} > RAM
|
|
||||||
|
|
||||||
.data : {
|
.boot.text : ALIGN(0x1000) {
|
||||||
*(.data .data.*)
|
*(.boot.text)
|
||||||
} > RAM
|
*(.boot.text.*)
|
||||||
|
}
|
||||||
|
|
||||||
.bss : {
|
.boot.rodata : ALIGN(0x1000) {
|
||||||
__bss_start = .;
|
*(.boot.rodata)
|
||||||
*(.bss .bss.*)
|
*(.boot.rodata.*)
|
||||||
*(COMMON)
|
}
|
||||||
__bss_end = .;
|
|
||||||
} > RAM
|
.boot.data : ALIGN(0x1000) {
|
||||||
|
*(.boot.data)
|
||||||
|
*(.boot.data.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.boot.bss (NOLOAD) : ALIGN(0x1000) {
|
||||||
|
*(.boot.bss)
|
||||||
|
*(.boot.bss.*)
|
||||||
|
}
|
||||||
|
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
__stack_top = . + 0x10000;
|
. += BOOT_STACK_SIZE;
|
||||||
|
__boot_stack_top = .;
|
||||||
. = ALIGN(0x1000);
|
. = ALIGN(0x1000);
|
||||||
PROVIDE(__memory_start = .);
|
__boot_phys_end = .;
|
||||||
|
|
||||||
|
__kernel_phys_start = .;
|
||||||
|
. = KERNEL_VIRT_OFFSET + __kernel_phys_start;
|
||||||
|
__kernel_start = .;
|
||||||
|
__kernel_virt_start = .;
|
||||||
|
|
||||||
|
.text : AT(ADDR(.text) - KERNEL_VIRT_OFFSET) ALIGN(0x1000) {
|
||||||
|
*(.text)
|
||||||
|
*(.text.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : AT(ADDR(.rodata) - KERNEL_VIRT_OFFSET) ALIGN(0x1000) {
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : AT(ADDR(.data) - KERNEL_VIRT_OFFSET) ALIGN(0x1000) {
|
||||||
|
PROVIDE(__global_pointer$ = . + 0x800);
|
||||||
|
*(.data)
|
||||||
|
*(.data.*)
|
||||||
|
*(.sdata)
|
||||||
|
*(.sdata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : AT(ADDR(.bss) - KERNEL_VIRT_OFFSET) ALIGN(0x1000) {
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss)
|
||||||
|
*(.bss.*)
|
||||||
|
*(.sbss)
|
||||||
|
*(.sbss.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(16);
|
||||||
|
. += KERNEL_STACK_SIZE;
|
||||||
|
__stack_top = .;
|
||||||
|
__bss_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
__kernel_end = ALIGN(., 0x1000);
|
||||||
|
__kernel_virt_end = __kernel_end;
|
||||||
|
__kernel_phys_end = __kernel_end - KERNEL_VIRT_OFFSET;
|
||||||
|
__memory_start = __kernel_phys_end;
|
||||||
|
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.eh_frame)
|
||||||
|
*(.eh_frame_hdr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
90
src/boot.S
Normal file
90
src/boot.S
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
.section .boot.text, "ax", @progbits
|
||||||
|
.globl _start
|
||||||
|
|
||||||
|
.equ PTE_VALID, 0x001
|
||||||
|
.equ PTE_READ, 0x002
|
||||||
|
.equ PTE_WRITE, 0x004
|
||||||
|
.equ PTE_EXECUTE, 0x008
|
||||||
|
.equ PTE_FLAGS, PTE_VALID | PTE_READ | PTE_WRITE | PTE_EXECUTE
|
||||||
|
|
||||||
|
.equ SATP_MODE_SV39, (8 << 60)
|
||||||
|
|
||||||
|
.equ LOW_RAM_ROOT_INDEX, (2 * 8)
|
||||||
|
.equ KERNEL_ROOT_INDEX, (0x102 * 8)
|
||||||
|
.equ PHYSMAP_ROOT_INDEX, (0x142 * 8)
|
||||||
|
.equ MMIO_ROOT_INDEX, (0x180 * 8)
|
||||||
|
|
||||||
|
.equ LOW_RAM_GIGAPAGE_PTE, 0x2000000f
|
||||||
|
.equ ZERO_GIGAPAGE_PTE, 0x0000000f
|
||||||
|
.equ UART_PHYS, 0x10000000
|
||||||
|
|
||||||
|
_start:
|
||||||
|
li fp, 0
|
||||||
|
li ra, 0
|
||||||
|
la sp, __boot_stack_top
|
||||||
|
|
||||||
|
la t0, boot_root_page
|
||||||
|
|
||||||
|
li t1, LOW_RAM_GIGAPAGE_PTE
|
||||||
|
sd t1, LOW_RAM_ROOT_INDEX(t0)
|
||||||
|
li t2, PHYSMAP_ROOT_INDEX
|
||||||
|
add t2, t2, t0
|
||||||
|
sd t1, 0(t2)
|
||||||
|
|
||||||
|
li t1, LOW_RAM_GIGAPAGE_PTE
|
||||||
|
li t2, KERNEL_ROOT_INDEX
|
||||||
|
add t2, t2, t0
|
||||||
|
sd t1, 0(t2)
|
||||||
|
li t1, ZERO_GIGAPAGE_PTE
|
||||||
|
li t2, MMIO_ROOT_INDEX
|
||||||
|
add t2, t2, t0
|
||||||
|
sd t1, 0(t2)
|
||||||
|
|
||||||
|
srli t1, t0, 12
|
||||||
|
li t2, SATP_MODE_SV39
|
||||||
|
or t1, t1, t2
|
||||||
|
csrw satp, t1
|
||||||
|
sfence.vma
|
||||||
|
|
||||||
|
li a2, UART_PHYS
|
||||||
|
la t3, memory_start_ptr
|
||||||
|
ld a3, 0(t3)
|
||||||
|
li a4, 0
|
||||||
|
la t3, bss_start_ptr
|
||||||
|
ld t0, 0(t3)
|
||||||
|
la t3, bss_end_ptr
|
||||||
|
ld t1, 0(t3)
|
||||||
|
bgeu t0, t1, 2f
|
||||||
|
1:
|
||||||
|
sd zero, 0(t0)
|
||||||
|
addi t0, t0, 8
|
||||||
|
bltu t0, t1, 1b
|
||||||
|
2:
|
||||||
|
la t3, stack_top_ptr
|
||||||
|
ld sp, 0(t3)
|
||||||
|
la t3, global_pointer_ptr
|
||||||
|
ld gp, 0(t3)
|
||||||
|
li fp, 0
|
||||||
|
la t3, kmain_ptr
|
||||||
|
ld t0, 0(t3)
|
||||||
|
jr t0
|
||||||
|
|
||||||
|
.section .boot.rodata, "a", @progbits
|
||||||
|
.balign 8
|
||||||
|
memory_start_ptr:
|
||||||
|
.dword __memory_start
|
||||||
|
bss_start_ptr:
|
||||||
|
.dword __bss_start
|
||||||
|
bss_end_ptr:
|
||||||
|
.dword __bss_end
|
||||||
|
stack_top_ptr:
|
||||||
|
.dword __stack_top
|
||||||
|
global_pointer_ptr:
|
||||||
|
.dword __global_pointer$
|
||||||
|
kmain_ptr:
|
||||||
|
.dword kmain
|
||||||
|
|
||||||
|
.section .boot.bss, "aw", @nobits
|
||||||
|
.balign 4096
|
||||||
|
boot_root_page:
|
||||||
|
.skip 4096
|
||||||
|
|
@ -2,60 +2,35 @@ const std = @import("std");
|
||||||
const Fdt = @import("../Fdt.zig");
|
const Fdt = @import("../Fdt.zig");
|
||||||
const Console = @This();
|
const Console = @This();
|
||||||
|
|
||||||
pub const Writer = struct {
|
|
||||||
base: *volatile u8,
|
|
||||||
interface: std.Io.Writer,
|
|
||||||
|
|
||||||
pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) !usize {
|
|
||||||
const self: *Writer = @fieldParentPtr("interface", io_w);
|
|
||||||
var written: usize = 0;
|
|
||||||
|
|
||||||
for (data[0 .. data.len - 1]) |chunk| {
|
|
||||||
for (chunk) |byte| {
|
|
||||||
self.base.* = byte;
|
|
||||||
}
|
|
||||||
written += chunk.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pattern = data[data.len - 1];
|
|
||||||
for (0..splat) |_| {
|
|
||||||
for (pattern) |byte| {
|
|
||||||
self.base.* = byte;
|
|
||||||
}
|
|
||||||
written += pattern.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mmio: *volatile u8,
|
mmio: *volatile u8,
|
||||||
|
|
||||||
|
pub fn initAt(address: usize) Console {
|
||||||
|
return .{
|
||||||
|
.mmio = @ptrFromInt(address),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn init(fdt: Fdt) ?Console {
|
pub fn init(fdt: Fdt) ?Console {
|
||||||
if (fdt.findFirstCompatible("ns16550a")) |console| {
|
if (fdt.findFirstCompatible("ns16550a")) |console| {
|
||||||
var iter = fdt.regIterator(console) orelse return null;
|
var iter = fdt.regIterator(console) orelse return null;
|
||||||
const start = iter.next().?.address;
|
const start = iter.next().?.address;
|
||||||
return .{
|
return initAt(@as(usize, @intCast(start)));
|
||||||
.mmio = @ptrFromInt(@as(usize, @intCast(start))),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writer(self: *const Console) Writer {
|
pub fn write(self: *const Console, bytes: []const u8) void {
|
||||||
return .{
|
for (bytes) |byte| {
|
||||||
.base = self.mmio,
|
self.mmio.* = byte;
|
||||||
.interface = std.Io.Writer {
|
}
|
||||||
.buffer = &[_]u8{},
|
|
||||||
.vtable = &.{.drain = Writer.drain},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print(self: *const Console, comptime s: []const u8, args: anytype) void {
|
pub fn print(self: *const Console, comptime s: []const u8, args: anytype) void {
|
||||||
var w = self.writer();
|
var buffer: [512]u8 = undefined;
|
||||||
w.interface.print(s, args) catch {
|
const formatted = std.fmt.bufPrint(&buffer, s, args) catch {
|
||||||
@panic("Failed to print debug message.\n");
|
self.write("debug print overflow\n");
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
self.write(formatted);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
96
src/kernel.zig
Normal file
96
src/kernel.zig
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Fdt = @import("Fdt.zig");
|
||||||
|
const Console = @import("drivers/Console.zig");
|
||||||
|
const debug = @import("debug.zig");
|
||||||
|
const mem = @import("mem.zig");
|
||||||
|
const isa = @import("riscv/isa.zig");
|
||||||
|
|
||||||
|
const KERNEL_PHYS_BASE: u64 = 0x80200000;
|
||||||
|
|
||||||
|
pub const panic = debug.KernelPanic;
|
||||||
|
|
||||||
|
pub export fn kmain(hartid: u64, fdt_phys: usize, console_phys: usize, alloc_start_phys: usize, memory_end_hint: usize) callconv(.c) noreturn {
|
||||||
|
_ = hartid;
|
||||||
|
|
||||||
|
const console = Console.initAt(@intCast(mem.physToMmioVirt(console_phys)));
|
||||||
|
debug.init(console);
|
||||||
|
debug.print("entered higher-half kernel.\n", .{});
|
||||||
|
|
||||||
|
const fdt = Fdt.parse(@ptrFromInt(mem.physToDirectMap(fdt_phys))) catch {
|
||||||
|
@panic("Unable to parse higher-half FDT.\n");
|
||||||
|
};
|
||||||
|
debug.print("fdt remapped at 0x{x}.\n", .{mem.physToDirectMap(fdt_phys)});
|
||||||
|
|
||||||
|
const root = fdt.root().?;
|
||||||
|
const memory = fdt.memory().?;
|
||||||
|
var reg_iter = Fdt.parseReg(memory.getProperty("reg").?.data, root.addressCells(), root.sizeCells());
|
||||||
|
const reg = reg_iter.next().?;
|
||||||
|
const detected_memory_end = reg.address + reg.size;
|
||||||
|
const memory_end = if (memory_end_hint != 0) @min(detected_memory_end, memory_end_hint) else detected_memory_end;
|
||||||
|
debug.print("detected RAM end at 0x{x}.\n", .{memory_end});
|
||||||
|
|
||||||
|
var buddy: mem.BuddyAllocator = .{};
|
||||||
|
const alloc_start = mem.physToDirectMap(alloc_start_phys);
|
||||||
|
buddy.init(@as([*]u8, @ptrFromInt(alloc_start))[0..memory_end - alloc_start_phys]);
|
||||||
|
debug.print("direct map allocator initialized.\n", .{});
|
||||||
|
|
||||||
|
const allocator = buddy.allocator();
|
||||||
|
const mmu_type = fdt.mmuType();
|
||||||
|
|
||||||
|
if (mmu_type != .bare) {
|
||||||
|
var table = isa.PageTable.init(allocator) catch {
|
||||||
|
@panic("Unable to allocate higher-half page table.\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
const kernel_flags: isa.PageTable.EntryFlags = .{
|
||||||
|
.valid = 1,
|
||||||
|
.read = 1,
|
||||||
|
.write = 1,
|
||||||
|
.execute = 1,
|
||||||
|
.user = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
table.mapRange(
|
||||||
|
allocator,
|
||||||
|
mem.physToKernelVirt(KERNEL_PHYS_BASE),
|
||||||
|
KERNEL_PHYS_BASE,
|
||||||
|
alloc_start_phys - KERNEL_PHYS_BASE,
|
||||||
|
kernel_flags,
|
||||||
|
mmu_type,
|
||||||
|
mem.PHYS_MAP_BASE,
|
||||||
|
) catch {
|
||||||
|
@panic("Unable to map higher-half kernel image.\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
table.mapRange(
|
||||||
|
allocator,
|
||||||
|
mem.physToDirectMap(reg.address),
|
||||||
|
reg.address,
|
||||||
|
memory_end - reg.address,
|
||||||
|
.{ .read = 1, .write = 1, .execute = 1 },
|
||||||
|
mmu_type,
|
||||||
|
mem.PHYS_MAP_BASE,
|
||||||
|
) catch {
|
||||||
|
@panic("Unable to map direct map window.\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
const console_page = std.mem.alignBackward(u64, @intCast(console_phys), mem.PAGE_SIZE);
|
||||||
|
table.map(
|
||||||
|
allocator,
|
||||||
|
mem.physToMmioVirt(console_page),
|
||||||
|
console_page,
|
||||||
|
.{ .read = 1, .write = 1, .execute = 1 },
|
||||||
|
mmu_type,
|
||||||
|
mem.PHYS_MAP_BASE,
|
||||||
|
) catch {
|
||||||
|
@panic("Unable to map console MMIO.\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
table.load(mmu_type, mem.PHYS_MAP_BASE);
|
||||||
|
debug.print("reloaded higher-half kernel page table.\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
asm volatile ("wfi");
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/main.zig
67
src/main.zig
|
|
@ -1,67 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const isa = @import("riscv/isa.zig");
|
|
||||||
const Fdt = @import("Fdt.zig");
|
|
||||||
const Console = @import("drivers/Console.zig");
|
|
||||||
const debug = @import("debug.zig");
|
|
||||||
const mem = @import("mem.zig");
|
|
||||||
|
|
||||||
const MEMORY_START = @extern([*]u8, .{.name = "__memory_start"});
|
|
||||||
|
|
||||||
pub const panic = debug.KernelPanic;
|
|
||||||
|
|
||||||
export fn _start() linksection(".text.init") callconv(.naked) noreturn {
|
|
||||||
asm volatile (
|
|
||||||
\\li fp, 0
|
|
||||||
\\li ra, 0
|
|
||||||
\\la sp, __stack_top
|
|
||||||
\\tail kmain
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn kmain(hartid: u64, fdt_ptr: *const anyopaque) callconv(.c) noreturn {
|
|
||||||
_ = hartid;
|
|
||||||
|
|
||||||
const fdt = Fdt.parse(fdt_ptr) catch {
|
|
||||||
while (true) asm volatile ("wfi");
|
|
||||||
};
|
|
||||||
|
|
||||||
const root = fdt.root().?;
|
|
||||||
|
|
||||||
const console = Console.init(fdt).?;
|
|
||||||
debug.init(console);
|
|
||||||
|
|
||||||
debug.print("booting hydra...\n", .{});
|
|
||||||
|
|
||||||
const memory = fdt.memory().?;
|
|
||||||
var reg_iter = Fdt.parseReg(memory.getProperty("reg").?.data, root.addressCells(), root.sizeCells());
|
|
||||||
const reg = reg_iter.next().?;
|
|
||||||
const memory_end = reg.address + reg.size;
|
|
||||||
|
|
||||||
var buddy: mem.BuddyAllocator = .{};
|
|
||||||
buddy.init(MEMORY_START[0..memory_end - @intFromPtr(MEMORY_START)]);
|
|
||||||
debug.print("memory allocator initialized.\n", .{});
|
|
||||||
|
|
||||||
const allocator = buddy.allocator();
|
|
||||||
const mmu_type = fdt.mmuType();
|
|
||||||
|
|
||||||
if (mmu_type == .bare) {
|
|
||||||
debug.print("mmu disabled by firmware description.\n", .{});
|
|
||||||
} else {
|
|
||||||
var table = isa.PageTable.init(allocator) catch {
|
|
||||||
@panic("Unable to create page table.\n");
|
|
||||||
};
|
|
||||||
table.identityMap(allocator, reg.address, memory_end, mmu_type) catch {
|
|
||||||
@panic("Unable to identity map kernel memory.\n");
|
|
||||||
};
|
|
||||||
table.map(allocator, @intFromPtr(console.mmio), @intFromPtr(console.mmio), .{ .read = 1, .write = 1, .execute = 1 }, mmu_type) catch {
|
|
||||||
@panic("Unable to map console MMIO.\n");
|
|
||||||
};
|
|
||||||
|
|
||||||
table.load(mmu_type);
|
|
||||||
debug.print("loaded kernel page table.\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
asm volatile ("wfi");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
19
src/mem.zig
19
src/mem.zig
|
|
@ -1,3 +1,22 @@
|
||||||
pub const BuddyAllocator = @import("mem/BuddyAllocator.zig");
|
pub const BuddyAllocator = @import("mem/BuddyAllocator.zig");
|
||||||
|
|
||||||
pub const PAGE_SIZE = 0x1000;
|
pub const PAGE_SIZE = 0x1000;
|
||||||
|
pub const KERNEL_VIRT_OFFSET: u64 = 0xffffffc000000000;
|
||||||
|
pub const PHYS_MAP_BASE: u64 = 0xffffffd000000000;
|
||||||
|
pub const MMIO_VIRT_OFFSET: u64 = 0xffffffe000000000;
|
||||||
|
|
||||||
|
pub fn physToKernelVirt(physical: u64) u64 {
|
||||||
|
return KERNEL_VIRT_OFFSET + physical;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physToDirectMap(physical: u64) u64 {
|
||||||
|
return PHYS_MAP_BASE + physical;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn directMapToPhys(virtual: u64) u64 {
|
||||||
|
return virtual - PHYS_MAP_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physToMmioVirt(physical: u64) u64 {
|
||||||
|
return MMIO_VIRT_OFFSET + physical;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ pub fn init(allocator: Allocator) !*PageTable {
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn identityMap(self: *PageTable, allocator: Allocator, start: u64, end: u64, mode: isa.Satp.Mode) !void {
|
pub fn identityMap(self: *PageTable, allocator: Allocator, start: u64, end: u64, mode: isa.Satp.Mode, direct_map_base: u64) !void {
|
||||||
const flags = EntryFlags{
|
const flags = EntryFlags{
|
||||||
.valid = 1,
|
.valid = 1,
|
||||||
.read = 1,
|
.read = 1,
|
||||||
|
|
@ -45,35 +45,46 @@ pub fn identityMap(self: *PageTable, allocator: Allocator, start: u64, end: u64,
|
||||||
.user = 0,
|
.user = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
var addr = start;
|
return self.mapRange(allocator, start, start, end - start, flags, mode, direct_map_base);
|
||||||
while (addr < end) {
|
}
|
||||||
const remaining = end - addr;
|
|
||||||
if (addr % (2 * 1024 * 1024) == 0 and remaining >= 2 * 1024 * 1024) {
|
pub fn mapRange(self: *PageTable, allocator: Allocator, virtual_start: u64, physical_start: u64, length: u64, flags: EntryFlags, mode: isa.Satp.Mode, direct_map_base: u64) !void {
|
||||||
try self.mapLarge2MiB(allocator, addr, addr, flags, mode);
|
if (length == 0) return;
|
||||||
addr += 2 * 1024 * 1024;
|
|
||||||
|
var virtual = virtual_start;
|
||||||
|
var physical = physical_start;
|
||||||
|
const virtual_end = virtual_start + length;
|
||||||
|
|
||||||
|
while (virtual < virtual_end) {
|
||||||
|
const remaining = virtual_end - virtual;
|
||||||
|
if (virtual % (2 * 1024 * 1024) == 0 and physical % (2 * 1024 * 1024) == 0 and remaining >= 2 * 1024 * 1024) {
|
||||||
|
try self.mapLarge2MiB(allocator, virtual, physical, flags, mode, direct_map_base);
|
||||||
|
virtual += 2 * 1024 * 1024;
|
||||||
|
physical += 2 * 1024 * 1024;
|
||||||
} else {
|
} else {
|
||||||
try self.map(allocator, addr, addr, flags, mode);
|
try self.map(allocator, virtual, physical, flags, mode, direct_map_base);
|
||||||
addr += 0x1000;
|
virtual += 0x1000;
|
||||||
|
physical += 0x1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(self: *const PageTable, mmu_type: isa.Satp.Mode) void {
|
pub fn load(self: *const PageTable, mmu_type: isa.Satp.Mode, direct_map_base: u64) void {
|
||||||
isa.write_satp(.{
|
isa.write_satp(.{
|
||||||
.ppn = @as(u44, @intCast(@intFromPtr(self) >> 12)),
|
.ppn = @as(u44, @intCast(pointerToPhysical(@intFromPtr(self), direct_map_base) >> 12)),
|
||||||
.mode = mmu_type,
|
.mode = mmu_type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map(self: *PageTable, allocator: Allocator, virtual: u64, physical: u64, flags: EntryFlags, mode: isa.Satp.Mode) !void {
|
pub fn map(self: *PageTable, allocator: Allocator, virtual: u64, physical: u64, flags: EntryFlags, mode: isa.Satp.Mode, direct_map_base: u64) !void {
|
||||||
return self.mapAtLevel(allocator, virtual, physical, flags, mode, 0);
|
return self.mapAtLevel(allocator, virtual, physical, flags, mode, 0, direct_map_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mapLarge2MiB(self: *PageTable, allocator: Allocator, virtual: u64, physical: u64, flags: EntryFlags, mode: isa.Satp.Mode) !void {
|
pub fn mapLarge2MiB(self: *PageTable, allocator: Allocator, virtual: u64, physical: u64, flags: EntryFlags, mode: isa.Satp.Mode, direct_map_base: u64) !void {
|
||||||
return self.mapAtLevel(allocator, virtual, physical, flags, mode, 1);
|
return self.mapAtLevel(allocator, virtual, physical, flags, mode, 1, direct_map_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mapAtLevel(self: *PageTable, allocator: Allocator, virtual: u64, physical: u64, flags: EntryFlags, mode: isa.Satp.Mode, leaf_level: usize) !void {
|
fn mapAtLevel(self: *PageTable, allocator: Allocator, virtual: u64, physical: u64, flags: EntryFlags, mode: isa.Satp.Mode, leaf_level: usize, direct_map_base: u64) !void {
|
||||||
const page_size: u64 = switch (leaf_level) {
|
const page_size: u64 = switch (leaf_level) {
|
||||||
0 => 4096,
|
0 => 4096,
|
||||||
1 => 2 * 1024 * 1024,
|
1 => 2 * 1024 * 1024,
|
||||||
|
|
@ -108,17 +119,27 @@ fn mapAtLevel(self: *PageTable, allocator: Allocator, virtual: u64, physical: u6
|
||||||
if (!isValid(entry.*)) {
|
if (!isValid(entry.*)) {
|
||||||
const new_table = try PageTable.init(allocator);
|
const new_table = try PageTable.init(allocator);
|
||||||
|
|
||||||
const table_phys = @intFromPtr(new_table);
|
const table_phys = pointerToPhysical(@intFromPtr(new_table), direct_map_base);
|
||||||
entry.* = encodeBranchEntry(table_phys);
|
entry.* = encodeBranchEntry(table_phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
const next_table_phys = decodePhysical(entry.*);
|
const next_table_phys = decodePhysical(entry.*);
|
||||||
current_table = @ptrFromInt(next_table_phys);
|
current_table = @ptrFromInt(physicalToPointer(next_table_phys, direct_map_base));
|
||||||
}
|
}
|
||||||
|
|
||||||
current_table.entries[vpn[leaf_level]] = encodeLeafEntry(physical, flags);
|
current_table.entries[vpn[leaf_level]] = encodeLeafEntry(physical, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pointerToPhysical(pointer: u64, direct_map_base: u64) u64 {
|
||||||
|
if (direct_map_base == 0) return pointer;
|
||||||
|
return pointer - direct_map_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn physicalToPointer(physical: u64, direct_map_base: u64) u64 {
|
||||||
|
if (direct_map_base == 0) return physical;
|
||||||
|
return physical + direct_map_base;
|
||||||
|
}
|
||||||
|
|
||||||
fn isValid(entry: u64) bool {
|
fn isValid(entry: u64) bool {
|
||||||
return (entry & PTE_VALID) != 0;
|
return (entry & PTE_VALID) != 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue