Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 192 additions & 6 deletions aarch32-cpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,201 @@ pub mod generic_timer;
#[cfg(any(test, doc, arm_architecture = "v8-r"))]
pub mod pmsav8;

/// Generate an SVC call with the given argument.
/// Generate an SVC call with no parameters.
///
/// Safe to call even in Supervisor (SupervisorCall) mode, as long as your Svc handler
/// saves and restores SPSR_svc correctly.
/// Puts the first argument in the instruction. Gives you back
/// the value left in `r0` by the handler.
///
/// ```rust,ignore
/// let value = svc!(0xFF);
/// ```
#[macro_export]
macro_rules! svc {
($r0:expr) => {
($num:expr) => { {
let retval: u32;
unsafe {
core::arch::asm!("svc {arg}", arg = const $num, lateout("r0") retval);
}
retval
} }
}

/// Generate an SVC call with 1 parameters
///
/// Puts the first argument in the instruction, and the parameter in r0. Gives you back
/// the value left in `r0` by the handler.
///
/// ```rust,ignore
/// const SYSCALL_FOO: u32 = 0x100;
/// let result = svc1!(0x00, SYSCALL_FOO);
/// ```
#[macro_export]
macro_rules! svc1 {
($num:expr, $arg0:expr) => { {
let retval: u32;
let arg0: u32 = $arg0;
unsafe {
core::arch::asm!(
// Do the SVCall
"svc {arg}",
arg = const $num,
inout("r0") arg0 => retval);
}
retval
} }
}

/// Generate an SVC call with 2 parameters
///
/// Puts the first argument in the instruction, and the parameters in r0-r1. Gives you back
/// the value left in `r0` by the handler.
///
/// ```rust,ignore
/// const SYSCALL_FOO: u32 = 0x100;
/// let result = svc2!(0x00, SYSCALL_FOO, 1);
/// ```
#[macro_export]
macro_rules! svc2 {
($num:expr, $arg0:expr, $arg1:expr) => { {
let retval: u32;
let arg0: u32 = $arg0;
let arg1: u32 = $arg1;
unsafe {
core::arch::asm!(
// Do the SVCall
"svc {arg}",
arg = const $num,
inout("r0") arg0 => retval,
in("r1") arg1);
}
retval
} }
}

/// Generate an SVC call with 3 parameters
///
/// Puts the first argument in the instruction, and the parameters in r0-r2. Gives you back
/// the value left in `r0` by the handler.
///
/// ```rust,ignore
/// const SYSCALL_FOO: u32 = 0x100;
/// let result = svc3!(0x00, SYSCALL_FOO, 1, 2);
/// ```
#[macro_export]
macro_rules! svc3 {
($num:expr, $arg0:expr, $arg1:expr, $arg2:expr) => { {
let retval: u32;
let arg0: u32 = $arg0;
let arg1: u32 = $arg1;
let arg2: u32 = $arg2;
unsafe {
core::arch::asm!(
// Do the SVCall
"svc {arg}",
arg = const $num,
inout("r0") arg0 => retval,
in("r1") arg1,
in("r2") arg2);
}
retval
} }
}

/// Generate an SVC call with 4 parameters
///
/// Puts the first argument in the instruction, and the parameters in r0-r3. Gives you back
/// the value left in `r0` by the handler.
///
/// ```rust,ignore
/// const SYSCALL_FOO: u32 = 0x100;
/// let result = svc4!(0x00, SYSCALL_FOO, 1, 2, 3);
/// ```
#[macro_export]
macro_rules! svc4 {
($num:expr, $arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr) => { {
let retval: u32;
let arg0: u32 = $arg0;
let arg1: u32 = $arg1;
let arg2: u32 = $arg2;
let arg3: u32 = $arg3;
unsafe {
core::arch::asm!(
// Do the SVCall
"svc {arg}",
arg = const $num,
inout("r0") arg0 => retval,
in("r1") arg1,
in("r2") arg2,
in("r3") arg3);
}
retval
} }
}

/// Generate an SVC call with 5 parameters
///
/// Puts the first argument in the instruction, and the parameters in r0-r4. Gives you back
/// the value left in `r0` by the handler.
///
/// ```rust,ignore
/// const SYSCALL_FOO: u32 = 0x100;
/// let result = svc5!(0x00, SYSCALL_FOO, 1, 2, 3, 4);
/// ```
#[macro_export]
macro_rules! svc5 {
($num:expr, $arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr) => { {
let retval: u32;
let arg0: u32 = $arg0;
let arg1: u32 = $arg1;
let arg2: u32 = $arg2;
let arg3: u32 = $arg3;
let arg4: u32 = $arg4;
unsafe {
core::arch::asm!(
// Do the SVCall
"svc {arg}",
arg = const $num,
inout("r0") arg0 => retval,
in("r1") arg1,
in("r2") arg2,
in("r3") arg3,
in("r4") arg4);
}
retval
} }
}

/// Generate an SVC call with 6 parameters
///
/// Puts the first argument in the instruction, and the parameters in r0-r5. Gives you back
/// the value left in `r0` by the handler.
///
/// ```rust,ignore
/// const SYSCALL_FOO: u32 = 0x100;
/// let result = svc6!(0x00, SYSCALL_FOO, 1, 2, 3, 4, 5);
/// ```
#[macro_export]
macro_rules! svc6 {
($num:expr, $arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => { {
let retval: u32;
let arg0: u32 = $arg0;
let arg1: u32 = $arg1;
let arg2: u32 = $arg2;
let arg3: u32 = $arg3;
let arg4: u32 = $arg4;
let arg5: u32 = $arg5;
unsafe {
core::arch::asm!("svc {arg}", arg = const $r0, out("lr") _);
core::arch::asm!(
// Do the SVCall
"svc {arg}",
arg = const $num,
inout("r0") arg0 => retval,
in("r1") arg1,
in("r2") arg2,
in("r3") arg3,
in("r4") arg4,
in("r5") arg5);
}
}
retval
} }
}
11 changes: 7 additions & 4 deletions aarch32-rt-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ fn handle_vector(args: TokenStream, input: TokenStream, kind: VectorKind) -> Tok
VectorKind::Interrupt => Exception::Irq,
};

let block = f.block;
let func_name = f.sig.ident.clone();
let block = f.block.clone();
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());

let handler = match exception {
Expand Down Expand Up @@ -387,16 +388,18 @@ fn handle_vector(args: TokenStream, input: TokenStream, kind: VectorKind) -> Tok
)
}
}
// extern "C" fn _svc_handler(addr: usize);
// extern "C" fn _svc_handler(arg: u32, args: &Frame) -> u32
Exception::SupervisorCall => {
let tramp_ident = Ident::new("__aarch32_rt_svc_handler", Span::call_site());
quote!(
#(#cfgs)*
#(#attrs)*
#[doc(hidden)]
#[export_name = "_svc_handler"]
pub unsafe extern "C" fn #tramp_ident(arg: u32) {
#block
pub unsafe extern "C" fn #tramp_ident(arg: u32, frame: &aarch32_rt::Frame) -> u32 {
#f

#func_name(arg, frame)
}
)
}
Expand Down
83 changes: 45 additions & 38 deletions aarch32-rt/src/arch_v4/abort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,37 @@ core::arch::global_asm!(
.global _asm_default_data_abort_handler
.type _asm_default_data_abort_handler, %function
_asm_default_data_abort_handler:
// Subtract 8 from the stored LR, see p.1214 of the ARMv7-A architecture manual.
subs lr, lr, #8
// state save from compiled code
stmfd sp!, {{ r0 }}
mrs r0, spsr
stmfd sp!, {{ r0 }}
sub lr, lr, #8 // Subtract 8 from LR, see p.1214 of the ARMv7-A architecture manual.
push {{ r12 }} // Save preserved register R12 - can now use it
mrs r12, spsr // grab SPSR
push {{ r12 }} // save SPSR value
mov r12, sp // align SP down to eight byte boundary using R12
and r12, r12, 7 //
sub sp, r12 // SP now aligned - only push 64-bit values from here
push {{ r0-r4, r12 }} // push alignment amount, and preserved registers - can now use R0-R3 (R4 is just padding)
"#,
crate::save_context!(),
crate::save_fpu_context!(),
r#"
// Pass the faulting instruction address to the handler.
mov r0, lr
// call C handler
bl _data_abort_handler
// if we get back here, assume they returned a new LR in r0
mov lr, r0
mov r0, lr // Pass the faulting instruction address to the handler.
bl _data_abort_handler // call C handler
mov lr, r0 // if we get back here, assume they returned a new LR in r0
"#,
crate::restore_context!(),
crate::restore_fpu_context!(),
r#"
// Return from the asm handler
ldmia sp!, {{ r0 }}
msr spsr, r0
ldmia sp!, {{ r0 }}
movs pc, lr
pop {{ r0-r4, r12 }} // restore preserved registers, dummy value, and alignment amount
add sp, r12 // restore SP alignment using R12
pop {{ r12 }} // restore SPSR using R12
msr spsr, r12 //
pop {{ r12 }} // restore R12
movs pc, lr // return from exception
.size _asm_default_data_abort_handler, . - _asm_default_data_abort_handler
"#
);

core::arch::global_asm!(
r#"
// Work around https://github.com/rust-lang/rust/issues/127269
.fpu vfp2


// Called from the vector table when we have a prefetch abort.
Expand All @@ -48,29 +55,29 @@ core::arch::global_asm!(
.global _asm_default_prefetch_abort_handler
.type _asm_default_prefetch_abort_handler, %function
_asm_default_prefetch_abort_handler:
// Subtract 4 from the stored LR, see p.1212 of the ARMv7-A architecture manual.
subs lr, lr, #4
// state save from compiled code
stmfd sp!, {{ r0 }}
mrs r0, spsr
stmfd sp!, {{ r0 }}
sub lr, lr, #4 // Subtract 4 from LR, see p.1212 of the ARMv7-A architecture manual.
push {{ r12 }} // Save preserved register R12 - can now use it
mrs r12, spsr // grab SPSR
push {{ r12 }} // save SPSR value
mov r12, sp // align SP down to eight byte boundary using R12
and r12, r12, 7 //
sub sp, r12 // SP now aligned - only push 64-bit values from here
push {{ r0-r4, r12 }} // push alignment amount, and preserved registers - can now use R0-R3 (R4 is just padding)
"#,
crate::save_context!(),
crate::save_fpu_context!(),
r#"
// Pass the faulting instruction address to the handler.
mov r0, lr
// call C handler
bl _prefetch_abort_handler
// if we get back here, assume they returned a new LR in r0
mov lr, r0
mov r0, lr // Pass the faulting instruction address to the handler.
bl _prefetch_abort_handler // call C handler
mov lr, r0 // if we get back here, assume they returned a new LR in r0
"#,
crate::restore_context!(),
crate::restore_fpu_context!(),
r#"
// Return from the asm handler
ldmia sp!, {{ r0 }}
msr spsr, r0
ldmia sp!, {{ r0 }}
movs pc, lr
pop {{ r0-r4, r12 }} // restore preserved registers, dummy value, and alignment amount
add sp, r12 // restore SP alignment using R12
pop {{ r12 }} // restore SPSR using R12
msr spsr, r12 //
pop {{ r12 }} // restore R12
movs pc, lr // return from exception
.size _asm_default_prefetch_abort_handler, . - _asm_default_prefetch_abort_handler
"#,
);
43 changes: 19 additions & 24 deletions aarch32-rt/src/arch_v4/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,28 @@ core::arch::global_asm!(
.global _asm_default_irq_handler
.type _asm_default_irq_handler, %function
_asm_default_irq_handler:
// make sure we jump back to the right place
sub lr, lr, 4
// save our LR
stmfd sp!, {{ lr }}
// The hardware has copied the interrupted task's CPSR to SPSR_irq
mrs lr, spsr
stmfd sp!, {{ lr }}
// switch to system mode so we can handle another interrupt
// (because if we interrupt irq mode we trash our own shadow registers)
msr cpsr_c, {sys_mode}
// save state to the system stack (adjusting SP for alignment)
"#,
crate::save_context!(),
sub lr, lr, 4 // make sure we jump back to the right place
push {{ lr }} // save adjusted LR to IRQ stack
mrs lr, spsr // The hardware has copied the interrupted task's CPSR to SPSR_irq - grab it and
push {{ lr }} // save it to IRQ stack using LR
msr cpsr_c, {sys_mode} // switch to system mode so we can handle another interrupt (because if we interrupt irq mode we trash our own shadow registers)
mov lr, sp // align SP down to eight byte boundary using LR
and lr, lr, 7 //
sub sp, lr // SP now aligned - only push 64-bit values from here
push {{ r0-r3, r12, lr }} // push alignment amount (in LR) and preserved registers
"#,
crate::save_fpu_context!(),
r#"
// call C handler (they may choose to re-enable interrupts)
bl _irq_handler
// restore from the system stack
bl _irq_handler // call C handler (they may choose to re-enable interrupts)
"#,
crate::restore_context!(),
crate::restore_fpu_context!(),
r#"
// switch back to IRQ mode (with IRQ masked)
msr cpsr_c, {irq_mode}
// load and restore SPSR
ldmia sp!, {{ lr }}
msr spsr, lr
// return
ldmfd sp!, {{ pc }}^
pop {{ r0-r3, r12, lr }} // restore alignment amount (in LR) and preserved registers
add sp, lr // restore SP alignment using LR
msr cpsr_c, {irq_mode} // switch back to IRQ mode (with IRQ masked)
pop {{ lr }} // load and restore SPSR using LR
msr spsr, lr //
ldmfd sp!, {{ pc }}^ // return from exception (^ => restore SPSR to CPSR)
.size _asm_default_irq_handler, . - _asm_default_irq_handler
"#,
// sys mode with IRQ masked
Expand Down
Loading