summaryrefslogtreecommitdiffstats
path: root/sys/syscall_pcb.c
blob: 4fe557bb3c9712ed05b412fcbab40207f01ba3d5 (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
#include "api/error.h"
#include "api/obj.h"
#include "api/syscall.h"
#include "jove.h"
#include "lib/printf.h"
#include "proc/process.h"
#include "proc/scheduler.h"
#include "syscall.h"
#include "errno.h"

int
s_syscall_pcb_yield(jove_owned_obj_t *pcb_obj,
        size_t bytes_left,
        void *payload_data)
{
    size_t bytes_needed = sizeof(pid_t);
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload");

    pid_t subject_pid = *((pid_t*)payload_data);
    return scheduler_yield(subject_pid);
}

int
s_syscall_pcb_send(jove_owned_obj_t *pcb_obj,
                   lockstack_t *lockstack,
                   jove_owned_obj_t *objdir_obj,
                   size_t bytes_left,
                   void *payload_data)
{
    size_t bytes_needed = sizeof(struct syscall_pcb_send);
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload");

    struct syscall_pcb_send *payload = payload_data;
    bytes_needed += payload->send_path_length;
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for subject path");

    jove_perm_obj_t subject_objdir = link_try_traverse_objdir(
        objdir_obj, lockstack, payload->send_path_length - 1, payload->send_path);
    if(errno) {
        klogf("Unable to get subject %P objdir : %s\n",
              payload->send_path, payload->send_path_length, errstr(errno));
        return -errno;
    }
    CHECK_OBJPERM(subject_objdir, SYSCALL_PERM_PCB_SEND_OBJDIR, "Subject objdir does not permit send");

    jove_owned_obj_t *subject = objdir_trygetlocal(subject_objdir.obj,
                                                   payload->send_path[payload->send_path_length-1]);
    if(subject == 0) {
        klogf("Unable to get subject %P object : %s\n",
              payload->send_path, payload->send_path_length, errstr(errno));
        return -errno;
    }

    return pcb_send(obj_deref(pcb_obj), payload->send_target, subject, payload->send_timeout);
}

int
s_syscall_pcb_recv(jove_owned_obj_t *pcb_obj,
                   lockstack_t *lockstack,
                   jove_owned_obj_t *objdir_obj,
                   size_t bytes_left,
                   void *payload_data)
{
    size_t bytes_needed = sizeof(struct syscall_pcb_recv);
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload");

    struct syscall_pcb_recv *payload = payload_data;
    bytes_needed += payload->recv_path_length * sizeof(objpath_part_t);
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for destination path");

    jove_perm_obj_t destination = link_try_traverse_objdir(
        objdir_obj, lockstack, payload->recv_path_length, payload->recv_path);
    if(errno) {
        klogf("Unable to get destination %P : %s\n",
              payload->recv_path, payload->recv_path_length, errstr(errno));
        return -errno;
    }
    CHECK_OBJPERM(destination, SYSCALL_PERM_PCB_RECV_DST, "Destination object does not permit recv.");

    return pcb_recv(obj_deref(pcb_obj), payload->recv_target, destination.obj, payload->recv_timeout);
}

int
_syscall_handle_pcb(syscall_context_t *ctx)
{
    switch(ctx->header->callid) {
        case SYSCALL_PCB_YIELD:
            if(ctx->target.permissions & SYSCALL_PERM_PCB_YIELD)
                return s_syscall_pcb_yield(ctx->target.obj, ctx->bytes_left, ctx->payload);
            return -EPERM;

        case SYSCALL_PCB_SEND:
            if(ctx->target.permissions & SYSCALL_PERM_PCB_SEND)
                return s_syscall_pcb_send(
                    ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload);
            return -EPERM;

        case SYSCALL_PCB_RECV:
            if(ctx->target.permissions & SYSCALL_PERM_PCB_RECV)
                return s_syscall_pcb_recv(
                    ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload);
            return -EPERM;

        default:
            return -EBADCALL;
    }
}