Add support for PQC secure boot with MCXA 5xx family of MCUs#36
Add support for PQC secure boot with MCXA 5xx family of MCUs#36alamfarjadf wants to merge 11 commits into
Conversation
There was a problem hiding this comment.
@JamesHuard This particular file maybe of interest to you.
There was a problem hiding this comment.
Let me connect with you offline, I'm currently building out the requirements for the SBL boot flow here and want to make sure we're aligned at that level (also there's a LOT of code here for me to review 😆 )
08f268c to
f185706
Compare
diondokter
left a comment
There was a problem hiding this comment.
Is there any split image support yet? If there is I can't find it (so please point me to it 😊)
Or are we assuming the ROM memory mapped it for us already?
| target = "thumbv8m.main-none-eabihf" | ||
|
|
||
| [target.thumbv8m.main-none-eabihf] | ||
| runner = "probe-rs run --chip MCXA577 --chip-description-path MCXA_custom.yaml" |
There was a problem hiding this comment.
I don't see the MCXA_custom.yaml committed here... Could we fix that?
There was a problem hiding this comment.
@alamfarjadf is this a file you're maintaining locally?
There was a problem hiding this comment.
@alamfarjadf is this a file you're maintaining locally?
Yes, I can add.
| const AIRCR: *mut u32 = 0xE000ED0C as *mut u32; | ||
| const AIRCR_VECTKEY: u32 = 0x5FA << 16; | ||
| const AIRCR_SYSRESETREQ: u32 = 1 << 2; | ||
| unsafe { | ||
| core::ptr::write_volatile(AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ); | ||
| } |
There was a problem hiding this comment.
cortex-m has a built-in function for this: https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.sys_reset
There was a problem hiding this comment.
Where does this code actually come from? Translated from the C SDK or something?
A lot of it is very non-obvious and has magic values
There was a problem hiding this comment.
@alamfarjadf can correct me, but I believe it's a mix of referencing the prelim Reference Manual and the C SDK for the part.
There was a problem hiding this comment.
Where does this code actually come from? Translated from the C SDK or something? A lot of it is very non-obvious and has magic values
@diondokter This is from the preliminary reference manual as well as NXP's own SDK code.
The magic values are strictly defined header/ magic values that NXP puts in the AHAB certificate and expects to be there.
Refer to chapter 7 of the SRM.
| // (similar to imxrt): disable interrupts & timer | ||
| // Disable all maskable interrupts | ||
| // info!("jump: disabling interrupts"); | ||
| #[cfg(target_arch = "arm")] | ||
| asm!("cpsid i", options(nostack, preserves_flags)); | ||
|
|
||
| // Disable SysTick (if previously configured by loader) | ||
| const SYST_CSR: *mut u32 = 0xE000E010 as *mut u32; // SysTick Control and Status Register | ||
| core::ptr::write_volatile(SYST_CSR, 0); | ||
| // info!("jump: SysTick disabled"); | ||
|
|
||
| // Disable NVIC interrupts & clear any pending bits (MCXN556s up to IRQ 155 → 5 * 32 blocks) | ||
| const NVIC_ICER_BASE: *mut u32 = 0xE000E180 as *mut u32; // Interrupt Clear/Enable Registers | ||
| const NVIC_ICPR_BASE: *mut u32 = 0xE000E280 as *mut u32; // Interrupt Clear/Pending Registers | ||
| for i in 0..5 { | ||
| core::ptr::write_volatile(NVIC_ICER_BASE.add(i), 0xFFFF_FFFF); | ||
| core::ptr::write_volatile(NVIC_ICPR_BASE.add(i), 0xFFFF_FFFF); | ||
| } | ||
| // info!("jump: NVIC interrupts disabled & pending cleared"); | ||
|
|
||
| // Clear selected system handler pending bits (SecureFault, PendSV) in SHCSR | ||
| const SCB_SHCSR: *mut u32 = 0xE000ED24 as *mut u32; // System Handler Control and State Register | ||
| // Write-1-to-clear for pending bits is not supported; instead, clear enable bits to avoid servicing. | ||
| // Ensure SVC/Debug/PendSV/SysTick not enabled by loader. | ||
| core::ptr::write_volatile(SCB_SHCSR, 0); | ||
| // info!("jump: SHCSR cleared"); | ||
|
|
||
| // Ensure privileged thread mode & use MSP (clear CONTROL.nPRIV & CONTROL.SPSEL) | ||
| #[cfg(target_arch = "arm")] | ||
| asm!("msr CONTROL, {0}", in(reg) 0u32, options(nostack, preserves_flags)); | ||
| #[cfg(target_arch = "arm")] | ||
| asm!("isb", options(nostack, preserves_flags)); | ||
|
|
||
| // Set VTOR to application's vector table | ||
| const SCB_VTOR: *mut u32 = 0xE000ED08 as *mut u32; | ||
| core::ptr::write_volatile(SCB_VTOR, entry); |
There was a problem hiding this comment.
This needs a pass. It does things we don't need (like touch the systick) and it uses raw pointer math while cortex-m can do things for us
There was a problem hiding this comment.
Agreed, I got carried away without being fully familiar with the with the cortex-m crate.
| let flash = InternalFlash::new(); | ||
| let journal = match FlashJournal::new::<JOURNAL_BUFFER_SIZE>(flash).await { | ||
| Ok(journal) => journal, | ||
| Err(_) => { | ||
| mcxa_error!("Critical: failed to initialize flash journal"); | ||
| loop { | ||
| cortex_m::asm::wfi(); | ||
| } | ||
| } | ||
| }; |
There was a problem hiding this comment.
I thought we weren't putting the journal in internal flash?
Or do we have a custom board impl for that? (privately)
There was a problem hiding this comment.
That is an update that's needed here. Journal should be the first partition in external flash, since the internal flash doesn't support multiwrite
There was a problem hiding this comment.
How opinionated should this be? Currently this is a very specific implementation. Another mcxa user might want to store things in different locations.
There was a problem hiding this comment.
Yea, agreed this is too opinionated. I think we should follow a similar method as was done on the RT6 part, where we can specify these using the partition TOML
The image header that the NXP ROM APIs/ROM Loader use has a section for identifying multiple images. The thought here is that it'd be a 'no-op' from an implementation perspective of the SBL firmware to support split-image, because it's already baked into the infra. The change then is in the build tooling to actually generate these additional fields and hashes. That's also where the open question is to NXP around if the secondary image(s) are simply hash verified or included in the full image signature block. |
@diondokter There is no split image support yet. From my understanding, the split image on the verification side should be opaque to the caller, IF the image is built correctly (The idea here is that the second executable occupies the area for the CRC binary and is hashed and verified automatically by the APIs). But that idea hasn't been validated yet partly because I haven't been able to generate a split image binary yet. We have reached out to NXP for further clarification and are awaiting their response. When we have a split binary, the API will use the single AHAB container to hash both binaries and validate them, so infrastructure needed is mostly on the artifact generation side (which is not published as part of this public PR yet but available in private repos). |
Adding ROM API support for MCXA 5xx family with Post-Quantum Cryptography hybrid secure boot (ML-DSA-87 and EC-DSA P384).
Added ec-slimloader-mcxa under libs and mcxa-577 examples (bootloader and blinky).
Validated on MCXA577 eval kit with hybrid signed AHAB MBI images which successfully authenticate and boot up.
Not yet added to PR: Imaging tools for MCXA.
BSD-3 license is acceptable (e.g. NXP-PAC), need to update deny.toml.
Clippy currently fails because SGI hashing PR waiting to be merged in embassy-mcxa