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

137 lines
3.9 KiB
Zig

const kernel = @import("../../kernel.zig");
const vmm = @import("vmm.zig");
const dtb = @import("../../util/dtb.zig");
const exception = @import("exception.zig");
const tls = @import("../../mem/tls.zig");
const arch = kernel.arch;
const mem = kernel.mem;
const log = kernel.debug.log;
const phys_memory = mem.phys;
extern const __aa64_bsp_stack_top: u8;
var g_dtb_address: u64 = undefined;
fn early_debug_print(byte: u8) void {
const address = 0x9000000;
@as(*volatile u32, @ptrFromInt(address)).* = byte;
}
fn reloc_address_to_upper(ptr: *const anyopaque) usize {
const p = @intFromPtr(ptr);
if (p >= vmm.KERNEL_VIRTUAL_BASE) {
return p;
} else {
return p + vmm.KERNEL_VIRTUAL_BASE;
}
}
fn reloc_address_to_lower(ptr: *const anyopaque) usize {
const p = @intFromPtr(ptr);
if (p >= vmm.KERNEL_VIRTUAL_BASE) {
return p - vmm.KERNEL_VIRTUAL_BASE;
} else {
return p;
}
}
fn aa64_bsp_upper_entry(real_address: u64) callconv(.C) noreturn {
// Relocate the kernel yet again
const rela_start = reloc_address_to_upper(&__rela_start);
const rela_end = reloc_address_to_upper(&__rela_end);
const rel_offset = vmm.KERNEL_VIRTUAL_BASE + real_address;
arch.barrier(.acq_rel);
aa64_relocate_kernel(rel_offset, rela_start, rela_end);
arch.barrier(.acq_rel);
log.set_write_fn(&early_debug_print);
exception.init();
mem.PhysicalAddress.g_virtualize_base = 0;
mem.PhysicalAddress.g_virtualize_size = 16 << 30;
setup_memory_from_fdt(real_address);
setup_per_cpu();
kernel.kernel_main();
}
pub export fn aa64_bsp_lower_entry(real_address: u64, dtb_address: u64) callconv(.C) noreturn {
g_dtb_address = dtb_address;
vmm.map_early(real_address);
const pc = @intFromPtr(&aa64_bsp_upper_entry) + vmm.KERNEL_VIRTUAL_BASE;
const sp = @intFromPtr(&__aa64_bsp_stack_top) + vmm.KERNEL_VIRTUAL_BASE;
long_jump(pc, sp, real_address);
}
// 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;
export fn aa64_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_AARCH64 = @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();
},
}
}
}
inline fn long_jump(pc: usize, sp: usize, a0: usize) noreturn {
asm volatile (
\\ mov sp, %[sp]
\\ br %[pc]
:
: [sp] "r" (sp),
[pc] "r" (pc),
[a0] "{x0}" (a0),
: "memory"
);
unreachable;
}
fn setup_memory_from_fdt(real_address: usize) void {
_ = real_address;
const kernel_start = reloc_address_to_lower(&__kernel_start); // 0
const kernel_end = reloc_address_to_lower(&__kernel_end); // whatever
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, kernel_end - kernel_start);
phys_memory.add_reserved_region("fdt", g_dtb_address, vmm.L3.align_up(fdt.bytes.len));
phys_memory.init();
}
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);
}