IRQ: Started on the local/driver side. Not a working state.
authorLukas Humbel <lukas.humbel@inf.ethz.ch>
Fri, 11 Mar 2016 14:21:32 +0000 (15:21 +0100)
committerLukas Humbel <lukas.humbel@inf.ethz.ch>
Wed, 6 Apr 2016 08:36:19 +0000 (10:36 +0200)
Signed-off-by: Lukas Humbel <lukas.humbel@inf.ethz.ch>

errors/errno.fugu
include/arch/x86_64/barrelfish/invocations_arch.h
include/barrelfish/inthandler.h
kernel/arch/x86_64/irq.c
kernel/arch/x86_64/syscall.c
kernel/include/arch/armv8/irq.h
kernel/include/arch/x86_64/irq.h
lib/barrelfish/inthandler.c
lib/pci/pci_client.c

index f646d6a..4f277d1 100755 (executable)
@@ -91,11 +91,15 @@ errors kernel SYS_ERR_ {
     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",
index 4c27ad4..3340963 100644 (file)
@@ -414,6 +414,12 @@ invoke_dispatcher_setup_guest(struct capref dispatcher,
                        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)
 {
index a3bf461..0374ea1 100644 (file)
@@ -16,6 +16,11 @@ __BEGIN_DECLS
 
 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,
index 2da5693..17b576a 100644 (file)
@@ -505,6 +505,63 @@ errval_t irq_table_alloc(int *outvec)
     }
 }
 
+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;
index c6f008d..02da281 100644 (file)
@@ -802,9 +802,7 @@ static struct sysret handle_trace_setup(struct capability *cap,
 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,
index 3b89065..f9724cc 100644 (file)
@@ -23,6 +23,7 @@ struct capability;
 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;
index 95801bf..8549abb 100644 (file)
@@ -158,6 +158,7 @@ struct task_state_segment {
 
 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);
index d83cd7b..2e5227f 100644 (file)
@@ -152,7 +152,64 @@ errval_t inthandler_setup_arm(interrupt_handler_fn handler, void *handler_arg,
 }
 
 /**
- * \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
index f385937..731e231 100644 (file)
@@ -77,28 +77,20 @@ errval_t pci_register_driver_movable_irq(pci_driver_init_fn init_func, uint32_t
                                          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.