| /* See COPYRIGHT for copyright information. */ | 
 |  | 
 | #include <ros/common.h> | 
 | #include <ros/ring_syscall.h> | 
 | #include <arch/types.h> | 
 | #include <arch/arch.h> | 
 | #include <arch/mmu.h> | 
 | #include <error.h> | 
 |  | 
 | #include <syscall.h> | 
 | #include <kmalloc.h> | 
 | #include <pmap.h> | 
 | #include <stdio.h> | 
 | #include <hashtable.h> | 
 | #include <smp.h> | 
 | #include <arsc_server.h> | 
 | #include <kref.h> | 
 |  | 
 |  | 
 |  | 
 | struct proc_list arsc_proc_list = TAILQ_HEAD_INITIALIZER(arsc_proc_list); | 
 | spinlock_t arsc_proc_lock = SPINLOCK_INITIALIZER_IRQSAVE; | 
 |  | 
 | intreg_t inline syscall_async(struct proc *p, syscall_req_t *call) | 
 | { | 
 | 	struct syscall* sc = call->sc; | 
 | 	return syscall(p, sc->num, sc->arg0, sc->arg1, | 
 | 	               sc->arg2, sc->arg3, sc->arg4, sc->arg5); | 
 | } | 
 |  | 
 | syscall_sring_t* sys_init_arsc(struct proc *p) | 
 | { | 
 | 	kref_get(&p->p_kref, 1);		/* we're storing an external ref here */ | 
 | 	syscall_sring_t* sring; | 
 | 	void * va; | 
 | 	// TODO: need to pin this page in the future when swapping happens | 
 | 	va = do_mmap(p,MMAP_LOWEST_VA, SYSCALLRINGSIZE, PROT_READ | PROT_WRITE, | 
 | 	             MAP_ANONYMOUS | MAP_POPULATE, NULL, 0); | 
 | 	pte_t pte = pgdir_walk(p->env_pgdir, (void*)va, 0); | 
 | 	assert(pte_walk_okay(pte)); | 
 | 	sring = (syscall_sring_t*) KADDR(pte_get_paddr(pte)); | 
 | 	/*make sure we are able to allocate the shared ring */ | 
 | 	assert(sring != NULL); | 
 |  	p->procdata->syscallring = sring; | 
 | 	/* Initialize the generic syscall ring buffer */ | 
 | 	SHARED_RING_INIT(sring); | 
 |  | 
 | 	BACK_RING_INIT(&p->syscallbackring, | 
 | 	               sring, | 
 | 	               SYSCALLRINGSIZE); | 
 |  | 
 | 	spin_lock_irqsave(&arsc_proc_lock); | 
 | 	TAILQ_INSERT_TAIL(&arsc_proc_list, p, proc_arsc_link); | 
 | 	spin_unlock_irqsave(&arsc_proc_lock); | 
 | 	return (syscall_sring_t*)va; | 
 | } | 
 |  | 
 | void arsc_server(uint32_t srcid, long a0, long a1, long a2) | 
 | { | 
 | 	struct proc *p = NULL; | 
 | 	TAILQ_INIT(&arsc_proc_list); | 
 | 	while (1) { | 
 | 		while (TAILQ_EMPTY(&arsc_proc_list)) | 
 | 			cpu_relax(); | 
 | 		 | 
 | 		TAILQ_FOREACH(p, &arsc_proc_list, proc_arsc_link) { | 
 | 			/* Probably want to try to process a dying process's syscalls.  If | 
 | 			 * not, just move it to an else case */ | 
 | 			process_generic_syscalls (p, MAX_ASRC_BATCH);  | 
 | 			if (p->state == PROC_DYING) { | 
 | 				TAILQ_REMOVE(&arsc_proc_list, p, proc_arsc_link); | 
 | 				proc_decref(p); | 
 | 				/* Need to break out, so the TAILQ_FOREACH doesn't flip out. | 
 | 				 * It's not fair, but we're not dealing with that yet anyway */ | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static intreg_t process_generic_syscalls(struct proc *p, size_t max) | 
 | { | 
 | 	size_t count = 0; | 
 | 	syscall_back_ring_t* sysbr = &p->syscallbackring; | 
 | 	struct per_cpu_info* pcpui = &per_cpu_info[core_id()]; | 
 | 	struct proc *old_proc; | 
 | 	// looking at a process not initialized to perform arsc.  | 
 | 	if (sysbr == NULL)  | 
 | 		return count; | 
 | 	/* Bail out if there is nothing to do */ | 
 | 	if (!RING_HAS_UNCONSUMED_REQUESTS(sysbr)) | 
 | 		return 0; | 
 | 	/* Switch to the address space of the process, so we can handle their | 
 | 	 * pointers, etc. */ | 
 | 	old_proc = switch_to(p); | 
 | 	// max is the most we'll process.  max = 0 means do as many as possible | 
 | 	// TODO: check for initialization of the ring.  | 
 | 	while (RING_HAS_UNCONSUMED_REQUESTS(sysbr) && ((!max)||(count < max)) ) { | 
 | 		// ASSUME: one queue per process | 
 | 		count++; | 
 | 		//printk("DEBUG PRE: sring->req_prod: %d, sring->rsp_prod: %d\n", | 
 | 		//	   sysbr->sring->req_prod, sysbr->sring->rsp_prod); | 
 | 		// might want to think about 0-ing this out, if we aren't | 
 | 		// going to explicitly fill in all fields | 
 | 		syscall_rsp_t rsp; | 
 | 		// this assumes we get our answer immediately for the syscall. | 
 | 		syscall_req_t* req = RING_GET_REQUEST(sysbr, ++sysbr->req_cons); | 
 | 		 | 
 | 		pcpui->cur_kthread->sysc = req->sc; | 
 | 		run_local_syscall(req->sc); // TODO: blocking call will block arcs as well. | 
 | 		 | 
 | 		// need to keep the slot in the ring buffer if it is blocked | 
 | 		(sysbr->rsp_prod_pvt)++; | 
 | 		req->status = RES_ready; | 
 | 		RING_PUSH_RESPONSES(sysbr); | 
 |  | 
 | 		//printk("DEBUG POST: sring->req_prod: %d, sring->rsp_prod: %d\n", | 
 | 		//	   sysbr->sring->req_prod, sysbr->sring->rsp_prod); | 
 | 	} | 
 | 	/* switch back to whatever context we were in before */ | 
 | 	switch_back(p, old_proc); | 
 | 	return (intreg_t)count; | 
 | } | 
 |  |