143 lines
4.4 KiB
Zig
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;
|
|
}
|