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#include <autoconf.h> 14#include <sel4platsupport/gen_config.h> 15#include <vka/object.h> 16#include <vka/vka.h> 17#include <vka/capops.h> 18#include <sel4platsupport/timer.h> 19#include <platsupport/ltimer.h> 20#include <sel4platsupport/device.h> 21#include <sel4platsupport/io.h> 22#include <utils/util.h> 23 24static void cleanup_timer_irq(vka_t *vka, sel4ps_irq_t *irq) 25{ 26 seL4_IRQHandler_Clear(irq->handler_path.capPtr); 27 /* clear the cslots */ 28 vka_cnode_delete(&irq->badged_ntfn_path); 29 vka_cnode_delete(&irq->handler_path); 30 /* free the cslots */ 31 vka_cspace_free(vka, irq->badged_ntfn_path.capPtr); 32 vka_cspace_free(vka, irq->handler_path.capPtr); 33} 34 35 36void sel4platsupport_destroy_timer(seL4_timer_t *timer, vka_t *vka) 37{ 38 ltimer_destroy(&timer->ltimer); 39 assert(timer->to.nirqs < MAX_IRQS); 40 for (size_t i = 0; i < timer->to.nirqs; i++) { 41 cleanup_timer_irq(vka, &timer->to.irqs[i]); 42 } 43 44 assert(timer->to.nobjs < MAX_OBJS); 45 for (size_t i = 0; i < timer->to.nobjs; i++) { 46 vka_free_object(vka, &timer->to.objs[i].obj); 47 } 48} 49 50void sel4platsupport_handle_timer_irq(seL4_timer_t *timer, seL4_Word badge) 51{ 52 assert(timer->to.nirqs < MAX_IRQS); 53 /* check which bits are set to find which irq to handle */ 54 for (unsigned long i = 0; badge && i < timer->to.nirqs; i++) { 55 /* invert the bit: we take the top badge bits to identify timers */ 56 long irq = seL4_BadgeBits - i - 1; 57 if (badge & BIT(irq)) { 58 /* mask the bit out of the badge */ 59 badge &= ~BIT(irq); 60 if (timer->to.irqs[i].irq.type != PS_NONE) { 61 int error = seL4_IRQHandler_Ack(timer->to.irqs[i].handler_path.capPtr); 62 if (error) { 63 ZF_LOGE("Failed to ack irq %lu, error %d", irq, error); 64 } 65 } 66 } 67 } 68} 69 70static int setup_irq(vka_t *vka, sel4ps_irq_t *irq, seL4_Word badge, seL4_CPtr ntfn) 71{ 72 int error = vka_cspace_alloc_path(vka, &irq->badged_ntfn_path); 73 cspacepath_t path; 74 vka_cspace_make_path(vka, ntfn, &path); 75 if (!error) { 76 /* badge it */ 77 error = vka_cnode_mint(&irq->badged_ntfn_path, &path, seL4_AllRights, badge); 78 } 79 if (!error) { 80 /* set notification *before* acking any pending IRQ to ensure there is no race where 81 * we lose an IRQ */ 82 error = seL4_IRQHandler_SetNotification(irq->handler_path.capPtr, irq->badged_ntfn_path.capPtr); 83 } 84 if (!error) { 85 error = seL4_IRQHandler_Ack(irq->handler_path.capPtr); 86 } 87 return error; 88} 89 90static int get_nth_pmem(vka_t *vka, ltimer_t *ltimer, sel4ps_pmem_t *obj, int n) 91{ 92 int error = ltimer_get_nth_pmem(ltimer, n, &obj->region); 93 if (!error && obj->region.length > PAGE_SIZE_4K) { 94 ZF_LOGE("Support for timers with anything but 4K pages unimplemented! length %zu", 95 (size_t) obj->region.length); 96 return ENOSYS; 97 } 98 99 obj->region.length = PAGE_SIZE_4K; 100 if (!error) { 101 error = vka_alloc_untyped_at(vka, seL4_PageBits, obj->region.base_addr, 102 &obj->obj); 103 } 104 obj->obj.size_bits = seL4_PageBits; 105 if (error) { 106 ZF_LOGF("Failed to obtain device-ut cap for default timer."); 107 } 108 return error; 109} 110 111static inline size_t get_nirqs(ltimer_t *ltimer) 112{ 113 size_t nirqs = ltimer_get_num_irqs(ltimer); 114 if (nirqs > MAX_IRQS) { 115 ZF_LOGE("MAX_IRQS insufficient for timer"); 116 return -1; 117 } 118 119 return nirqs; 120} 121 122static int init_timer_internal(vka_t *vka, simple_t *simple, seL4_CPtr ntfn, 123 seL4_timer_t *timer, size_t nirqs) 124{ 125 126 /* set up the irq caps the timer needs */ 127 timer->to.nirqs = 0; 128 for (size_t i = 0; i < nirqs; i++) { 129 assert(timer->to.irqs[i].irq.type != PS_NONE); 130 int error = sel4platsupport_copy_irq_cap(vka, simple, &timer->to.irqs[i].irq, 131 &timer->to.irqs[i].handler_path); 132 if (!error) { 133 error = setup_irq(vka, &timer->to.irqs[i], BIT(seL4_BadgeBits - i - 1), ntfn); 134 } 135 if (error) { 136 sel4platsupport_destroy_timer(timer, vka); 137 return error; 138 } 139 /* increment as we go to aid destruction */ 140 timer->to.nirqs++; 141 } 142 143 timer->to.nobjs = 0; 144 return 0; 145} 146 147int sel4platsupport_init_default_timer_ops(vka_t *vka, UNUSED vspace_t *vspace, simple_t *simple, 148 ps_io_ops_t ops, seL4_CPtr ntfn, seL4_timer_t *timer) 149{ 150 int error; 151 if (timer == NULL) { 152 return EINVAL; 153 } 154 155 error = ltimer_default_describe(&timer->ltimer, ops); 156 157 if (!error) { 158 size_t nirqs = get_nirqs(&timer->ltimer); 159 for (size_t i = 0; i < nirqs; i++) { 160 error = ltimer_get_nth_irq(&timer->ltimer, i, &timer->to.irqs[i].irq); 161 if (error) { 162 return error; 163 } 164 } 165 error = init_timer_internal(vka, simple, ntfn, timer, nirqs); 166 } 167 168 if (!error) { 169 error = ltimer_default_init(&timer->ltimer, ops, NULL, NULL); 170 } 171 return error; 172} 173 174int sel4platsupport_init_default_timer(vka_t *vka, vspace_t *vspace, simple_t *simple, 175 seL4_CPtr ntfn, seL4_timer_t *timer) 176{ 177 int error; 178 179 /* initialise io ops */ 180 ps_io_ops_t ops; 181 memset(&ops, 0, sizeof(ops)); 182 error = sel4platsupport_new_io_ops(vspace, vka, simple, &ops); 183 if (!error) { 184 /* we have no way of storing the fact that we allocated these io ops so we'll just leak 185 * them forever */ 186 return sel4platsupport_init_default_timer_ops(vka, vspace, simple, ops, ntfn, timer); 187 } 188 return error; 189} 190 191int sel4platsupport_init_timer_irqs(vka_t *vka, simple_t *simple, 192 seL4_CPtr ntfn, seL4_timer_t *timer, timer_objects_t *to) 193{ 194 if (timer == NULL) { 195 return EINVAL; 196 } 197 198 /* copy the timer objects */ 199 timer->to = *to; 200 return init_timer_internal(vka, simple, ntfn, timer, to->nirqs); 201} 202 203 204int sel4platsupport_init_default_timer_caps(vka_t *vka, vspace_t *vspace, simple_t *simple, 205 timer_objects_t *timer_objects) 206{ 207 /* initialise io ops */ 208 ps_io_ops_t ops; 209 memset(&ops, 0, sizeof(ops)); 210 int error = sel4platsupport_new_io_ops(vspace, vka, simple, &ops); 211 if (error) { 212 ZF_LOGE("Failed to get io ops"); 213 return error;; 214 } 215 216 /* Allocate timer irqs. */ 217 ltimer_t ltimer; 218 error = ltimer_default_describe(<imer, ops); 219 if (error) { 220 ZF_LOGE("Failed to describe default timer"); 221 return error; 222 } 223 224 /* set up the irq caps the timer needs */ 225 size_t nirqs = get_nirqs(<imer); 226 for (size_t i = 0; i < nirqs; i++) { 227 error = ltimer_get_nth_irq(<imer, i, &timer_objects->irqs[i].irq); 228 assert(timer_objects->irqs[i].irq.type != PS_NONE); 229 if (!error) { 230 error = sel4platsupport_copy_irq_cap(vka, simple, &timer_objects->irqs[i].irq, 231 &timer_objects->irqs[i].handler_path); 232 } 233 if (error) { 234 ZF_LOGE("Failed to get irq cap %zu", i); 235 return error; 236 } 237 timer_objects->nirqs++; 238 } 239 240 /* Obtain untyped frame caps for PS default ltimer. 241 * currently this code assumes all timers need a 4k frame. 242 */ 243 size_t nobjs = ltimer_get_num_pmems(<imer); 244 if (nobjs > MAX_OBJS) { 245 ZF_LOGE("MAX_OBJS insufficient for timer"); 246 return -1; 247 } 248 249 for (size_t i = 0; i < nobjs; i++) { 250 error = get_nth_pmem(vka, <imer, &timer_objects->objs[i], i); 251 timer_objects->objs[i].obj.size_bits = seL4_PageBits; 252 if (error) { 253 ZF_LOGE("Failed to get nth pmem"); 254 return error; 255 } 256 /* increment as we go to aid destruction */ 257 timer_objects->nobjs++; 258 } 259 260 return error; 261} 262 263seL4_CPtr sel4platsupport_timer_objs_get_irq_cap(timer_objects_t *to, int id, irq_type_t type) 264{ 265 for (size_t i = 0; i < to->nirqs; i++) { 266 if (to->irqs[i].irq.type == type) { 267 switch (type) { 268 case PS_MSI: 269 if (to->irqs[i].irq.msi.vector == id) { 270 return to->irqs[i].handler_path.capPtr; 271 } 272 break; 273 case PS_IOAPIC: 274 if (to->irqs[i].irq.ioapic.pin == id) { 275 return to->irqs[i].handler_path.capPtr; 276 } 277 break; 278 case PS_INTERRUPT: 279 if (to->irqs[i].irq.irq.number == id) { 280 return to->irqs[i].handler_path.capPtr; 281 } 282 break; 283 case PS_TRIGGER: 284 if (to->irqs[i].irq.trigger.number == id) { 285 return to->irqs[i].handler_path.capPtr; 286 } 287 break; 288 case PS_NONE: 289 ZF_LOGE("Invalid irq type"); 290 break; 291 default: 292 ZF_LOGE("Unsupported irq type"); 293 } 294 } 295 } 296 297 ZF_LOGE("Could not find irq"); 298 return seL4_CapNull; 299} 300