109 lines
3.3 KiB
Zig
109 lines
3.3 KiB
Zig
const std = @import("std");
|
|
|
|
extern fn console_write(ptr: [*]const u8, len: usize) void;
|
|
|
|
// Embed the Subject Zero binary
|
|
export var subject_bin = @embedFile("subject.bin");
|
|
|
|
export fn ion_loader_load(path: [*:0]const u8) u64 {
|
|
_ = path;
|
|
|
|
console_write("[Loader] Parsing ELF\n", 21);
|
|
|
|
// Verify ELF Magic
|
|
const magic = subject_bin[0..4];
|
|
if (magic[0] != 0x7F or magic[1] != 'E' or magic[2] != 'L' or magic[3] != 'F') {
|
|
console_write("[Loader] ERROR: Invalid ELF magic\n", 35);
|
|
return 0;
|
|
}
|
|
|
|
// Parse ELF64 Header
|
|
const e_entry = read_u64_le(subject_bin[0x18..0x20]);
|
|
const e_phoff = read_u64_le(subject_bin[0x20..0x28]);
|
|
const e_phentsize = read_u16_le(subject_bin[0x36..0x38]);
|
|
const e_phnum = read_u16_le(subject_bin[0x38..0x3a]);
|
|
|
|
console_write("[Loader] Entry: 0x", 18);
|
|
print_hex(e_entry);
|
|
console_write("\n[Loader] Loading ", 17);
|
|
print_hex(e_phnum);
|
|
console_write(" segments\n", 10);
|
|
|
|
// Load each PT_LOAD segment
|
|
var i: usize = 0;
|
|
while (i < e_phnum) : (i += 1) {
|
|
const ph_offset = e_phoff + (i * e_phentsize);
|
|
const p_type = read_u32_le(subject_bin[ph_offset .. ph_offset + 4]);
|
|
|
|
if (p_type == 1) { // PT_LOAD
|
|
const p_offset = read_u64_le(subject_bin[ph_offset + 8 .. ph_offset + 16]);
|
|
const p_vaddr = read_u64_le(subject_bin[ph_offset + 16 .. ph_offset + 24]);
|
|
const p_filesz = read_u64_le(subject_bin[ph_offset + 32 .. ph_offset + 40]);
|
|
const p_memsz = read_u64_le(subject_bin[ph_offset + 40 .. ph_offset + 48]);
|
|
|
|
const dest = @as([*]u8, @ptrFromInt(p_vaddr));
|
|
|
|
// Copy file content
|
|
if (p_filesz > 0) {
|
|
const src = subject_bin[p_offset .. p_offset + p_filesz];
|
|
@memcpy(dest[0..p_filesz], src);
|
|
}
|
|
|
|
// Zero BSS (memsz > filesz)
|
|
if (p_memsz > p_filesz) {
|
|
@memset(dest[p_filesz..p_memsz], 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
console_write("[Loader] ELF loaded successfully\n", 33);
|
|
return e_entry;
|
|
}
|
|
|
|
fn read_u16_le(bytes: []const u8) u16 {
|
|
return @as(u16, bytes[0]) | (@as(u16, bytes[1]) << 8);
|
|
}
|
|
|
|
fn read_u32_le(bytes: []const u8) u32 {
|
|
return @as(u32, bytes[0]) |
|
|
(@as(u32, bytes[1]) << 8) |
|
|
(@as(u32, bytes[2]) << 16) |
|
|
(@as(u32, bytes[3]) << 24);
|
|
}
|
|
|
|
fn read_u64_le(bytes: []const u8) u64 {
|
|
var result: u64 = 0;
|
|
var j: usize = 0;
|
|
while (j < 8) : (j += 1) {
|
|
result |= @as(u64, bytes[j]) << @intCast(j * 8);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn print_hex(value: u64) void {
|
|
const hex_chars = "0123456789ABCDEF";
|
|
var buf: [16]u8 = undefined;
|
|
var i: usize = 0;
|
|
while (i < 16) : (i += 1) {
|
|
const shift: u6 = @intCast((15 - i) * 4);
|
|
const nibble = (value >> shift) & 0xF;
|
|
buf[i] = hex_chars[nibble];
|
|
}
|
|
console_write(&buf, 16);
|
|
}
|
|
|
|
export fn launch_subject() void {
|
|
const target_addr = ion_loader_load("/sysro/bin/subject");
|
|
console_write("[Loader] Jumping...\n", 20);
|
|
|
|
const entry = @as(*const fn () void, @ptrFromInt(target_addr));
|
|
entry();
|
|
}
|
|
|
|
pub fn panic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
|
|
console_write("[Loader] PANIC: ", 16);
|
|
console_write(msg.ptr, msg.len);
|
|
console_write("\n", 1);
|
|
while (true) {}
|
|
}
|