Files
zing/src/arch/riscv64/boot.zig
T

143 lines
4.4 KiB
Zig

const sbi = @import("sbi.zig");
const debug = @import("../../debug.zig");
const kernel = @import("../../kernel.zig");
const vmm = @import("vmm.zig");
const regs = @import("regs.zig");
const dtb = @import("../../util/dtb.zig");
const mem = @import("../../mem.zig");
const arena = @import("../../arena.zig");
const exception = @import("exception.zig");
const tls = @import("../../mem/tls.zig");
const phys_memory = mem.phys;
const PAGE_SIZE = mem.vmm.PAGE_SIZE;
const log = debug.log;
const arch = kernel.arch;
extern const __rv64_bsp_stack_top: u8;
var g_dtb_address: usize = 0;
var g_bsp_hart_id: u32 = 0;
fn bsp_upper_entry(real_address: usize, unused: usize) callconv(.C) noreturn {
_ = unused;
arch.barrier(.acq_rel);
// Relocate the kernel yet again, this time to another base
const rela_start = @intFromPtr(&__rela_start);
const rela_end = @intFromPtr(&__rela_end);
const rel_offset = vmm.KERNEL_VIRTUAL_BASE + vmm.L1.offset(real_address);
arch.barrier(.acq_rel);
rv64_relocate_kernel(rel_offset, rela_start, rela_end);
vmm.unmap_early();
// Setup exception handling
exception.init();
debug.log.set_write_fn(&sbi.debug_print_byte);
kernel.mem.PhysicalAddress.g_virtualize_base = 0;
kernel.mem.PhysicalAddress.g_virtualize_size = vmm.virtualize_range();
// Setup physical memory management
setup_memory_from_fdt(real_address);
setup_per_cpu();
arch.impl.t_hart_id = g_bsp_hart_id;
kernel.kernel_main();
}
pub export fn rv64_bsp_lower_entry(real_address: usize, bsp_hart_id: usize, dtb_address: usize) callconv(.C) noreturn {
debug.log.set_write_fn(&sbi.debug_print_byte);
g_dtb_address = dtb_address;
g_bsp_hart_id = @truncate(bsp_hart_id);
vmm.map_early(real_address);
// &bspUpperEntry will yield a pointer like: X + P, where
// * X is symbol's raw address,
// * P is the physical load base of the image (0x80200000 on rv64 usually)
//
// Relocate the address to point to Y + P, where Y is the virtual load base
const real_address_l1_offset = vmm.L1.offset(real_address);
const virtual_entry = @intFromPtr(&bsp_upper_entry) + vmm.KERNEL_VIRTUAL_BASE //
- real_address + real_address_l1_offset;
const virtual_sp = @intFromPtr(&__rv64_bsp_stack_top) + vmm.KERNEL_VIRTUAL_BASE //
- real_address + real_address_l1_offset;
long_jump(virtual_entry, virtual_sp, real_address, 0);
arch.halt();
}
// Functions used by the boot process
extern const __rela_start: u8;
extern const __rela_end: u8;
extern var __kernel_start: u8;
extern var __kernel_end: u8;
fn setup_per_cpu() void {
const tls_data = tls.load_kernel_tls_image();
const tp = @intFromPtr(tls_data.ptr);
log.info("Set TP = 0x{x}", .{tp});
arch.set_thread_pointer(tp);
}
export fn rv64_relocate_kernel(image_base: usize, rela_start: usize, rela_end: usize) void {
const elf = @import("std").elf;
const rela_table_ptr = @as([*]elf.Rela, @ptrFromInt(rela_start));
const rela_count = (rela_end - rela_start) / @sizeOf(elf.Rela);
const rela_table = rela_table_ptr[0..rela_count];
for (rela_table) |entry| {
const rela_type: elf.R_RISCV = @enumFromInt(entry.r_type());
switch (rela_type) {
.RELATIVE => {
const value = @as(*isize, @ptrFromInt(image_base + entry.r_offset));
value.* = @as(isize, @bitCast(image_base)) + entry.r_addend;
},
else => {
arch.halt();
},
}
}
}
fn setup_memory_from_fdt(real_address: usize) void {
const kernel_start = @intFromPtr(&__kernel_start);
const kernel_end = @intFromPtr(&__kernel_end);
const fdt = dtb.Fdt.from_physical_address(.{ .raw = g_dtb_address }) catch |err| {
log.panic("Cannot initialize raw DTB: {}", .{err});
};
fdt.add_physical_memory_to_system();
phys_memory.add_reserved_region(
"kernel",
kernel_start -
(vmm.KERNEL_VIRTUAL_BASE + vmm.L1.offset(real_address)) + real_address,
kernel_end - kernel_start,
);
phys_memory.add_reserved_region("fdt", g_dtb_address, vmm.L3.align_up(fdt.bytes.len));
phys_memory.init();
}
inline fn long_jump(pc: usize, sp: usize, a0: usize, a1: usize) noreturn {
asm volatile (
\\ mv sp, %[sp]
\\ jr %[pc]
:
: [a0] "{a0}" (a0),
[a1] "{a1}" (a1),
[pc] "r" (pc),
[sp] "r" (sp),
: "memory"
);
unreachable;
}