Skip to main content

atmos/kernel/
interrupt.rs

1#![allow(static_mut_refs)]
2use crate::kernel::fifo::Fifo;
3use spin::Mutex;
4
5// グローバルな入力イベントキュー (FIFO)
6pub static KBD_FIFO: Mutex<Fifo<16>> = Mutex::new(Fifo::new());
7pub static MOUSE_FIFO: Mutex<Fifo<128>> = Mutex::new(Fifo::new());
8pub static UART_FIFO: Mutex<Fifo<128>> = Mutex::new(Fifo::new());
9
10const UART0_BASE: usize = 0x3F20_1000;
11const UART0_DR: *mut u32 = UART0_BASE as *mut u32;
12const UART0_FR: *mut u32 = (UART0_BASE + 0x18) as *mut u32;
13const UART0_IMSC: *mut u32 = (UART0_BASE + 0x38) as *mut u32;
14const UART0_MIS: *mut u32 = (UART0_BASE + 0x40) as *mut u32;
15const UART0_ICR: *mut u32 = (UART0_BASE + 0x44) as *mut u32;
16
17const ENABLE_IRQS_2: *mut u32 = 0x3F00_B214 as *mut u32;
18const IRQ_PENDING_2: *mut u32 = 0x3F00_B208 as *mut u32;
19
20// BCM2837 コアローカル割り込みコントローラ (QA7) レジスタ定義
21const LOCAL_CONTROL_BASE: usize = 0x4000_0000;
22const CORE_TIMER_INT_CTRL_BASE: usize = LOCAL_CONTROL_BASE + 0x40;
23const CORE_INT_SRC_BASE: usize = LOCAL_CONTROL_BASE + 0x60;
24
25const UART0_IRQ_BIT: u32 = 1 << 25; // IRQ 57 (57 - 32 = 25)
26
27#[inline]
28fn core_id() -> usize {
29    let mpidr: u64;
30    unsafe {
31        core::arch::asm!("mrs {}, mpidr_el1", out(reg) mpidr);
32    }
33    (mpidr & 0xFF) as usize
34}
35
36pub fn init() {
37    unsafe {
38        // 1. 割り込みコントローラで UART0 (IRQ 57) を有効化
39        core::ptr::write_volatile(ENABLE_IRQS_2, UART0_IRQ_BIT);
40
41        // 2. UART0 (PL011) の受信割り込みマスクを有効化 (RXIM: ビット4 = 0x10)
42        core::ptr::write_volatile(UART0_IMSC, 0x10);
43
44        // 3. 初期の割り込みクリア
45        core::ptr::write_volatile(UART0_ICR, 0x10);
46
47        // 4. Core0の物理非セキュアタイマー割り込み (nCNTPNSIRQ = Bit 1) を許可
48        let ctrl_ptr = CORE_TIMER_INT_CTRL_BASE as *mut u32; // Core0: オフセット = コア番号 * 4 = 0
49        core::ptr::write_volatile(ctrl_ptr, 1 << 1);
50    }
51}
52
53pub fn init_secondary() {
54    unsafe {
55        let cid = core_id();
56        let ctrl_ptr = (CORE_TIMER_INT_CTRL_BASE + (cid * 4)) as *mut u32;
57        core::ptr::write_volatile(ctrl_ptr, 1 << 1);
58    }
59}
60
61/// CPU全体のIRQ割り込みを許可します (MSR DAIFCLR)
62pub fn enable_interrupts() {
63    unsafe {
64        core::arch::asm!("msr daifclr, #2", options(nomem, nostack));
65    }
66}
67
68/// CPU全体のIRQ割り込みを禁止します (MSR DAIFSET)
69pub fn disable_interrupts() {
70    unsafe {
71        core::arch::asm!("msr daifset, #2", options(nomem, nostack));
72    }
73}
74
75#[no_mangle]
76pub extern "C" fn rust_irq_handler() {
77    unsafe {
78        let cid = core_id();
79        let src_ptr = (CORE_INT_SRC_BASE + (cid * 4)) as *mut u32;
80        let int_src = core::ptr::read_volatile(src_ptr);
81
82        let mut timer_fired = false;
83
84        // 1. コアのローカル割り込みソース(タイマー等)を確認
85        if (int_src & (1 << 1)) != 0 {
86            crate::kernel::timer::handle_timer_irq();
87            timer_fired = true;
88        }
89
90        // UART / USB などの共有割り込み (GPU IRQ)
91        // ルーティング先のコア(デフォルトCore0)のみで処理する (他コアとの多重処理による競合・フリーズ防止)
92        if cid == 0
93            && (core::ptr::read_volatile(IRQ_PENDING_2) & UART0_IRQ_BIT) != 0
94            && (core::ptr::read_volatile(UART0_MIS) & 0x10) != 0
95        {
96            while (core::ptr::read_volatile(UART0_FR) & 0x10) == 0 {
97                let data = core::ptr::read_volatile(UART0_DR) & 0xFF;
98                let _ = UART_FIFO.lock().push(data);
99            }
100            core::ptr::write_volatile(UART0_ICR, 0x10);
101        }
102
103        // すべての割り込みの処理とデバイス側のクリアが完了した後に、タイマー処理(Ticksカウントダウン & タイムスライス管理)を実行する
104        if timer_fired {
105            crate::kernel::scheduler::decrement_wait_ticks();
106            crate::kernel::scheduler::scheduler_tick();
107        }
108
109        // 割り込み出口でのプリエンプション(強制再スケジュール)チェック
110        if crate::kernel::scheduler::should_preempt() {
111            crate::kernel::scheduler::schedule();
112        }
113    }
114}