libsel4platsupport: Refactor the IRQ sources
This commit refactors the IRQ sources and pulls out common code into
separate functions. This is in preparation of a more simpler/mini IRQ
interface.
diff --git a/libsel4platsupport/src/irq.c b/libsel4platsupport/src/irq.c
index 3280837..fef4948 100644
--- a/libsel4platsupport/src/irq.c
+++ b/libsel4platsupport/src/irq.c
@@ -206,11 +206,84 @@
return CTZL(unallocated_bitfield);
}
-static irq_id_t sel4platsupport_irq_register(void *cookie, ps_irq_t irq, irq_callback_fn_t callback,
- void *callback_data)
+static int irq_set_ntfn_common(irq_cookie_t *irq_cookie, ntfn_id_t ntfn_id, irq_id_t irq_id,
+ seL4_Word *ret_badge)
{
- irq_cookie_t *irq_cookie = cookie;
+ irq_entry_t *irq_entry = &(irq_cookie->irq_table[irq_id]);
+ /* Check if the IRQ is already bound to something */
+ if (irq_entry->paired_ntfn > UNPAIRED_ID) {
+ return -EINVAL;
+ }
+
+ ntfn_entry_t *ntfn_entry = &(irq_cookie->ntfn_table[ntfn_id]);
+
+ /* Check if we have space to bound another IRQ to this notification */
+ if (ntfn_entry->num_irqs_bound >= MAX_INTERRUPTS_TO_NOTIFICATIONS) {
+ return -ENOSPC;
+ }
+
+ /* Find an empty space (unclaimed bit in the badge) for the IRQ */
+ int badge_index = find_free_ntfn_badge_index(ntfn_entry);
+ if (badge_index == -1) {
+ return -ENOSPC;
+ }
+
+ /* Allocate a CSpace slot and mint the root notification object with badge */
+ cspacepath_t mint_path = {0};
+ int error = vka_cspace_alloc_path(irq_cookie->vka, &mint_path);
+ if (error) {
+ return -ENOMEM;
+ }
+
+ seL4_Word badge = BIT(badge_index);
+ error = vka_cnode_mint(&mint_path, &(ntfn_entry->root_ntfn_path), seL4_AllRights, badge);
+ if (error) {
+ vka_cspace_free_path(irq_cookie->vka, mint_path);
+ return -ENOMEM;
+ }
+
+ /* Bind the notification with the handler now */
+ error = seL4_IRQHandler_SetNotification(irq_entry->handler_path.capPtr, mint_path.capPtr);
+ if (error) {
+ ZF_LOGE("Failed to set a notification with the IRQ handler");
+ error = vka_cnode_delete(&mint_path);
+ ZF_LOGF_IF(error, "Failed to cleanup after a failed IRQ set ntfn operation");
+ vka_cspace_free_path(irq_cookie->vka, mint_path);
+ return -EFAULT;
+ }
+
+ /* Acknowledge the handler so interrupts can arrive on the notification */
+ error = seL4_IRQHandler_Ack(irq_entry->handler_path.capPtr);
+ if (error) {
+ ZF_LOGE("Failed to ack an IRQ handler");
+ error = seL4_IRQHandler_Clear(irq_entry->handler_path.capPtr);
+ ZF_LOGF_IF(error, "Failed to unpair a notification after a failed IRQ set ntfn operation");
+ error = vka_cnode_delete(&mint_path);
+ ZF_LOGF_IF(error, "Failed to cleanup after a failed IRQ set ntfn operation");
+ vka_cspace_free_path(irq_cookie->vka, mint_path);
+ return -EFAULT;
+ }
+
+ if (ret_badge) {
+ *ret_badge = badge;
+ }
+
+ /* Fill in the bookkeeping information */
+ ntfn_entry->num_irqs_bound++;
+ ntfn_entry->status_bitfield |= badge;
+ ntfn_entry->bound_irqs[badge_index] = irq_id;
+
+ irq_entry->ntfn_path = mint_path;
+ irq_entry->paired_ntfn = ntfn_id;
+ irq_entry->allocated_badge_index = badge_index;
+
+ return 0;
+}
+
+static irq_id_t irq_register_common(irq_cookie_t *irq_cookie, ps_irq_t irq, irq_callback_fn_t callback,
+ void *callback_data)
+{
if (check_irq_id_all_allocated(irq_cookie)) {
return -EMFILE;
}
@@ -252,104 +325,26 @@
return free_id;
}
-static int sel4platsupport_irq_unregister(void *cookie, irq_id_t irq_id)
+static void provide_ntfn_common(irq_cookie_t *irq_cookie, seL4_CPtr ntfn, seL4_Word usable_mask,
+ ntfn_id_t allocated_id)
{
- irq_cookie_t *irq_cookie = cookie;
+ cspacepath_t ntfn_path = {0};
+ vka_cspace_make_path(irq_cookie->vka, ntfn, &ntfn_path);
- if (!check_irq_id_is_valid(irq_cookie, irq_id)) {
- return -EINVAL;
- }
+ /* Clear the notification entry and then fill in bookkeeping information */
+ ntfn_entry_t *ntfn_entry = &(irq_cookie->ntfn_table[allocated_id]);
+ memset(ntfn_entry, 0, sizeof(ntfn_entry_t));
+ ntfn_entry->allocated = true;
+ ntfn_entry->root_ntfn_path = ntfn_path;
+ ntfn_entry->usable_mask = usable_mask;
- if (!check_irq_id_is_allocated(irq_cookie, irq_id)) {
- return -EINVAL;
- }
-
- irq_entry_t *irq_entry = &(irq_cookie->irq_table[irq_id]);
-
- if (irq_entry->paired_ntfn > UNPAIRED_ID) {
- /* Clear the handler */
- int error = seL4_IRQHandler_Clear(irq_entry->handler_path.capPtr);
- if (error) {
- /* Give a slightly ambigious message as we don't want to leak implementation details */
- ZF_LOGE("Failed to unregister an IRQ");
- return -EFAULT;
- }
-
- /* Delete the notification */
- vka_cnode_delete(&(irq_entry->ntfn_path));
- vka_cspace_free_path(irq_cookie->vka, irq_entry->ntfn_path);
-
- /* Clear the necessary information in the notification array */
- ntfn_entry_t *ntfn_entry = &(irq_cookie->ntfn_table[irq_entry->paired_ntfn]);
- ntfn_entry->status_bitfield &= ~BIT(irq_entry->allocated_badge_index);
- ntfn_entry->pending_bitfield &= ~BIT(irq_entry->allocated_badge_index);
- ntfn_entry->bound_irqs[irq_entry->allocated_badge_index] = UNPAIRED_ID;
- ntfn_entry->num_irqs_bound--;
- }
-
- /* Delete the handler */
- vka_cnode_delete(&(irq_entry->handler_path));
- vka_cspace_free_path(irq_cookie->vka, irq_entry->handler_path);
-
- /* Zero-out the entire entry */
- memset(irq_entry, 0, sizeof(irq_entry_t));
- /* Reset parts of the entry */
- irq_entry->paired_ntfn = UNPAIRED_ID;
- irq_entry->allocated_badge_index = UNALLOCATED_BADGE_INDEX;
-
- irq_cookie->num_registered_irqs--;
- unfill_bit_in_bitfield(irq_cookie->allocated_irq_bitfields, irq_id);
-
- return 0;
+ irq_cookie->num_allocated_ntfns++;
+ fill_bit_in_bitfield(irq_cookie->allocated_ntfn_bitfields, allocated_id);
}
-static int sel4platsupport_irq_acknowledge(void *ack_data)
+static irq_cookie_t *new_irq_ops_common(vka_t *vka, simple_t *simple, irq_interface_config_t irq_config,
+ ps_malloc_ops_t *malloc_ops)
{
- if (!ack_data) {
- return -EINVAL;
- }
-
- int ret = 0;
-
- ack_data_t *data = ack_data;
- irq_cookie_t *irq_cookie = data->irq_cookie;
- irq_id_t irq_id = data->irq_id;
-
- if (!check_irq_id_is_valid(irq_cookie, irq_id)) {
- ret = -EINVAL;
- goto exit;
- }
-
- if (!check_irq_id_is_allocated(irq_cookie, irq_id)) {
- ret = -EINVAL;
- goto exit;
- }
-
- irq_entry_t *irq_entry = &(irq_cookie->irq_table[irq_id]);
- int error = seL4_IRQHandler_Ack(irq_entry->handler_path.capPtr);
- if (error) {
- ZF_LOGE("Failed to acknowledge IRQ");
- ret = -EFAULT;
- goto exit;
- }
-
-exit:
- ps_free(irq_cookie->malloc_ops, sizeof(ack_data_t), data);
-
- return ret;
-}
-
-int sel4platsupport_new_irq_ops(ps_irq_ops_t *irq_ops, vka_t *vka, simple_t *simple,
- irq_interface_config_t irq_config, ps_malloc_ops_t *malloc_ops)
-{
- if (!irq_ops || !vka || !simple || !malloc_ops) {
- return -EINVAL;
- }
-
- if (irq_config.max_irq_ids == 0 || irq_config.max_ntfn_ids == 0) {
- return -EINVAL;
- }
-
int err = 0;
irq_cookie_t *cookie = 0;
@@ -406,12 +401,7 @@
cookie->num_irq_bitfields = num_irq_bitfields;
cookie->num_ntfn_bitfields = num_ntfn_bitfields;
- /* Fill in the actual IRQ ops structure now */
- irq_ops->cookie = (void *) cookie;
- irq_ops->irq_register_fn = sel4platsupport_irq_register;
- irq_ops->irq_unregister_fn = sel4platsupport_irq_unregister;
-
- return 0;
+ return cookie;
error:
if (cookie) {
@@ -431,24 +421,127 @@
ps_free(malloc_ops, sizeof(irq_cookie_t), cookie);
}
- return -ENOMEM;
+ return NULL;
}
-static void provide_ntfn_common(irq_cookie_t *irq_cookie, seL4_CPtr ntfn, seL4_Word usable_mask,
- ntfn_id_t allocated_id)
+static int sel4platsupport_irq_unregister(void *cookie, irq_id_t irq_id)
{
- cspacepath_t ntfn_path = {0};
- vka_cspace_make_path(irq_cookie->vka, ntfn, &ntfn_path);
+ irq_cookie_t *irq_cookie = cookie;
- /* Clear the notification entry and then fill in bookkeeping information */
- ntfn_entry_t *ntfn_entry = &(irq_cookie->ntfn_table[allocated_id]);
- memset(ntfn_entry, 0, sizeof(ntfn_entry_t));
- ntfn_entry->allocated = true;
- ntfn_entry->root_ntfn_path = ntfn_path;
- ntfn_entry->usable_mask = usable_mask;
+ if (!check_irq_id_is_valid(irq_cookie, irq_id)) {
+ return -EINVAL;
+ }
- irq_cookie->num_allocated_ntfns++;
- fill_bit_in_bitfield(irq_cookie->allocated_ntfn_bitfields, allocated_id);
+ if (!check_irq_id_is_allocated(irq_cookie, irq_id)) {
+ return -EINVAL;
+ }
+
+ irq_entry_t *irq_entry = &(irq_cookie->irq_table[irq_id]);
+
+ if (irq_entry->paired_ntfn > UNPAIRED_ID) {
+ /* Clear the handler */
+ int error = seL4_IRQHandler_Clear(irq_entry->handler_path.capPtr);
+ if (error) {
+ /* Give a slightly ambigious message as we don't want to leak implementation details */
+ ZF_LOGE("Failed to unregister an IRQ");
+ return -EFAULT;
+ }
+
+ /* Delete the notification */
+ vka_cnode_delete(&(irq_entry->ntfn_path));
+ vka_cspace_free_path(irq_cookie->vka, irq_entry->ntfn_path);
+
+ /* Clear the necessary information in the notification array */
+ ntfn_entry_t *ntfn_entry = &(irq_cookie->ntfn_table[irq_entry->paired_ntfn]);
+ ntfn_entry->status_bitfield &= ~BIT(irq_entry->allocated_badge_index);
+ ntfn_entry->pending_bitfield &= ~BIT(irq_entry->allocated_badge_index);
+ ntfn_entry->bound_irqs[irq_entry->allocated_badge_index] = UNPAIRED_ID;
+ ntfn_entry->num_irqs_bound--;
+ }
+
+ /* Delete the handler */
+ vka_cnode_delete(&(irq_entry->handler_path));
+ vka_cspace_free_path(irq_cookie->vka, irq_entry->handler_path);
+
+ /* Zero-out the entire entry */
+ memset(irq_entry, 0, sizeof(irq_entry_t));
+ /* Reset parts of the entry */
+ irq_entry->paired_ntfn = UNPAIRED_ID;
+ irq_entry->allocated_badge_index = UNALLOCATED_BADGE_INDEX;
+
+ irq_cookie->num_registered_irqs--;
+ unfill_bit_in_bitfield(irq_cookie->allocated_irq_bitfields, irq_id);
+
+ return 0;
+}
+
+/* The register function for the standard IRQ interface */
+static irq_id_t sel4platsupport_irq_register(void *cookie, ps_irq_t irq, irq_callback_fn_t callback,
+ void *callback_data)
+{
+ irq_cookie_t *irq_cookie = cookie;
+
+ return irq_register_common(irq_cookie, irq, callback, callback_data);
+}
+
+static int sel4platsupport_irq_acknowledge(void *ack_data)
+{
+ if (!ack_data) {
+ return -EINVAL;
+ }
+
+ int ret = 0;
+
+ ack_data_t *data = ack_data;
+ irq_cookie_t *irq_cookie = data->irq_cookie;
+ irq_id_t irq_id = data->irq_id;
+
+ if (!check_irq_id_is_valid(irq_cookie, irq_id)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (!check_irq_id_is_allocated(irq_cookie, irq_id)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ irq_entry_t *irq_entry = &(irq_cookie->irq_table[irq_id]);
+ int error = seL4_IRQHandler_Ack(irq_entry->handler_path.capPtr);
+ if (error) {
+ ZF_LOGE("Failed to acknowledge IRQ");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+exit:
+ ps_free(irq_cookie->malloc_ops, sizeof(ack_data_t), data);
+
+ return ret;
+}
+
+int sel4platsupport_new_irq_ops(ps_irq_ops_t *irq_ops, vka_t *vka, simple_t *simple,
+ irq_interface_config_t irq_config, ps_malloc_ops_t *malloc_ops)
+{
+ if (!irq_ops || !vka || !simple || !malloc_ops) {
+ return -EINVAL;
+ }
+
+ if (irq_config.max_irq_ids == 0 || irq_config.max_ntfn_ids == 0) {
+ return -EINVAL;
+ }
+
+ irq_cookie_t *cookie = new_irq_ops_common(vka, simple, irq_config, malloc_ops);
+ if (!cookie) {
+ return -ENOMEM;
+ }
+
+ /* Fill in the actual IRQ ops structure now */
+ irq_ops->cookie = (void *) cookie;
+ irq_ops->irq_register_fn = sel4platsupport_irq_register;
+ irq_ops->irq_unregister_fn = sel4platsupport_irq_unregister;
+
+ return 0;
}
ntfn_id_t sel4platsupport_irq_provide_ntfn(ps_irq_ops_t *irq_ops, seL4_CPtr ntfn, seL4_Word usable_mask)
@@ -565,76 +658,7 @@
return -EINVAL;
}
- irq_entry_t *irq_entry = &(irq_cookie->irq_table[irq_id]);
-
- /* Check if the IRQ is already bound to something */
- if (irq_entry->paired_ntfn > UNPAIRED_ID) {
- return -EINVAL;
- }
-
- ntfn_entry_t *ntfn_entry = &(irq_cookie->ntfn_table[ntfn_id]);
-
- /* Check if we have space to bound another IRQ to this notification */
- if (ntfn_entry->num_irqs_bound >= MAX_INTERRUPTS_TO_NOTIFICATIONS) {
- return -ENOSPC;
- }
-
- /* Find an empty space (unclaimed bit in the badge) for the IRQ */
- int badge_index = find_free_ntfn_badge_index(ntfn_entry);
- if (badge_index == -1) {
- return -ENOSPC;
- }
-
- /* Allocate a CSpace slot and mint the root notification object with badge */
- cspacepath_t mint_path = {0};
- int error = vka_cspace_alloc_path(irq_cookie->vka, &mint_path);
- if (error) {
- return -ENOMEM;
- }
-
- seL4_Word badge = BIT(badge_index);
- error = vka_cnode_mint(&mint_path, &(ntfn_entry->root_ntfn_path), seL4_AllRights, badge);
- if (error) {
- vka_cspace_free_path(irq_cookie->vka, mint_path);
- return -ENOMEM;
- }
-
- /* Bind the notification with the handler now */
- error = seL4_IRQHandler_SetNotification(irq_entry->handler_path.capPtr, mint_path.capPtr);
- if (error) {
- ZF_LOGE("Failed to set a notification with the IRQ handler");
- error = vka_cnode_delete(&mint_path);
- ZF_LOGF_IF(error, "Failed to cleanup after a failed IRQ set ntfn operation");
- vka_cspace_free_path(irq_cookie->vka, mint_path);
- return -EFAULT;
- }
-
- /* Acknowledge the handler so interrupts can arrive on the notification */
- error = seL4_IRQHandler_Ack(irq_entry->handler_path.capPtr);
- if (error) {
- ZF_LOGE("Failed to ack an IRQ handler");
- error = seL4_IRQHandler_Clear(irq_entry->handler_path.capPtr);
- ZF_LOGF_IF(error, "Failed to unpair a notification after a failed IRQ set ntfn operation");
- error = vka_cnode_delete(&mint_path);
- ZF_LOGF_IF(error, "Failed to cleanup after a failed IRQ set ntfn operation");
- vka_cspace_free_path(irq_cookie->vka, mint_path);
- return -EFAULT;
- }
-
- if (ret_badge) {
- *ret_badge = badge;
- }
-
- /* Fill in the bookkeeping information */
- ntfn_entry->num_irqs_bound++;
- ntfn_entry->status_bitfield |= badge;
- ntfn_entry->bound_irqs[badge_index] = irq_id;
-
- irq_entry->ntfn_path = mint_path;
- irq_entry->paired_ntfn = ntfn_id;
- irq_entry->allocated_badge_index = badge_index;
-
- return 0;
+ return irq_set_ntfn_common(irq_cookie, ntfn_id, irq_id, ret_badge);
}
int sel4platsupport_irq_unset_ntfn(ps_irq_ops_t *irq_ops, irq_id_t irq_id)