aboutsummaryrefslogtreecommitdiff
path: root/src/os.zig
blob: a41b812852953edadbc0a8cfacd810543be174fd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

const std = @import("std");
pub const hwinfo = @import("hwinfo.zig");

pub const max_args = 6;

const Result = struct {
    value: usize,
    error_code: usize,
};

const SyscallError = error{Kernel};

fn autoCast(value: anytype) usize {
    return switch (@typeInfo(@TypeOf(value))) {
        .Type => @compileError("cannot pass type to system call"),
        .Void => @compileError("cannot pass void to system call"),
        .NoReturn => @compileError("cannot pass noreturn to system call"),
        .Pointer => @intFromPtr(value),
        .Bool => @intFromBool(value),
        else => value,
    };
}

fn ecall(number: usize, args: anytype) Result {
    var registers = [_]usize{0} ** max_args;
    inline for (args, 0..) |arg, i| {
        if (i >= max_args) @compileError("too many arguments to system call");
        registers[i] = autoCast(arg);
    }

    var result: Result = undefined;
    asm volatile (
        \\ ecall
        \\ sd a0, 0(%[value])
        \\ sd a1, 0(%[error_code])
        :
        : [value] "r" (&result.value),
          [error_code] "r" (&result.error_code),
          [a0] "{a0}" (registers[0]),
          [a1] "{a1}" (registers[1]),
          [a2] "{a2}" (registers[2]),
          [a3] "{a3}" (registers[3]),
          [a4] "{a4}" (registers[4]),
          [a5] "{a5}" (registers[5]),
          [number] "{a7}" (number),
    );
    return result;
}

pub fn errorName(code: u16, buffer: []u8) !usize {
    const result = ecall(100000, .{
        code,
        buffer.ptr,
        buffer.len,
    });
    if (result.error_code != 0) return SyscallError.Kernel;
    return result.value;
}

pub fn consoleWrite(bytes: []const u8) !usize {
    const result = ecall(100001, .{ bytes.ptr, bytes.len });
    if (result.error_code != 0) return SyscallError.Kernel;
    return result.value;
}

pub fn launch(bytes: []align(@alignOf(std.elf.Elf64_Ehdr)) const u8) !usize {
    const result = ecall(100002, .{ bytes.ptr, bytes.len });
    if (result.error_code != 0) return SyscallError.Kernel;
    return result.value;
}

pub fn end() noreturn {
    _ = ecall(100003, .{});
    unreachable;
}

pub fn terminate(pid: u16, thread: usize) !void {
    const result = ecall(100004, .{ pid, thread });
    if (result.error_code != 0) return SyscallError.Kernel;
}

pub fn processId() u16 {
    const result = ecall(100005, .{});
    return result.value;
}

pub fn threadId() usize {
    const result = ecall(100006, .{});
    return result.value;
}

pub fn devicesByKind(kind: hwinfo.DevKind, devices: []hwinfo.Dev) !usize {
    const result = ecall(100007, .{ kind, devices.ptr, devices.len });
    if (result.error_code != 0) return SyscallError.Kernel;
    return result.value;
}

pub fn unlock(reg_addr: usize, writable: bool) !usize {
    const result = ecall(100008, .{ reg_addr, writable });
    if (result.error_code != 0) return SyscallError.Kernel;
    return result.value;
}

pub fn lock(vaddr: usize) !void {
    const result = ecall(100009, .{vaddr});
    if (result.error_code != 0) return SyscallError.Kernel;
}

pub fn join(channel: usize) !void {
    const result = ecall(100010, .{channel});
    if (result.error_code != 0) return SyscallError.Kernel;
}

pub fn leave(channel: usize) void {
    _ = ecall(100011, .{channel});
}

pub fn pass(channel: usize, receiver: u16, identify: bool, bytes: []const u8) !void {
    const result = ecall(100012, .{ channel, receiver, identify, bytes.ptr, bytes.len });
    if (result.error_code != 0) return SyscallError.Kernel;
}

pub fn receive(channel: usize, sender: ?*u16, buffer: []u8) !usize {
    const result = ecall(100013, .{ channel, @intFromPtr(sender), buffer.ptr, buffer.len });
    if (result.error_code != 0) return SyscallError.Kernel;
    return result.value;
}