summaryrefslogtreecommitdiffstats
path: root/sys/syscall.c
blob: 0351c95b6e0753bbaa64661cbec3c5ba2641e4b7 (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
#include "sys/syscall.h"
#include "arch/x86_64/hal/obj.h"
#include "hal/smp.h"
#include "hal/process.h"
#include "jove.h"
#include "lib/printf.h"
#include "sys/link.h"
#include "sys/message.h"

int __syscall_generic_objpath(jove_owned_obj_t *objdir, size_t payload_bytes, void *payload_data, jove_owned_obj_t **retobj)
{
    size_t bytes_needed = sizeof(struct syscall_generic_objpath);
    CHECK_TOOSMALL(bytes_needed, payload_bytes,
            "Message too small for payload.");
    struct syscall_generic_objpath *payload = payload_data;
 
    bytes_needed += payload->pathlen << 1;
    CHECK_TOOSMALL(bytes_needed, payload_bytes,
            "Message too small for object path.");
        
    errno = 0;
    *retobj = objdir_getobj(objdir, payload->path, payload->pathlen);
    return errno;
}

int
_syscall_handle_generic(
        jove_owned_obj_t *pcb_obj,
        jove_owned_obj_t *objdir,
        jove_owned_obj_t *message_obj,
        jove_owned_obj_t *target_obj,
        struct syscall_header *header,
        size_t bytes_left,
        void *payload)
{
    pcb_t *pcb = obj_deref(pcb_obj);
    kprintf("syscall: Process %i encountered stub syscall on object %P\n", pcb_pid(pcb), header->path, header->pathlen);
    return EBADOBJ;
}

static const syscall_handle_t s_syscall_handles[128] = {
    [JOVE_OBJ_NONE] = NULL,
    [JOVE_OBJ_UNTYPED] = _syscall_handle_untyped,
    [JOVE_OBJ_OBJDIR] = _syscall_handle_objdir,
    [JOVE_OBJ_PAGEDIR] = _syscall_handle_generic,
    [JOVE_OBJ_PROCESSOR] = _syscall_handle_generic,
    [JOVE_OBJ_PROCESS] = _syscall_handle_generic,
    [JOVE_OBJ_ACPI_TABLE] = _syscall_handle_generic,
    [JOVE_OBJ_INT_HANDLE] = _syscall_handle_generic,
    [JOVE_OBJ_INITRD_FILE] = _syscall_handle_generic,
    [JOVE_OBJ_FRAMEBUFFER] = _syscall_handle_generic,
    [JOVE_OBJ_VIRTTERM] = _syscall_handle_vtt,
    [JOVE_OBJ_MESSAGE] = _syscall_handle_generic,
    [JOVE_OBJ_LINK] = _syscall_handle_generic,
};

int
syscall_handler(uintmax_t message_path_raw, uint16_t message_pathlen)
{
    uint16_t *message_path = (uint16_t*)&message_path_raw;
    if(message_pathlen > sizeof(uintmax_t) >> 1) {
        return EBADPATH;
    }

    jove_owned_obj_t *pcb_obj = process_current();
    pcb_t *pcb = obj_deref(pcb_obj);
    jove_owned_obj_t *objdir = pcb_rootdir(pcb);
    jove_owned_obj_t *message_obj = objdir_getobj(objdir, message_path, message_pathlen);

    int sysret = 0;
    if(message_obj == 0) {
        sysret = errno;
        goto release_premsg;
    }

    if(obj_gettype_linked(message_obj) != JOVE_OBJ_MESSAGE) {
        kprintf("syscall: Process %i tried to call syscall with invalid object: %P\n", pcb_pid(pcb), message_path, message_pathlen);
        sysret = EBADOBJ;
        goto release_return;
    }

    size_t messagelen = message_len(message_obj);
    void *messagedata = message_data(message_obj);
    struct syscall_header *header = messagedata;

    size_t bytes_needed = sizeof(struct syscall_header) + header->pathlen * 2;
    if(bytes_needed > messagelen) {
        //Target path exceeds message length.
        kprintf("syscall: Process %i tried to call syscall with target path too big for message.\n", pcb_pid(pcb));
        sysret = ETOOSMALL;
        goto release_return;
    }
    jove_owned_obj_t *target = objdir_getobj(objdir, header->path, header->pathlen);
    if(target == 0) {
        //Could not find payload target in pcb rootdir.
        kprintf("syscall: Process %i tried to call syscall with bad target path %P\n", 
                pcb_pid(pcb), header->path, header->pathlen);
        sysret = errno;
        goto release_return;
    }

    uint8_t target_type = obj_gettype(target);
    size_t bytes_left = messagelen - bytes_needed;
    if(target_type > 0x7F) {
        sysret = _syscall_handle_arch(
                pcb_obj, objdir, message_obj, target,
                header, bytes_left, messagedata + bytes_needed);
    }else{
        syscall_handle_t call_handle = s_syscall_handles[obj_gettype(target)];
        if(call_handle == NULL) {
            kprintf("syscall: Process %i tried to call syscall on object %P which doesn't support syscalls!\n",
                    pcb_pid(pcb), header->path, header->pathlen);
            sysret = EBADOBJ;
        }else 
            sysret = call_handle(
                    pcb_obj, objdir, message_obj, target, 
                    header, bytes_left, messagedata + bytes_needed);
    }
    obj_release(target);
release_return:
    obj_release(message_obj);
release_premsg:
    obj_release(objdir);
    obj_release(pcb_obj);
    return sysret;
}