2019-12-18 06:35:58 +08:00
|
|
|
#![no_std]
|
2020-05-01 07:11:35 +08:00
|
|
|
#![feature(llvm_asm, global_asm)]
|
2019-12-18 06:35:58 +08:00
|
|
|
#![feature(never_type)]
|
2020-07-28 12:36:16 +08:00
|
|
|
#![feature(const_fn)]
|
2019-12-18 06:35:58 +08:00
|
|
|
|
2020-04-09 08:49:24 +08:00
|
|
|
extern crate alloc;
|
|
|
|
|
2019-05-05 20:56:23 +08:00
|
|
|
pub mod asm;
|
2019-10-18 06:11:51 +08:00
|
|
|
pub mod cache;
|
2021-01-28 10:58:17 +08:00
|
|
|
mod fpu;
|
|
|
|
pub mod l2c;
|
2019-06-17 09:32:10 +08:00
|
|
|
pub mod mmu;
|
2019-11-18 09:13:54 +08:00
|
|
|
pub mod mutex;
|
2021-01-28 10:58:17 +08:00
|
|
|
pub mod regs;
|
2020-08-04 12:59:23 +08:00
|
|
|
pub mod semaphore;
|
2021-01-28 10:58:17 +08:00
|
|
|
pub mod sync_channel;
|
2020-06-18 06:51:13 +08:00
|
|
|
mod uncached;
|
2020-07-03 16:02:34 +08:00
|
|
|
pub use fpu::enable_fpu;
|
2021-01-28 10:58:17 +08:00
|
|
|
pub use uncached::UncachedSlice;
|
2019-05-31 02:30:19 +08:00
|
|
|
|
|
|
|
global_asm!(include_str!("exceptions.s"));
|
2020-08-04 13:50:42 +08:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn spin_lock_yield() {
|
|
|
|
#[cfg(feature = "power_saving")]
|
|
|
|
asm::wfe();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn notify_spin_lock() {
|
|
|
|
#[cfg(feature = "power_saving")]
|
|
|
|
{
|
|
|
|
asm::dsb();
|
|
|
|
asm::sev();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-28 10:58:17 +08:00
|
|
|
#[macro_export]
|
2023-11-20 12:30:27 +08:00
|
|
|
/// Interrupt handler, which setup the stack and preserve registers before jumping to actual interrupt handler.
|
|
|
|
/// Registers r0-r12, PC, SP and CPSR are restored after the actual handler.
|
|
|
|
///
|
2021-01-28 10:58:17 +08:00
|
|
|
/// - `name` is the name of the interrupt, should be the same as the one defined in vector table.
|
|
|
|
/// - `name2` is the name for the actual handler, should be different from name.
|
|
|
|
/// - `stack0` is the stack for the interrupt handler when called from core0.
|
|
|
|
/// - `stack1` is the stack for the interrupt handler when called from core1.
|
|
|
|
/// - `body` is the body of the actual interrupt handler, should be a normal unsafe rust function
|
|
|
|
/// body.
|
|
|
|
///
|
2023-11-20 12:30:27 +08:00
|
|
|
/// Note that the interrupt handler would use the same stack as normal programs by default.
|
2021-01-28 10:58:17 +08:00
|
|
|
macro_rules! interrupt_handler {
|
|
|
|
($name:ident, $name2:ident, $stack0:ident, $stack1:ident, $body:block) => {
|
|
|
|
#[link_section = ".text.boot"]
|
|
|
|
#[no_mangle]
|
|
|
|
#[naked]
|
|
|
|
pub unsafe extern "C" fn $name() -> ! {
|
|
|
|
asm!(
|
|
|
|
// setup SP, depending on CPU 0 or 1
|
2023-11-20 12:30:27 +08:00
|
|
|
// and preserve registers
|
|
|
|
"sub lr, lr, #4",
|
|
|
|
"stmfd sp!, {{r0-r12, lr}}",
|
2021-01-28 10:58:17 +08:00
|
|
|
"mrc p15, #0, r0, c0, c0, #5",
|
|
|
|
concat!("movw r1, :lower16:", stringify!($stack0)),
|
|
|
|
concat!("movt r1, :upper16:", stringify!($stack0)),
|
|
|
|
"tst r0, #3",
|
|
|
|
concat!("movwne r1, :lower16:", stringify!($stack1)),
|
|
|
|
concat!("movtne r1, :upper16:", stringify!($stack1)),
|
2023-11-20 12:30:27 +08:00
|
|
|
"mov r0, sp",
|
2021-01-28 10:58:17 +08:00
|
|
|
"mov sp, r1",
|
2023-11-20 12:30:27 +08:00
|
|
|
"push {{r0, r1}}", // 2 registers are pushed to maintain 8 byte stack alignment
|
2021-01-28 10:58:17 +08:00
|
|
|
concat!("bl ", stringify!($name2)),
|
2023-11-20 12:30:27 +08:00
|
|
|
"pop {{r0, r1}}",
|
|
|
|
"mov sp, r0",
|
|
|
|
"ldmfd sp!, {{r0-r12, pc}}^", // caret ^ : copy SPSR to the CPSR
|
2021-01-28 10:58:17 +08:00
|
|
|
options(noreturn)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2023-11-20 12:30:27 +08:00
|
|
|
pub unsafe extern "C" fn $name2() $body
|
2021-01-28 10:58:17 +08:00
|
|
|
};
|
|
|
|
}
|