Last active
September 30, 2025 16:00
-
-
Save DrSensor/4f326af86e21d5fe625bbd8570e2ae70 to your computer and use it in GitHub Desktop.
unsafe ISR problem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [build] | |
| target = "riscv32imac-unknown-none-elf" | |
| [target.riscv32imac-unknown-none-elf] | |
| runner = "qemu-runner.sh" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [package] | |
| name = "isr-i2c-sim" | |
| version = "0.1.0" | |
| edition = "2021" | |
| [dependencies] | |
| riscv = "0.9" # riscv register helpers | |
| riscv-rt = "0.11" # runtime + interrupt vectors | |
| panic-halt = "0.2" # halting panic handler | |
| cortex-m-semihosting = "0.5" # optional for semihost logging (works on some QEMU setups) | |
| [profile.release] | |
| opt-level = "z" | |
| codegen-units = 1 | |
| lto = true | |
| [package.metadata.cargo-targets] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using sysbus | |
| mach create "i2c_isr_test" | |
| # Use a generic RISC-V 'virt' machine | |
| machine LoadPlatformDescription @platforms/cpus/riscv32-virt.repl | |
| # Load our firmware ELF | |
| sysbus LoadELF @target/riscv32imac-unknown-none-elf/release/isr-i2c-sim | |
| # Create a timer that periodically triggers the machine timer interrupt | |
| emulation CreateTimer "irqTimer" 0.01 # 10ms period | |
| irqTimer -> irq 7 # IRQ7 is machine timer on virt | |
| irqTimer Enabled true | |
| # Start emulation | |
| start |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #![no_std] | |
| #![no_main] | |
| use core::cell::UnsafeCell; | |
| use core::panic::PanicInfo; | |
| use core::sync::atomic::{AtomicBool, Ordering}; | |
| use riscv::register::{mie, mstatus}; | |
| use riscv_rt::entry; | |
| #[no_mangle] | |
| pub static mut LOG_BUF: [u8; 4096] = [0; 4096]; | |
| #[no_mangle] | |
| pub static mut LOG_POS: usize = 0; | |
| fn log_bytes(bytes: &[u8]) { | |
| unsafe { | |
| let mut p = LOG_POS; | |
| for &b in bytes { | |
| LOG_BUF[p % LOG_BUF.len()] = b; | |
| p += 1; | |
| } | |
| LOG_POS = p; | |
| } | |
| } | |
| fn log_line(s: &str) { | |
| log_bytes(s.as_bytes()); | |
| log_bytes(b"\n"); | |
| } | |
| /// Very simple MockI2c | |
| struct MockI2c { | |
| tx_count: u32, | |
| } | |
| impl MockI2c { | |
| const fn new() -> Self { Self { tx_count: 0 } } | |
| fn start(&mut self, id: u32) { | |
| self.tx_count = self.tx_count.wrapping_add(1); | |
| log_line("START"); | |
| busy_delay(2000); | |
| } | |
| fn write(&mut self, id: u32, b: u8) { | |
| let buf = [b]; | |
| log_bytes(b"BYTE:"); | |
| log_bytes(&buf); | |
| log_bytes(b"\n"); | |
| busy_delay(2000); | |
| } | |
| fn stop(&mut self, id: u32) { | |
| log_line("STOP"); | |
| busy_delay(1000); | |
| } | |
| } | |
| fn busy_delay(n: u32) { | |
| for _ in 0..n { | |
| core::sync::atomic::compiler_fence(Ordering::SeqCst); | |
| } | |
| } | |
| /// Shared I²C instance | |
| static mut GLOBAL_I2C: UnsafeCell<MockI2c> = UnsafeCell::new(MockI2c::new()); | |
| /// Flag for safe mode ISR deferral | |
| static ISR_FLAG: AtomicBool = AtomicBool::new(false); | |
| #[entry] | |
| fn main() -> ! { | |
| unsafe { | |
| mstatus::set_mie(); | |
| mie::set_mtimer(); | |
| } | |
| log_line("boot"); | |
| for i in 0..200 { | |
| // optional jitter | |
| busy_delay(500); | |
| // ✅ Safe mode: check ISR flag | |
| #[cfg(feature = "safe")] | |
| if ISR_FLAG.swap(false, Ordering::Relaxed) { | |
| unsafe { | |
| let p = &mut *GLOBAL_I2C.get(); | |
| p.start(0xDEAD); | |
| p.write(0xDEAD, 0xEE); | |
| p.stop(0xDEAD); | |
| } | |
| } | |
| // Main transaction | |
| unsafe { | |
| let p = &mut *GLOBAL_I2C.get(); | |
| let txid = 1000 + i; | |
| p.start(txid); | |
| for b in 0..3 { | |
| p.write(txid, b); | |
| } | |
| p.stop(txid); | |
| } | |
| } | |
| log_line("done"); | |
| loop {} | |
| } | |
| #[export_name = "MachineTimer"] | |
| pub extern "C" fn machine_timer() { | |
| #[cfg(not(feature = "safe"))] | |
| unsafe { | |
| let p = &mut *GLOBAL_I2C.get(); | |
| p.start(0xDEAD); | |
| p.write(0xDEAD, 0xEE); | |
| p.stop(0xDEAD); | |
| } | |
| #[cfg(feature = "safe")] | |
| { | |
| ISR_FLAG.store(true, Ordering::Relaxed); | |
| } | |
| } | |
| #[panic_handler] | |
| fn panic(_info: &PanicInfo) -> ! { | |
| log_line("panic"); | |
| loop {} | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| MEMORY | |
| { | |
| RAM : ORIGIN = 0x8000_0000, LENGTH = 64K | |
| FLASH : ORIGIN = 0x200000, LENGTH = 512K | |
| } | |
| _estack = ORIGIN(RAM) + LENGTH(RAM); | |
| SECTIONS | |
| { | |
| .text : { KEEP(*(.vectors)); *(.text*) } > FLASH | |
| .rodata : { *(.rodata*) } > FLASH | |
| .data : { *(.data*) } > RAM AT > FLASH | |
| .bss : { *(.bss*) } > RAM | |
| /DISCARD/ : { *(.eh_frame) } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| case $2 in | |
| unsafe) | |
| cargo build --release | |
| ;; | |
| safe) | |
| cargo build --release --features safe | |
| ;; | |
| esac | |
| case $1 in | |
| qemu) # Example: using qemu-system-riscv32 for sifive_emulate (adjust as needed) | |
| qemu-system-riscv32 -machine sifive_u -nographic -kernel target/riscv32imac-unknown-none-elf/release/isr-i2c-sim | |
| ;; | |
| renode) | |
| renode isr-i2c-sim.resc & | |
| sysbus ReadBlockFromSymbol "LOG_BUF" 512 | |
| ;; | |
| test) | |
| renode-test test_isr_i2c.robot | |
| ;; | |
| esac |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| rustup target add riscv32imac-unknown-none-elf | |
| cargo install cargo-binutils | |
| rustup component add llvm-tools-preview |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| *** Settings *** | |
| Library RenodeLibrary | |
| *** Variables *** | |
| ${ELF} @target/riscv32imac-unknown-none-elf/release/isr-i2c-sim | |
| *** Test Cases *** | |
| Unsafe ISR Should Show Interleaving | |
| Start Emulation isr-i2c-sim.resc | |
| Execute Command sysbus LoadELF ${ELF} | |
| Start Emulation | |
| Sleep 1s | |
| ${pos}= Execute Command sysbus ReadDoubleWordFromSymbol "LOG_POS" | |
| ${data}= Execute Command sysbus ReadBlockFromSymbol "LOG_BUF" 512 | |
| Log ${data} | |
| Should Contain ${data} DEAD # check ISR marker appears mid-main | |
| Safe ISR Should Not Interleave | |
| Start Emulation isr-i2c-sim.resc | |
| Execute Command sysbus LoadELF ${ELF} | |
| Start Emulation | |
| Sleep 1s | |
| ${pos}= Execute Command sysbus ReadDoubleWordFromSymbol "LOG_POS" | |
| ${data}= Execute Command sysbus ReadBlockFromSymbol "LOG_BUF" 512 | |
| Log ${data} | |
| Should Not Contain ${data} Interleaved |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment