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
1 change: 0 additions & 1 deletion cortex-a-rt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ version = "0.1.0"

[dependencies]
cortex-ar = {version = "0.1.0", path = "../cortex-ar"}
semihosting = {version = "0.1.18", features = ["stdio"]}

[features]
# Enable the FPU on start-up, even on a soft-float EABI target
Expand Down
12 changes: 9 additions & 3 deletions cortex-a-rt/link.x
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,16 @@ ASSERT(_abt_stack_size % 8 == 0, "ERROR(cortex-a-rt): size of ABT stack is not 8
ASSERT(_und_stack_size % 8 == 0, "ERROR(cortex-a-rt): size of UND stack is not 8-byte aligned");
ASSERT(_svc_stack_size % 8 == 0, "ERROR(cortex-a-rt): size of SVC stack is not 8-byte aligned");

PROVIDE(_asm_undefined_handler =_asm_default_handler);
PROVIDE(_asm_prefetch_handler =_asm_default_handler);
PROVIDE(_asm_abort_handler =_asm_default_handler);
/* Weak aliases for ASM default handlers */
PROVIDE(_asm_undefined_handler =_asm_default_undefined_handler);
PROVIDE(_asm_prefetch_handler =_asm_default_prefetch_handler);
PROVIDE(_asm_abort_handler =_asm_default_abort_handler);
PROVIDE(_asm_fiq_handler =_asm_default_fiq_handler);

/* Weak aliases for C default handlers */
PROVIDE(_undefined_handler =_default_handler);
PROVIDE(_abort_handler =_default_handler);
PROVIDE(_prefetch_handler =_default_handler);
PROVIDE(_irq_handler =_default_handler);
PROVIDE(_svc_handler =_default_handler);
PROVIDE(_start =_default_start);
212 changes: 190 additions & 22 deletions cortex-a-rt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Run-time support for Arm Cortex-A
//! # Run-time support for Arm Cortex-A
//!
//! This library implements a simple Arm vector table, suitable for getting into
//! a Rust application running in System Mode. It also provides a reference start up method.
Expand All @@ -22,47 +22,116 @@
//!
//! We assume the following global symbols exist:
//!
//! * `__start` - a Reset handler. Our linker script PROVIDEs a default function
//! at `_default_start` but you can override it. Most Cortex-A SoCs require
//! a chip specific startup for tasks like MMU initialization or chip specific
//! initialization routines.
//! ### Constants
//!
//! * `_stack_top` - the address of the top of some region of RAM that we can
//! use as stack space, with eight-byte alignment. Our linker script PROVIDEs
//! a default pointing at the top of RAM.
//! * `__sbss` - the start of zero-initialised data in RAM. Must be 4-byte
//! aligned.
//! * `__ebss` - the end of zero-initialised data in RAM. Must be 4-byte
//! aligned.
//! * `_fiq_stack_size` - the number of bytes to be reserved for stack space
//! when in FIQ mode; must be a multiple of 8.
//! * `_irq_stack_size` - the number of bytes to be reserved for stack space
//! when in FIQ mode; must be a multiple of 8.
//! * `_svc_stack_size` - the number of bytes to be reserved for stack space
//! when in SVC mode; must be a multiple of 8.F
//! when in SVC mode; must be a multiple of 8.
//! * `__sdata` - the start of initialised data in RAM. Must be 4-byte aligned.
//! * `__edata` - the end of initialised data in RAM. Must be 4-byte aligned.
//! * `__sidata` - the start of the initialisation values for data, in read-only
//! memory. Must be 4-byte aligned.
//!
//! ### Functions
//!
//! * `boot_core` - the `extern "C"` entry point to your application. The CPU ID
//! will be passed as the first argument to this function.
//!
//! Expected prototype:
//!
//! ```rust
//! #[unsafe(no_mangle)]
//! extern "C" fn boot_core(cpu_id: u32) -> !;
//! ```
//!
//! * `_svc_handler` - an `extern "C"` function to call when an SVC Exception
//! occurs. Our linker script PROVIDEs a default function at
//! `_default_handler` but you can override it.
//!
//! Expected prototype:
//!
//! ```rust
//! #[unsafe(no_mangle)]
//! extern "C" fn _svc_handler(svc: u32);
//! ```
//!
//! * `_irq_handler` - an `extern "C"` function to call when an Interrupt
//! occurs. Our linker script PROVIDEs a default function at
//! `_default_handler` but you can override it.
//!
//! Expected prototype:
//!
//! ```rust
//! #[unsafe(no_mangle)]
//! extern "C" fn _irq_handler();
//! ```
//!
//! * `_undefined_handler` - an `extern "C"` function to call when an Undefined Exception
//! occurs. Our linker script PROVIDEs a default function at
//! `_default_handler` but you can override it. It will be called by the
//! `_asm_default_undefined_handler` unless that function is overriden as well.
//!
//! Expected prototype:
//!
//! ```rust
//! #[unsafe(no_mangle)]
//! extern "C" fn _undefined_handler(faulting_instruction: u32);
//! ```
//!
//! * `_abort_handler` - an `extern "C"` function to call when a Data Abort Exception
//! occurs. Our linker script PROVIDEs a default function at
//! `_default_handler` but you can override it. It will be called by the
//! `_asm_default_abort_handler` unless that function is overriden as well.
//!
//! Expected prototype:
//!
//! ```rust
//! #[unsafe(no_mangle)]
//! extern "C" fn _abort_handler(faulting_instruction: u32);
//! ```
//!
//! * `_prefetch_handler` - an `extern "C"` function to call when a Prefetch Abort Exception
//! occurs. Our linker script PROVIDEs a default function at
//! `_default_handler` but you can override it. It will be called by the
//! `_asm_default_prefetch_handler` unless that function is overriden as well.
//!
//! Expected prototype:
//!
//! ```rust
//! #[unsafe(no_mangle)]
//! extern "C" fn _prefetch_handler(faulting_instruction: u32);
//! ```
//!
//! ### ASM functions
//!
//! * `__start` - a Reset handler. Our linker script PROVIDEs a default function
//! at `_default_start` but you can override it. Most Cortex-A SoCs require
//! a chip specific startup for tasks like MMU initialization or chip specific
//! initialization routines.
//! * `_asm_fiq_handler` - a naked function to call when a Fast Interrupt
//! Request (FIQ) occurs. Our linker script PROVIDEs a default function at
//! `_asm_default_fiq_handler` but you can override it.
//! * `_asm_undefined_handler` - a naked function to call when an Undefined
//! Exception occurs. Our linker script PROVIDEs a default function at
//! `_asm_default_handler` but you can override it.
//! `_asm_default_undefined_handler` but you can override it.
//! * `_asm_prefetch_handler` - a naked function to call when an Prefetch
//! Exception occurs. Our linker script PROVIDEs a default function at
//! `_asm_default_handler` but you can override it.
//! `_asm_default_prefetch_handler` but you can override it. The provided default
//! handler will perform an exception return to the faulting address.
//! * `_asm_abort_handler` - a naked function to call when an Abort Exception
//! occurs. Our linker script PROVIDEs a default function at
//! `_asm_default_handler` but you can override it.
//! * `boot_core` - the `extern "C"` entry point to your application. The CPU ID
//! will be passed as the first argument to this fumction.
//! * `__sdata` - the start of initialised data in RAM. Must be 4-byte aligned.
//! * `__edata` - the end of initialised data in RAM. Must be 4-byte aligned.
//! * `__sidata` - the start of the initialisation values for data, in read-only
//! memory. Must be 4-byte aligned.
//! * `__sbss` - the start of zero-initialised data in RAM. Must be 4-byte
//! aligned.
//! * `__ebss` - the end of zero-initialised data in RAM. Must be 4-byte
//! aligned.
//! `_asm_default_abort_handler` but you can override it. The provided default handler
//! will perform an exception return to the faulting address.
//!
//! On start-up, the memory between `__sbss` and `__ebss` is zeroed, and the
//! memory between `__sdata` and `__edata` is initialised with the data found at
Expand Down Expand Up @@ -95,19 +164,28 @@
//! If our start-up routine doesn't work for you (e.g. if you have to initialise
//! your memory controller before you touch RAM), supply your own `_start`
//! function (but feel free to call our `_default_start` as part of it).
//!
//! ## Examples
//!
//! You can find example code using QEMU inside the
//! [project repository](https://github.com/rust-embedded/cortex-ar/tree/main/examples)

#![no_std]

use cortex_ar::register::{cpsr::ProcessorMode, Cpsr};
use cortex_ar::{
asm::nop,
register::{cpsr::ProcessorMode, Cpsr},
};

/// Our default exception handler.
///
/// We end up here if an exception fires and the weak 'PROVIDE' in the link.x
/// file hasn't been over-ridden.
#[no_mangle]
pub extern "C" fn _default_handler() {
semihosting::eprintln!("Unhandled exception!");
semihosting::process::abort();
loop {
nop();
}
}

// The Interrupt Vector Table, and some default assembly-language handler.
Expand Down Expand Up @@ -319,6 +397,7 @@ core::arch::global_asm!(
rfefd sp!
.size _asm_svc_handler, . - _asm_svc_handler


// Called from the vector table when we have an interrupt.
// Saves state and calls a C-compatible handler like
// `extern "C" fn irq_handler();`
Expand All @@ -337,9 +416,98 @@ core::arch::global_asm!(
r#"
rfefd sp!
.size _asm_irq_handler, . - _asm_irq_handler


// Called from the vector table when we have an undefined exception.
// Saves state and calls a C-compatible handler like
// `extern "C" fn _undefined_handler();`
.global _asm_default_undefined_handler
.type _asm_default_undefined_handler, %function
_asm_default_undefined_handler:
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
// and to return to the failing instruction after the C handler returns.
// Load processor status
mrs r4, cpsr
// Occurred in Thumb state?
tst r4, {t_bit}
// If not in Thumb mode, branch to not_thumb
beq not_thumb
subs lr, lr, #2
b done
not_thumb:
// Subtract 4 from LR (ARM mode)
subs lr, lr, #4
done:
// state save from compiled code
srsfd sp!, {und_mode}
"#,
save_context!(),
r#"
// Pass the faulting instruction address to the handler.
mov r0, lr
// call C handler
bl _undefined_handler
"#,
restore_context!(),
r#"
// Return to the failing instruction which is the recommended approach by ARM.
rfefd sp!
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler


// Called from the vector table when we have an undefined exception.
// Saves state and calls a C-compatible handler like
// `extern "C" fn _prefetch_handler();`
.global _asm_default_prefetch_handler
.type _asm_default_prefetch_handler, %function
_asm_default_prefetch_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
srsfd sp!, {abt_mode}
"#,
save_context!(),
r#"
// Pass the faulting instruction address to the handler.
mov r0, lr
// call C handler
bl _prefetch_handler
"#,
restore_context!(),
r#"
// Return to the failing instruction which is the recommended approach by ARM.
rfefd sp!
.size _asm_default_prefetch_handler, . - _asm_default_prefetch_handler


// Called from the vector table when we have an undefined exception.
// Saves state and calls a C-compatible handler like
// `extern "C" fn _abort_handler();`
.global _asm_default_abort_handler
.type _asm_default_abort_handler, %function
_asm_default_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
srsfd sp!, {abt_mode}
"#,
save_context!(),
r#"
// Pass the faulting instruction address to the handler.
mov r0, lr
// call C handler
bl _abort_handler
"#,
restore_context!(),
r#"
// Return to the failing instruction which is the recommended approach by ARM.
rfefd sp!
.size _asm_default_abort_handler, . - _asm_default_abort_handler
"#,
svc_mode = const ProcessorMode::Svc as u8,
irq_mode = const ProcessorMode::Irq as u8,
und_mode = const ProcessorMode::Und as u8,
abt_mode = const ProcessorMode::Abt as u8,
t_bit = const {
Cpsr::new_with_raw_value(0)
.with_t(true)
Expand Down
1 change: 1 addition & 0 deletions cortex-ar/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ version = "0.1.0"
[dependencies]
arbitrary-int = "1.3.0"
bitbybit = "1.3.3"
num_enum = { version = "0.7", default-features = false }
critical-section = {version = "1.2.0", features = ["restore-state-bool"], optional = true}
defmt = {version = "0.3", optional = true}

Expand Down
1 change: 1 addition & 0 deletions cortex-ar/src/register/dfar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use crate::register::{SysReg, SysRegRead, SysRegWrite};

/// DFAR (*Data Fault Address Register*)
#[derive(Debug)]
pub struct Dfar(pub u32);
impl SysReg for Dfar {
const CP: u32 = 15;
Expand Down
Loading