Skip to content

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

Merged
merged 3 commits into from
Mar 24, 2025
Merged

Conversation

robamu
Copy link
Contributor

@robamu robamu commented Feb 24, 2025

MMU code: d04c503

Maybe there are some overlaps with Cortex-R? Some of the attributes are protection related

@robamu robamu requested a review from a team February 24, 2025 11:31
@robamu robamu marked this pull request as draft February 24, 2025 11:32
@jonathanpallant
Copy link
Contributor

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.

@jonathanpallant
Copy link
Contributor

The unit test job failed, because it runs only in the ./cortex-r directory, so .github/workflows/build.yml needs updating.

@jonathanpallant
Copy link
Contributor

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.

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");
Copy link
Contributor

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 :)

Copy link
Contributor Author

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?

Copy link
Contributor

@jonathanpallant jonathanpallant Feb 25, 2025

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.

Copy link
Contributor Author

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

@robamu
Copy link
Contributor Author

robamu commented Feb 25, 2025

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.

@jonathanpallant
Copy link
Contributor

jonathanpallant commented Feb 25, 2025

Yeah, maybe it actually makes sense to have a versatileab-examples folder, which builds for either Cortex-R5 or Cortex-A5 (say), and a separate mps3-an536-examples folder which builds for Cortex-R52.

Edit: or examples/versatileab.

@robamu
Copy link
Contributor Author

robamu commented Feb 25, 2025

We could do that. Should we then just accept duplicate code, for example for examples like hello.rs?

@robamu robamu force-pushed the cortex-a-addition branch 2 times, most recently from 8cd48b1 to 0ff142b Compare February 25, 2025 16:59
@jonathanpallant
Copy link
Contributor

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!

@@ -7,6 +7,10 @@ mod critical_section;

pub mod asm;
pub mod interrupt;
<<<<<<< HEAD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops


/// 1 MB section translation entry, mapping a 1 MB region to a physical address.
#[derive(Debug, Copy, Clone)]
pub struct L1Section(pub u32);
Copy link
Contributor

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?

Copy link
Contributor Author

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.

any(target_abi = "eabihf", feature = "eabi-fpu")
))]
#[cfg(not(any(target_abi = "eabihf", feature = "eabi-fpu")))]
macro_rules! restore_context {
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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

Copy link
Contributor Author

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please

@robamu
Copy link
Contributor Author

robamu commented Feb 25, 2025

Should I already split the examples, or is this something you want to have a look at?

@robamu
Copy link
Contributor Author

robamu commented Feb 25, 2025

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:

/home/rmueller/ROMEO/cortex-r-a/cortex-ar/src/mmu.rs|136 col 1-27 error| custom attribute panicked message: Invalid path segment. Expected Enumeration or Option<Enumeration>

@thejpster
Copy link
Contributor

Is your L1EntryType marked exhaustive = true?

@thejpster
Copy link
Contributor

#[bitbybit::bitenum(u5, exhaustive = false)]
wasn't exhaustive, so the field type has to be wrapped in Option in the struct that contains it.

@robamu
Copy link
Contributor Author

robamu commented Feb 25, 2025

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

@thejpster
Copy link
Contributor

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 .cargo/config file.

@robamu
Copy link
Contributor Author

robamu commented Feb 26, 2025

I found out why the MMU code does not work. The macro does not like a fully qualified arbitrary_int path like arbitrary_int::u2.. I will file crate an issue for this.

UPDATE: Issue danlehmann/bitfield#68

@robamu
Copy link
Contributor Author

robamu commented Feb 26, 2025

By the way, I made some other tweaks to the examples:

  • Compile time check to assert correct targets. Otherwise, QEMU will just hang up
  • To allow still checking the workspace for all targets, exclude the examples from workspace. This means for running the examples that you have to navigate into the folder, or use --manifest-path <relPath>

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 :)

@robamu
Copy link
Contributor Author

robamu commented Feb 26, 2025

Oh, and I also added one thing which is a breaking change for arm-targets: The process method now returns the target information as part of a struct. I wanted to use this for solving the issue with the workspace compilation, but it did not solve the issue in the end. However, I think it could still be useful to return the information structure for easier processing in the build.rs

@@ -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
Copy link
Contributor Author

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

Copy link
Contributor

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.

@robamu robamu marked this pull request as ready for review March 1, 2025 10:34
@robamu robamu force-pushed the cortex-a-addition branch from 5d3ab2a to c88cd09 Compare March 1, 2025 10:46
/// Let's test some timers!
#[cfg(arm_architecture = "v8-r")]
#[export_name = "main"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this unmangled?

Copy link
Contributor Author

@robamu robamu Mar 3, 2025

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() {
Copy link
Contributor

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?

Copy link
Contributor Author

@robamu robamu Mar 3, 2025

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

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 vdp-dp is not specified. I removed the --all-features build, but I tried that locally and I do not get these errors..

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

Ah I used check instead of build, which is apparently an important difference here

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

I'll also add one more thing: stack setup for UND and ABT

@robamu robamu force-pushed the cortex-a-addition branch from 93f0b36 to 37e3132 Compare March 3, 2025 10:27
@jonathanpallant
Copy link
Contributor

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 vdp-dp is not specified. I removed the --all-features build, but I tried that locally and I do not get these errors..

Is that related to this issue?

// Work around https://github.com/rust-lang/rust/issues/127269

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

Possibly.. I will test whether adding .fpu vfpv3-32 fixes something ...

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

Hmm, the only way to make build work with the vfp-dp feature for cortex-a-rt specifically is to add the following build flags for the cortex-a target:

[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.

@jonathanpallant
Copy link
Contributor

jonathanpallant commented Mar 3, 2025

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 ;)

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

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 vfp-dp feature in the cortex-a-rt crate.

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

I have updated the docs and the README

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

Oops, I just saw that there are some outstanding code review suggestions

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

If everything looks okay for you, I can do one more squash :)

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

Rebased based on upstream main and updated/added changelogs

@robamu robamu force-pushed the cortex-a-addition branch from 6503b5f to f452c5f Compare March 3, 2025 15:49
@thejpster
Copy link
Contributor

Are you building the examples in CI? I couldn't see where.

@robamu
Copy link
Contributor Author

robamu commented Mar 3, 2025

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
@robamu robamu force-pushed the cortex-a-addition branch from 15d718e to 3d2319b Compare March 4, 2025 08:20
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

any(target_abi = "eabihf", feature = "eabi-fpu")
))]
#[cfg(not(any(target_abi = "eabihf", feature = "eabi-fpu")))]
macro_rules! restore_context {
Copy link
Contributor

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
Copy link
Contributor

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.

}

/// The main function of our Rust application.
///
/// Called by [`kmain`].
fn main() -> Result<(), core::fmt::Error> {
#[export_name = "main"]
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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() {
Copy link
Contributor

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.

@thejpster
Copy link
Contributor

This LGTM but now @rust-embedded/arm has to approve.

@adamgreig adamgreig merged commit 42f7cca into rust-embedded:main Mar 24, 2025
57 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants