aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kernel.zig6
-rw-r--r--src/lib/process.zig157
2 files changed, 118 insertions, 45 deletions
diff --git a/src/kernel.zig b/src/kernel.zig
index f63fb5e..9f1ee45 100644
--- a/src/kernel.zig
+++ b/src/kernel.zig
@@ -13,6 +13,7 @@ const paging = @import("lib/paging.zig");
const pci = @import("lib/pci.zig");
const plic = @import("lib/plic.zig");
const process = @import("lib/process.zig");
+const userinit = @import("lib/userinit.zig");
const Error = error{
HartIdOutOfRange,
@@ -195,6 +196,7 @@ fn pagedRun() !noreturn {
}
}
- try w.print("Enter process demo\r\n", .{});
- try process.demo(allocator);
+ try w.print("Start init process\r\n", .{});
+ var userinit_stream = std.io.fixedBufferStream(userinit.tarball);
+ try process.runInit(allocator, userinit_stream.reader());
}
diff --git a/src/lib/process.zig b/src/lib/process.zig
index 241c2f5..17b90df 100644
--- a/src/lib/process.zig
+++ b/src/lib/process.zig
@@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
+const builtin = @import("builtin");
const std = @import("std");
const instructions = @import("instructions.zig");
@@ -9,6 +10,8 @@ const paging = @import("paging.zig");
const time = @import("sbi/time.zig");
const trap = @import("trap.zig");
+const elf = std.elf;
+
pub const schedule_interval_millis = 1;
pub var list = std.mem.zeroInit(std.DoublyLinkedList(Info), .{});
@@ -19,6 +22,15 @@ var next_pid: u16 = 1;
pub const Error = error{
EmptySchedule,
+ NoInit,
+};
+
+pub const ExeError = error{
+ BadEndian,
+ BadArch,
+ BadBitLen,
+ NotStaticExe,
+ BranchPerms,
};
pub const State = enum(u8) {
@@ -47,40 +59,6 @@ pub const Info = extern struct {
}
};
-fn new(entry: usize) !Info {
- const stack = try paging.alloc(num_stack_pages);
- errdefer paging.free(stack);
-
- const procmem: *paging.Table = @alignCast(@ptrCast(try paging.zeroedAlloc(1)));
- errdefer paging.free(procmem);
-
- var proc = Info{
- .id = next_pid,
- .trap_frame = std.mem.zeroInit(trap.Frame, .{}),
- .stack = @ptrCast(stack),
- .pc = entry,
- .page_table = procmem,
- .state = .waiting,
- };
-
- const stack_top = @intFromPtr(proc.stack) + num_stack_pages * paging.page_size;
- proc.trap_frame.general_purpose_registers[2] = stack_top;
-
- try procmem.mapKernel();
-
- try procmem.map(entry, entry, paging.EntryFlags.userReadExec, 0);
- // Not using identityMapRange because this is going to be expanded for non-relocatable binaries.
- for (0..num_stack_pages) |page| {
- const vaddr = @intFromPtr(proc.stack) + page * paging.page_size;
- const paddr = @intFromPtr(proc.stack) + page * paging.page_size;
-
- try procmem.map(vaddr, paddr, paging.EntryFlags.userReadWrite, 0);
- }
-
- next_pid += 1;
- return proc;
-}
-
pub fn next() ?*Info {
if (list.popFirst()) |info| {
list.append(info);
@@ -151,20 +129,113 @@ pub fn switchTo(proc: *Info) noreturn {
unreachable;
}
-pub fn demo(allocator: std.mem.Allocator) !noreturn {
- const entry: []align(4) volatile u8 = try paging.zeroedAlloc(1);
- defer paging.free(entry);
+pub fn create(allocator: std.mem.Allocator, elf_buf: []align(@alignOf(elf.Elf64_Ehdr)) const u8) !*Info {
+ const hdr_buf: *align(@alignOf(elf.Elf64_Ehdr)) const [@sizeOf(elf.Elf64_Ehdr)]u8 = elf_buf[0..@sizeOf(elf.Elf64_Ehdr)];
+ const hdr = try elf.Header.parse(@ptrCast(hdr_buf));
+
+ try validateElfHeader(hdr, hdr_buf);
- entry[0] = 0x73;
- entry[1] = 0x00;
- entry[2] = 0x00;
- entry[3] = 0x00;
+ const len_aligned = std.mem.alignForwardLog2(elf_buf.len, paging.log2_page_size);
+ const num_pages = len_aligned / paging.page_size + 1;
+ const pages = try paging.zeroedAlloc(num_pages);
+ errdefer paging.free(pages);
+
+ const procmem: *paging.Table = @ptrCast(try paging.zeroedAlloc(1));
+ errdefer paging.free(procmem);
+
+ try procmem.mapKernel();
+
+ const parse_source = std.io.fixedBufferStream(elf_buf[@sizeOf(elf.Elf64_Ehdr)..]);
+
+ var it = hdr.program_header_iterator(parse_source);
+ while (try it.next()) |phdr| {
+ if (phdr.p_type != elf.PT_LOAD) continue;
+ if (phdr.p_memsz == 0) continue;
+
+ // fixme: Could crash (out-of-bounds read).
+ @memcpy(pages[phdr.p_offset..], elf_buf[phdr.p_offset .. phdr.p_offset + phdr.p_memsz]);
+
+ const memsz_aligned = std.mem.alignForwardLog2(phdr.p_memsz, paging.log2_page_size);
+ const num_mappings = @divExact(memsz_aligned, paging.page_size);
+ for (0..num_mappings) |page| {
+ const vaddr = phdr.p_vaddr + page * paging.page_size;
+ const paddr = @intFromPtr(pages.ptr) + phdr.p_offset + page * paging.page_size;
+ const flags = paging.EntryFlags{
+ .valid = 1,
+ .read = @bitCast(phdr.p_flags & elf.PF_R != 0),
+ .write = @bitCast(phdr.p_flags & elf.PF_W != 0),
+ .exec = @bitCast(phdr.p_flags & elf.PF_X != 0),
+ .user = 1,
+ .global = 0,
+ .accessed = 1,
+ .dirty = @bitCast(phdr.p_flags & elf.PF_W != 0),
+ };
+
+ if (!@bitCast(flags.read) and !@bitCast(flags.write) and !@bitCast(flags.exec)) {
+ return ExeError.BranchPerms;
+ }
+
+ try procmem.map(vaddr, paddr, flags, 0);
+ }
+ }
+
+ const stack = try paging.zeroedAlloc(num_stack_pages);
+ errdefer paging.free(stack);
+
+ const stack_top = @intFromPtr(stack.ptr) + num_stack_pages * paging.page_size;
+ try procmem.identityMapRange(@intFromPtr(stack.ptr), stack_top, paging.EntryFlags.userReadWrite);
+
+ var proc = Info{
+ .id = next_pid,
+ .trap_frame = std.mem.zeroInit(trap.Frame, .{}),
+ .stack = @ptrCast(stack),
+ .pc = hdr.entry,
+ .page_table = procmem,
+ .state = .waiting,
+ };
+ proc.trap_frame.general_purpose_registers[2] = stack_top;
- const proc = try new(@intFromPtr(entry.ptr));
const proc_node = try allocator.create(std.DoublyLinkedList(Info).Node);
proc_node.data = proc;
list.prepend(proc_node);
+ return &proc_node.data;
+}
+
+pub fn runInit(allocator: std.mem.Allocator, reader: anytype) !noreturn {
+ var file_name_buffer: [4096]u8 = undefined;
+ var link_name_buffer: [4096]u8 = undefined;
+
+ var it = std.tar.iterator(reader, .{
+ .file_name_buffer = file_name_buffer[0..],
+ .link_name_buffer = link_name_buffer[0..],
+ });
+ const exe = while (try it.next()) |file| {
+ if (std.mem.eql(u8, file.name, "./init")) {
+ break file;
+ }
+ } else return Error.NoInit;
+
+ const alignment = @alignOf(elf.Elf64_Ehdr);
+
+ var exe_list = std.ArrayListAligned(u8, alignment).init(allocator);
+ defer exe_list.deinit();
+ try exe.reader().readAllArrayListAligned(alignment, &exe_list, exe.size);
+
+ const proc = try create(allocator, exe_list.items);
+
try time.interruptInMillis(schedule_interval_millis);
- switchTo(&proc_node.data);
+ switchTo(proc);
+}
+
+fn validateElfHeader(hdr: elf.Header, hdr_buf: *align(@alignOf(elf.Elf64_Ehdr)) const [@sizeOf(elf.Elf64_Ehdr)]u8) !void {
+ const arch = builtin.cpu.arch;
+
+ if (hdr.endian != arch.endian()) return ExeError.BadEndian;
+ if (hdr.machine != arch.toElfMachine()) return ExeError.BadArch;
+ if (!hdr.is_64) return ExeError.BadBitLen;
+
+ const hdr64 = @as(*const elf.Elf64_Ehdr, @ptrCast(hdr_buf));
+
+ if (hdr64.e_type != .EXEC) return ExeError.NotStaticExe;
}