-
Notifications
You must be signed in to change notification settings - Fork 8
Cortex-A addition #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Ah! Does it make sense to keep the examples together? Would every example always work (or at least compile) for both a Cortex-A target and a Cortex-R target? I guess perhaps as much as they compile and work for both an Armv7-R target and an Armv8-R target. |
The unit test job failed, because it runs only in the |
d04c503
to
0720e13
Compare
Do you want to look at #9 so we can get that merged? Then I can publish a first version of cortex-r-a and cortex-r-rt, and then this PR will get much smaller because most of the rename will be out of the way. |
cortex-a-rt/link.x
Outdated
PROVIDE(_und_stack_size = 0x400); | ||
PROVIDE(_svc_stack_size = 0x1000); | ||
|
||
ASSERT(_stack_top % 8 == 0, "ERROR(cortex-r-rt): top of stack is not 8-byte aligned"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The help text in these asserts needs changing now :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did update it.. On that note, should we add those stacks to cortex-r as well? maybe with smaller/tweaked sizes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes please. Cortex-R machines always seem to have like 1MB of RAM for each core, so no need to make the stacks super small (and users can over-ride the sizes if they want). Stack overflows are pretty miserable to debug so let's try and avoid them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add that as a separate PR
I am not sure whether or not splitting the examples is better to be honest. If you look at the code adaption, you can already see that the entry points have different names, that would be a better case for separated examples. I specifically made a macro so the correct entry point is declared for the given architecture. Other than that, there is a lot of common code though. I guess there is only so much we can do in these QEMU examples because they also have to be generic. |
Yeah, maybe it actually makes sense to have a Edit: or |
We could do that. Should we then just accept duplicate code, for example for examples like hello.rs? |
8cd48b1
to
0ff142b
Compare
The examples are short, so I would take duplicate examples over trying to support multiple linker scripts / memory maps / hardware configurations within one example binary crate. I'm just trying to pick my battles here! |
cortex-ar/src/lib.rs
Outdated
@@ -7,6 +7,10 @@ mod critical_section; | |||
|
|||
pub mod asm; | |||
pub mod interrupt; | |||
<<<<<<< HEAD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops
cortex-ar/src/mmu.rs
Outdated
|
||
/// 1 MB section translation entry, mapping a 1 MB region to a physical address. | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct L1Section(pub u32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps a bitbybit::bitfield is useful here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be useful. I never used the crate before, I can have a look at it.
cortex-r-rt/src/lib.rs
Outdated
any(target_abi = "eabihf", feature = "eabi-fpu") | ||
))] | ||
#[cfg(not(any(target_abi = "eabihf", feature = "eabi-fpu")))] | ||
macro_rules! restore_context { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I preferred these as save/restore pairs, because save and restore have to match whilst FPU-save and no-fpu-save don't have to match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, they're still pairs right? Or did I mess something up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you moved the first restore_context to after the second save_context and it was before?
It was
save A
restore A
save B
restore B
It's now
save A
save B
restore A
restore B
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah you just mean the order they appear. I can put this back to the old order, no problem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please
4f4e49e
to
e2c7336
Compare
Should I already split the examples, or is this something you want to have a look at? |
For some reason this code does not compile/work: /// 1 MB section translation entry, mapping a 1 MB region to a physical address.
#[derive(Debug)]
#[bitbybit::bitfield(u32)]
pub struct L1Section {
#[bits(20..=31, rw)]
phys_base: arbitrary_int::u12,
#[bit(16, rw)]
ng: bool,
#[bit(16, rw)]
s: bool,
#[bit(15, rw)]
apx: bool,
#[bits(12..=14, rw)]
tex: arbitrary_int::u3,
#[bits(10..=11, rw)]
ap: arbitrary_int::u2,
#[bit(9, rw)]
p_bit: bool,
#[bits(5..=8, rw)]
domain: arbitrary_int::u4,
#[bit(4, rw)]
xn: bool,
#[bit(3, rw)]
c: bool,
#[bit(2, rw)]
b: bool,
#[bits(0..=1, rw)]
entry_type: L1EntryType,
} error:
|
cc95202
to
b9a4e02
Compare
Is your L1EntryType marked |
Option in the struct that contains it.
|
Hmm I find this error really confusing. Kept the L1Section using bitbybit commented because it still throws weird errors. The L1EntryType is exhaustive. I actually split the examples.. Should I split versatileab into a cortex-m/cortex-a part or use cfg directives? Right now, it only works for cortex-a. Kind of forgot that versatileab was also used for cortex-r, until I looked at the runners again |
Yeah behing able to run it with a Cortex-R5 is kind of an undocumented secret. You should be able to have one example build for both armv7a-none-eabi and armv7r-none-eabi - just set up different runners in the |
I found out why the MMU code does not work. The macro does not like a fully qualified arbitrary_int path like UPDATE: Issue danlehmann/bitfield#68 |
By the way, I made some other tweaks to the examples:
What do you think about these changes? Other than that, I am trying to add the armv7a target to your test shell script. Update coming soon :) |
ad2acc2
to
517ad7f
Compare
Oh, and I also added one thing which is a breaking change for arm-targets: The |
@@ -1,5 +1,8 @@ | |||
MIDR { implementer=0x41 variant=0x1 arch=0xf part_no=0xc15 rev=0x3 } | |||
CPSR { N=0 Z=1 C=1 V=0 Q=0 J=0 E=0 A=1 I=1 F=1 T=0 MODE=Ok(Sys) } | |||
Mpidr(3221225472) | |||
SCTLR { IE=0 TE=0 NMFI=0 EE=0 U=0 FI=0 DZ=0 BR=0 RR=0 V=0 I=0 Z=0 SW=0 C=0 A=0 M=0 } before setting C, I and Z |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BR became 0 here for some reason
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine. It's just the start up state of the processor.
5d3ab2a
to
c88cd09
Compare
/// Let's test some timers! | ||
#[cfg(arm_architecture = "v8-r")] | ||
#[export_name = "main"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this unmangled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Zynq target, I had issues stepping through code when the main method was not explicitely exported as "main". I have not tried stepping through the code with QEMU, but I assumed this is just generally a good idea. This is also something that is done by the cortex-m-rt entry point macro.
/// It is called by the start-up code in `cortex-m-rt`. | ||
#[no_mangle] | ||
#[cfg(arm_profile = "r")] | ||
pub extern "C" fn kmain() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should add the CPU core argument to the cortex-R start up too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not know whether Cortex-R has multi-core. If it has, that might make sense. If this is done, maybe it could also be renamed to boot_core
, allowing to unify the methods and avoiding the macro?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
My chip has two clusters of four R52s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need special startup code adaption for this? For Cortex-A specifically, Both cores start executing the start up code simultaneously. The Cortex-A programmers manual recommends letting just one core do the start up routine, so I put one core to sleep with wfe
instruction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll check the docs. But let's merge this anyway.
I wonder why I can not re-produce these CI errors locally.. It complains about the VFP-DP registers not being available for certain targets, but this should not happen if |
Ah I used |
I'll also add one more thing: stack setup for UND and ABT |
93f0b36
to
37e3132
Compare
Is that related to this issue? cortex-ar/cortex-r-rt/src/lib.rs Line 244 in 8f91e39
|
Possibly.. I will test whether adding |
Hmm, the only way to make [target.armv7a-none-eabihf]
runner = "qemu-system-arm -machine versatileab -cpu cortex-a8 -semihosting -nographic -kernel"
rustflags = [
"-Ctarget-cpu=cortex-a8",
"-Ctarget-feature=+vfp3",
"-Ctarget-feature=+neon",
"-Clink-arg=-Tlink.x",
# Can be useful for debugging.
# "-Clink-args=-Map=app.map"
]
The workaround from the Github issue is not required for cortex-a I think. The VSMR instruction always seems to work. |
I'm surprised +vfp3 is required? The target spec looks like: rustc +nightly --print target-features --target armv7a-none-eabihf --print target-spec-json -Z unstable-options {
"abi": "eabihf",
"arch": "arm",
"c-enum-min-bits": 8,
"crt-objects-fallback": "false",
"data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
"disable-redzone": true,
"emit-debug-gdb-scripts": false,
"features": "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align",
"linker": "rust-lld",
"linker-flavor": "gnu-lld",
"llvm-floatabi": "hard",
"llvm-target": "armv7a-none-eabihf",
"max-atomic-width": 64,
"metadata": {
"description": "Bare Armv7-A, hardfloat",
"host_tools": false,
"std": false,
"tier": 3
},
"panic-strategy": "abort",
"relocation-model": "static",
"target-pointer-width": "32"
} Either way, that's something the binary authors will have to worry about. For us it's only relevant for the example crate, and we can add those options there. Edit: And the README ;) |
Uh, I have not tried omitting vfp3 actually. I wanted to be really explicit for the Zynq target. Very useful command, I think I tried to find this in the source code/docs but could not, so I just set the important stuff explicitly. I can document the |
I have updated the docs and the README |
Oops, I just saw that there are some outstanding code review suggestions |
If everything looks okay for you, I can do one more squash :) |
Rebased based on upstream main and updated/added changelogs |
6503b5f
to
f452c5f
Compare
Are you building the examples in CI? I couldn't see where. |
It is done as part of the QEMU tests / tests.sh, but only for versatileab. It would probably make sense to build them in addition as well. |
- Add armv7a architecture handling to the crate. - Add new `cortex-a-rt` reference run time crate. - Add basic armv7a checks to CI - `kmain` renamed to `boot_core` for Cortex-A where multi-processor systems are common. - Add armv7a to examples for basic verification with QEMU - Split example code into dedicated folders for QEMU targets - Build examples in CI as well
15d718e
to
3d2319b
Compare
README.md
Outdated
* [arm-targets](./arm-targets/) - a helper library for your build.rs that sets various `--cfg` flags according to the current target | ||
|
||
There are also example programs for QEMU in the [cortex-r-examples](./cortex-r-examples/) folder. | ||
There are also example programs for QEMU in the [examples](./-examples/) folder. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo
cortex-r-rt/src/lib.rs
Outdated
any(target_abi = "eabihf", feature = "eabi-fpu") | ||
))] | ||
#[cfg(not(any(target_abi = "eabihf", feature = "eabi-fpu")))] | ||
macro_rules! restore_context { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please
@@ -1,5 +1,8 @@ | |||
MIDR { implementer=0x41 variant=0x1 arch=0xf part_no=0xc15 rev=0x3 } | |||
CPSR { N=0 Z=1 C=1 V=0 Q=0 J=0 E=0 A=1 I=1 F=1 T=0 MODE=Ok(Sys) } | |||
Mpidr(3221225472) | |||
SCTLR { IE=0 TE=0 NMFI=0 EE=0 U=0 FI=0 DZ=0 BR=0 RR=0 V=0 I=0 Z=0 SW=0 C=0 A=0 M=0 } before setting C, I and Z |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine. It's just the start up state of the processor.
examples/mps3-an536/src/bin/svc.rs
Outdated
} | ||
|
||
/// The main function of our Rust application. | ||
/// | ||
/// Called by [`kmain`]. | ||
fn main() -> Result<(), core::fmt::Error> { | ||
#[export_name = "main"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would take this out. I haven't needed it with TRACE32 or GDB.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, this is interesting.. It was important for my Zynq target, I received a really weird call stack and extremely slow stepping if main was not exported like this. I will take it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the demangling for all the mps3-an536 examples
/// It is called by the start-up code in `cortex-m-rt`. | ||
#[no_mangle] | ||
#[cfg(arm_profile = "r")] | ||
pub extern "C" fn kmain() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
My chip has two clusters of four R52s.
This LGTM but now @rust-embedded/arm has to approve. |
MMU code: d04c503
Maybe there are some overlaps with Cortex-R? Some of the attributes are protection related