akaros/kern/src/arsc.c
<<
>>
Prefs
   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
  21struct proc_list arsc_proc_list = TAILQ_HEAD_INITIALIZER(arsc_proc_list);
  22spinlock_t arsc_proc_lock = SPINLOCK_INITIALIZER_IRQSAVE;
  23
  24intreg_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
  31syscall_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
  59void 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
  85static 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
 131