Sanitize vcoreid from untrusted sources
[akaros.git] / kern / src / arsc.c
1 /* See COPYRIGHT for copyright information. */
2
3 #include <ros/common.h>
4 #include <ros/ring_syscall.h>
5 #include <arch/types.h>
6 #include <arch/arch.h>
7 #include <arch/mmu.h>
8 #include <error.h>
9
10 #include <syscall.h>
11 #include <kmalloc.h>
12 #include <pmap.h>
13 #include <stdio.h>
14 #include <hashtable.h>
15 #include <smp.h>
16 #include <arsc_server.h>
17 #include <kref.h>
18
19
20
21 struct proc_list arsc_proc_list = TAILQ_HEAD_INITIALIZER(arsc_proc_list);
22 spinlock_t arsc_proc_lock = SPINLOCK_INITIALIZER_IRQSAVE;
23
24 intreg_t inline syscall_async(struct proc *p, syscall_req_t *call)
25 {
26         struct syscall* sc = call->sc;
27         return syscall(p, sc->num, sc->arg0, sc->arg1,
28                        sc->arg2, sc->arg3, sc->arg4, sc->arg5);
29 }
30
31 syscall_sring_t* sys_init_arsc(struct proc *p)
32 {
33         kref_get(&p->p_kref, 1);        /* we're storing an external ref here */
34         syscall_sring_t* sring;
35         void * va;
36
37         // TODO: need to pin this page in the future when swapping happens
38         va = do_mmap(p,MMAP_LOWEST_VA, SYSCALLRINGSIZE, PROT_READ | PROT_WRITE,
39                      MAP_ANONYMOUS | MAP_POPULATE | MAP_PRIVATE, NULL, 0);
40         pte_t pte = pgdir_walk(p->env_pgdir, (void*)va, 0);
41         assert(pte_walk_okay(pte));
42         sring = (syscall_sring_t*) KADDR(pte_get_paddr(pte));
43         /*make sure we are able to allocate the shared ring */
44         assert(sring != NULL);
45         p->procdata->syscallring = sring;
46         /* Initialize the generic syscall ring buffer */
47         SHARED_RING_INIT(sring);
48
49         BACK_RING_INIT(&p->syscallbackring,
50                        sring,
51                        SYSCALLRINGSIZE);
52
53         spin_lock_irqsave(&arsc_proc_lock);
54         TAILQ_INSERT_TAIL(&arsc_proc_list, p, proc_arsc_link);
55         spin_unlock_irqsave(&arsc_proc_lock);
56         return (syscall_sring_t*)va;
57 }
58
59 void arsc_server(uint32_t srcid, long a0, long a1, long a2)
60 {
61         struct proc *p = NULL;
62
63         TAILQ_INIT(&arsc_proc_list);
64         while (1) {
65                 while (TAILQ_EMPTY(&arsc_proc_list))
66                         cpu_relax();
67
68                 TAILQ_FOREACH(p, &arsc_proc_list, proc_arsc_link) {
69                         /* Probably want to try to process a dying process's
70                          * syscalls.  If not, just move it to an else case */
71                         process_generic_syscalls (p, MAX_ASRC_BATCH);
72                         if (proc_is_dying(p)) {
73                                 TAILQ_REMOVE(&arsc_proc_list, p,
74                                              proc_arsc_link);
75                                 proc_decref(p);
76                                 /* Need to break out, so the TAILQ_FOREACH
77                                  * doesn't flip out.  It's not fair, but we're
78                                  * not dealing with that yet anyway */
79                                 break;
80                         }
81                 }
82         }
83 }
84
85 static intreg_t process_generic_syscalls(struct proc *p, size_t max)
86 {
87         size_t count = 0;
88         syscall_back_ring_t* sysbr = &p->syscallbackring;
89         struct per_cpu_info* pcpui = &per_cpu_info[core_id()];
90         uintptr_t old_proc;
91
92         // looking at a process not initialized to perform arsc.
93         if (sysbr == NULL)
94                 return count;
95         /* Bail out if there is nothing to do */
96         if (!RING_HAS_UNCONSUMED_REQUESTS(sysbr))
97                 return 0;
98         /* Switch to the address space of the process, so we can handle their
99          * pointers, etc. */
100         old_proc = switch_to(p);
101         // max is the most we'll process.  max = 0 means do as many as possible
102         // TODO: check for initialization of the ring.
103         while (RING_HAS_UNCONSUMED_REQUESTS(sysbr) && ((!max)||(count < max))) {
104                 // ASSUME: one queue per process
105                 count++;
106                 //printk("DEBUG PRE sring->req_prod: %d, sring->rsp_prod: %d\n",
107                 //         sysbr->sring->req_prod, sysbr->sring->rsp_prod);
108                 // might want to think about 0-ing this out, if we aren't
109                 // going to explicitly fill in all fields
110                 syscall_rsp_t rsp;
111                 // this assumes we get our answer immediately for the syscall.
112                 syscall_req_t* req = RING_GET_REQUEST(sysbr, ++sysbr->req_cons);
113
114                 pcpui->cur_kthread->sysc = req->sc;
115                 // TODO: blocking call will block arcs as well.
116                 run_local_syscall(req->sc);
117
118                 // need to keep the slot in the ring buffer if it is blocked
119                 (sysbr->rsp_prod_pvt)++;
120                 req->status = RES_ready;
121                 RING_PUSH_RESPONSES(sysbr);
122
123                 //printk("DEBUG PST sring->req_prod: %d, sring->rsp_prod: %d\n",
124                 //         sysbr->sring->req_prod, sysbr->sring->rsp_prod);
125         }
126         /* switch back to whatever context we were in before */
127         switch_back(p, old_proc);
128         return (intreg_t)count;
129 }
130