From ba31e1b82379abfc00cbc3ef46dfb57e7216b162 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Thu, 28 May 2009 12:52:14 +0300 Subject: [PATCH] Added ipc save/restore for page-fault ipcs. The save restore routines save all primary message registers and ipc flags. --- include/l4/generic/tcb.h | 18 +++++++++++++-- src/api/ipc.c | 47 ++++++++++++++++++++++---------------- src/arch/arm/exception.c | 49 ++++++++++++++++++++++++++++++++++------ 3 files changed, 86 insertions(+), 28 deletions(-) diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 04bc044..1fa5dc6 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -145,15 +145,29 @@ static inline unsigned int tcb_get_ipc_flags(struct ktcb *task) return task->ipc_flags; } +static inline unsigned int +ipc_flags_set_type(unsigned int flags, unsigned int type) +{ + flags &= ~IPC_FLAGS_TYPE_MASK; + flags |= type & IPC_FLAGS_TYPE_MASK; + return flags; +} + +static inline unsigned int ipc_flags_get_type(unsigned int flags) +{ + return flags & IPC_FLAGS_TYPE_MASK; +} + static inline void tcb_set_ipc_type(struct ktcb *task, unsigned int type) { - task->ipc_flags = type & IPC_FLAGS_TYPE_MASK; + task->ipc_flags = ipc_flags_set_type(task->ipc_flags, + type); } static inline unsigned int tcb_get_ipc_type(struct ktcb *task) { - return task->ipc_flags & IPC_FLAGS_TYPE_MASK; + return ipc_flags_get_type(task->ipc_flags); } #define THREAD_IDS_MAX 1024 diff --git a/src/api/ipc.c b/src/api/ipc.c index d2f999a..d1680c8 100644 --- a/src/api/ipc.c +++ b/src/api/ipc.c @@ -506,29 +506,38 @@ static inline int __sys_ipc(l4id_t to, l4id_t from, { int ret; - switch (ipc_type) { - case IPC_SEND: - if (flags & IPC_FLAGS_EXTENDED) + if (ipc_flags_get_type(flags) == IPC_FLAGS_EXTENDED) { + switch (ipc_type) { + case IPC_SEND: ret = ipc_send_extended(to, flags); - else - ret = ipc_send(to, flags); - break; - case IPC_RECV: - if (flags & IPC_FLAGS_EXTENDED) + break; + case IPC_RECV: ret = ipc_recv_extended(from, flags); - else - ret = ipc_recv(from, flags); - break; - case IPC_SENDRECV: - if (flags & IPC_FLAGS_EXTENDED) + break; + case IPC_SENDRECV: ret = ipc_sendrecv_extended(to, from, flags); - else + break; + case IPC_INVALID: + default: + printk("Unsupported ipc operation.\n"); + ret = -ENOSYS; + } + } else { + switch (ipc_type) { + case IPC_SEND: + ret = ipc_send(to, flags); + break; + case IPC_RECV: + ret = ipc_recv(from, flags); + break; + case IPC_SENDRECV: ret = ipc_sendrecv(to, from, flags); - break; - case IPC_INVALID: - default: - printk("Unsupported ipc operation.\n"); - ret = -ENOSYS; + break; + case IPC_INVALID: + default: + printk("Unsupported ipc operation.\n"); + ret = -ENOSYS; + } } return ret; } diff --git a/src/arch/arm/exception.c b/src/arch/arm/exception.c index 3cb5041..df6445c 100644 --- a/src/arch/arm/exception.c +++ b/src/arch/arm/exception.c @@ -25,6 +25,39 @@ #define dbg_abort(...) #endif +struct ipc_state { + u32 mr[MR_TOTAL]; + unsigned int flags; +}; + +void ipc_save_state(struct ipc_state *state) +{ + unsigned int *mr0_current = KTCB_REF_MR0(current); + + BUG_ON(!mr0_current); + + /* Save primary message registers */ + for (int i = 0; i < MR_TOTAL; i++) + state->mr[i] = mr0_current[i]; + + /* Save ipc flags */ + state->flags = tcb_get_ipc_flags(current); +} + +void ipc_restore_state(struct ipc_state *state) +{ + unsigned int *mr0_current = KTCB_REF_MR0(current); + + BUG_ON(!mr0_current); + + /* Restore primary message registers */ + for (int i = 0; i < MR_TOTAL; i++) + mr0_current[i] = state->mr[i]; + + /* Restore ipc flags */ + tcb_set_ipc_flags(current, state->flags); +} + /* Send data fault ipc to the faulty task's pager */ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far) { @@ -32,7 +65,6 @@ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far) u32 mr[MR_TOTAL] = { [MR_TAG] = L4_IPC_TAG_PFAULT, [MR_SENDER] = current->tid }; fault_kdata_t *fault = (fault_kdata_t *)&mr[MR_UNUSED_START]; - unsigned int saved_flags; /* Fill in fault information to pass over during ipc */ fault->faulty_pc = faulty_pc; @@ -58,16 +90,12 @@ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far) ((unsigned long)&mr[0] - offsetof(syscall_context_t, r3)); - /* Save current ipc flags and set current flags to short ipc */ - saved_flags = tcb_get_ipc_flags(current); + /* Set current flags to short ipc */ tcb_set_ipc_flags(current, IPC_FLAGS_SHORT); /* Send ipc to the task's pager */ ipc_sendrecv(current->pagerid, current->pagerid, 0); - /* Restore ipc flags */ - tcb_set_ipc_flags(current, saved_flags); - /* * FIXME: CHECK TASK KILL REPLY !!! * Here, pager has handled the request and sent us back a message. @@ -87,15 +115,22 @@ int pager_pagein_request(unsigned long addr, unsigned long size, unsigned int fl { u32 abort; unsigned long npages = __pfn(align_up(size, PAGE_SIZE)); + struct ipc_state ipc_state; set_abort_type(abort, ARM_DABT); - printk("%s: Kernel initiating paging-in requests\n", __FUNCTION__); + // printk("%s: Kernel initiating paging-in requests\n", __FUNCTION__); + + /* Save current ipc state */ + ipc_save_state(&ipc_state); /* For every page to be used by the kernel send a page-in request */ for (int i = 0; i < npages; i++) fault_ipc_to_pager(0, abort, addr + (i * PAGE_SIZE)); + /* Restore ipc state */ + ipc_restore_state(&ipc_state); + return 0; }