Next Generation WASM Microkernel Operating System
at trap_handler 82 lines 2.3 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8use crate::state::cpu_local; 9use alloc::sync::Arc; 10use core::num::NonZero; 11use hashbrown::HashMap; 12use kasync::sync::wait_queue::WaitQueue; 13use spin::{LazyLock, RwLock}; 14 15pub trait InterruptController { 16 fn irq_claim(&mut self) -> Option<IrqClaim>; 17 fn irq_complete(&mut self, claim: IrqClaim); 18 fn irq_mask(&mut self, irq_num: u32); 19 fn irq_unmask(&mut self, irq_num: u32); 20} 21 22#[derive(Debug, Clone, Copy, PartialEq, Eq)] 23pub struct IrqClaim(NonZero<u32>); 24 25impl IrqClaim { 26 pub unsafe fn from_raw(raw: NonZero<u32>) -> Self { 27 Self(raw) 28 } 29 pub fn as_u32(self) -> u32 { 30 self.0.get() 31 } 32} 33 34// hashbrown doesn't have a good const constructor, therefore the `LazyLock` 35static QUEUES: LazyLock<RwLock<HashMap<u32, Arc<WaitQueue>>>> = 36 LazyLock::new(|| RwLock::new(HashMap::new())); 37 38pub fn trigger_irq(irq_ctl: &mut dyn InterruptController) { 39 let Some(claim) = irq_ctl.irq_claim() else { 40 // Spurious interrupt 41 return; 42 }; 43 44 // acknowledge the interrupt as fast as possible 45 irq_ctl.irq_complete(claim); 46 47 let queues = QUEUES.read(); 48 if let Some(queue) = queues.get(&claim.as_u32()) { 49 tracing::trace!("waking wakers for irq-{}", claim.as_u32()); 50 let woken = queue.wake_all(); 51 tracing::trace!("woke {woken} wakers for irq-{}", claim.as_u32()); 52 } 53} 54 55pub async fn next_event(irq_num: u32) -> Result<(), kasync::Closed> { 56 cpu_local() 57 .arch 58 .cpu 59 .interrupt_controller() 60 .irq_unmask(irq_num); 61 62 let wait = { 63 let mut queues = QUEUES.write(); 64 let wait = queues 65 .entry(irq_num) 66 .or_insert_with(|| Arc::new(WaitQueue::new())) 67 .wait_owned(); 68 // don't hold the RwLock guard across the await point 69 drop(queues); 70 wait 71 }; 72 73 let res = wait.await; 74 75 cpu_local() 76 .arch 77 .cpu 78 .interrupt_controller() 79 .irq_mask(irq_num); 80 81 res 82}