Skip to content
Open
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
204 changes: 198 additions & 6 deletions aarch32-cpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,207 @@ 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, out("lr") _);
}
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,
out("lr") _);
}
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,
out("lr") _);
}
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,
out("lr") _);
}
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,
out("lr") _);
}
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,
out("lr") _);
}
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,
out("lr") _);
}
}
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
"#,
);
Loading