1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13/*- 14 * Copyright (c) 2014 Antti Kantee. All Rights Reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38#include <sel4/kernel.h> 39#include <sel4/helpers.h> 40#include <sel4/sel4.h> 41#include <bmk-core/core.h> 42#include <bmk-core/memalloc.h> 43#include <bmk-core/printf.h> 44#include <bmk-core/queue.h> 45#include <bmk-core/sched.h> 46 47#include <bmk-rumpuser/rumpuser.h> 48 49#define INTR_LEVELS (BMK_MAXINTR+1) 50#define INTR_ROUTED BMK_MAXINTR 51 52/* This is arbitrary and is safe to increment */ 53#define SOFT_INTRS 1 54 55struct intrhand { 56 int (*ih_fun)(void *); 57 void *ih_arg; 58 59 SLIST_ENTRY(intrhand) ih_entries; 60}; 61 62SLIST_HEAD(isr_ihead, intrhand); 63static struct isr_ihead isr_ih[INTR_LEVELS]; 64static struct isr_ihead isr_ih_soft[SOFT_INTRS]; 65 66static volatile unsigned int isr_todo; 67static volatile unsigned int isr_todo_soft; 68static unsigned int isr_lowest = sizeof(isr_todo) * 8; 69static unsigned int isr_soft_lowest = SOFT_INTRS-1; 70 71static struct bmk_thread *isr_thread; 72 73 74static void process_handlers(isr_type_t type, unsigned int isrcopy, unsigned lowest) { 75 for (int i = lowest; isrcopy; i++) { 76 struct intrhand *ih; 77 78 bmk_assert(i < sizeof(isrcopy) * 8); 79 if ((isrcopy & (BIT(i))) == 0) { 80 continue; 81 } 82 isrcopy &= ~(BIT(i)); 83 if (type == HARDWARE_INT) { 84 85 SLIST_FOREACH(ih, &isr_ih[i], ih_entries) { 86 ih->ih_fun(ih->ih_arg); 87 } 88 /* Ack seL4 interrupt now that it has been handled */ 89 if (is_hw_pci_config(&env.custom_simple)) { 90 if (!config_set(CONFIG_USE_MSI_ETH)) { 91 int error = seL4_IRQHandler_Ack(env.caps[i]); 92 ZF_LOGF_IFERR(error, "seL4_IRQHandler_Ack failed"); 93 } 94 } else { 95 env.custom_simple.ethernet_intr_config.eth_irq_acknowledge(); 96 } 97 } else if (type == SOFTWARE_EVENT) { 98 SLIST_FOREACH(ih, &isr_ih_soft[i], ih_entries) { 99 ih->ih_fun(ih->ih_arg); 100 } 101 } 102 } 103 104} 105 106/* thread context we use to deliver interrupts to the rump kernel */ 107static void 108doisr(void *arg) 109{ 110 rumpuser__hyp.hyp_schedule(); 111 rumpuser__hyp.hyp_lwproc_newlwp(0); 112 rumpuser__hyp.hyp_unschedule(); 113 114 bmk_platform_splhigh(); 115 for (;;) { 116 unsigned int isrcopy; 117 int nlocks = 1; 118 119 /* Process hardware interrupt handlers */ 120 isrcopy = isr_todo; 121 isr_todo = 0; 122 bmk_platform_splx(0); 123 rumpkern_sched(nlocks, NULL); 124 process_handlers(HARDWARE_INT, isrcopy, isr_lowest); 125 rumpkern_unsched(&nlocks, NULL); 126 127 /* Process software event handlers */ 128 bmk_platform_splhigh(); 129 isrcopy = isr_todo_soft; 130 isr_todo_soft = 0; 131 bmk_platform_splx(0); 132 rumpkern_sched(nlocks, NULL); 133 process_handlers(SOFTWARE_EVENT, isrcopy, isr_soft_lowest); 134 rumpkern_unsched(&nlocks, NULL); 135 136 bmk_platform_splhigh(); 137 if (isr_todo || isr_todo_soft) { 138 continue; 139 } 140 141 /* no interrupts left. block until the next one. */ 142 bmk_sched_blockprepare(); 143 144 bmk_platform_splx(0); 145 bmk_sched_block(); 146 bmk_platform_splhigh(); 147 } 148} 149 150static int alloc_number(void) { 151 static int intr_reserved = 0; 152 if (intr_reserved >= SOFT_INTRS) { 153 bmk_platform_halt("No more interrupt slots available."); 154 } 155 intr_reserved++; 156 return intr_reserved -1; 157} 158 159int 160bmk_isr_rumpkernel(int (*func)(void *), void *arg, int intr, isr_type_t type) 161{ 162 if (type == SOFTWARE_EVENT) { 163 intr = alloc_number(); 164 } else if (type == HARDWARE_INT) { 165 166 if (intr > sizeof(isr_todo) * 8 || intr > BMK_MAXINTR) { 167 bmk_platform_halt("bmk_isr_rumpkernel: intr"); 168 } 169 170 } 171 struct intrhand *ih = bmk_xmalloc_bmk(sizeof(*ih)); 172 if (!ih) { 173 bmk_platform_halt("bmk_isr_rumpkernel: xmalloc"); 174 } 175 176 ih->ih_fun = func; 177 ih->ih_arg = arg; 178 if (type == HARDWARE_INT) { 179 180 SLIST_INSERT_HEAD(&isr_ih[intr], ih, ih_entries); 181 if ((unsigned)intr < isr_lowest) { 182 isr_lowest = intr; 183 } 184 } else if (type == SOFTWARE_EVENT) { 185 SLIST_INSERT_HEAD(&isr_ih_soft[intr], ih, ih_entries); 186 if ((unsigned)intr < isr_soft_lowest) { 187 isr_soft_lowest = intr; 188 } 189 } 190 return intr; 191} 192 193void 194isr(int which, int soft_which) 195{ 196 /* schedule the interrupt handler */ 197 isr_todo_soft |= soft_which; 198 isr_todo |= which; 199 200 bmk_sched_wake(isr_thread); 201} 202 203void 204intr_init(void) 205{ 206 int i; 207 208 for (i = 0; i < INTR_LEVELS; i++) { 209 SLIST_INIT(&isr_ih[i]); 210 } 211 212 for (i = 0; i < SOFT_INTRS; i++) { 213 SLIST_INIT(&isr_ih_soft[i]); 214 } 215 216 isr_thread = bmk_sched_create("isrthr", NULL, 0, doisr, NULL, NULL, 0); 217 if (!isr_thread) { 218 bmk_platform_halt("intr_init"); 219 } 220} 221