WIP: test objects
This commit is contained in:
+19
-1
@@ -1,3 +1,21 @@
|
|||||||
pub const SyscallNumber = enum(usize) { SYS_debug_write = 1, SYS_exit = 2, _ };
|
pub const SyscallNumber = enum(usize) {
|
||||||
|
SYS_send = 1,
|
||||||
|
SYS_recv = 2,
|
||||||
|
SYS_sendrecv = 3,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ProcessObjectAction = enum(usize) {
|
||||||
|
ZO_process_exit = 1,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PhysicalMemoryObjectAction = enum(usize) {
|
||||||
|
ZO_physical_memory_allocate = 1,
|
||||||
|
ZO_physical_memory_free = 2,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
pub const MAX_SYSCALL: usize = 32;
|
pub const MAX_SYSCALL: usize = 32;
|
||||||
|
|
||||||
|
pub const Handle = enum(u32) { _ };
|
||||||
|
|||||||
@@ -92,10 +92,7 @@ export fn __aa64_el0_sync_handler(frame: *ExceptionFrame) callconv(.C) void {
|
|||||||
|
|
||||||
switch (esr.as_enum()) {
|
switch (esr.as_enum()) {
|
||||||
.svc => {
|
.svc => {
|
||||||
const func = frame.xN[8];
|
syscall.syscall_handler(frame.xN[8], frame.xN[0..6]);
|
||||||
const args = frame.xN[0..6];
|
|
||||||
const result = syscall.syscall_handler(func, args);
|
|
||||||
frame.xN[0] = result;
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
|
|||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
const mem = @import("mem.zig");
|
||||||
|
const kernel = @import("kernel.zig");
|
||||||
|
const thread = @import("thread.zig");
|
||||||
|
const abi = @import("abi");
|
||||||
|
|
||||||
|
const ProcessAddressSpace = mem.vmm.ProcessAddressSpace;
|
||||||
|
const log = kernel.log;
|
||||||
|
const Thread = thread.Thread;
|
||||||
|
|
||||||
|
pub const PhysicalMemoryObject = struct {
|
||||||
|
fn send(self: *const PhysicalMemoryObject, caller: *Thread, message: *const [5]usize) usize {
|
||||||
|
_ = self;
|
||||||
|
_ = caller;
|
||||||
|
_ = message;
|
||||||
|
@panic("TODO: physical memory object messaging");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sendrecv(self: *const PhysicalMemoryObject, caller: *Thread, message: *[5]usize) usize {
|
||||||
|
switch (@as(abi.PhysicalMemoryObjectAction, @enumFromInt(message[0]))) {
|
||||||
|
.ZO_physical_memory_allocate => {
|
||||||
|
// TODO somehow track ownership of the memory by the process
|
||||||
|
const pages = mem.phys.alloc_pages(message[1]) orelse {
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
log.info("{*}: allocated {} pages: 0x{x}", .{caller, message[1], pages.raw});
|
||||||
|
message[0] = pages.raw;
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
.ZO_physical_memory_free => {
|
||||||
|
@panic("TODO: ZO_physical_memory_free");
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
@panic("TODO: invalid message to Physical Memory Object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ProcessObject = struct {
|
||||||
|
inner: *Thread,
|
||||||
|
|
||||||
|
fn send(self: *const ProcessObject, caller: *Thread, message: *const [5]usize) usize {
|
||||||
|
_ = self;
|
||||||
|
// TODO define this in IDL/ABI
|
||||||
|
switch (@as(abi.ProcessObjectAction, @enumFromInt(message[0]))) {
|
||||||
|
.ZO_process_exit => {
|
||||||
|
log.info("{*} exited with code 0x{x} ({})", .{caller, message[1], message[1]});
|
||||||
|
Thread.exit_current();
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
@panic("TODO: invalid message to Process Object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sendrecv(self: *const ProcessObject, caller: *Thread, message: *[5]usize) usize {
|
||||||
|
_ = self;
|
||||||
|
_ = caller;
|
||||||
|
_ = message;
|
||||||
|
@panic("TODO: ProcessObject sendrecv()");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DebugObject = struct {
|
||||||
|
fn send(self: *const DebugObject, caller: *Thread, message: *const [5]usize) usize {
|
||||||
|
_ = self;
|
||||||
|
// Debug has only one message
|
||||||
|
const text = @as([*]u8, @ptrFromInt(message[0]))[0..message[1]];
|
||||||
|
log.info("{*}: {s}", .{ caller, text });
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sendrecv(self: *const DebugObject, caller: *Thread, message: *[5]usize) usize {
|
||||||
|
_ = self;
|
||||||
|
_ = caller;
|
||||||
|
_ = message;
|
||||||
|
@panic("TODO: DebugObject sendrecv()");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Object = union(enum) {
|
||||||
|
physical_memory: PhysicalMemoryObject,
|
||||||
|
process: ProcessObject,
|
||||||
|
debug: DebugObject,
|
||||||
|
// TODO userspace "object" can be placed here
|
||||||
|
|
||||||
|
pub fn send(self: Object, caller: *Thread, message: *const [5]usize) usize {
|
||||||
|
return switch (self) {
|
||||||
|
.physical_memory => |physical_memory| physical_memory.send(caller, message),
|
||||||
|
.process => |process| process.send(caller, message),
|
||||||
|
.debug => |debug| debug.send(caller, message),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sendrecv(self: Object, caller: *Thread, message: *[5]usize) usize {
|
||||||
|
return switch (self) {
|
||||||
|
.physical_memory => |physical_memory| physical_memory.sendrecv(caller, message),
|
||||||
|
.process => |process| process.sendrecv(caller, message),
|
||||||
|
.debug => |debug| debug.sendrecv(caller, message),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
+26
-14
@@ -5,39 +5,51 @@ const thread = kernel.thread;
|
|||||||
const Thread = thread.Thread;
|
const Thread = thread.Thread;
|
||||||
const log = kernel.log;
|
const log = kernel.log;
|
||||||
|
|
||||||
pub const SyscallFn = *const fn (*Thread, []usize) usize;
|
pub const SyscallFn = *const fn (*Thread, *[6]usize) void;
|
||||||
|
|
||||||
pub const syscall_table: [abi.MAX_SYSCALL]?SyscallFn = make_syscall_table();
|
pub const syscall_table: [abi.MAX_SYSCALL]?SyscallFn = make_syscall_table();
|
||||||
|
|
||||||
fn make_syscall_table() [abi.MAX_SYSCALL]?SyscallFn {
|
fn make_syscall_table() [abi.MAX_SYSCALL]?SyscallFn {
|
||||||
const SC = abi.SyscallNumber;
|
const SC = abi.SyscallNumber;
|
||||||
var array = [_]?SyscallFn{undefined} ** abi.MAX_SYSCALL;
|
var array = [_]?SyscallFn{undefined} ** abi.MAX_SYSCALL;
|
||||||
array[@intFromEnum(SC.SYS_debug_write)] = sys_debug_write;
|
array[@intFromEnum(SC.SYS_send)] = sys_send;
|
||||||
array[@intFromEnum(SC.SYS_exit)] = sys_exit;
|
array[@intFromEnum(SC.SYS_recv)] = sys_recv;
|
||||||
|
array[@intFromEnum(SC.SYS_sendrecv)] = sys_sendrecv;
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sys_exit(cthread: *Thread, args: []usize) usize {
|
fn sys_send(cthread: *Thread, frame: *[6]usize) void {
|
||||||
log.info("{*} exits with code {}", .{ cthread, args[0] });
|
const handle: abi.Handle = @enumFromInt(frame[0]);
|
||||||
Thread.exit_current();
|
const object = cthread.handle(handle) orelse {
|
||||||
|
@panic("TODO: userspace invoked non-existent handle");
|
||||||
|
};
|
||||||
|
frame[0] = object.send(cthread, frame[1..6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sys_debug_write(cthread: *Thread, args: []usize) usize {
|
fn sys_recv(cthread: *Thread, frame: *[6]usize) void {
|
||||||
const message = @as([*]const u8, @ptrFromInt(args[0]))[0..args[1]];
|
_ = cthread;
|
||||||
log.debug("{*}: {s}", .{ cthread, message });
|
_ = frame;
|
||||||
return 0;
|
@panic("TODO: SYS_recv()");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sys_undefined_syscall(cthread: *Thread, args: []usize) usize {
|
fn sys_sendrecv(cthread: *Thread, frame: *[6]usize) void {
|
||||||
_ = args;
|
const handle: abi.Handle = @enumFromInt(frame[0]);
|
||||||
|
const object = cthread.handle(handle) orelse {
|
||||||
|
@panic("TODO: userspace invoked non-existent handle");
|
||||||
|
};
|
||||||
|
frame[0] = object.sendrecv(cthread, frame[1..6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_undefined_syscall(cthread: *Thread, frame: *[6]usize) void {
|
||||||
|
_ = frame;
|
||||||
log.warn("{*} invoked an undefined syscall", .{cthread});
|
log.warn("{*} invoked an undefined syscall", .{cthread});
|
||||||
Thread.exit_current();
|
Thread.exit_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscall_handler(func: usize, args: []usize) usize {
|
pub fn syscall_handler(func: usize, frame: *[6]usize) void {
|
||||||
const cthread = thread.Thread.current();
|
const cthread = thread.Thread.current();
|
||||||
const handler = if (func >= abi.MAX_SYSCALL) sys_undefined_syscall //
|
const handler = if (func >= abi.MAX_SYSCALL) sys_undefined_syscall //
|
||||||
else syscall_table[func] //
|
else syscall_table[func] //
|
||||||
orelse sys_undefined_syscall;
|
orelse sys_undefined_syscall;
|
||||||
return handler(cthread, args);
|
handler(cthread, frame);
|
||||||
}
|
}
|
||||||
|
|||||||
+117
-82
@@ -7,8 +7,12 @@ const arch = @import("kernel.zig").arch;
|
|||||||
const log = @import("debug.zig").log;
|
const log = @import("debug.zig").log;
|
||||||
const mem = @import("mem.zig");
|
const mem = @import("mem.zig");
|
||||||
const sync = @import("sync.zig");
|
const sync = @import("sync.zig");
|
||||||
|
const object = @import("object.zig");
|
||||||
|
const abi = @import("abi");
|
||||||
|
|
||||||
const ProcessAddressSpace = mem.vmm.ProcessAddressSpace;
|
const ProcessAddressSpace = mem.vmm.ProcessAddressSpace;
|
||||||
|
const Object = object.Object;
|
||||||
|
const Handle = abi.Handle;
|
||||||
|
|
||||||
// TODO: are kernel threads needed at all if we're doing a microkernel?
|
// TODO: are kernel threads needed at all if we're doing a microkernel?
|
||||||
|
|
||||||
@@ -27,6 +31,113 @@ pub fn idle_function(arg: usize) callconv(.C) noreturn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a single execution thread.
|
||||||
|
pub const Thread = struct {
|
||||||
|
const MAX_HANDLES: usize = 64;
|
||||||
|
|
||||||
|
/// Arena.
|
||||||
|
allocator: *arena.Arena,
|
||||||
|
/// Architecture-specific task context.
|
||||||
|
arch_context: arch.Context,
|
||||||
|
|
||||||
|
/// Queue to which this thread belongs
|
||||||
|
queue: ?*Queue = null,
|
||||||
|
/// Next thread in the queue.
|
||||||
|
next: ?*Thread = null,
|
||||||
|
/// Previous thread in the queue.
|
||||||
|
prev: ?*Thread = null,
|
||||||
|
|
||||||
|
// TODO move to process
|
||||||
|
address_space: ?ProcessAddressSpace = null,
|
||||||
|
// TODO move to process
|
||||||
|
handle_table: [MAX_HANDLES]?Object = [_]?Object{null} ** MAX_HANDLES,
|
||||||
|
|
||||||
|
pub const Error = error{out_of_memory} || mem.vmm.AddressSpaceError;
|
||||||
|
|
||||||
|
/// Creates a new (kernel) thread with given `function` and `arg`ument.
|
||||||
|
pub fn create_kernel(a: *arena.Arena, function: *const KernelThreadFn, arg: usize) *Thread {
|
||||||
|
const thread = a.create(Thread);
|
||||||
|
thread.* = .{
|
||||||
|
.allocator = a,
|
||||||
|
.arch_context = arch.Context.kernel(function, arg),
|
||||||
|
};
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_user(
|
||||||
|
a: *arena.Arena,
|
||||||
|
address_space: ProcessAddressSpace,
|
||||||
|
pc: usize,
|
||||||
|
sp: usize,
|
||||||
|
arg: usize,
|
||||||
|
) *Thread {
|
||||||
|
const thread = a.create(Thread);
|
||||||
|
thread.* = .{
|
||||||
|
.allocator = a,
|
||||||
|
.address_space = address_space,
|
||||||
|
.arch_context = arch.Context.user(&address_space, pc, sp, arg),
|
||||||
|
};
|
||||||
|
// "self" process object is granted to all processes
|
||||||
|
const process_object = Object{ .process = object.ProcessObject {
|
||||||
|
.inner = thread,
|
||||||
|
} };
|
||||||
|
_ = thread.grant(process_object);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enters the thread, does not return.
|
||||||
|
pub fn enter(self: *@This()) noreturn {
|
||||||
|
self.arch_context.enter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Switches from `from` to `self` thread.
|
||||||
|
pub fn switch_from(self: *@This(), from: *@This()) void {
|
||||||
|
self.arch_context.switch_from(&from.arch_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grant(self: *@This(), obj: Object) Handle {
|
||||||
|
for (0..MAX_HANDLES) |i| {
|
||||||
|
if (self.handle_table[i] == null) {
|
||||||
|
self.handle_table[i] = obj;
|
||||||
|
return @enumFromInt(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@panic("TODO: ran out of objects");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(self: *@This(), h: Handle) ?Object {
|
||||||
|
const index = @as(usize, @intFromEnum(h));
|
||||||
|
if (index > MAX_HANDLES or index == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return self.handle_table[index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue(self: *@This()) void {
|
||||||
|
// TODO queueing information should be put under a lock for SMP to work properly
|
||||||
|
if (self.queue) |q| {
|
||||||
|
q.dequeue(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current() *@This() {
|
||||||
|
return Queue.t_this_cpu.?.current.?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit_current() noreturn {
|
||||||
|
// Mask IRQs so they don't break current thread's state
|
||||||
|
const mask = arch.IrqGuard.acquire();
|
||||||
|
defer mask.release();
|
||||||
|
|
||||||
|
const curr = Thread.current();
|
||||||
|
curr.dequeue();
|
||||||
|
|
||||||
|
yield();
|
||||||
|
|
||||||
|
@panic("This code should not be reachable");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Per-CPU thread queue structure.
|
/// Per-CPU thread queue structure.
|
||||||
pub const Queue = struct {
|
pub const Queue = struct {
|
||||||
/// Idle task context. Used when there are no other tasks running.
|
/// Idle task context. Used when there are no other tasks running.
|
||||||
@@ -152,86 +263,6 @@ pub const Queue = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents a single execution thread.
|
|
||||||
pub const Thread = struct {
|
|
||||||
/// Arena.
|
|
||||||
allocator: *arena.Arena,
|
|
||||||
/// Architecture-specific task context.
|
|
||||||
arch_context: arch.Context,
|
|
||||||
|
|
||||||
/// Queue to which this thread belongs
|
|
||||||
queue: ?*Queue = null,
|
|
||||||
/// Next thread in the queue.
|
|
||||||
next: ?*Thread = null,
|
|
||||||
/// Previous thread in the queue.
|
|
||||||
prev: ?*Thread = null,
|
|
||||||
|
|
||||||
// TODO move to process
|
|
||||||
address_space: ?ProcessAddressSpace = null,
|
|
||||||
|
|
||||||
pub const Error = error{out_of_memory} || mem.vmm.AddressSpaceError;
|
|
||||||
|
|
||||||
/// Creates a new (kernel) thread with given `function` and `arg`ument.
|
|
||||||
pub fn create_kernel(a: *arena.Arena, function: *const KernelThreadFn, arg: usize) *Thread {
|
|
||||||
const thread = a.create(Thread);
|
|
||||||
thread.* = .{
|
|
||||||
.allocator = a,
|
|
||||||
.arch_context = arch.Context.kernel(function, arg),
|
|
||||||
};
|
|
||||||
return thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_user(
|
|
||||||
a: *arena.Arena,
|
|
||||||
address_space: ProcessAddressSpace,
|
|
||||||
pc: usize,
|
|
||||||
sp: usize,
|
|
||||||
arg: usize,
|
|
||||||
) *Thread {
|
|
||||||
const thread = a.create(Thread);
|
|
||||||
thread.* = .{
|
|
||||||
.allocator = a,
|
|
||||||
.address_space = address_space,
|
|
||||||
.arch_context = arch.Context.user(&address_space, pc, sp, arg),
|
|
||||||
};
|
|
||||||
return thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enters the thread, does not return.
|
|
||||||
pub fn enter(self: *@This()) noreturn {
|
|
||||||
self.arch_context.enter();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Switches from `from` to `self` thread.
|
|
||||||
pub fn switch_from(self: *@This(), from: *@This()) void {
|
|
||||||
self.arch_context.switch_from(&from.arch_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dequeue(self: *@This()) void {
|
|
||||||
// TODO queueing information should be put under a lock for SMP to work properly
|
|
||||||
if (self.queue) |q| {
|
|
||||||
q.dequeue(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current() *@This() {
|
|
||||||
return Queue.t_this_cpu.?.current.?;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exit_current() noreturn {
|
|
||||||
// Mask IRQs so they don't break current thread's state
|
|
||||||
const mask = arch.IrqGuard.acquire();
|
|
||||||
defer mask.release();
|
|
||||||
|
|
||||||
const curr = Thread.current();
|
|
||||||
curr.dequeue();
|
|
||||||
|
|
||||||
yield();
|
|
||||||
|
|
||||||
@panic("This code should not be reachable");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Helper data structure to represent kernel stacks in task contexts.
|
/// Helper data structure to represent kernel stacks in task contexts.
|
||||||
pub fn KStack(comptime SIZE: usize) type {
|
pub fn KStack(comptime SIZE: usize) type {
|
||||||
return extern struct {
|
return extern struct {
|
||||||
@@ -292,6 +323,7 @@ pub fn yield() void {
|
|||||||
|
|
||||||
pub fn test_create_user_from_code(a: *arena.Arena, code: []const u8) Thread.Error!*Thread {
|
pub fn test_create_user_from_code(a: *arena.Arena, code: []const u8) Thread.Error!*Thread {
|
||||||
const L3 = mem.vmm.L3;
|
const L3 = mem.vmm.L3;
|
||||||
|
const CODE_BASE: usize = 0x200000;
|
||||||
|
|
||||||
var address_space = try ProcessAddressSpace.init(a);
|
var address_space = try ProcessAddressSpace.init(a);
|
||||||
errdefer {
|
errdefer {
|
||||||
@@ -302,7 +334,7 @@ pub fn test_create_user_from_code(a: *arena.Arena, code: []const u8) Thread.Erro
|
|||||||
const code_page_count = L3.page_count(code.len);
|
const code_page_count = L3.page_count(code.len);
|
||||||
log.info("Code is {} pages", .{code_page_count});
|
log.info("Code is {} pages", .{code_page_count});
|
||||||
var offset: usize = 0;
|
var offset: usize = 0;
|
||||||
var address: usize = 0x200000;
|
var address: usize = CODE_BASE;
|
||||||
while (offset < code.len) {
|
while (offset < code.len) {
|
||||||
const page_offset = address % L3.SIZE;
|
const page_offset = address % L3.SIZE;
|
||||||
const amount = @min(L3.SIZE - page_offset, code.len - offset);
|
const amount = @min(L3.SIZE - page_offset, code.len - offset);
|
||||||
@@ -327,7 +359,10 @@ pub fn test_create_user_from_code(a: *arena.Arena, code: []const u8) Thread.Erro
|
|||||||
|
|
||||||
log.info("Enter with sp = 0x{x}", .{sp});
|
log.info("Enter with sp = 0x{x}", .{sp});
|
||||||
|
|
||||||
const thread = Thread.create_user(a, address_space, 0x200000, sp, 1234);
|
const thread = Thread.create_user(a, address_space, CODE_BASE, sp, 1234);
|
||||||
|
|
||||||
|
_ = thread.grant(Object { .physical_memory = object.PhysicalMemoryObject {} });
|
||||||
|
_ = thread.grant(Object { .debug = object.DebugObject {} });
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ SECTIONS {
|
|||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.eh_frame_hdr : {
|
||||||
|
*(.eh_frame_hdr*)
|
||||||
|
}
|
||||||
|
.eh_frame : {
|
||||||
|
*(.eh_frame*)
|
||||||
|
}
|
||||||
|
|
||||||
.data : ALIGN(4K) {
|
.data : ALIGN(4K) {
|
||||||
*(.data*)
|
*(.data*)
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-8
@@ -1,22 +1,55 @@
|
|||||||
const abi = @import("abi");
|
const abi = @import("abi");
|
||||||
|
|
||||||
pub const syscall = struct {
|
pub const syscall = struct {
|
||||||
pub fn syscall1(func: abi.SyscallNumber, arg0: usize) usize {
|
pub fn send(handle: u32, msg: *const [5]usize) usize {
|
||||||
return asm volatile ("svc #0"
|
return asm volatile ("svc #0"
|
||||||
: [result] "={x0}" (-> usize),
|
: [result] "={x0}" (-> usize),
|
||||||
: [arg0] "{x0}" (arg0),
|
: [a0] "{x0}" (handle),
|
||||||
[func] "{x8}" (@intFromEnum(func)),
|
[a1] "{x1}" (msg[0]),
|
||||||
|
[a2] "{x2}" (msg[1]),
|
||||||
|
[a3] "{x3}" (msg[2]),
|
||||||
|
[a4] "{x4}" (msg[3]),
|
||||||
|
[a5] "{x5}" (msg[4]),
|
||||||
|
[func] "{x8}" (@intFromEnum(abi.SyscallNumber.SYS_send)),
|
||||||
: "memory"
|
: "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscall2(func: abi.SyscallNumber, arg0: usize, arg1: usize) usize {
|
pub fn sendrecv(handle: u32, msg: *const[5]usize, buffer: *[5]usize) usize {
|
||||||
return asm volatile ("svc #0"
|
return asm volatile (
|
||||||
|
\\ svc #0
|
||||||
|
\\ stp x1, x2, [%[buf], #16 * 0]
|
||||||
|
\\ stp x3, x4, [%[buf], #16 * 1]
|
||||||
|
\\ str x5, [%[buf], #16 * 2]
|
||||||
: [result] "={x0}" (-> usize),
|
: [result] "={x0}" (-> usize),
|
||||||
: [arg0] "{x0}" (arg0),
|
: [a0] "{x0}" (handle),
|
||||||
[arg1] "{x1}" (arg1),
|
[a1] "{x1}" (msg[0]),
|
||||||
[func] "{x8}" (@intFromEnum(func)),
|
[a2] "{x2}" (msg[1]),
|
||||||
|
[a3] "{x3}" (msg[2]),
|
||||||
|
[a4] "{x4}" (msg[3]),
|
||||||
|
[a5] "{x5}" (msg[4]),
|
||||||
|
[func] "{x8}" (@intFromEnum(abi.SyscallNumber.SYS_sendrecv)),
|
||||||
|
[buf] "r" (buffer),
|
||||||
: "memory"
|
: "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn syscall1(func: abi.SyscallNumber, arg0: usize) usize {
|
||||||
|
// return asm volatile ("svc #0"
|
||||||
|
// : [result] "={x0}" (-> usize),
|
||||||
|
// : [arg0] "{x0}" (arg0),
|
||||||
|
// [func] "{x8}" (@intFromEnum(func)),
|
||||||
|
// : "memory"
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn syscall2(func: abi.SyscallNumber, arg0: usize, arg1: usize) usize {
|
||||||
|
// return asm volatile ("svc #0"
|
||||||
|
// : [result] "={x0}" (-> usize),
|
||||||
|
// : [arg0] "{x0}" (arg0),
|
||||||
|
// [arg1] "{x1}" (arg1),
|
||||||
|
// [func] "{x8}" (@intFromEnum(func)),
|
||||||
|
// : "memory"
|
||||||
|
// );
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|||||||
+52
-2
@@ -1,8 +1,58 @@
|
|||||||
pub const arch = @import("arch.zig");
|
pub const arch = @import("arch.zig");
|
||||||
pub const syscall = @import("syscall.zig");
|
pub const syscall = @import("syscall.zig");
|
||||||
pub const log = @import("log.zig");
|
pub const log = @import("log.zig");
|
||||||
|
const abi = @import("abi");
|
||||||
|
|
||||||
|
const Handle = abi.Handle;
|
||||||
|
|
||||||
|
fn debug_write(handle: Handle, message: []const u8) void {
|
||||||
|
_ = syscall.send(handle, &.{
|
||||||
|
@intFromPtr(message.ptr),
|
||||||
|
message.len,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit_process(handle: Handle, code: u32) noreturn {
|
||||||
|
_ = syscall.send(handle, &.{
|
||||||
|
@intFromEnum(abi.ProcessObjectAction.ZO_process_exit),
|
||||||
|
code,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
});
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate_memory(handle: Handle, count: usize) u64 {
|
||||||
|
var output: [5]usize = undefined;
|
||||||
|
// TODO error code
|
||||||
|
_ = syscall.sendrecv(
|
||||||
|
handle,
|
||||||
|
&.{
|
||||||
|
@intFromEnum(abi.PhysicalMemoryObjectAction.ZO_physical_memory_allocate),
|
||||||
|
count,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
&output,
|
||||||
|
);
|
||||||
|
return output[0];
|
||||||
|
}
|
||||||
|
|
||||||
export fn _start(arg: usize) linksection(".text.entry") callconv(.C) noreturn {
|
export fn _start(arg: usize) linksection(".text.entry") callconv(.C) noreturn {
|
||||||
log.println("arg=0x{x} ({})", .{ arg, arg });
|
// TODO make the kernel provide those dynamically somehow
|
||||||
syscall.exit(0);
|
const SELF_PROCESS_HANDLE: Handle = @enumFromInt(1);
|
||||||
|
const PHYSICAL_MEMORY_HANDLE: Handle = @enumFromInt(2);
|
||||||
|
const DEBUG_HANDLE: Handle = @enumFromInt(3);
|
||||||
|
|
||||||
|
_ = arg;
|
||||||
|
const mem = allocate_memory(PHYSICAL_MEMORY_HANDLE, 8);
|
||||||
|
_ = mem;
|
||||||
|
|
||||||
|
debug_write(DEBUG_HANDLE, "Hello!!!");
|
||||||
|
exit_process(SELF_PROCESS_HANDLE, 4321);
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-6
@@ -2,13 +2,24 @@ const arch = @import("arch.zig");
|
|||||||
const abi = @import("abi");
|
const abi = @import("abi");
|
||||||
|
|
||||||
const sc = arch.syscall;
|
const sc = arch.syscall;
|
||||||
const SC = abi.SyscallNumber;
|
|
||||||
|
|
||||||
pub fn exit(code: u32) noreturn {
|
pub inline fn send(object: abi.Handle, msg: *const [5]usize) usize {
|
||||||
_ = sc.syscall1(SC.SYS_exit, code);
|
return sc.send(@intFromEnum(object), msg);
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_write(text: []const u8) void {
|
pub inline fn recv(object: abi.Handle, buffer: *[5]usize) usize {
|
||||||
_ = sc.syscall2(SC.SYS_debug_write, @intFromPtr(text.ptr), text.len);
|
return sc.recv(@intFromEnum(object), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn sendrecv(object: abi.Handle, msg: *const [5]usize, buffer: *[5]usize) usize {
|
||||||
|
return sc.sendrecv(@intFromEnum(object), msg, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn exit(code: u32) noreturn {
|
||||||
|
// _ = sc.syscall1(SC.SYS_exit, code);
|
||||||
|
// unreachable;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn debug_write(text: []const u8) void {
|
||||||
|
// _ = sc.syscall2(SC.SYS_debug_write, @intFromPtr(text.ptr), text.len);
|
||||||
|
// }
|
||||||
|
|||||||
Reference in New Issue
Block a user