From 6e40a2b60133d1715249488c7f0bd014384ec5c0 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sat, 28 Nov 2009 19:13:23 +0200 Subject: [PATCH] Preliminary irq registration call + irq capability checking Need to add irqctrl capabilities and irq bits to device memory caps. Also need to initialize irq field of devmem caps. --- include/l4/api/capability.h | 5 +- include/l4/api/errno.h | 1 + include/l4/drivers/irq/pl190/pl190_vic.h | 20 +-- include/l4/generic/cap-types.h | 25 ++-- include/l4/generic/capability.h | 3 + include/l4/generic/container.h | 3 +- include/l4/generic/irq.h | 41 +++---- include/l4/generic/tcb.h | 5 +- include/l4/glue/arm/message.h | 5 +- include/l4/platform/pb926/irq.h | 55 ++++++--- src/api/ipc.c | 4 +- src/drivers/irq/pl190/pl190_vic.c | 31 +++-- src/generic/capability.c | 149 +++++++++++++++++++++++ src/generic/irq.c | 114 +++++++++++++---- src/generic/resource.c | 4 +- src/generic/tcb.c | 17 ++- src/platform/pb926/irq.c | 8 +- 17 files changed, 380 insertions(+), 110 deletions(-) diff --git a/include/l4/api/capability.h b/include/l4/api/capability.h index 4b58399..229b475 100644 --- a/include/l4/api/capability.h +++ b/include/l4/api/capability.h @@ -89,8 +89,9 @@ struct capability { /* Use count of resource */ unsigned long used; - /* User attributes on capability such as device type, irqno */ - u32 uattr[2]; + /* Device attributes, if this is a device. */ + unsigned int attr; + l4id_t irq; }; #endif /* __API_CAPABILITY_H__ */ diff --git a/include/l4/api/errno.h b/include/l4/api/errno.h index fc6c1c9..6d50a54 100644 --- a/include/l4/api/errno.h +++ b/include/l4/api/errno.h @@ -139,5 +139,6 @@ #define EACTIVE 132 /* Task active */ #define ENOIPC 133 /* General IPC error */ #define ENOCAP 134 /* None or insufficient capability */ +#define ENOUTCB 135 /* Task has no utcb set up */ #endif /* __ERRNO_H__ */ diff --git a/include/l4/drivers/irq/pl190/pl190_vic.h b/include/l4/drivers/irq/pl190/pl190_vic.h index 65adb79..fc13458 100644 --- a/include/l4/drivers/irq/pl190/pl190_vic.h +++ b/include/l4/drivers/irq/pl190/pl190_vic.h @@ -9,6 +9,7 @@ #define __PL190_VIC_H__ #include INC_PLAT(platform.h) +#include INC_ARCH(types.h) #define PL190_BASE PLATFORM_IRQCTRL_BASE #define PL190_SIC_BASE PLATFORM_SIRQCTRL_BASE @@ -42,15 +43,16 @@ #define PL190_SIC_PICENCLR (PL190_SIC_BASE + 0x24) void pl190_vic_init(void); -void pl190_ack_irq(int irq); -void pl190_mask_irq(int irq); -void pl190_unmask_irq(int irq); -int pl190_read_irq(void); +void pl190_ack_irq(l4id_t irq); +void pl190_mask_irq(l4id_t irq); +void pl190_unmask_irq(l4id_t irq); +l4id_t pl190_read_irq(void); -int pl190_sic_read_irq(void); -void pl190_sic_mask_irq(int irq); -void pl190_sic_mask_irq(int irq); -void pl190_sic_ack_irq(int irq); -void pl190_sic_unmask_irq(int irq); +l4id_t pl190_sic_read_irq(void); +void pl190_sic_mask_irq(l4id_t irq); +void pl190_sic_mask_irq(l4id_t irq); +void pl190_sic_ack_irq(l4id_t irq); +void pl190_sic_unmask_irq(l4id_t irq); void pl190_sic_init(void); + #endif /* __PL190_VIC_H__ */ diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index 118f9b3..789cba2 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -15,7 +15,7 @@ #define CAP_TYPE_MAP_PHYSMEM (1 << 2) #define CAP_TYPE_MAP_VIRTMEM (1 << 3) #define CAP_TYPE_IPC (1 << 4) -#define CAP_TYPE_SCHED (1 << 5) +#define CAP_TYPE_IRQCTRL (1 << 5) #define CAP_TYPE_UMUTEX (1 << 6) #define CAP_TYPE_QUANTITY (1 << 7) #define CAP_TYPE_CAP (1 << 8) @@ -52,17 +52,16 @@ #define CAP_DEVNUM_MASK 0xFFFF0000 #define CAP_DEVNUM_SHIFT 16 -#define cap_is_devmem(c) (c)->uattr[0] +#define cap_is_devmem(c) ((c)->attr) #define cap_set_devtype(c, devtype) \ - {(c)->uattr[0] &= ~CAP_DEVTYPE_MASK; \ - (c)->uattr[0] |= CAP_DEVTYPE_MASK & devtype;} + {(c)->attr &= ~CAP_DEVTYPE_MASK; \ + (c)->attr |= CAP_DEVTYPE_MASK & devtype;} #define cap_set_devnum(c, devnum) \ - {(c)->uattr[0] &= ~CAP_DEVNUM_MASK; \ - (c)->uattr[0] |= CAP_DEVNUM_MASK & devnum;} + {(c)->attr &= ~CAP_DEVNUM_MASK; \ + (c)->attr |= CAP_DEVNUM_MASK & devnum;} #define cap_devnum(c) \ - (((c)->uattr[0] & CAP_DEVNUM_MASK) >> CAP_DEVNUM_SHIFT) -#define cap_devtype(c) ((c)->uattr[0] & CAP_DEVTYPE_MASK) -#define cap_irqno(c) ((c)->uattr[1]) + (((c)->attr & CAP_DEVNUM_MASK) >> CAP_DEVNUM_SHIFT) +#define cap_devtype(c) ((c)->attr & CAP_DEVTYPE_MASK) /* * Access permissions @@ -103,6 +102,14 @@ #define CAP_MAP_UNMAP (1 << 5) #define CAP_MAP_UTCB (1 << 6) +/* + * IRQ Control capability + * + * This is a common one and it applies to both + * CAP_TYPE_IRQCTRL and CAP_TYPE_MAP_PHYSMEM + */ +#define CAP_IRQCTRL_REGISTER (1 << 7) + /* Ipc capability */ #define CAP_IPC_SEND (1 << 0) #define CAP_IPC_RECV (1 << 1) diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index f25a44c..e11a0bc 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -104,4 +104,7 @@ int cap_ipc_check(l4id_t to, l4id_t from, int cap_cap_check(struct ktcb *task, unsigned int req, unsigned int flags); int cap_mutex_check(unsigned long mutex_address, int mutex_op); +int cap_irq_check(struct ktcb *registrant, unsigned int req, + unsigned int flags, l4id_t irq); + #endif /* __GENERIC_CAPABILITY_H__ */ diff --git a/include/l4/generic/container.h b/include/l4/generic/container.h index 08e837b..e192acb 100644 --- a/include/l4/generic/container.h +++ b/include/l4/generic/container.h @@ -60,7 +60,8 @@ struct cap_info { unsigned long start; unsigned long end; unsigned long size; - unsigned int uattr[2]; /* User-level attributes (like device types) */ + unsigned int attr; /* Attributes (like device types) */ + l4id_t irq; }; diff --git a/include/l4/generic/irq.h b/include/l4/generic/irq.h index 9504758..e8a70d5 100644 --- a/include/l4/generic/irq.h +++ b/include/l4/generic/irq.h @@ -8,17 +8,18 @@ #include #include INC_PLAT(irq.h) +#include INC_ARCH(types.h) /* Represents none or spurious irq */ -#define IRQ_NIL (-1) +#define IRQ_NIL 0xFFFFFFFF /* Successful irq handling state */ #define IRQ_HANDLED 0 -typedef void (*irq_op_t)(int irq); +typedef void (*irq_op_t)(l4id_t irq); struct irq_chip_ops { void (*init)(void); - int (*read_irq)(void); + l4id_t (*read_irq)(void); irq_op_t ack_and_mask; irq_op_t unmask; }; @@ -27,16 +28,24 @@ struct irq_chip { char name[32]; int level; /* Cascading level */ int cascade; /* The irq that lower chip uses on this chip */ - int offset; /* The global offset for this irq chip */ + int start; /* The global irq offset for this chip */ + int end; /* End of this chip's irqs */ struct irq_chip_ops ops; }; -typedef int (*irq_handler_t)(void); +struct irq_desc; +typedef int (*irq_handler_t)(struct irq_desc *irq_desc); struct irq_desc { char name[8]; struct irq_chip *chip; - /* TODO: This could be a list for multiple handlers */ + /* Thread registered for this irq */ + struct ktcb *irq_thread; + + /* Notification slot for this irq */ + int task_notify_slot; + + /* NOTE: This could be a list for multiple handlers for shared irqs */ irq_handler_t handler; }; @@ -48,7 +57,7 @@ static inline void irq_enable(int irq_index) struct irq_desc *this_irq = irq_desc_array + irq_index; struct irq_chip *this_chip = this_irq->chip; - this_chip->ops.unmask(irq_index - this_chip->offset); + this_chip->ops.unmask(irq_index - this_chip->start); } static inline void irq_disable(int irq_index) @@ -56,23 +65,11 @@ static inline void irq_disable(int irq_index) struct irq_desc *this_irq = irq_desc_array + irq_index; struct irq_chip *this_chip = this_irq->chip; - this_chip->ops.ack_and_mask(irq_index - this_chip->offset); + this_chip->ops.ack_and_mask(irq_index - this_chip->start); } -static inline void register_irq(char *name, int irq_index, irq_handler_t handler) -{ - struct irq_desc *this_desc = irq_desc_array + irq_index; - struct irq_chip *current_chip = irq_chip_array; - - strncpy(&this_desc->name[0], name, sizeof(this_desc->name)); - - for (int i = 0; i < IRQ_CHIPS_MAX; i++) - if (irq_index <= current_chip->offset) { - this_desc->chip = current_chip; - break; - } - this_desc->handler = handler; -} +int irq_register(struct ktcb *task, int notify_slot, + l4id_t irq_index, irq_handler_t handler); void do_irq(void); void irq_controllers_init(void); diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index b160d75..f65ebfd 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -132,6 +132,9 @@ struct ktcb { struct waitqueue_head wqh_send; l4id_t expected_sender; + /* Waitqueue for notifiactions */ + struct waitqueue_head wqh_notify; + /* Waitqueue for pagers to wait for task states */ struct waitqueue_head wqh_pager; @@ -180,7 +183,7 @@ void ktcb_list_remove(struct ktcb *task, struct ktcb_list *ktcb_list); void ktcb_list_add(struct ktcb *new, struct ktcb_list *ktcb_list); void init_ktcb_list(struct ktcb_list *ktcb_list); void task_update_utcb(struct ktcb *task); -int tcb_check_and_lazy_map_utcb(struct ktcb *task); +int tcb_check_and_lazy_map_utcb(struct ktcb *task, int page_in); #endif /* __TCB_H__ */ diff --git a/include/l4/glue/arm/message.h b/include/l4/glue/arm/message.h index eafcc69..0d9a8c8 100644 --- a/include/l4/glue/arm/message.h +++ b/include/l4/glue/arm/message.h @@ -78,12 +78,15 @@ #include INC_GLUE(memlayout.h) +#define TASK_NOTIFY_SLOTS 8 +#define TASK_NOTIFY_MAX 0xFF + #if !defined (__ASSEMBLY__) struct utcb { u32 mr[MR_TOTAL]; /* MRs that are mapped to real registers */ u32 saved_tag; /* Saved tag field for stacked ipcs */ u32 saved_sender; /* Saved sender field for stacked ipcs */ - u8 notify[8]; /* Notification slots */ + u8 notify[TASK_NOTIFY_SLOTS]; /* Notification slots */ u32 mr_rest[MR_REST]; /* Complete the utcb for up to 64 words */ }; #endif diff --git a/include/l4/platform/pb926/irq.h b/include/l4/platform/pb926/irq.h index ecfad92..0a95b51 100644 --- a/include/l4/platform/pb926/irq.h +++ b/include/l4/platform/pb926/irq.h @@ -4,24 +4,47 @@ #define IRQ_CHIPS_MAX 2 #define IRQS_MAX 64 -/* IRQ indices. */ -#define IRQ_TIMER01 4 -#define IRQ_TIMER23 5 -#define IRQ_RTC 10 -#define IRQ_UART0 12 -#define IRQ_UART1 13 -#define IRQ_UART2 14 -#define IRQ_SIC 31 +/* Global irq numbers */ +#define IRQ_TIMER01 (VIC_IRQ_TIMER01 + VIC_CHIP_OFFSET) +#define IRQ_TIMER23 (VIC_IRQ_TIMER23 + VIC_CHIP_OFFSET) +#define IRQ_RTC (VIC_IRQ_RTC + VIC_CHIP_OFFSET) +#define IRQ_UART0 (VIC_IRQ_UART0 + VIC_CHIP_OFFSET) +#define IRQ_UART1 (VIC_IRQ_UART1 + VIC_CHIP_OFFSET) +#define IRQ_UART2 (VIC_IRQ_UART2 + VIC_CHIP_OFFSET) +#define IRQ_SIC (VIC_IRQ_SIC + VIC_CHIP_OFFSET) -/* Cascading definitions */ +#define IRQ_SICSWI (SIC_IRQ_SWI + SIC_CHIP_OFFSET) +#define IRQ_UART3 (SIC_IRQ_UART3 + SIC_CHIP_OFFSET) -#define PIC_IRQS_MAX 31 /* Total irqs on PIC */ -/* The local irq line of the dummy peripheral on this chip */ -#define LOCALIRQ_DUMMY 15 -/* The irq index offset of this chip, is the maximum of previous chip + 1 */ -#define SIRQ_CHIP_OFFSET (PIC_IRQS_MAX + 1) -/* The global irq number of dummy is the local irq line + it's chip offset */ -#define IRQ_DUMMY (LOCALIRQ_DUMMY + SIRQ_CHIP_OFFSET) +/* Vectored Interrupt Controller local IRQ numbers */ +#define VIC_IRQ_TIMER01 4 +#define VIC_IRQ_TIMER23 5 +#define VIC_IRQ_RTC 10 +#define VIC_IRQ_UART0 12 +#define VIC_IRQ_UART1 13 +#define VIC_IRQ_UART2 14 +#define VIC_IRQ_SIC 31 + +/* Secondary Interrupt controller local IRQ numbers */ +#define SIC_IRQ_SWI 0 +#define SIC_IRQ_UART3 6 + +/* Maximum irqs on VIC and SIC */ +#define VIC_IRQS_MAX 32 +#define SIC_IRQS_MAX 32 + + +/* + * Globally unique irq chip offsets: + * + * A global irq number is calculated as + * chip_offset + local_irq_offset. + * + * This way, the global irq number uniquely represents + * an irq on any irq chip. + */ +#define VIC_CHIP_OFFSET 0 +#define SIC_CHIP_OFFSET 32 #endif /* __PLATFORM_IRQ_H__ */ diff --git a/src/api/ipc.c b/src/api/ipc.c index 799364f..6e91366 100644 --- a/src/api/ipc.c +++ b/src/api/ipc.c @@ -41,9 +41,9 @@ int ipc_full_copy(struct ktcb *to, struct ktcb *from) return ret; /* Check that utcb memory accesses won't fault us */ - if ((ret = tcb_check_and_lazy_map_utcb(to)) < 0) + if ((ret = tcb_check_and_lazy_map_utcb(to, 1)) < 0) return ret; - if ((ret = tcb_check_and_lazy_map_utcb(from)) < 0) + if ((ret = tcb_check_and_lazy_map_utcb(from, 1)) < 0) return ret; /* Directly copy from one utcb to another */ diff --git a/src/drivers/irq/pl190/pl190_vic.c b/src/drivers/irq/pl190/pl190_vic.c index 2b8a310..769dec4 100644 --- a/src/drivers/irq/pl190/pl190_vic.c +++ b/src/drivers/irq/pl190/pl190_vic.c @@ -10,6 +10,7 @@ #include #include +#include /* FIXME: Fix the stupid uart driver and change to single definition of this! */ #if defined(read) @@ -28,13 +29,16 @@ : clrbit(bitvect, (base + reg))) /* Returns the irq number on this chip converting the irq bitvector */ -int pl190_read_irq(void) +l4id_t pl190_read_irq(void) { - /* This also correctly returns a negative value for a spurious irq. */ - return 31 - __clz(read(PL190_VIC_IRQSTATUS)); + l4id_t irq; + if ((irq =__clz(read(PL190_VIC_IRQSTATUS)))) + return irq; + else + return IRQ_NIL; } -void pl190_mask_irq(int irq) +void pl190_mask_irq(l4id_t irq) { /* Reading WO registers blows QEMU/PB926. * setbit((1 << irq), PL190_VIC_INTENCLEAR); */ @@ -42,32 +46,37 @@ void pl190_mask_irq(int irq) } /* Ack is same as mask */ -void pl190_ack_irq(int irq) +void pl190_ack_irq(l4id_t irq) { pl190_mask_irq(irq); } -void pl190_unmask_irq(int irq) +void pl190_unmask_irq(l4id_t irq) { setbit(1 << irq, PL190_VIC_INTENABLE); } -int pl190_sic_read_irq(void) +l4id_t pl190_sic_read_irq(void) { - return 32 - __clz(read(PL190_SIC_STATUS)); + l4id_t irq; + + if ((irq =__clz(read(PL190_SIC_STATUS)))) + return irq; + else + return IRQ_NIL; } -void pl190_sic_mask_irq(int irq) +void pl190_sic_mask_irq(l4id_t irq) { write(1 << irq, PL190_SIC_ENCLR); } -void pl190_sic_ack_irq(int irq) +void pl190_sic_ack_irq(l4id_t irq) { pl190_sic_mask_irq(irq); } -void pl190_sic_unmask_irq(int irq) +void pl190_sic_unmask_irq(l4id_t irq) { setbit(1 << irq, PL190_SIC_ENSET); } diff --git a/src/generic/capability.c b/src/generic/capability.c index 2a128b6..360131b 100644 --- a/src/generic/capability.c +++ b/src/generic/capability.c @@ -15,6 +15,7 @@ #include #include #include +#include #include INC_GLUE(message.h) #include INC_GLUE(ipc.h) @@ -642,6 +643,119 @@ struct capability *cap_match_mem(struct capability *cap, return cap; } +struct sys_irqctrl_args { + struct ktcb *registrant; + unsigned int req; + unsigned int flags; + l4id_t irq; +}; + +/* + * CAP_TYPE_MAP already matched upon entry. + * + * Match only device-specific details, e.g. irq registration + * capability + */ +struct capability *cap_match_devmem(struct capability *cap, + void *args_ptr) +{ + struct sys_irqctrl_args *args = args_ptr; + struct ktcb *target = args->registrant; + unsigned int perms; + + /* It must be a physmem type */ + if (cap_type(cap) != CAP_TYPE_MAP_PHYSMEM) + return 0; + + /* It must be a device */ + if (!cap_is_devmem(cap)) + return 0; + + /* Irq numbers should match */ + if (cap->irq != args->irq) + return 0; + + /* Check permissions, we only check irq specific */ + switch (args->req) { + case IRQ_CONTROL_REGISTER: + perms = CAP_IRQCTRL_REGISTER; + if ((cap->access & perms) != perms) + return 0; + break; + default: + /* Anything else is an invalid/unrecognised argument */ + return 0; + } + + /* + * Check that irq registration to target is covered + * by the capability containment rules. + */ + switch (cap_rtype(cap)) { + case CAP_RTYPE_THREAD: + if (target->tid != cap->resid) + return 0; + break; + case CAP_RTYPE_SPACE: + if (target->space->spid != cap->resid) + return 0; + break; + case CAP_RTYPE_CONTAINER: + if (target->container->cid != cap->resid) + return 0; + break; + default: + BUG(); /* Unknown cap type is a bug */ + } + + return cap; +} + +/* + * CAP_TYPE_IRQCTRL already matched + */ +struct capability *cap_match_irqctrl(struct capability *cap, + void *args_ptr) +{ + struct sys_irqctrl_args *args = args_ptr; + struct ktcb *target = args->registrant; + + /* Check operation privileges */ + switch (args->req) { + case IRQ_CONTROL_REGISTER: + if (!(cap->access & CAP_IRQCTRL_REGISTER)) + return 0; + break; + default: + /* We refuse to accept anything else */ + return 0; + } + + /* + * Target thread is the thread that is going to + * handle the irqs. Check if capability matches + * the target in any of its containment level. + */ + switch (cap_rtype(cap)) { + case CAP_RTYPE_THREAD: + if (target->tid != cap->resid) + return 0; + break; + case CAP_RTYPE_SPACE: + if (target->space->spid != cap->resid) + return 0; + break; + case CAP_RTYPE_CONTAINER: + if (target->container->cid != cap->resid) + return 0; + break; + default: + BUG(); /* Unknown cap type is a bug */ + } + + return cap; +} + #if defined(CONFIG_CAPABILITIES) int cap_mutex_check(unsigned long mutex_address, int mutex_op) { @@ -761,6 +875,34 @@ int cap_thread_check(struct ktcb *task, return 0; } + +int cap_irq_check(struct ktcb *registrant, unsigned int req, + unsigned int flags, l4id_t irq) +{ + struct sys_irqctrl_args args = { + .registrant = registrant, + .req = req, + .flags = flags, + .irq = irq, + }; + + /* Find the irq control capability of caller */ + if (!(cap_find(current, cap_match_irqctrl, + &args, CAP_TYPE_IRQCTRL))) + return -ENOCAP; + + /* + * Find the device capability and + * check that it allows irq registration + */ + if (!(cap_find(current, cap_match_devmem, + &args, CAP_TYPE_MAP_PHYSMEM))) + return -ENOCAP; + + return 0; +} + + #else /* Meaning !CONFIG_CAPABILITIES */ int cap_mutex_check(unsigned long mutex_address, int mutex_op) { @@ -795,4 +937,11 @@ int cap_thread_check(struct ktcb *task, { return 0; } + +int cap_irq_check(struct ktcb *registrant, unsigned int req, + unsigned int flags, l4id_t irq) +{ + return 0; +} + #endif /* End of !CONFIG_CAPABILITIES */ diff --git a/src/generic/irq.c b/src/generic/irq.c index 5ad1814..04dfaa2 100644 --- a/src/generic/irq.c +++ b/src/generic/irq.c @@ -1,9 +1,8 @@ /* - * Kernel irq handling (core irqs like timer). Also hope to add thread-level - * irq handling in the future. - * - * Copyright (C) 2007 Bahadir Balban + * Kernel irq handling (core irqs like timer). + * Also thread-level irq handling. * + * Copyright (C) 2007 - 2009 Bahadir Balban */ #include #include @@ -16,7 +15,33 @@ #include INC_PLAT(irq.h) #include INC_ARCH(exception.h) -/* This enables the lower chip on the current chip, if such chaining exists. */ +/* + * Registers a userspace thread as an irq handler. + */ +int irq_register(struct ktcb *task, int notify_slot, + l4id_t irq_index, irq_handler_t handler) +{ + struct irq_desc *this_desc = irq_desc_array + irq_index; + struct irq_chip *current_chip = irq_chip_array; + + for (int i = 0; i < IRQ_CHIPS_MAX; i++) { + if (irq_index >= current_chip->start && + irq_index < current_chip->end) { + this_desc->chip = current_chip; + break; + } + } + /* Setup the handler */ + this_desc->handler = handler; + + /* Setup the slot to notify the task */ + this_desc->task_notify_slot = notify_slot; + + return 0; +} + + +/* If there is cascading, enable it. */ static inline void cascade_irq_chip(struct irq_chip *this_chip) { if (this_chip->cascade >= 0) { @@ -31,51 +56,86 @@ void irq_controllers_init(void) for (int i = 0; i < IRQ_CHIPS_MAX; i++) { this_chip = irq_chip_array + i; - /* Initialise the irq chips (e.g. reset all registers) */ + + /* Initialise the irq chip (e.g. reset all registers) */ this_chip->ops.init(); - /* Enable cascaded irqs if needed */ + + /* Enable cascaded irq on this chip if it exists */ cascade_irq_chip(this_chip); } } -int global_irq_index(void) + +/* + * Finds the global irq number by looping over irq chips. + * + * Global irq number = + * Unique irq chip_offset defined by us + irq number local to chip + */ +l4id_t global_irq_index(void) { struct irq_chip *this_chip; - int irq_index = 0; + l4id_t irq_index = 0; - /* Loop over irq chips from top to bottom until - * the actual irq on the lowest chip is found */ + /* + * Loop over all chips, starting from the top + * (i.e. nearest to the cpu) + */ for (int i = 0; i < IRQ_CHIPS_MAX; i++) { + + /* Get the chip */ this_chip = irq_chip_array + i; - BUG_ON((irq_index = this_chip->ops.read_irq()) < 0); - if (irq_index != this_chip->cascade) { - irq_index += this_chip->offset; - /* Found the real irq, return */ - break; - } - /* Hit the cascading irq. Continue on next irq chip. */ + + /* Find local irq that is triggered on this chip */ + BUG_ON((irq_index = + this_chip->ops.read_irq()) == IRQ_NIL); + + /* See if this irq is a cascaded irq */ + if (irq_index == this_chip->cascade) + continue; /* Yes, continue to next chip */ + + /* + * Irq was initiated from this chip. Add this chip's + * global irq offset and return it + */ + irq_index += this_chip->start; + return irq_index; } - return irq_index; + + /* + * Cascaded irq detected, but no lower chips + * left to process. This should not happen + */ + BUG(); + + return IRQ_NIL; } void do_irq(void) { - int irq_index = global_irq_index(); + l4id_t irq_index = global_irq_index(); struct irq_desc *this_irq = irq_desc_array + irq_index; - /* TODO: This can be easily done few instructions quicker by some - * immediate read/disable/enable_all(). We stick with this clear - * implementation for now. */ + /* + * Note, this can be easily done a few instructions + * quicker by some immediate read/disable/enable_all(). + * + * We currently stick with it as it is clearer. + */ irq_disable(irq_index); + + /* Re-enable all irqs */ enable_irqs(); - /* TODO: Call irq_thread_notify(irq_index) for threaded irqs. */ + + /* Handle the irq */ BUG_ON(!this_irq->handler); - if (this_irq->handler() != IRQ_HANDLED) { - printk("Spurious or broken irq\n"); BUG(); + if (this_irq->handler(this_irq) != IRQ_HANDLED) { + printk("Spurious or broken irq\n"); + BUG(); } + irq_enable(irq_index); } - diff --git a/src/generic/resource.c b/src/generic/resource.c index 3d3b5eb..62751e3 100644 --- a/src/generic/resource.c +++ b/src/generic/resource.c @@ -345,9 +345,9 @@ int memcap_request_device(struct cap_list *cap_list, printk("%s: FATAL: Device memory requested " "does not match any available device " "capabilities start=0x%lx, end=0x%lx " - "uattr=0x%x\n", __KERNELNAME__, + "attr=0x%x\n", __KERNELNAME__, __pfn_to_addr(devcap->start), - __pfn_to_addr(devcap->end), devcap->uattr[0]); + __pfn_to_addr(devcap->end), devcap->attr); BUG(); } diff --git a/src/generic/tcb.c b/src/generic/tcb.c index dce4b47..507bcea 100644 --- a/src/generic/tcb.c +++ b/src/generic/tcb.c @@ -221,16 +221,19 @@ void task_update_utcb(struct ktcb *task) * upon an ipc that requires the kernel to access that utcb, in other * words foreign utcbs are mapped lazily. */ -int tcb_check_and_lazy_map_utcb(struct ktcb *task) +int tcb_check_and_lazy_map_utcb(struct ktcb *task, int page_in) { unsigned int phys; int ret; - BUG_ON(!task->utcb_address); + if (!task->utcb_address) + return -ENOUTCB; /* - * If task == current && not mapped, + * If task == current && not mapped && page_in, * page-in, if not return -EFAULT + * If task == current && not mapped && !page_in, + * return -EFAULT * If task != current && not mapped, * return -EFAULT since can't page-in on behalf of it. * If task != current && task mapped, @@ -239,10 +242,16 @@ int tcb_check_and_lazy_map_utcb(struct ktcb *task) * but mapped == current mapped, return 0 */ + /* FIXME: + * + * Do the check_access part without distinguishing current/non-current + * Do the rest (i.e. mapping the value to the current table) only if the utcb is non-current + */ + if (current == task) { /* Check own utcb, if not there, page it in */ if ((ret = check_access(task->utcb_address, UTCB_SIZE, - MAP_SVC_RW_FLAGS, 1)) < 0) + MAP_SVC_RW_FLAGS, page_in)) < 0) return -EFAULT; else return 0; diff --git a/src/platform/pb926/irq.c b/src/platform/pb926/irq.c index 6fe18ef..d24ca2c 100644 --- a/src/platform/pb926/irq.c +++ b/src/platform/pb926/irq.c @@ -17,7 +17,8 @@ struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { .name = "Vectored irq controller", .level = 0, .cascade = IRQ_SIC, - .offset = 0, + .start = VIC_CHIP_OFFSET, + .end = VIC_CHIP_OFFSET + VIC_IRQS_MAX, .ops = { .init = pl190_vic_init, .read_irq = pl190_read_irq, @@ -29,7 +30,8 @@ struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { .name = "Secondary irq controller", .level = 1, .cascade = IRQ_NIL, - .offset = SIRQ_CHIP_OFFSET, + .start = SIC_CHIP_OFFSET, + .end = SIC_CHIP_OFFSET + SIC_IRQS_MAX, .ops = { .init = pl190_sic_init, .read_irq = pl190_sic_read_irq, @@ -39,7 +41,7 @@ struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { }, }; -static int platform_timer_handler(void) +static int platform_timer_handler(struct irq_desc *desc) { /* * Microkernel is using just TIMER0,