seL4_timer_t * sel4platsupport_get_pit(vka_t *vka, simple_t *simple, ps_io_port_ops_t *ops, seL4_CPtr notification) { seL4_pit_data_t *data = malloc(sizeof(seL4_pit_data_t)); if (data == NULL) { ZF_LOGE("Failed to allocate object of size %zu\n", sizeof(*data)); goto error; } seL4_timer_t *pit = calloc(1, sizeof(*pit)); if (pit == NULL) { ZF_LOGE("Failed to malloc object of size %zu\n", sizeof(*pit)); goto error; } pit->destroy = pit_destroyer; pit->handle_irq = pit_handle_irq; pit->data = data; /* set up irq */ cspacepath_t dest; if (sel4platsupport_copy_irq_cap(vka, simple, PIT_INTERRUPT, &dest) != seL4_NoError) { goto error; } data->irq = dest.capPtr; /* bind to endpoint */ if (seL4_IRQHandler_SetNotification(data->irq, notification) != seL4_NoError) { ZF_LOGE("seL4_IRQHandler_SetEndpoint failed\n"); goto error; } /* ack (api hack) */ seL4_IRQHandler_Ack(data->irq); /* finally set up the actual timer */ pit->timer = pit_get_timer(ops); if (pit->timer == NULL) { goto error; } /* sucess */ return pit; error: if (data != NULL) { free(data); } if (data->irq != 0) { timer_common_cleanup_irq(vka, data->irq); } return NULL; }
int dev_handle_irq(dev_irq_state_t *irqState, uint32_t irq, dev_irq_callback_fn_t callback, void *cookie) { assert(irqState && irqState->magic == DEVICE_IRQ_MAGIC); if (irq >= DEVICE_MAX_IRQ) { ROS_ERROR("dev_handle_irq IRQ num too high. Try raising DEVICE_MAX_IRQ."); assert(!"Try raising DEVICE_MAX_IRQ."); return EINVALIDPARAM; } /* Retrieve the handler, if necessary. */ if (!irqState->handler[irq].handler) { assert(irqState->cfg.getIRQHandlerEndpoint); irqState->handler[irq].handler = irqState->cfg.getIRQHandlerEndpoint( irqState->cfg.getIRQHandlerEndpointCookie, irq ); if (!irqState->handler[irq].handler) { ROS_WARNING("dev_handle_irq : could not get IRQ handler for irq %u.\n", irq); return EINVALID; } } /* Determine next round-robin channel to go in. */ uint32_t nextChannel = irqState->cfg.badgeBaseBit + irqState->nextIRQChannel; cvector_add(&irqState->channel[irqState->nextIRQChannel], (cvector_item_t) irq); irqState->nextIRQChannel = (irqState->nextIRQChannel + 1) % irqState->cfg.numIRQChannels; /* Mint the badged AEP. */ assert(irqState->cfg.notifyAsyncEP); seL4_CPtr irqBadge = srv_mint((1 << nextChannel) | irqState->cfg.badgeMaskBits, irqState->cfg.notifyAsyncEP); if (!irqBadge) { ROS_WARNING("dev_handle_irq : could not mint badged aep for irq %u.\n", irq); return EINVALID; } /* Assign AEP to the IRQ handler. */ int error = seL4_IRQHandler_SetNotification(irqState->handler[irq].handler, irqBadge); if (error) { ROS_WARNING("dev_handle_irq : could not set notify aep for irq %u.\n", irq); csfree_delete(irqBadge); return EINVALID; } seL4_IRQHandler_Ack(irqState->handler[irq].handler); /* Set callback function and cookie. */ irqState->handler[irq].callback = callback; irqState->handler[irq].cookie = cookie; csfree_delete(irqBadge); return ESUCCESS; }
/* Binds and IRQ to an endpoint */ static seL4_CPtr irq_bind(irq_t irq, seL4_CPtr notification_cap, int idx, vka_t* vka, simple_t *simple) { seL4_CPtr irq_cap, bnotification_cap; cspacepath_t irq_path, notification_path, bnotification_path; seL4_CapData_t badge; int err; /* Create an IRQ cap */ err = vka_cspace_alloc(vka, &irq_cap); if (err != 0) { ZF_LOGE("Failed to allocate cslot for irq\n"); return seL4_CapNull; } vka_cspace_make_path(vka, irq_cap, &irq_path); err = simple_get_IRQ_control(simple, irq, irq_path); if (err != seL4_NoError) { ZF_LOGE("Failed to get cap to irq_number %d\n", irq); vka_cspace_free(vka, irq_cap); return seL4_CapNull; } /* Badge the provided endpoint. The bit position of the badge tells us the array * index of the associated IRQ data. */ err = vka_cspace_alloc(vka, &bnotification_cap); if (err != 0) { ZF_LOGE("Failed to allocate cslot for irq\n"); vka_cspace_free(vka, irq_cap); return seL4_CapNull; } vka_cspace_make_path(vka, notification_cap, ¬ification_path); vka_cspace_make_path(vka, bnotification_cap, &bnotification_path); badge = seL4_CapData_Badge_new(BIT(idx)); err = vka_cnode_mint(&bnotification_path, ¬ification_path, seL4_AllRights, badge); if (err != seL4_NoError) { ZF_LOGE("Failed to badge IRQ notification endpoint\n"); vka_cspace_free(vka, irq_cap); vka_cspace_free(vka, bnotification_cap); return seL4_CapNull; } /* bind the IRQ cap to our badged endpoint */ err = seL4_IRQHandler_SetNotification(irq_cap, bnotification_cap); if (err != seL4_NoError) { ZF_LOGE("Failed to bind IRQ handler to notification\n"); vka_cspace_free(vka, irq_cap); vka_cspace_free(vka, bnotification_cap); return seL4_CapNull; } /* Finally ACK any pending IRQ and enable the IRQ */ seL4_IRQHandler_Ack(irq_cap); DIRQSERVER("Registered IRQ %d with badge 0x%lx\n", irq, BIT(idx)); return irq_cap; }
seL4_timer_t * sel4platsupport_get_pit(vka_t *vka, simple_t *simple, ps_io_port_ops_t *ops, seL4_CPtr notification) { seL4_timer_t *pit = calloc(1, sizeof(*pit)); if (pit == NULL) { ZF_LOGE("Failed to malloc object of size %zu\n", sizeof(*pit)); return NULL; } /* initialise an io port ops interface if none was provided */ if (ops == NULL) { ops = calloc(1, sizeof(*ops)); if (ops == NULL) { ZF_LOGE("Failed to malloc object of size %zu", sizeof(*ops)); goto error; } /* store ops pointer in pit so it can be freed later */ pit->data = ops; if (sel4platsupport_get_io_port_ops(ops, simple) != 0) { ZF_LOGE("Failed to initialise io port ops"); goto error; } } else { pit->data = NULL; } pit->destroy = pit_destroyer; pit->handle_irq = timer_common_handle_irq; /* set up irq */ cspacepath_t dest; if (sel4platsupport_copy_irq_cap(vka, simple, PIT_INTERRUPT, &dest) != seL4_NoError) { goto error; } pit->irq = dest.capPtr; /* bind to endpoint */ if (seL4_IRQHandler_SetNotification(pit->irq, notification) != seL4_NoError) { ZF_LOGE("seL4_IRQHandler_SetEndpoint failed\n"); goto error; } /* ack (api hack) */ seL4_IRQHandler_Ack(pit->irq); /* finally set up the actual timer */ pit->timer = pit_get_timer(ops); if (pit->timer == NULL) { goto error; } /* sucess */ return pit; error: if (pit->irq != 0) { timer_common_cleanup_irq(vka, pit->irq); free(pit->data); free(pit); } return NULL; }