/kernel/trunk/generic/include/syscall/syscall.h |
---|
51,6 → 51,8 |
SYS_IPC_FORWARD_FAST, |
SYS_IPC_WAIT, |
SYS_IPC_HANGUP, |
SYS_IPC_REGISTER_IRQ, |
SYS_IPC_UNREGISTER_IRQ, |
SYS_MAP_PHYSMEM, |
SYS_IOSPACE_ENABLE, |
SYSCALL_END |
/kernel/trunk/generic/include/ipc/sysipc.h |
---|
29,6 → 29,8 |
#ifndef __SYSIPC_H__ |
#define __SYSIPC_H__ |
#include <ipc/ipc.h> |
__native sys_ipc_call_sync_fast(__native phoneid, __native method, |
__native arg1, ipc_data_t *data); |
__native sys_ipc_call_sync(__native phoneid, ipc_data_t *question, |
43,6 → 45,9 |
__native sys_ipc_forward_fast(__native callid, __native phoneid, |
__native method, __native arg1); |
__native sys_ipc_hangup(int phoneid); |
__native sys_ipc_register_irq(__native irq); |
__native sys_ipc_unregister_irq(__native irq); |
void irq_ipc_bind_arch(__native irq); |
#endif |
/kernel/trunk/generic/include/ipc/ipc.h |
---|
43,6 → 43,7 |
* userspace, will be discarded */ |
#define IPC_CALL_FORWARDED (1<<3) /* Call was forwarded */ |
#define IPC_CALL_CONN_ME_TO (1<<4) /* Identify connect_me_to */ |
#define IPC_CALL_NOTIF (1<<5) /* Interrupt notification */ |
/* Flags for ipc_wait_for_call */ |
#define IPC_WAIT_NONBLOCKING 1 |
119,6 → 120,8 |
* is hung up |
*/ |
#define IPC_M_PHONE_HUNGUP 3 |
/** Interrupt notification */ |
#define IPC_M_INTERRUPT 4 |
/* Well-known methods */ |
154,6 → 157,9 |
link_t dispatched_calls; /* Should be hash table in the future */ |
link_t answers; /**< Answered calls */ |
SPINLOCK_DECLARE(irq_lock); |
link_t irq_notifs; /**< Notifications from IRQ handlers */ |
}; |
typedef enum { |
195,7 → 201,7 |
extern void ipc_phone_init(phone_t *phone); |
extern void ipc_phone_connect(phone_t *phone, answerbox_t *box); |
extern void ipc_call_free(call_t *call); |
extern call_t * ipc_call_alloc(void); |
extern call_t * ipc_call_alloc(int flags); |
extern void ipc_answerbox_init(answerbox_t *box); |
extern void ipc_call_static_init(call_t *call); |
extern void task_print_list(void); |
204,6 → 210,11 |
extern int ipc_phone_hangup(phone_t *phone); |
extern void ipc_backsend_err(phone_t *phone, call_t *call, __native err); |
extern int ipc_irq_register(answerbox_t *box, int irq); |
extern void ipc_irq_send_notif(int irq); |
extern void ipc_irq_unregister(answerbox_t *box, int irq); |
extern answerbox_t *ipc_phone_0; |
#endif |
/kernel/trunk/generic/include/errno.h |
---|
40,5 → 40,6 |
#define EHANGUP -7 /* Answerbox closed connection, call sys_ipc_hangup |
* to close the connection. Used by answerbox |
* to close the connection. */ |
#define EEXISTS -8 /* Entry already exists */ |
#endif |
/kernel/trunk/generic/src/syscall/syscall.c |
---|
96,6 → 96,8 |
sys_ipc_forward_fast, |
sys_ipc_wait_for_call, |
sys_ipc_hangup, |
sys_ipc_register_irq, |
sys_ipc_unregister_irq, |
/* DDI related syscalls. */ |
sys_physmem_map, |
/kernel/trunk/generic/src/ipc/sysipc.c |
---|
36,8 → 36,8 |
#include <ipc/ipc.h> |
#include <ipc/sysipc.h> |
#include <ipc/ipcrsc.h> |
#include <arch/interrupt.h> |
#include <print.h> |
#include <arch.h> |
#include <proc/thread.h> |
274,7 → 274,7 |
GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL); |
call = ipc_call_alloc(); |
call = ipc_call_alloc(0); |
IPC_SET_METHOD(call->data, method); |
IPC_SET_ARG1(call->data, arg1); |
IPC_SET_ARG2(call->data, arg2); |
302,7 → 302,7 |
GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL); |
call = ipc_call_alloc(); |
call = ipc_call_alloc(0); |
copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args)); |
if (!(res=request_preprocess(call))) |
ipc_call(phone, call); |
441,6 → 441,14 |
if (!call) |
return 0; |
if (call->flags & IPC_CALL_NOTIF) { |
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC)); |
STRUCT_TO_USPACE(&calldata->args, &call->data.args); |
ipc_call_free(call); |
return ((__native)call) | IPC_CALLID_NOTIFICATION; |
} |
if (call->flags & IPC_CALL_ANSWERED) { |
process_answer(call); |
467,3 → 475,24 |
STRUCT_TO_USPACE(calldata, &call->data); |
return (__native)call; |
} |
/** Connect irq handler to task */ |
__native sys_ipc_register_irq(__native irq) |
{ |
if (irq >= IRQ_COUNT) |
return -ELIMIT; |
irq_ipc_bind_arch(irq); |
return ipc_irq_register(&TASK->answerbox, irq); |
} |
/* Disconnect irq handler from task */ |
__native sys_ipc_unregister_irq(__native irq) |
{ |
if (irq >= IRQ_COUNT) |
return -ELIMIT; |
ipc_irq_unregister(&TASK->answerbox, irq); |
return 0; |
} |
/kernel/trunk/generic/src/ipc/ipc.c |
---|
43,6 → 43,7 |
#include <print.h> |
#include <proc/thread.h> |
#include <arch/interrupt.h> |
/* Open channel that is assigned automatically to new tasks */ |
answerbox_t *ipc_phone_0 = NULL; |
49,6 → 50,14 |
static slab_cache_t *ipc_call_slab; |
typedef struct { |
SPINLOCK_DECLARE(lock); |
answerbox_t *box; |
} ipc_irq_t; |
static ipc_irq_t *irq_conns = NULL; |
static int irq_conns_size; |
/* Initialize new call */ |
static void _ipc_call_init(call_t *call) |
{ |
61,12 → 70,14 |
* |
* The call is initialized, so that the reply will be directed |
* to TASK->answerbox |
* |
* @param flags Parameters for slab_alloc (ATOMIC, etc.) |
*/ |
call_t * ipc_call_alloc(void) |
call_t * ipc_call_alloc(int flags) |
{ |
call_t *call; |
call = slab_alloc(ipc_call_slab, 0); |
call = slab_alloc(ipc_call_slab, flags); |
_ipc_call_init(call); |
return call; |
90,11 → 101,13 |
void ipc_answerbox_init(answerbox_t *box) |
{ |
spinlock_initialize(&box->lock, "ipc_box_lock"); |
spinlock_initialize(&box->irq_lock, "ipc_box_irqlock"); |
waitq_initialize(&box->wq); |
list_initialize(&box->connected_phones); |
list_initialize(&box->calls); |
list_initialize(&box->dispatched_calls); |
list_initialize(&box->answers); |
list_initialize(&box->irq_notifs); |
box->task = TASK; |
} |
261,7 → 274,7 |
phone->callee = NULL; |
spinlock_unlock(&box->lock); |
call = ipc_call_alloc(); |
call = ipc_call_alloc(0); |
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP); |
call->flags |= IPC_CALL_DISCARD_ANSWER; |
_ipc_call(phone, box, call); |
301,6 → 314,7 |
call_t * ipc_wait_for_call(answerbox_t *box, int flags) |
{ |
call_t *request; |
ipl_t ipl; |
restart: |
if (flags & IPC_WAIT_NONBLOCKING) { |
310,7 → 324,16 |
waitq_sleep(&box->wq); |
spinlock_lock(&box->lock); |
if (!list_empty(&box->answers)) { |
if (!list_empty(&box->irq_notifs)) { |
ipl = interrupts_disable(); |
spinlock_lock(&box->irq_lock); |
request = list_get_instance(box->answers.next, call_t, list); |
list_remove(&request->list); |
spinlock_unlock(&box->irq_lock); |
interrupts_restore(ipl); |
} else if (!list_empty(&box->answers)) { |
/* Handle asynchronous answers */ |
request = list_get_instance(box->answers.next, call_t, list); |
list_remove(&request->list); |
333,15 → 356,6 |
return request; |
} |
/** Initilize ipc subsystem */ |
void ipc_init(void) |
{ |
ipc_call_slab = slab_cache_create("ipc_call", |
sizeof(call_t), |
0, |
NULL, NULL, 0); |
} |
/** Answer all calls from list with EHANGUP msg */ |
static void ipc_cleanup_call_list(link_t *lst) |
{ |
356,6 → 370,26 |
} |
} |
/** Disconnect all irq's notifications |
* |
* TODO: It may be better to do some linked list, so that |
* we wouldn't need to go through whole array every cleanup |
*/ |
static void ipc_irq_cleanup(answerbox_t *box) |
{ |
int i; |
ipl_t ipl; |
for (i=0; i < irq_conns_size; i++) { |
ipl = interrupts_disable(); |
spinlock_lock(&irq_conns[i].lock); |
if (irq_conns[i].box == box) |
irq_conns[i].box = NULL; |
spinlock_unlock(&irq_conns[i].lock); |
interrupts_restore(ipl); |
} |
} |
/** Cleans up all IPC communication of the given task |
* |
* |
370,6 → 404,9 |
for (i=0;i < IPC_MAX_PHONES; i++) |
ipc_phone_hangup(&task->phones[i]); |
/* Disconnect all connected irqs */ |
ipc_irq_cleanup(&task->answerbox); |
/* Disconnect all phones connected to our answerbox */ |
restart_phones: |
spinlock_lock(&task->answerbox.lock); |
405,3 → 442,89 |
ipc_call_free(call); |
} |
} |
/** Initialize table of interrupt handlers */ |
static void ipc_irq_make_table(int irqcount) |
{ |
int i; |
irq_conns_size = irqcount; |
irq_conns = malloc(irqcount * (sizeof(*irq_conns)), 0); |
for (i=0; i < irqcount; i++) { |
spinlock_initialize(&irq_conns[i].lock, "irq_ipc_lock"); |
irq_conns[i].box = NULL; |
} |
} |
void ipc_irq_unregister(answerbox_t *box, int irq) |
{ |
ipl_t ipl; |
ipl = interrupts_disable(); |
spinlock_lock(&irq_conns[irq].lock); |
if (irq_conns[irq].box == box) |
irq_conns[irq].box = NULL; |
spinlock_unlock(&irq_conns[irq].lock); |
interrupts_restore(ipl); |
} |
/** Register an answerbox as a receiving end of interrupts notifications */ |
int ipc_irq_register(answerbox_t *box, int irq) |
{ |
ipl_t ipl; |
ASSERT(irq_conns); |
ipl = interrupts_disable(); |
spinlock_lock(&irq_conns[irq].lock); |
if (irq_conns[irq].box) { |
spinlock_unlock(&irq_conns[irq].lock); |
interrupts_restore(ipl); |
return EEXISTS; |
} |
irq_conns[irq].box = box; |
spinlock_unlock(&irq_conns[irq].lock); |
interrupts_restore(ipl); |
return 0; |
} |
/** Notify process that an irq had happend |
* |
* We expect interrupts to be disabled |
*/ |
void ipc_irq_send_notif(int irq) |
{ |
call_t *call; |
ASSERT(irq_conns); |
spinlock_lock(&irq_conns[irq].lock); |
if (irq_conns[irq].box) { |
call = ipc_call_alloc(FRAME_ATOMIC); |
call->flags |= IPC_CALL_NOTIF; |
IPC_SET_METHOD(call->data, IPC_M_INTERRUPT); |
IPC_SET_ARG1(call->data, irq); |
spinlock_lock(&irq_conns[irq].box->irq_lock); |
list_append(&call->list, &irq_conns[irq].box->irq_notifs); |
spinlock_unlock(&irq_conns[irq].box->irq_lock); |
waitq_wakeup(&irq_conns[irq].box->wq, 0); |
} |
spinlock_unlock(&irq_conns[irq].lock); |
} |
/** Initilize ipc subsystem */ |
void ipc_init(void) |
{ |
ipc_call_slab = slab_cache_create("ipc_call", |
sizeof(call_t), |
0, |
NULL, NULL, 0); |
ipc_irq_make_table(IRQ_COUNT); |
} |
/kernel/trunk/arch/amd64/src/interrupt.c |
---|
44,6 → 44,8 |
#include <proc/task.h> |
#include <synch/spinlock.h> |
#include <arch/ddi/ddi.h> |
#include <interrupt.h> |
#include <ipc/sysipc.h> |
void print_info_errcode(int n, istate_t *istate) |
{ |
153,3 → 155,18 |
panic("no eoi_function\n"); |
} |
static void ipc_int(int n, istate_t *istate) |
{ |
trap_virtual_eoi(); |
ipc_irq_send_notif(n-IVT_IRQBASE); |
} |
/* Reregister irq to be IPC-ready */ |
void irq_ipc_bind_arch(__native irq) |
{ |
if (irq == IRQ_CLK) |
return; |
exc_register(IVT_IRQBASE+irq, "ipc_int", ipc_int); |
} |
/kernel/trunk/arch/mips32/include/interrupt.h |
---|
33,6 → 33,7 |
#define IVT_ITEMS 40 |
#define INT_OFFSET 32 |
#define IRQ_COUNT 8 |
#define int_register(it, name, handler) exc_register(((it)+INT_OFFSET),name,handler) |
/kernel/trunk/arch/mips32/src/interrupt.c |
---|
34,6 → 34,8 |
#include <time/clock.h> |
#include <arch/drivers/arc.h> |
#include <ipc/sysipc.h> |
/** Disable interrupts. |
* |
* @return Old interrupt priority level. |
83,11 → 85,13 |
static void swint0(int n, istate_t *istate) |
{ |
cp0_cause_write(cp0_cause_read() & ~(1 << 8)); /* clear SW0 interrupt */ |
ipc_irq_send_notif(0); |
} |
static void swint1(int n, istate_t *istate) |
{ |
cp0_cause_write(cp0_cause_read() & ~(1 << 9)); /* clear SW1 interrupt */ |
ipc_irq_send_notif(1); |
} |
/* Initialize basic tables for exception dispatching */ |
97,3 → 101,19 |
int_register(0, "swint0", swint0); |
int_register(1, "swint1", swint1); |
} |
#include <print.h> |
static void ipc_int(int n, istate_t *istate) |
{ |
ipc_irq_send_notif(n-INT_OFFSET); |
} |
/* Reregister irq to be IPC-ready */ |
void irq_ipc_bind_arch(__native irq) |
{ |
/* Do not allow to redefine timer */ |
/* Swint0, Swint1 are already handled */ |
if (irq == TIMER_IRQ || irq < 2) |
return; |
int_register(irq, "ipc_int", ipc_int); |
} |
/kernel/trunk/arch/ia32/src/interrupt.c |
---|
43,6 → 43,8 |
#include <proc/task.h> |
#include <synch/spinlock.h> |
#include <arch/ddi/ddi.h> |
#include <ipc/sysipc.h> |
#include <interrupt.h> |
/* |
* Interrupt and exception dispatching. |
184,3 → 186,18 |
panic("no eoi_function\n"); |
} |
static void ipc_int(int n, istate_t *istate) |
{ |
trap_virtual_eoi(); |
ipc_irq_send_notif(n-IVT_IRQBASE); |
} |
/* Reregister irq to be IPC-ready */ |
void irq_ipc_bind_arch(__native irq) |
{ |
if (irq == IRQ_CLK) |
return; |
exc_register(IVT_IRQBASE+irq, "ipc_int", ipc_int); |
} |