Support for mixed architectures (ARM + RISC-V at the same time) #2502

Open
opened 2025-06-04 11:06:25 -05:00 by dsseng · 9 comments
dsseng commented 2025-06-04 11:06:25 -05:00 (Migrated from github.com)

I could not find this neither in examples nor in the datasheet, but datasheet does mention that both architectures can be used at the same time, with sync primitives working as well.

I'm mostly asking for documentation here, not necessarily SDK support. So the known flow is that we can request BootROM to activate a certain arch at reboot, which will then be selected and an image will be found to make it run.

However, BootROM starts core 0, and it's program's job to bring up core 1. So some of my questions:

  1. Seems like I can place core 1 entrypoint outside of the main partition, in case I want it to evade Secure Boot? Use case: cpu0 runs "OS", and cpu1 runs user-modifiable code (a minimalist program not touching clocks or other hardware driven by cpu0). This is a rather specific task, but seems possible. Could you please confirm?
  2. Can we somehow set the core selection, then assert and deassert core 1 reset (as we must do to boot cpu1), so that it starts with the desired architecture?
  3. If Secure Boot is active, can I only force cpu0 (which actually runs SB checks) to the Arm-only mode, and make it bring up the second core as RISC-V? Or is the second core prevented from initializing to RISC-V after OTP is written for SB enable?

Thank you!

I could not find this neither in examples nor in the datasheet, but datasheet does mention that both architectures can be used at the same time, with sync primitives working as well. I'm mostly asking for documentation here, not necessarily SDK support. So the known flow is that we can request BootROM to activate a certain arch at reboot, which will then be selected and an image will be found to make it run. However, BootROM starts core 0, and it's program's job to bring up core 1. So some of my questions: 1. Seems like I can place core 1 entrypoint outside of the main partition, in case I want it to evade Secure Boot? Use case: cpu0 runs "OS", and cpu1 runs user-modifiable code (a minimalist program not touching clocks or other hardware driven by cpu0). This is a rather specific task, but seems possible. Could you please confirm? 2. Can we somehow set the core selection, then assert and deassert core 1 reset (as we must do to boot cpu1), so that it starts with the desired architecture? 3. If Secure Boot is active, can I only force cpu0 (which actually runs SB checks) to the Arm-only mode, and make it bring up the second core as RISC-V? Or is the second core prevented from initializing to RISC-V after OTP is written for SB enable? Thank you!
Wren6991 commented 2025-06-04 11:15:40 -05:00 (Migrated from github.com)

Seems like I can place core 1 entrypoint outside of the main partition, in case I want it to evade Secure Boot? Use case: cpu0 runs "OS", and cpu1 runs user-modifiable code (a minimalist program not touching clocks or other hardware driven by cpu0). This is a rather specific task, but seems possible. Could you please confirm?

The way I have done this is building a RISC-V binary to embed inside the Arm binary, and forcing the RISC-V entry point to be at a known location (the start of the RISC-V binary).

You can embed one binary inside the other with #embed, xxd, .incbin etc

Can we somehow set the core selection, then assert and deassert core 1 reset (as we must do to boot cpu1), so that it starts with the desired architecture?

Yes. From core 0 just set bit 1 of otp_hw->archsel and then toggle the core 1 reset via PSM_FRCE_OFF_PROC1_BITS.

If Secure Boot is active, can I only force cpu0 (which actually runs SB checks) to the Arm-only mode, and make it bring up the second core as RISC-V? Or is the second core prevented from initializing to RISC-V after OTP is written for SB enable?

Enabling secure boot prevents selection of the RISC-V cores. You won't be able to write nonzero values to ARCHSEL.

> Seems like I can place core 1 entrypoint outside of the main partition, in case I want it to evade Secure Boot? Use case: cpu0 runs "OS", and cpu1 runs user-modifiable code (a minimalist program not touching clocks or other hardware driven by cpu0). This is a rather specific task, but seems possible. Could you please confirm? The way I have done this is building a RISC-V binary to embed inside the Arm binary, and forcing the RISC-V entry point to be at a known location (the start of the RISC-V binary). You can embed one binary inside the other with `#embed`, `xxd`, `.incbin` etc > Can we somehow set the core selection, then assert and deassert core 1 reset (as we must do to boot cpu1), so that it starts with the desired architecture? Yes. From core 0 just set bit 1 of `otp_hw->archsel` and then toggle the core 1 reset via `PSM_FRCE_OFF_PROC1_BITS`. > If Secure Boot is active, can I only force cpu0 (which actually runs SB checks) to the Arm-only mode, and make it bring up the second core as RISC-V? Or is the second core prevented from initializing to RISC-V after OTP is written for SB enable? Enabling secure boot prevents selection of the RISC-V cores. You won't be able to write nonzero values to ARCHSEL.
dsseng commented 2025-06-04 11:23:05 -05:00 (Migrated from github.com)

Thanks for clarification, mixed-arch seems really cool!

The way I have done this is building a RISC-V binary to embed inside the Arm binary, and forcing the RISC-V entry point to be at a known location (the start of the RISC-V binary).

You can embed one binary inside the other with #embed, xxd, .incbin etc

Basically similar to what I want to use (but perhaps a separate partition at a known offset). Cool when you can handle the second CPU yourself!

Yes. From core 0 just set bit 1 of otp_hw->archsel and then toggle the core 1 reset via PSM_FRCE_OFF_PROC1_BITS.

Okay, so the ordinary core bring-up procedure makes the hardware re-read the ARCHSEL flag for it, without a full-chip reset. Cool! It just happens to be located in the OTP block, but is completely read-writeable and not persistent, right? Just want to be extra safe

Enabling secure boot prevents selection of the RISC-V cores. You won't be able to write nonzero values to ARCHSEL.

Got it, thanks! Might be a consideration for the next spin or something, since even if not possible to boot RISC-V securely, then only core 0 actually needs to be made ARM-only, and its firmware could take care of enforcing authenticity of the core 1 code (either by embedding into itself or verifying before execution).

Thanks for clarification, mixed-arch seems really cool! > The way I have done this is building a RISC-V binary to embed inside the Arm binary, and forcing the RISC-V entry point to be at a known location (the start of the RISC-V binary). > > You can embed one binary inside the other with `#embed`, `xxd`, `.incbin` etc Basically similar to what I want to use (but perhaps a separate partition at a known offset). Cool when you can handle the second CPU yourself! > Yes. From core 0 just set bit 1 of otp_hw->archsel and then toggle the core 1 reset via PSM_FRCE_OFF_PROC1_BITS. Okay, so the ordinary core bring-up procedure makes the hardware re-read the ARCHSEL flag for it, without a full-chip reset. Cool! It just happens to be located in the OTP block, but _is completely read-writeable and not persistent, right_? Just want to be extra safe > Enabling secure boot prevents selection of the RISC-V cores. You won't be able to write nonzero values to ARCHSEL. Got it, thanks! Might be a consideration for the next spin or something, since even if not possible to boot RISC-V securely, then only core 0 actually needs to be made ARM-only, and its firmware could take care of enforcing authenticity of the core 1 code (either by embedding into itself or verifying before execution).
Wren6991 commented 2025-06-04 11:25:08 -05:00 (Migrated from github.com)

Okay, so the ordinary core bring-up procedure makes the hardware re-read the ARCHSEL flag for it, without a full-chip reset. Cool! It just happens to be located in the OTP block, but is completely read-writeable and not persistent, right? Just want to be extra safe

Yes, registers under OTP_BASE are just normal peripheral registers that happen to be closely associated with the OTP or the OTP PSM.

Got it, thanks! Might be a consideration for the next spin or something, since even if not possible to boot RISC-V securely, then only core 0 actually needs to be made ARM-only, and its firmware could take care of enforcing authenticity of the core 1 code (either by embedding into itself or verifying before execution).

We wanted to avoid any use of RISC-V cores or RISC-V debug to sidestep secure boot, and this was the simplest method.

