1/* 2 * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9#include <kernel.h> 10#include <stdio.h> 11#include <string.h> 12#include <arch/arm/arm.h> 13#include <barrelfish_kpi/lmp.h> 14#include <barrelfish_kpi/syscalls.h> 15#include <barrelfish_kpi/sys_debug.h> 16 17#include <arch/armv7/irq.h> 18 19#include <paging_kernel_arch.h> 20#include <dispatch.h> 21#include <exec.h> 22#include <stdio.h> 23#include <syscall.h> 24#include <arch/arm/syscall_arm.h> 25#include <kcb.h> 26#include <arch/arm/gic.h> 27 28/** 29 * \brief User-space IRQ dispatch table. 30 * 31 * This is essentially a big CNode holding #NDISPATCH capability 32 * entries to local endpoints of user-space applications listening to 33 * the interrupts. 34 */ 35static struct cte irq_dispatch[NDISPATCH]; 36 37errval_t irq_table_set(unsigned int nidt, capaddr_t endpoint) 38{ 39 errval_t err; 40 struct cte *recv; 41 42 err = caps_lookup_slot(&dcb_current->cspace.cap, endpoint, 43 2, &recv, CAPRIGHTS_WRITE); 44 if (err_is_fail(err)) { 45 return err_push(err, SYS_ERR_IRQ_LOOKUP); 46 } 47 48 assert(recv != NULL); 49 50 // Return w/error if cap is not an endpoint 51 if (recv->cap.type != ObjType_EndPoint) { 52 return SYS_ERR_IRQ_NOT_ENDPOINT; 53 } 54 55 // Return w/error if no listener on endpoint 56 if (recv->cap.u.endpoint.listener == NULL) { 57 return SYS_ERR_IRQ_NO_LISTENER; 58 } 59 60 if (nidt < NDISPATCH) { 61 // check that we don't overwrite someone else's handler 62 if (irq_dispatch[nidt].cap.type != ObjType_Null) { 63 printf("kernel: installing new handler for IRQ %d\n", nidt); 64 } 65 err = caps_copy_to_cte(&irq_dispatch[nidt], recv, false, 0, 0); 66 67 // Route the interrupt to this CPU, as we're the only CPU driver that 68 // knows where to send it. XXX - this should change once we have more 69 // sophisticated interrupt routing. 70 // 71 // The mapping of interrupt interfaces to cores doesn't seem to be 72 // documented anywhere for the A9, and this will have to be different 73 // if we're using affinity routing on GICv3+ systems. 74 gic_enable_interrupt(nidt, BIT(my_core_id), 0, 75 GIC_IRQ_EDGE_TRIGGERED, GIC_IRQ_N_TO_N); 76#if 0 77 if (err_is_ok(err)) { 78 // Unmask interrupt if on PIC 79 if(nidt < 16) { 80 pic_toggle_irq(nidt, true); 81 } 82 } 83#endif 84 return err; 85 } 86 87 return SYS_ERR_IRQ_INVALID; 88} 89 90errval_t irq_table_delete(unsigned int nidt) 91{ 92 if (nidt < NDISPATCH) { 93 irq_dispatch[nidt].cap.type = ObjType_Null; 94 95 /* todo: gic disable irq */ 96 97 return SYS_ERR_OK; 98 } 99 return SYS_ERR_IRQ_INVALID; 100} 101 102errval_t irq_table_notify_domains(struct kcb *kcb) 103{ 104 uintptr_t msg[] = { 1 }; 105 for (int i = 0; i < NDISPATCH; i++) { 106 if (kcb->irq_dispatch[i].cap.type == ObjType_EndPoint) { 107 struct capability *cap = &kcb->irq_dispatch[i].cap; 108 // 1 word message as notification 109 errval_t err = lmp_deliver_payload(cap, NULL, msg, 1, false, false); 110 if (err_is_fail(err)) { 111 if (err_no(err) == SYS_ERR_LMP_BUF_OVERFLOW) { 112 struct dispatcher_shared_generic *disp = 113 get_dispatcher_shared_generic(cap->u.endpoint.listener->disp); 114 printk(LOG_DEBUG, "%.*s: IRQ message buffer overflow\n", 115 DISP_NAME_LEN, disp->name); 116 } else { 117 printk(LOG_ERR, "Unexpected error delivering IRQ\n"); 118 } 119 } 120 } 121 kcb->irq_dispatch[i].cap.type = ObjType_Null; 122 } 123 return SYS_ERR_OK; 124} 125 126/** 127 * \brief Send interrupt notification to user-space listener. 128 * 129 * Sends an interrupt notification IDC to a local endpoint that 130 * listens for IRQ notifications. 131 * 132 * \param irq IRQ# to send in notification. 133 */ 134void send_user_interrupt(int irq) 135{ 136 assert(irq >= 0 && irq < NDISPATCH); 137 struct capability *cap = &irq_dispatch[irq].cap; 138 139 // Return on null cap (unhandled interrupt) 140 if (cap->type == ObjType_Null) { 141 printk(LOG_WARN, "unhandled IRQ %d\n", irq); 142 return; 143 } 144 145 // Otherwise, cap needs to be an endpoint 146 assert(cap->type == ObjType_EndPoint); 147 errval_t err = lmp_deliver_notification(cap); 148 if (err_is_fail(err)) { 149 if (err_no(err) == SYS_ERR_LMP_BUF_OVERFLOW) { 150 struct dispatcher_shared_generic *disp = 151 get_dispatcher_shared_generic( 152 cap->u.endpoint.listener->disp); 153 printk(LOG_DEBUG, "%.*s: IRQ message buffer overflow\n", 154 DISP_NAME_LEN, disp->name); 155 } else { 156 printk(LOG_ERR, "Unexpected error delivering IRQ\n"); 157 } 158 } 159 160#ifdef SCHEDULER_RR 161 /* XXX: run the handler dispatcher immediately 162 * we shouldn't do this (we should let the scheduler decide), but because 163 * our default scheduler is braindead, this is a quick hack to make sure 164 * that mostly-sane things happen 165 */ 166 dispatch(cap->u.endpoint.listener); 167#else 168 dispatch(schedule()); 169#endif 170} 171