diff --git a/artiq/compiler/kernel.ld b/artiq/compiler/kernel.ld index 6523d631a0..fafbea2af3 100644 --- a/artiq/compiler/kernel.ld +++ b/artiq/compiler/kernel.ld @@ -50,4 +50,7 @@ SECTIONS . = ALIGN(4); _end = .; } + + . = ALIGN(0x1000); + _sstack_guard = .; } diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 194952672d..77d2625389 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "fringe" version = "1.2.1" -source = "git+https://git.m-labs.hk/M-Labs/libfringe.git?rev=9748bb#9748bb8af86c131d45be1238ea4d5f965a974630" +source = "git+https://git.m-labs.hk/M-Labs/libfringe.git?rev=3ecbe5#3ecbe53f7644b18ee46ebd5b2ca12c9cbceec43a" dependencies = [ "libc 0.2.101", ] diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 1ef7426a11..9a41bdb4b5 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -17,7 +17,7 @@ use board_misoc::slave_fpga; #[cfg(has_ethmac)] use board_misoc::{clock, ethmac, net_settings}; use board_misoc::uart_console::Console; -use riscv::register::{mcause, mepc}; +use riscv::register::{mcause, mepc, mtval}; fn check_integrity() -> bool { extern { @@ -522,7 +522,8 @@ pub extern fn main() -> i32 { pub extern fn exception(_regs: *const u32) { let pc = mepc::read(); let cause = mcause::read().cause(); - panic!("{:?} at PC {:#08x}", cause, u32::try_from(pc).unwrap()) + let mtval = mtval::read(); + panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval); } #[no_mangle] diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index aaedbd018a..d915d7e812 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -23,7 +23,7 @@ use proto_artiq::{kernel_proto, rpc_proto}; use kernel_proto::*; #[cfg(has_rtio_dma)] use board_misoc::csr; -use riscv::register::{mcause, mepc}; +use riscv::register::{mcause, mepc, mtval}; fn send(request: &Message) { unsafe { mailbox::send(request as *const _ as usize) } @@ -493,11 +493,13 @@ pub unsafe fn main() { let _end = library.lookup(b"_end").unwrap(); let __modinit__ = library.lookup(b"__modinit__").unwrap(); let typeinfo = library.lookup(b"typeinfo"); + let _sstack_guard = library.lookup(b"_sstack_guard").unwrap(); LIBRARY = Some(library); ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize); + board_misoc::pmp::init_stack_guard(_sstack_guard as usize); board_misoc::cache::flush_cpu_dcache(); board_misoc::cache::flush_cpu_icache(); @@ -530,7 +532,8 @@ pub unsafe fn main() { pub extern fn exception(_regs: *const u32) { let pc = mepc::read(); let cause = mcause::read().cause(); - panic!("{:?} at PC {:#08x}", cause, u32::try_from(pc).unwrap()) + let mtval = mtval::read(); + panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval); } #[no_mangle] diff --git a/artiq/firmware/libboard_misoc/riscv32ima/boot.rs b/artiq/firmware/libboard_misoc/riscv32ima/boot.rs index 32e9cfbc39..0d2254da13 100644 --- a/artiq/firmware/libboard_misoc/riscv32ima/boot.rs +++ b/artiq/firmware/libboard_misoc/riscv32ima/boot.rs @@ -1,4 +1,5 @@ -use super::cache; +use super::{cache, pmp}; +use riscv::register::*; pub unsafe fn reset() -> ! { llvm_asm!(r#" @@ -16,3 +17,14 @@ pub unsafe fn jump(addr: usize) -> ! { "# : : "r"(addr) : : "volatile"); loop {} } + +pub unsafe fn start_user(addr: usize) -> ! { + pmp::enable_user_memory(); + mstatus::set_mpp(mstatus::MPP::User); + mepc::write(addr); + llvm_asm!( + "mret" + : : : : "volatile" + ); + unreachable!() +} diff --git a/artiq/firmware/libboard_misoc/riscv32ima/mod.rs b/artiq/firmware/libboard_misoc/riscv32ima/mod.rs index 217ef713f0..a8f498adc1 100644 --- a/artiq/firmware/libboard_misoc/riscv32ima/mod.rs +++ b/artiq/firmware/libboard_misoc/riscv32ima/mod.rs @@ -1,2 +1,3 @@ pub mod cache; pub mod boot; +pub mod pmp; diff --git a/artiq/firmware/libboard_misoc/riscv32ima/pmp.rs b/artiq/firmware/libboard_misoc/riscv32ima/pmp.rs new file mode 100644 index 0000000000..9ac80b9e3e --- /dev/null +++ b/artiq/firmware/libboard_misoc/riscv32ima/pmp.rs @@ -0,0 +1,55 @@ +use riscv::register::{pmpaddr0, pmpaddr1, pmpaddr2, pmpaddr3, pmpcfg0}; + +static mut THREAD_DEPTH: u8 = 0; + +const PMP_L : usize = 0b10000000; +const PMP_NAPOT: usize = 0b00011000; +const PMP_X : usize = 0b00000100; +const PMP_W : usize = 0b00000010; +const PMP_R : usize = 0b00000001; +const PMP_OFF : usize = 0b00000000; + +#[inline(always)] +pub unsafe fn init_stack_guard(guard_base: usize) { + pmpaddr2::write((guard_base >> 2) | ((0x1000 - 1) >> 3)); + pmpcfg0::write((PMP_L | PMP_NAPOT) << 16); +} + +#[inline(always)] +pub fn enable_user_memory() { + pmpaddr3::write((0x80000000 - 1) >> 3); + pmpcfg0::write((PMP_L | PMP_NAPOT | PMP_X | PMP_W | PMP_R) << 24); +} + +#[inline(always)] +pub unsafe fn push_pmp_region(addr: usize) { + let pmp_addr = (addr >> 2) | ((0x1000 - 1) >> 3); + match THREAD_DEPTH { + // Activate PMP0 when switching from main stack to thread + 0 => { + pmpaddr0::write(pmp_addr); + pmpcfg0::write(PMP_NAPOT); + } + + // Temporarily activate PMP1 when spawning a thread from a thread + // The thread should swap back to the main stack very soon after init + 1 => { + pmpaddr1::write(pmp_addr); + pmpcfg0::write(PMP_NAPOT << 8 | PMP_NAPOT); + } + + // Thread *running* another thread should not be possible + _ => unreachable!() + } + THREAD_DEPTH += 1; +} + +#[inline(always)] +pub unsafe fn pop_pmp_region() { + THREAD_DEPTH -= 1; + match THREAD_DEPTH { + 0 => pmpcfg0::write(PMP_OFF), + 1 => pmpcfg0::write(PMP_NAPOT), + _ => unreachable!() + } +} diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index a29acbb861..ee987ad2d4 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -32,6 +32,6 @@ riscv = { version = "0.6.0", features = ["inline-asm"] } [dependencies.fringe] git = "https://git.m-labs.hk/M-Labs/libfringe.git" -rev = "9748bb" +rev = "3ecbe5" default-features = false features = ["alloc"] diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index c04ec3a052..45fb76f911 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -29,7 +29,7 @@ use core::cell::RefCell; use core::convert::TryFrom; use smoltcp::wire::IpCidr; -use board_misoc::{csr, ident, clock, spiflash, config, net_settings}; +use board_misoc::{csr, ident, clock, spiflash, config, net_settings, pmp, boot}; #[cfg(has_ethmac)] use board_misoc::ethmac; #[cfg(has_drtio)] @@ -40,7 +40,7 @@ use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_pro #[cfg(has_rtio_analyzer)] use proto_artiq::analyzer_proto; -use riscv::register::{mcause, mepc}; +use riscv::register::{mcause, mepc, mtval}; mod rtio_clocking; mod rtio_mgt; @@ -247,10 +247,15 @@ pub extern fn main() -> i32 { extern { static mut _fheap: u8; static mut _eheap: u8; + static mut _sstack_guard: u8; } ALLOC.add_range(&mut _fheap, &mut _eheap); - logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup); + pmp::init_stack_guard(&_sstack_guard as *const u8 as usize); + + logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(|| + boot::start_user(startup as usize) + ); 0 } @@ -285,6 +290,18 @@ pub extern fn exception(regs: *const TrapFrame) { mcause::Trap::Interrupt(source) => { info!("Called interrupt with {:?}", source); }, + + mcause::Trap::Exception(mcause::Exception::UserEnvCall) => { + unsafe { + if (*regs).a7 == 0 { + pmp::pop_pmp_region() + } else { + pmp::push_pmp_region((*regs).a7) + } + } + mepc::write(pc + 4); + }, + mcause::Trap::Exception(e) => { println!("Trap frame: {:x?}", unsafe { *regs }); @@ -302,7 +319,8 @@ pub extern fn exception(regs: *const TrapFrame) { } hexdump(u32::try_from(pc).unwrap()); - panic!("exception {:?} at PC 0x{:x}", e, u32::try_from(pc).unwrap()) + let mtval = mtval::read(); + panic!("exception {:?} at PC 0x{:x}, trap value 0x{:x}", e, u32::try_from(pc).unwrap(), mtval) } } } diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 81138fea3f..9f60bf3ac1 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -69,8 +69,11 @@ SECTIONS _ebss = .; } > runtime - .stack (NOLOAD) : ALIGN(16) + .stack (NOLOAD) : ALIGN(0x1000) { + _sstack_guard = .; + . += 0x1000; + _estack = .; . += 0x10000; _fstack = . - 16; } > runtime diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 7b182a3e47..d6a3472699 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -61,7 +61,8 @@ impl Thread { let spawned = io.spawned.clone(); let sockets = io.sockets.clone(); - let stack = OwnedStack::new(stack_size); + // Add a 4k stack guard to the stack of any new threads + let stack = OwnedStack::new(stack_size + 4096); ThreadHandle::new(Thread { generator: Generator::unsafe_new(stack, |yielder, _| { f(Io { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index f9e3d9e7c0..e0ec836127 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -9,7 +9,7 @@ extern crate board_artiq; extern crate riscv; use core::convert::TryFrom; -use board_misoc::{csr, ident, clock, uart_logger, i2c}; +use board_misoc::{csr, ident, clock, uart_logger, i2c, pmp}; #[cfg(has_si5324)] use board_artiq::si5324; #[cfg(has_wrpll)] @@ -18,7 +18,7 @@ use board_artiq::{spi, drtioaux}; use board_artiq::drtio_routing; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; -use riscv::register::{mcause, mepc}; +use riscv::register::{mcause, mepc, mtval}; mod repeater; #[cfg(has_jdcg)] @@ -449,6 +449,14 @@ const SI5324_SETTINGS: si5324::FrequencySettings #[no_mangle] pub extern fn main() -> i32 { + extern { + static mut _sstack_guard: u8; + } + + unsafe { + pmp::init_stack_guard(&_sstack_guard as *const u8 as usize); + } + clock::init(); uart_logger::ConsoleLogger::register(); @@ -662,7 +670,8 @@ pub extern fn exception(_regs: *const u32) { } hexdump(u32::try_from(pc).unwrap()); - panic!("exception {:?} at PC 0x{:x}", cause, u32::try_from(pc).unwrap()) + let mtval = mtval::read(); + panic!("exception {:?} at PC 0x{:x}, trap value 0x{:x}", cause, u32::try_from(pc).unwrap(), mtval) } #[no_mangle] diff --git a/artiq/firmware/satman/satman.ld b/artiq/firmware/satman/satman.ld index bf7ef51d04..37de797c2e 100644 --- a/artiq/firmware/satman/satman.ld +++ b/artiq/firmware/satman/satman.ld @@ -58,8 +58,10 @@ SECTIONS _ebss = .; } > main_ram - .stack (NOLOAD) : ALIGN(16) + .stack (NOLOAD) : ALIGN(0x1000) { + _sstack_guard = .; + . += 0x1000; _estack = .; . += 0x10000; _fstack = . - 16; diff --git a/flake.lock b/flake.lock index e97a381794..e0cc41607b 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1631098960, - "narHash": "sha256-6j6G/omHEFAnI2x7UvdrviGDNqiq1Fjd1A58Q6uc4sQ=", + "lastModified": 1633625029, + "narHash": "sha256-Ia3kwnN9DhcskAIElLSKb4u/OK7nZU/P0TkaikAX790=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "12eb1d16ae3b6cbf0ea83e9228bca8ffd7cfe347", + "rev": "781b1f8e3a2194e1e233cd62b4f2193e129a07f7", "type": "github" }, "original": { @@ -45,11 +45,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1628592379, - "narHash": "sha256-TQV6p0+Ri9HVge4qUKOCXe96cmcimNZ3R4sVwNY67DA=", + "lastModified": 1633615575, + "narHash": "sha256-frh+WVOkEKMpVEMhdE/GZKSj82XnSC8OF8SWNluk/Yg=", "owner": "m-labs", "repo": "migen", - "rev": "27dbf03edd75c32dc1706e2a1316950c3a8d452a", + "rev": "6e3f8e565704b4293174aedfb15b3470d233f528", "type": "github" }, "original": { @@ -61,11 +61,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1631240866, - "narHash": "sha256-dal999XLFvS8Ol1hZnQjx7q/UfAXkzSMhAWcZKCDPx4=", + "lastModified": 1633679103, + "narHash": "sha256-1BPWfwetUZZCCZ+ldNKJvNm7Gls1AkmGYSZapNuM65s=", "ref": "master", - "rev": "c9572e777febf7abcfbebf624e0323d82600f267", - "revCount": 2371, + "rev": "7c1f614ed3ad9ce0fd3291feccb1e5e4ff65adb3", + "revCount": 2372, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" @@ -95,11 +95,11 @@ "src-sipyco": { "flake": false, "locked": { - "lastModified": 1623807309, - "narHash": "sha256-FTRAS4RjqDOygu6+cP8mKbZHu/YZ7YKpEe2gSzJc9rk=", + "lastModified": 1632832039, + "narHash": "sha256-GYXXCCOxNZyy6j7qScB3/QWUUCEVX+4tM4bXXVGXty0=", "owner": "m-labs", "repo": "sipyco", - "rev": "20c946aad78872fe60b78d9b57a624d69f3eea47", + "rev": "b83d8e5d82b25dba9393f0c12bdc5253f8138545", "type": "github" }, "original": {