mirror of
https://github.com/drasko/codezero.git
synced 2026-04-17 17:29:04 +02:00
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.
This commit is contained in:
@@ -89,8 +89,9 @@ struct capability {
|
|||||||
/* Use count of resource */
|
/* Use count of resource */
|
||||||
unsigned long used;
|
unsigned long used;
|
||||||
|
|
||||||
/* User attributes on capability such as device type, irqno */
|
/* Device attributes, if this is a device. */
|
||||||
u32 uattr[2];
|
unsigned int attr;
|
||||||
|
l4id_t irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __API_CAPABILITY_H__ */
|
#endif /* __API_CAPABILITY_H__ */
|
||||||
|
|||||||
@@ -139,5 +139,6 @@
|
|||||||
#define EACTIVE 132 /* Task active */
|
#define EACTIVE 132 /* Task active */
|
||||||
#define ENOIPC 133 /* General IPC error */
|
#define ENOIPC 133 /* General IPC error */
|
||||||
#define ENOCAP 134 /* None or insufficient capability */
|
#define ENOCAP 134 /* None or insufficient capability */
|
||||||
|
#define ENOUTCB 135 /* Task has no utcb set up */
|
||||||
|
|
||||||
#endif /* __ERRNO_H__ */
|
#endif /* __ERRNO_H__ */
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define __PL190_VIC_H__
|
#define __PL190_VIC_H__
|
||||||
|
|
||||||
#include INC_PLAT(platform.h)
|
#include INC_PLAT(platform.h)
|
||||||
|
#include INC_ARCH(types.h)
|
||||||
|
|
||||||
#define PL190_BASE PLATFORM_IRQCTRL_BASE
|
#define PL190_BASE PLATFORM_IRQCTRL_BASE
|
||||||
#define PL190_SIC_BASE PLATFORM_SIRQCTRL_BASE
|
#define PL190_SIC_BASE PLATFORM_SIRQCTRL_BASE
|
||||||
@@ -42,15 +43,16 @@
|
|||||||
#define PL190_SIC_PICENCLR (PL190_SIC_BASE + 0x24)
|
#define PL190_SIC_PICENCLR (PL190_SIC_BASE + 0x24)
|
||||||
|
|
||||||
void pl190_vic_init(void);
|
void pl190_vic_init(void);
|
||||||
void pl190_ack_irq(int irq);
|
void pl190_ack_irq(l4id_t irq);
|
||||||
void pl190_mask_irq(int irq);
|
void pl190_mask_irq(l4id_t irq);
|
||||||
void pl190_unmask_irq(int irq);
|
void pl190_unmask_irq(l4id_t irq);
|
||||||
int pl190_read_irq(void);
|
l4id_t pl190_read_irq(void);
|
||||||
|
|
||||||
int pl190_sic_read_irq(void);
|
l4id_t pl190_sic_read_irq(void);
|
||||||
void pl190_sic_mask_irq(int irq);
|
void pl190_sic_mask_irq(l4id_t irq);
|
||||||
void pl190_sic_mask_irq(int irq);
|
void pl190_sic_mask_irq(l4id_t irq);
|
||||||
void pl190_sic_ack_irq(int irq);
|
void pl190_sic_ack_irq(l4id_t irq);
|
||||||
void pl190_sic_unmask_irq(int irq);
|
void pl190_sic_unmask_irq(l4id_t irq);
|
||||||
void pl190_sic_init(void);
|
void pl190_sic_init(void);
|
||||||
|
|
||||||
#endif /* __PL190_VIC_H__ */
|
#endif /* __PL190_VIC_H__ */
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#define CAP_TYPE_MAP_PHYSMEM (1 << 2)
|
#define CAP_TYPE_MAP_PHYSMEM (1 << 2)
|
||||||
#define CAP_TYPE_MAP_VIRTMEM (1 << 3)
|
#define CAP_TYPE_MAP_VIRTMEM (1 << 3)
|
||||||
#define CAP_TYPE_IPC (1 << 4)
|
#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_UMUTEX (1 << 6)
|
||||||
#define CAP_TYPE_QUANTITY (1 << 7)
|
#define CAP_TYPE_QUANTITY (1 << 7)
|
||||||
#define CAP_TYPE_CAP (1 << 8)
|
#define CAP_TYPE_CAP (1 << 8)
|
||||||
@@ -52,17 +52,16 @@
|
|||||||
#define CAP_DEVNUM_MASK 0xFFFF0000
|
#define CAP_DEVNUM_MASK 0xFFFF0000
|
||||||
#define CAP_DEVNUM_SHIFT 16
|
#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) \
|
#define cap_set_devtype(c, devtype) \
|
||||||
{(c)->uattr[0] &= ~CAP_DEVTYPE_MASK; \
|
{(c)->attr &= ~CAP_DEVTYPE_MASK; \
|
||||||
(c)->uattr[0] |= CAP_DEVTYPE_MASK & devtype;}
|
(c)->attr |= CAP_DEVTYPE_MASK & devtype;}
|
||||||
#define cap_set_devnum(c, devnum) \
|
#define cap_set_devnum(c, devnum) \
|
||||||
{(c)->uattr[0] &= ~CAP_DEVNUM_MASK; \
|
{(c)->attr &= ~CAP_DEVNUM_MASK; \
|
||||||
(c)->uattr[0] |= CAP_DEVNUM_MASK & devnum;}
|
(c)->attr |= CAP_DEVNUM_MASK & devnum;}
|
||||||
#define cap_devnum(c) \
|
#define cap_devnum(c) \
|
||||||
(((c)->uattr[0] & CAP_DEVNUM_MASK) >> CAP_DEVNUM_SHIFT)
|
(((c)->attr & CAP_DEVNUM_MASK) >> CAP_DEVNUM_SHIFT)
|
||||||
#define cap_devtype(c) ((c)->uattr[0] & CAP_DEVTYPE_MASK)
|
#define cap_devtype(c) ((c)->attr & CAP_DEVTYPE_MASK)
|
||||||
#define cap_irqno(c) ((c)->uattr[1])
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Access permissions
|
* Access permissions
|
||||||
@@ -103,6 +102,14 @@
|
|||||||
#define CAP_MAP_UNMAP (1 << 5)
|
#define CAP_MAP_UNMAP (1 << 5)
|
||||||
#define CAP_MAP_UTCB (1 << 6)
|
#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 */
|
/* Ipc capability */
|
||||||
#define CAP_IPC_SEND (1 << 0)
|
#define CAP_IPC_SEND (1 << 0)
|
||||||
#define CAP_IPC_RECV (1 << 1)
|
#define CAP_IPC_RECV (1 << 1)
|
||||||
|
|||||||
@@ -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_cap_check(struct ktcb *task, unsigned int req, unsigned int flags);
|
||||||
int cap_mutex_check(unsigned long mutex_address, int mutex_op);
|
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__ */
|
#endif /* __GENERIC_CAPABILITY_H__ */
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ struct cap_info {
|
|||||||
unsigned long start;
|
unsigned long start;
|
||||||
unsigned long end;
|
unsigned long end;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
unsigned int uattr[2]; /* User-level attributes (like device types) */
|
unsigned int attr; /* Attributes (like device types) */
|
||||||
|
l4id_t irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,18 @@
|
|||||||
|
|
||||||
#include <l4/lib/string.h>
|
#include <l4/lib/string.h>
|
||||||
#include INC_PLAT(irq.h)
|
#include INC_PLAT(irq.h)
|
||||||
|
#include INC_ARCH(types.h)
|
||||||
|
|
||||||
/* Represents none or spurious irq */
|
/* Represents none or spurious irq */
|
||||||
#define IRQ_NIL (-1)
|
#define IRQ_NIL 0xFFFFFFFF
|
||||||
|
|
||||||
/* Successful irq handling state */
|
/* Successful irq handling state */
|
||||||
#define IRQ_HANDLED 0
|
#define IRQ_HANDLED 0
|
||||||
|
|
||||||
typedef void (*irq_op_t)(int irq);
|
typedef void (*irq_op_t)(l4id_t irq);
|
||||||
struct irq_chip_ops {
|
struct irq_chip_ops {
|
||||||
void (*init)(void);
|
void (*init)(void);
|
||||||
int (*read_irq)(void);
|
l4id_t (*read_irq)(void);
|
||||||
irq_op_t ack_and_mask;
|
irq_op_t ack_and_mask;
|
||||||
irq_op_t unmask;
|
irq_op_t unmask;
|
||||||
};
|
};
|
||||||
@@ -27,16 +28,24 @@ struct irq_chip {
|
|||||||
char name[32];
|
char name[32];
|
||||||
int level; /* Cascading level */
|
int level; /* Cascading level */
|
||||||
int cascade; /* The irq that lower chip uses on this chip */
|
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;
|
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 {
|
struct irq_desc {
|
||||||
char name[8];
|
char name[8];
|
||||||
struct irq_chip *chip;
|
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;
|
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_desc *this_irq = irq_desc_array + irq_index;
|
||||||
struct irq_chip *this_chip = this_irq->chip;
|
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)
|
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_desc *this_irq = irq_desc_array + irq_index;
|
||||||
struct irq_chip *this_chip = this_irq->chip;
|
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)
|
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_irq(void);
|
void do_irq(void);
|
||||||
void irq_controllers_init(void);
|
void irq_controllers_init(void);
|
||||||
|
|||||||
@@ -132,6 +132,9 @@ struct ktcb {
|
|||||||
struct waitqueue_head wqh_send;
|
struct waitqueue_head wqh_send;
|
||||||
l4id_t expected_sender;
|
l4id_t expected_sender;
|
||||||
|
|
||||||
|
/* Waitqueue for notifiactions */
|
||||||
|
struct waitqueue_head wqh_notify;
|
||||||
|
|
||||||
/* Waitqueue for pagers to wait for task states */
|
/* Waitqueue for pagers to wait for task states */
|
||||||
struct waitqueue_head wqh_pager;
|
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 ktcb_list_add(struct ktcb *new, struct ktcb_list *ktcb_list);
|
||||||
void init_ktcb_list(struct ktcb_list *ktcb_list);
|
void init_ktcb_list(struct ktcb_list *ktcb_list);
|
||||||
void task_update_utcb(struct ktcb *task);
|
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__ */
|
#endif /* __TCB_H__ */
|
||||||
|
|
||||||
|
|||||||
@@ -78,12 +78,15 @@
|
|||||||
|
|
||||||
#include INC_GLUE(memlayout.h)
|
#include INC_GLUE(memlayout.h)
|
||||||
|
|
||||||
|
#define TASK_NOTIFY_SLOTS 8
|
||||||
|
#define TASK_NOTIFY_MAX 0xFF
|
||||||
|
|
||||||
#if !defined (__ASSEMBLY__)
|
#if !defined (__ASSEMBLY__)
|
||||||
struct utcb {
|
struct utcb {
|
||||||
u32 mr[MR_TOTAL]; /* MRs that are mapped to real registers */
|
u32 mr[MR_TOTAL]; /* MRs that are mapped to real registers */
|
||||||
u32 saved_tag; /* Saved tag field for stacked ipcs */
|
u32 saved_tag; /* Saved tag field for stacked ipcs */
|
||||||
u32 saved_sender; /* Saved sender 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 */
|
u32 mr_rest[MR_REST]; /* Complete the utcb for up to 64 words */
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,24 +4,47 @@
|
|||||||
#define IRQ_CHIPS_MAX 2
|
#define IRQ_CHIPS_MAX 2
|
||||||
#define IRQS_MAX 64
|
#define IRQS_MAX 64
|
||||||
|
|
||||||
/* IRQ indices. */
|
/* Global irq numbers */
|
||||||
#define IRQ_TIMER01 4
|
#define IRQ_TIMER01 (VIC_IRQ_TIMER01 + VIC_CHIP_OFFSET)
|
||||||
#define IRQ_TIMER23 5
|
#define IRQ_TIMER23 (VIC_IRQ_TIMER23 + VIC_CHIP_OFFSET)
|
||||||
#define IRQ_RTC 10
|
#define IRQ_RTC (VIC_IRQ_RTC + VIC_CHIP_OFFSET)
|
||||||
#define IRQ_UART0 12
|
#define IRQ_UART0 (VIC_IRQ_UART0 + VIC_CHIP_OFFSET)
|
||||||
#define IRQ_UART1 13
|
#define IRQ_UART1 (VIC_IRQ_UART1 + VIC_CHIP_OFFSET)
|
||||||
#define IRQ_UART2 14
|
#define IRQ_UART2 (VIC_IRQ_UART2 + VIC_CHIP_OFFSET)
|
||||||
#define IRQ_SIC 31
|
#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 */
|
/* Vectored Interrupt Controller local IRQ numbers */
|
||||||
/* The local irq line of the dummy peripheral on this chip */
|
#define VIC_IRQ_TIMER01 4
|
||||||
#define LOCALIRQ_DUMMY 15
|
#define VIC_IRQ_TIMER23 5
|
||||||
/* The irq index offset of this chip, is the maximum of previous chip + 1 */
|
#define VIC_IRQ_RTC 10
|
||||||
#define SIRQ_CHIP_OFFSET (PIC_IRQS_MAX + 1)
|
#define VIC_IRQ_UART0 12
|
||||||
/* The global irq number of dummy is the local irq line + it's chip offset */
|
#define VIC_IRQ_UART1 13
|
||||||
#define IRQ_DUMMY (LOCALIRQ_DUMMY + SIRQ_CHIP_OFFSET)
|
#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__ */
|
#endif /* __PLATFORM_IRQ_H__ */
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ int ipc_full_copy(struct ktcb *to, struct ktcb *from)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Check that utcb memory accesses won't fault us */
|
/* 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;
|
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;
|
return ret;
|
||||||
|
|
||||||
/* Directly copy from one utcb to another */
|
/* Directly copy from one utcb to another */
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <l4/lib/bit.h>
|
#include <l4/lib/bit.h>
|
||||||
#include <l4/drivers/irq/pl190/pl190_vic.h>
|
#include <l4/drivers/irq/pl190/pl190_vic.h>
|
||||||
|
#include <l4/generic/irq.h>
|
||||||
|
|
||||||
/* FIXME: Fix the stupid uart driver and change to single definition of this! */
|
/* FIXME: Fix the stupid uart driver and change to single definition of this! */
|
||||||
#if defined(read)
|
#if defined(read)
|
||||||
@@ -28,13 +29,16 @@
|
|||||||
: clrbit(bitvect, (base + reg)))
|
: clrbit(bitvect, (base + reg)))
|
||||||
|
|
||||||
/* Returns the irq number on this chip converting the irq bitvector */
|
/* 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. */
|
l4id_t irq;
|
||||||
return 31 - __clz(read(PL190_VIC_IRQSTATUS));
|
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.
|
/* Reading WO registers blows QEMU/PB926.
|
||||||
* setbit((1 << irq), PL190_VIC_INTENCLEAR); */
|
* setbit((1 << irq), PL190_VIC_INTENCLEAR); */
|
||||||
@@ -42,32 +46,37 @@ void pl190_mask_irq(int irq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ack is same as mask */
|
/* Ack is same as mask */
|
||||||
void pl190_ack_irq(int irq)
|
void pl190_ack_irq(l4id_t irq)
|
||||||
{
|
{
|
||||||
pl190_mask_irq(irq);
|
pl190_mask_irq(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pl190_unmask_irq(int irq)
|
void pl190_unmask_irq(l4id_t irq)
|
||||||
{
|
{
|
||||||
setbit(1 << irq, PL190_VIC_INTENABLE);
|
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);
|
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);
|
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);
|
setbit(1 << irq, PL190_SIC_ENSET);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <l4/api/thread.h>
|
#include <l4/api/thread.h>
|
||||||
#include <l4/api/exregs.h>
|
#include <l4/api/exregs.h>
|
||||||
#include <l4/api/ipc.h>
|
#include <l4/api/ipc.h>
|
||||||
|
#include <l4/api/irq.h>
|
||||||
#include INC_GLUE(message.h)
|
#include INC_GLUE(message.h)
|
||||||
#include INC_GLUE(ipc.h)
|
#include INC_GLUE(ipc.h)
|
||||||
|
|
||||||
@@ -642,6 +643,119 @@ struct capability *cap_match_mem(struct capability *cap,
|
|||||||
return 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)
|
#if defined(CONFIG_CAPABILITIES)
|
||||||
int cap_mutex_check(unsigned long mutex_address, int mutex_op)
|
int cap_mutex_check(unsigned long mutex_address, int mutex_op)
|
||||||
{
|
{
|
||||||
@@ -761,6 +875,34 @@ int cap_thread_check(struct ktcb *task,
|
|||||||
return 0;
|
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 */
|
#else /* Meaning !CONFIG_CAPABILITIES */
|
||||||
int cap_mutex_check(unsigned long mutex_address, int mutex_op)
|
int cap_mutex_check(unsigned long mutex_address, int mutex_op)
|
||||||
{
|
{
|
||||||
@@ -795,4 +937,11 @@ int cap_thread_check(struct ktcb *task,
|
|||||||
{
|
{
|
||||||
return 0;
|
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 */
|
#endif /* End of !CONFIG_CAPABILITIES */
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Kernel irq handling (core irqs like timer). Also hope to add thread-level
|
* Kernel irq handling (core irqs like timer).
|
||||||
* irq handling in the future.
|
* Also thread-level irq handling.
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Bahadir Balban
|
|
||||||
*
|
*
|
||||||
|
* Copyright (C) 2007 - 2009 Bahadir Balban
|
||||||
*/
|
*/
|
||||||
#include <l4/config.h>
|
#include <l4/config.h>
|
||||||
#include <l4/macros.h>
|
#include <l4/macros.h>
|
||||||
@@ -16,7 +15,33 @@
|
|||||||
#include INC_PLAT(irq.h)
|
#include INC_PLAT(irq.h)
|
||||||
#include INC_ARCH(exception.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)
|
static inline void cascade_irq_chip(struct irq_chip *this_chip)
|
||||||
{
|
{
|
||||||
if (this_chip->cascade >= 0) {
|
if (this_chip->cascade >= 0) {
|
||||||
@@ -31,51 +56,86 @@ void irq_controllers_init(void)
|
|||||||
|
|
||||||
for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
|
for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
|
||||||
this_chip = irq_chip_array + 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();
|
this_chip->ops.init();
|
||||||
/* Enable cascaded irqs if needed */
|
|
||||||
|
/* Enable cascaded irq on this chip if it exists */
|
||||||
cascade_irq_chip(this_chip);
|
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;
|
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++) {
|
for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
|
||||||
|
|
||||||
|
/* Get the chip */
|
||||||
this_chip = irq_chip_array + i;
|
this_chip = irq_chip_array + i;
|
||||||
BUG_ON((irq_index = this_chip->ops.read_irq()) < 0);
|
|
||||||
if (irq_index != this_chip->cascade) {
|
/* Find local irq that is triggered on this chip */
|
||||||
irq_index += this_chip->offset;
|
BUG_ON((irq_index =
|
||||||
/* Found the real irq, return */
|
this_chip->ops.read_irq()) == IRQ_NIL);
|
||||||
break;
|
|
||||||
}
|
/* See if this irq is a cascaded irq */
|
||||||
/* Hit the cascading irq. Continue on next irq chip. */
|
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)
|
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;
|
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
|
* Note, this can be easily done a few instructions
|
||||||
* implementation for now. */
|
* quicker by some immediate read/disable/enable_all().
|
||||||
|
*
|
||||||
|
* We currently stick with it as it is clearer.
|
||||||
|
*/
|
||||||
irq_disable(irq_index);
|
irq_disable(irq_index);
|
||||||
|
|
||||||
|
/* Re-enable all irqs */
|
||||||
enable_irqs();
|
enable_irqs();
|
||||||
/* TODO: Call irq_thread_notify(irq_index) for threaded irqs. */
|
|
||||||
|
/* Handle the irq */
|
||||||
BUG_ON(!this_irq->handler);
|
BUG_ON(!this_irq->handler);
|
||||||
if (this_irq->handler() != IRQ_HANDLED) {
|
if (this_irq->handler(this_irq) != IRQ_HANDLED) {
|
||||||
printk("Spurious or broken irq\n"); BUG();
|
printk("Spurious or broken irq\n");
|
||||||
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
irq_enable(irq_index);
|
irq_enable(irq_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -345,9 +345,9 @@ int memcap_request_device(struct cap_list *cap_list,
|
|||||||
printk("%s: FATAL: Device memory requested "
|
printk("%s: FATAL: Device memory requested "
|
||||||
"does not match any available device "
|
"does not match any available device "
|
||||||
"capabilities start=0x%lx, end=0x%lx "
|
"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->start),
|
||||||
__pfn_to_addr(devcap->end), devcap->uattr[0]);
|
__pfn_to_addr(devcap->end), devcap->attr);
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -221,16 +221,19 @@ void task_update_utcb(struct ktcb *task)
|
|||||||
* upon an ipc that requires the kernel to access that utcb, in other
|
* upon an ipc that requires the kernel to access that utcb, in other
|
||||||
* words foreign utcbs are mapped lazily.
|
* 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;
|
unsigned int phys;
|
||||||
int ret;
|
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
|
* page-in, if not return -EFAULT
|
||||||
|
* If task == current && not mapped && !page_in,
|
||||||
|
* return -EFAULT
|
||||||
* If task != current && not mapped,
|
* If task != current && not mapped,
|
||||||
* return -EFAULT since can't page-in on behalf of it.
|
* return -EFAULT since can't page-in on behalf of it.
|
||||||
* If task != current && task mapped,
|
* 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
|
* 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) {
|
if (current == task) {
|
||||||
/* Check own utcb, if not there, page it in */
|
/* Check own utcb, if not there, page it in */
|
||||||
if ((ret = check_access(task->utcb_address, UTCB_SIZE,
|
if ((ret = check_access(task->utcb_address, UTCB_SIZE,
|
||||||
MAP_SVC_RW_FLAGS, 1)) < 0)
|
MAP_SVC_RW_FLAGS, page_in)) < 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = {
|
|||||||
.name = "Vectored irq controller",
|
.name = "Vectored irq controller",
|
||||||
.level = 0,
|
.level = 0,
|
||||||
.cascade = IRQ_SIC,
|
.cascade = IRQ_SIC,
|
||||||
.offset = 0,
|
.start = VIC_CHIP_OFFSET,
|
||||||
|
.end = VIC_CHIP_OFFSET + VIC_IRQS_MAX,
|
||||||
.ops = {
|
.ops = {
|
||||||
.init = pl190_vic_init,
|
.init = pl190_vic_init,
|
||||||
.read_irq = pl190_read_irq,
|
.read_irq = pl190_read_irq,
|
||||||
@@ -29,7 +30,8 @@ struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = {
|
|||||||
.name = "Secondary irq controller",
|
.name = "Secondary irq controller",
|
||||||
.level = 1,
|
.level = 1,
|
||||||
.cascade = IRQ_NIL,
|
.cascade = IRQ_NIL,
|
||||||
.offset = SIRQ_CHIP_OFFSET,
|
.start = SIC_CHIP_OFFSET,
|
||||||
|
.end = SIC_CHIP_OFFSET + SIC_IRQS_MAX,
|
||||||
.ops = {
|
.ops = {
|
||||||
.init = pl190_sic_init,
|
.init = pl190_sic_init,
|
||||||
.read_irq = pl190_sic_read_irq,
|
.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,
|
* Microkernel is using just TIMER0,
|
||||||
|
|||||||
Reference in New Issue
Block a user