> Okay, so the ordinary core bring-up procedure makes the hardware re-read the ARCHSEL flag for it, without a full-chip reset. Cool! It just happens to be located in the OTP block, but is completely read-writeable and not persistent, right? Just want to be extra safe Yes, registers under `OTP_BASE` are just normal peripheral registers that happen to be closely associated with the OTP or the OTP PSM. > Got it, thanks! Might be a consideration for the next spin or something, since even if not possible to boot RISC-V securely, then only core 0 actually needs to be made ARM-only, and its firmware could take care of enforcing authenticity of the core 1 code (either by embedding into itself or verifying before execution). We wanted to avoid any use of RISC-V cores or RISC-V debug to sidestep secure boot, and this was the simplest method.
dsseng commented 2025-06-04 11:31:31 -05:00 (Migrated from github.com)

Understood that, thanks. Should I close this or keep as a docs improvement proposal?

Understood that, thanks. Should I close this or keep as a docs improvement proposal?
dsseng commented 2025-06-04 11:41:03 -05:00 (Migrated from github.com)

Another question (not really practical yet a cool thing). Can I reset and re-select the architecture for cpu1 multiple times without full reset? Like archsel = 0, reset, run Arm code, archsel = 1, reset, run Hazard3 code, reset into Arm again? Basically the only prohibited management from cpu0 to cpu1 is resetting while running a critical section or holding spinlocks?

Another question (not really practical yet a cool thing). Can I reset and re-select the architecture for cpu1 multiple times without full reset? Like archsel = 0, reset, run Arm code, archsel = 1, reset, run Hazard3 code, reset into Arm again? Basically the only prohibited management from cpu0 to cpu1 is resetting while running a critical section or holding spinlocks?
Wren6991 commented 2025-06-04 11:57:19 -05:00 (Migrated from github.com)

Yes, I had a demo where all four cores were rendering 1/4 each of a DVI output by rebooting at 120 Hz.

I think the current level of documentation is a good self-selection for the people who want to try this :-)

Yes, I had a demo where all four cores were rendering 1/4 each of a DVI output by rebooting at 120 Hz. I think the current level of documentation is a good self-selection for the people who want to try this :-)
Wren6991 commented 2025-06-04 11:58:59 -05:00 (Migrated from github.com)

Basically the only prohibited management from cpu0 to cpu1 is resetting while running a critical section or holding spinlocks?

Not just spinlocks, any reset of a processor that's holding any kind of software lock will lead to a sequence break. This is true even if you're not mixing your architectures.

> Basically the only prohibited management from cpu0 to cpu1 is resetting while running a critical section or holding spinlocks? Not just spinlocks, any reset of a processor that's holding any kind of software lock will lead to a sequence break. This is true even if you're not mixing your architectures.
dsseng commented 2025-06-04 12:04:32 -05:00 (Migrated from github.com)

Yes, I had a demo where all four cores were rendering 1/4 each of a DVI output by rebooting at 120 Hz.

I think the current level of documentation is a good self-selection for the people who want to try this :-)

Why did they have to reboot (and maybe switch arch?)?

> Yes, I had a demo where all four cores were rendering 1/4 each of a DVI output by rebooting at 120 Hz. > > I think the current level of documentation is a good self-selection for the people who want to try this :-) Why did they have to reboot (and maybe switch arch?)?
dsseng commented 2025-06-04 12:05:28 -05:00 (Migrated from github.com)

Basically the only prohibited management from cpu0 to cpu1 is resetting while running a critical section or holding spinlocks?

Not just spinlocks, any reset of a processor that's holding any kind of software lock will lead to a sequence break. This is true even if you're not mixing your architectures.

Gotcha, but actually re-resetting and re-selecting arch are both valid as long as the core isn't in critical sections nor holds a lock?

> > Basically the only prohibited management from cpu0 to cpu1 is resetting while running a critical section or holding spinlocks? > > Not just spinlocks, any reset of a processor that's holding any kind of software lock will lead to a sequence break. This is true even if you're not mixing your architectures. Gotcha, but actually re-resetting and re-selecting arch are both valid as long as the core isn't in critical sections nor holds a lock?
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk#2502
No description provided.