failure VM_FRAME_TOO_SMALL "Frame too small for superpage mapping",
// errors related to IRQ table
- failure IRQ_LOOKUP "Specified capability was not found while inserting in IRQ table",
- failure IRQ_NOT_ENDPOINT "Specified capability is not an endpoint cap",
- failure IRQ_NO_LISTENER "No listener on specified endpoint cap", // ??
- failure IRQ_INVALID "Invalid interrupt number",
- failure IRQ_NO_FREE_VECTOR "Unable to allocate vector",
+ failure IRQ_LOOKUP "Specified capability was not found while inserting in IRQ table",
+ failure IRQ_NOT_ENDPOINT "Specified capability is not an endpoint cap",
+ failure IRQ_NO_LISTENER "No listener on specified endpoint cap", // ??
+ failure IRQ_INVALID "Invalid interrupt number",
+ failure IRQ_NO_FREE_VECTOR "Unable to allocate vector",
+ failure IRQ_LOOKUP_DEST "Specified capability was not found while connecting IRQ",
+ failure IRQ_LOOKUP_EP "Specified endpoint capability was not found while connecting IRQ",
+ failure IRQ_NOT_IRQ_TYPE "Specified capability is not an IRQ cap",
+ failure IRQ_WRONG_CONTROLLER "Specified IRQ capability does not target local controller",
// IO capability
failure IO_PORT_INVALID "IO port out of range",
get_cap_addr(guest_control_cap)).error;
}
+static inline errval_t invoke_irq_connect(struct capref irqcap, struct capref epcap)
+{
+ struct sysret ret = cap_invoke2(irqcap, IRQCmd_Connect, get_cap_addr(epcap));
+ return ret.error;
+}
+
static inline errval_t invoke_irqtable_alloc_vector(struct capref irqcap, int *retirq)
{
typedef void (*interrupt_handler_fn)(void *);
+
+errval_t inthandler_setup_movable_cap(struct capref dest_cap, interrupt_handler_fn handler, void *handler_arg,
+ interrupt_handler_fn reloc_handler,
+ void *reloc_handler_arg);
+
errval_t inthandler_setup_movable(interrupt_handler_fn handler, void *handler_arg,
interrupt_handler_fn reloc_handler,
void *reloc_handler_arg,
}
}
+errval_t irq_connect(capaddr_t dest, capaddr_t endpoint)
+{
+ errval_t err;
+ struct cte *recv;
+ struct cte *irq;
+
+
+ // Lookup & check message endpoint cap
+ err = caps_lookup_slot(&dcb_current->cspace.cap, endpoint,
+ CPTR_BITS, &recv, CAPRIGHTS_WRITE);
+ if (err_is_fail(err)) {
+ return err_push(err, SYS_ERR_IRQ_LOOKUP_EP);
+ }
+
+ assert(recv != NULL);
+
+ // Return w/error if cap is not an endpoint
+ if(recv->cap.type != ObjType_EndPoint) {
+ return SYS_ERR_IRQ_NOT_ENDPOINT;
+ }
+
+ // Return w/error if no listener on endpoint
+ if(recv->cap.u.endpoint.listener == NULL) {
+ return SYS_ERR_IRQ_NO_LISTENER;
+ }
+
+ // Lookup & check irq capability
+ err = caps_lookup_slot(&dcb_current->cspace.cap, dest,
+ CPTR_BITS, &irq, CAPRIGHTS_WRITE);
+ if (err_is_fail(err)) {
+ return err_push(err, SYS_ERR_IRQ_LOOKUP_DEST);
+ }
+
+ assert(irq != NULL);
+
+ if(irq->cap.type != ObjType_IRQ){
+ return SYS_ERR_IRQ_NOT_IRQ_TYPE;
+ }
+
+ //TODO: Set the lapic_controller_id
+ const uint64_t lapic_controller_id = 0;
+ if(irq->cap.u.irq.controller != lapic_controller_id) {
+ return SYS_ERR_IRQ_WRONG_CONTROLLER;
+ }
+
+ uint64_t nidt = irq->cap.u.irq.line;
+ assert(nidt < NDISPATCH);
+
+ // check that we don't overwrite someone else's handler
+ if (kcb_current->irq_dispatch[nidt].cap.type != ObjType_Null) {
+ printf("kernel: installing new handler for IRQ %"PRIu64"\n", nidt);
+ }
+ err = caps_copy_to_cte(&kcb_current->irq_dispatch[nidt], recv, false, 0, 0);
+ return err;
+
+}
+
errval_t irq_table_set(unsigned int nidt, capaddr_t endpoint)
{
errval_t err;
static struct sysret handle_irq_connect(struct capability *to, int cmd,
uintptr_t *args)
{
- assert(!"NYI");
- return SYSRET(SYS_ERR_OK);
-
+ return SYSRET(irq_connect(args[0], args[1]));
}
static struct sysret handle_irq_table_alloc(struct capability *to, int cmd,
struct idc_recv_msg;
//struct sysret irq_table_set(struct capability *to, struct idc_recv_msg *msg);
//struct sysret irq_table_delete(struct capability *to, struct idc_recv_msg *msg);
+
errval_t irq_table_set(unsigned int nidt, capaddr_t endpoint);
errval_t irq_table_delete(unsigned int nidt);
struct kcb;
void setup_default_idt(void);
+errval_t irq_connect(capaddr_t dest, capaddr_t endpoint);
errval_t irq_table_alloc(int *outvec);
errval_t irq_table_set(unsigned int nidt, capaddr_t endpoint);
errval_t irq_table_delete(unsigned int nidt);
}
/**
- * \brief Setup an interrupt handler function to receive device interrupts
+ * \brief Setup an interrupt handler function to receive device interrupts targeted at dest_cap
+ *
+ * \param dest_cap Capability to an interrupt line that targets the last level controller (such as local APIC)
+ * \param handler Handler function
+ * \param handler_arg Argument passed to #handler
+ */
+errval_t inthandler_setup_movable_cap(struct capref dest_cap, interrupt_handler_fn handler, void *handler_arg,
+ interrupt_handler_fn reloc_handler,
+ void *reloc_handler_arg)
+{
+ errval_t err;
+
+ if(barrelfish_interrupt_waitset == NULL) {
+ barrelfish_interrupt_waitset = get_default_waitset();
+ }
+
+ /* alloc state */
+ struct interrupt_handler_state *state;
+ state = malloc(sizeof(struct interrupt_handler_state));
+ assert(state != NULL);
+
+ state->handler = handler;
+ state->handler_arg = handler_arg;
+ state->reloc_handler = reloc_handler;
+ state->reloc_handler_arg = reloc_handler_arg;
+
+ /* create endpoint to handle interrupts */
+ struct capref epcap;
+
+ // use minimum-sized endpoint, because we don't need to buffer >1 interrupt
+ err = endpoint_create(LMP_RECV_LENGTH, &epcap, &state->idcep);
+ if (err_is_fail(err)) {
+ free(state);
+ return err_push(err, LIB_ERR_ENDPOINT_CREATE);
+ }
+
+ // register to receive on this endpoint
+ struct event_closure cl = {
+ .handler = generic_interrupt_handler,
+ .arg = state,
+ };
+ err = lmp_endpoint_register(state->idcep, barrelfish_interrupt_waitset, cl);
+ if (err_is_fail(err)) {
+ lmp_endpoint_free(state->idcep);
+ // TODO: release vector
+ free(state);
+ return err_push(err, LIB_ERR_LMP_ENDPOINT_REGISTER);
+ }
+
+ // Connect dest_cap with endpoint
+ invoke_irq_connect(dest_cap, epcap);
+
+
+ return SYS_ERR_OK;
+}
+
+/**
+ * \brief Deprecated. inthandler_setup_moveable_cap Setup an interrupt handler function to receive device interrupts.
*
* \param handler Handler function
* \param handler_arg Argument passed to #handler
interrupt_handler_fn reloc_handler,
void *reloc_handler_arg)
{
- uint32_t vector = INVALID_VECTOR;
pci_caps_per_bar_t *caps_per_bar = NULL;
uint8_t nbars;
errval_t err, msgerr;
+ uint8_t vector = 32;
- if (handler != NULL && reloc_handler != NULL) {
- // register movable interrupt
- err = inthandler_setup_movable(handler, handler_arg, reloc_handler,
- reloc_handler_arg, &vector);
- if (err_is_fail(err)) {
- return err;
- }
+ struct capref dummy;
- assert(vector != INVALID_VECTOR);
- } else if (handler != NULL) {
- // register non-movable interrupt
- err = inthandler_setup(handler, handler_arg, &vector);
+ if (handler != NULL) {
+ // register interrupt. Becomes unmovable if reloc_handler == NULL
+ err = inthandler_setup_movable_cap(dummy, handler, handler_arg, reloc_handler,
+ reloc_handler_arg);
if (err_is_fail(err)) {
return err;
}
- //printf("pci_client.c: got vector %"PRIu32"\n", vector);
- assert(vector != INVALID_VECTOR);
}
err = pci_client->vtbl.