Description
Background
I have created two different rt
crates that I'm using to target two different
devices. I'd like to merge those two crates and this one into a generic crate
that handles all these different use cases.
These are the devices I'm targeting:
- The RPU (two Cortex-R5 cores) in the Zynq Ultrascale+. repository
These cores have no Flash memory but they have private RAM (Tightly Coupled
Memory, AKA TCM) and access to shared RAM (On-Chip Memory, AKA OCM).
The TCM starts at address 0x0
so the vector table is placed in RAM as well.
The interrupt controller in these cores follows the GICv1 architecture and I
have a custom IRQ trampoline to make all interrupts
preemptible (the IRQ handler is not reentrant out of the box) -- I need
preemption to implement Real Time for The Masses (RTFM).
- RM42 LaunchPad. repository
(This device (RM42L432) is similar to the TMS570. @paoloteti has a BSP for this
in paoloteti/ti-hercules-bsp and paoloteti/tsm570ls3137.)
This device has Flash memory but I'm placing all my program (.text, .rodata and
.vectors) in RAM. The motivation for doing this is that (a) OpenOCD doesn't have
a Flash loader for this device (because it requires a proprietary binary blob)
and (b) TI Flash loader (UNIFLASH) is painfully slow.
Because the vector table can't be relocated (it must be located at address 0x0
and RAM starts at 0x0800_0000
) I'm using the two tables technique recommended
in SPNA236.
I haven't looked at the interrupt controller (VIM) of this device but I also
want preemptible interrupts on this device.
Required changes / questions
Exception handlers ABI
Cortex-R exception handlers don't follow the C ABI / AAPCS so a trampoline is
needed to let the user override them with extern "C"
functions (see
#[exception]
attribute). Without the trampoline returning from the handler
could result in undefined behavior. I think a trampoline like the one shown
below would be appropriate:
SVCTrampoline:
push {r0, r1, r2, r3, ip, lr}
bl SVC ; provided by the user
pop {r0, r1, r2, r3, ip, lr}
movs pc, lr
Divergent exception handlers?
I'm not sure if Undefined
, DataAbort
and PrefetchAbort
should be allowed
to return. Returning from them could lead to undefined behavior, for example:
// invalid memory access; triggers a DataAbort exception
let x: SomeEnum = ptr::read(0xdead_beef);
// if DataAbort returns then this match is done on an `undef` value
match x {
// ..
}
In some cases it might be possible to fix the underlying error and continue.
For example, returning from an Undefined
exception triggered by trying to
execute a VFP instruction on a device without a FPU should be safe if the
handler performs the operation in software. Though if you run into something
like that at runtime it means you picked the wrong compilation target.
Per-exception stack pointer
Most, if not all, exceptions have their own stack pointer. I would like to see
an option (e.g. Cargo feature) to ignore the banked stack pointer and instead
continue using the current stack. This behavior matches the Cortex-M behavior
which I'm familiar with.
To me having more stacks means more chances of having them run into each other
(undefined behavior) but probably there's a good reason for having separate
stack pointers.
Preemptible IRQ / FIQ
As I mentioned before, I need preemptible interrupts for RTFM. On the
Ultrascale+ I made IRQ reentrant to achieve this. Is there a use case for
keeping IRQ non-reentrant (CPSR.I is set on entry)? i.e. should IRQ reentrancy
be behind a Cargo feature?
I haven't use the FIQ yet -- on the Ultrascale+ there's an option to service
secure device interrupts through FIQ and non-secure interrupts through IRQ, but
I assume it's also non-reentrant by default (CPSR.F is set on entry). Is there a
use case for a reentrant FIQ?
Stable channel
This crate should compile on stable. I don't see anything preventing us from
removing the nightly features that are currently being used. The uses of asm!
,
global_asm!
and #[naked]
can be replaced with external assembly / binary
blobs.
Custom linker scripts
To support placing the program in Flash and RAM and also placing the whole
program in RAM we need support for user defined linker scripts. I have an idea
of how to implement this which I'll post as an RFC on the cortex-m-rt
issue tracker
(at some point). I'll link the RFC here once it's up.
Are there are more requirements that need to be taken into account to make this
crate as generic as possible? What should be the defaults where options are
provided? e.g. Should IRQ be reentrant or non-reentrant by default?
cc @kenkeiter