From ef7a23d23a751fb50ec53ef0d3e5cf1dfeb5aebb Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Mon, 17 Mar 2008 18:49:13 +0800 Subject: [PATCH] ipc implemented. Signed-off-by: Guanqun Lu --- kern/init.c | 2 +- kern/syscall.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- lib/ipc.c | 32 +++++++++++++++++++++++--- 3 files changed, 100 insertions(+), 6 deletions(-) diff --git a/kern/init.c b/kern/init.c index b346267..7305baf 100644 --- a/kern/init.c +++ b/kern/init.c @@ -49,7 +49,7 @@ i386_init(void) ENV_CREATE2(TEST, TESTSIZE) #else // Touch all you want. - ENV_CREATE(user_spin); + ENV_CREATE(user_primes); #endif // TEST* // Schedule and run the first user environment! diff --git a/kern/syscall.c b/kern/syscall.c index 457e6a9..a8d64f5 100644 --- a/kern/syscall.c +++ b/kern/syscall.c @@ -358,7 +358,56 @@ static int sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm) { // LAB 4: Your code here. - panic("sys_ipc_try_send not implemented"); + struct Env *target; + struct Page *page; + pte_t *pte; + int r, ret = 0; + + if ((r = envid2env(envid, &target, 0)) < 0) + return -E_BAD_ENV; + + if (!target->env_ipc_recving) + return -E_IPC_NOT_RECV; + + // srcva is not null, then + // we need to map it, thus sharing the map + if (srcva) { + if ((unsigned int)srcva >= UTOP) + return -E_INVAL; + + if (srcva != ROUNDDOWN(srcva, PGSIZE)) + return -E_INVAL; + + if ((page = page_lookup(curenv->env_pgdir, srcva, &pte)) == NULL) + return -E_INVAL; + + // PTE_U and PTE_P must be set + if (!(perm & PTE_U) || !(perm & PTE_P)) + return -E_INVAL; + // other bits than PTE_{U,P,W,AVAIL} are set + if (perm & ((~(PTE_U | PTE_P | PTE_W | PTE_AVAIL)) & 0xfff)) + return -E_INVAL; + // perm has PTE_W, but scrpte is read-only. + if ((perm & PTE_W) && !(*pte & PTE_W)) + return -E_INVAL; + + if (target->env_ipc_dstva == srcva && + page_insert(target->env_pgdir, page, srcva, perm) < 0) + return -E_NO_MEM; + + ret = 1; + } + + target->env_ipc_recving = 0; + target->env_ipc_value = value; + target->env_ipc_from = curenv->env_id; + if (ret) + target->env_ipc_perm = perm; + else + target->env_ipc_perm = 0; + target->env_status = ENV_RUNNABLE; + + return ret; } // Block until a value is ready. Record that you want to receive @@ -376,7 +425,19 @@ static int sys_ipc_recv(void *dstva) { // LAB 4: Your code here. - panic("sys_ipc_recv not implemented"); + if ((unsigned int)dstva >= UTOP || dstva != ROUNDDOWN(dstva, PGSIZE)) + return -E_INVAL; + + curenv->env_ipc_dstva = dstva; + curenv->env_ipc_recving = 1; + curenv->env_status = ENV_NOT_RUNNABLE; + // set the return value to be zero, + // it is necessary, because the 'return' statement + // after 'sched_yield' will never be executed, + // actually it is skipped. + curenv->env_tf.tf_regs.reg_eax = 0; + // give up the CPU + sched_yield(); return 0; } @@ -444,6 +505,13 @@ syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, case SYS_phy_page: ret = sys_phy_page((envid_t)a1, (void *)a2); break; + case SYS_ipc_try_send: + ret = sys_ipc_try_send((envid_t)a1, (uint32_t)a2, + (void *)a3, (int)a4); + break; + case SYS_ipc_recv: + ret = sys_ipc_recv((void *)a1); + break; default: // NSYSCALLS ret = -E_INVAL; diff --git a/lib/ipc.c b/lib/ipc.c index 950c9c7..ba7e003 100644 --- a/lib/ipc.c +++ b/lib/ipc.c @@ -18,8 +18,24 @@ int32_t ipc_recv(envid_t *from_env_store, void *pg, int *perm_store) { // LAB 4: Your code here. - panic("ipc_recv not implemented"); - return 0; + int r; + + if (!pg) + pg = (void *)USTACKTOP; + + if ((r = sys_ipc_recv(pg)) < 0) { + if (from_env_store) + *from_env_store = 0; + if (perm_store) + *perm_store = 0; + return r; + } else { + if (from_env_store) + *from_env_store = env->env_ipc_from; + if (perm_store) + *perm_store = env->env_ipc_perm; + return env->env_ipc_value; + } } // Send 'val' (and 'pg' with 'perm', assuming 'pg' is nonnull) to 'toenv'. @@ -34,6 +50,16 @@ void ipc_send(envid_t to_env, uint32_t val, void *pg, int perm) { // LAB 4: Your code here. - panic("ipc_send not implemented"); + int r; + + while (1) { + r = sys_ipc_try_send(to_env, val, pg, perm); + if (r >= 0) + return; + if (r != -E_IPC_NOT_RECV) + panic("sys_ipc_try_send error: %e", r); + + sys_yield(); + } } -- 2.11.4.GIT