Skip to content
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

nRF5340 support #1779

Open
maxd-nordic opened this issue Mar 6, 2024 · 13 comments
Open

nRF5340 support #1779

maxd-nordic opened this issue Mar 6, 2024 · 13 comments
Labels
New Target New debug target
Milestone

Comments

@maxd-nordic
Copy link

Hi! I'm wondering whether it would be feasible to add nRF53 support to BMP.
The nRF5340 is a little bit different than the others though, so I'm not sure if this is compatible with BMP's architecture:

  • the two cores have private flash areas that need to be programmed from the respective core
  • the network core needs to be powered up by the application core
  • the AP of a core is disabled when APPROTECT is active
  • APPROTECT is activated automatically if the program doesn't keep it off
  • Nordic-specific CTRL-APs need to be used for unlocking
  • supporting only the application core is not an option since BLE can only be done by the network core and that is the main feature of the SoC
@dragonmux
Copy link
Member

👋🏼 It's nice to see some help showing up from one of the vendors for once 😄

So:

  1. When BMD discovers the target, it will find each core individually. If there's a way to tell which core is which, the probe routine can register just the Flash region for that core with the target structure representing it.
  2. If the application core is discovered first, the probe routine can, just as with the Flash, do core-specific actions such as powering up other cores - APs are discovered and probed sequentially, so as long as AP0 can bring up AP1 (for example), then BMD won't notice the changing environment and discovery will work how you'd hope.
  3. That's unfortunate though, if we can identify a nRF53 device from the DP information or otherwise inject AP preparation somewhere in
    void adiv5_dp_init(adiv5_debug_port_s *const dp)
    then as long as the debugger is able to re-enable the APs, that's solvable.
  4. That's rather more awkward
  5. Where are those in the AP sequence? If we can identify an nRF53 part from the DP information such as the DP TARGETID register, or via the ID information (IDR, any other specific identification registers Nordic implements in their CTRL-AP register space) of those CTRL-APs, that can be solved for. It's a bit more awkward but not impossible to go back and re-evaluate an AP if the CTRL-APs come after the core ones.

Hope that helps, and we'll be happy to provide a guiding hand and advice if you're able to contribute an implementation for discovery of nRF53 devices. Our feature/64-bit-cortex-support branch is probably highly indicated to be merged before this though due to all the fixes it does to

adiv5_access_port_s *adiv5_new_ap(adiv5_debug_port_s *dp, uint8_t apsel)
which currently grossly mishandles AP discovery for non-MEM-AP types, and which doesn't handle CSW correctly for all MEM-AP types.

@dragonmux dragonmux added the New Target New debug target label Mar 6, 2024
@dragonmux dragonmux added this to the v2.1 release milestone Nov 22, 2024
@canatella
Copy link

I'm starting a new project based on that device and I'm really sad to not be able to use my BMPs. Could you please update this issue if there's some branch somewhere I can help with? Thanks!

@canatella
Copy link

So, I never really played with firware programming using SWD, but I'm giving it a go and scratching my itch. It's early stage and probably not working, but in case anyone is looking: https://github.com/canatella/blackmagic/tree/nrf5430-support
Managed to program the application core but not still having some issues debugging it.

@canatella
Copy link

I updated the code, it now supports flashing the network code and I have some fixups. @maxd-nordic My device has never been protected so I didn't need to unprotected. Am I right that if the CTRL APP app protect and secure app protect matches the values in the UICR, I can assume its unprotected ? And if it is not, what am I supposed to do ?

@maxd-nordic
Copy link
Author

@canatella thanks for doing this! I didn't have the time myself. If you can do memory reads on the MEM-AP, protection is not engaged. I usually check the CSW dbgstatus bit of the AP. nRF53 has hardened APPROTECT. That means the chip will default into protected mode unless both UICR and firmware tell it to keep the debug port open. Most firmware will do this by default, but if you do an ERASEALL operation using the special CRTL AP, you can get there. The protection will not engage until you do a pin reset. You can flash firmware that keeps the port open or just unlock right before flashing your own firmware. Note that you need the app core to start the net core.

Some extra info: In theory, there are also two other protection levels: SECUREAPPROTECT and ERASEPROTECT. The former allows you to only disable debugging secure mode stuff, while the non-secure domain can still be debugged. The latter is there to make it impossible to repurpose the chip after it was programmed. I recommend ignoring both of these, they only spell trouble. Also, block protection for flash blocks exists. Generally, CTRL AP ERASEALL solves any protection issues. If you enable ERASEALL by accident, the chip is fried. You might be lucky that it just looks like ERASEALL is enabled - we had that problem recently. If you use Nordic's official tools, we have a recovery operation which sets UICR and flashes a special firmware to both cores to keep the access ports open.

@canatella
Copy link

@maxd-nordic Is the usual way of developing with this chip to build without APPROTECT for debugging and enable APPROTECT for production ? Or do people actually debug with APPROTECT ? In which case I guess you always need to do ERASEALL, flash and then debug without resetting.

@maxd-nordic
Copy link
Author

@canatella Often, it's not used at all. The intended purpose is to enable it in production builds of your firmware. Another option is to implement a feature in your firmware to disable APPROTECT on demand. A software authentication mechanism can be implemented to guard your secret firmware.

@canatella
Copy link

canatella commented Dec 26, 2024

Alright, thanks!

@dragonmux, I have everything working but now I'm wondering what's the best UX. When the APPROTECT mode is enabled, the main core AP is disabled and it can be that the network core is not powered on, so no ap is detected:

AP   0: IDR=84770001 -> Disabled

And so nothing is displayed in the scan list. I can think of multiple ways to handle this.

  • Using a prepare function in adiv5.c before looping over the APs that detect if APPROTECT is enabled and automatically run that ERASEALL operation and power up the network core so that the 2 AP's are available when the user runs swd_scan. That is the simplest UX wise but it also means if there is somehow important data on there it could be lost ? @maxd-nordic is that something we should care about?
  • Using a platform custom command so that the user can manually trigger the ERASEALL operation and power up the net core before running mon swd_scan

Solution 2 might be the best as a user can put that command in the .gdbinit if he doesn't care about loosing data and I can make the command only actually call ERASEALL if needed. It seems there's some infrastructure already there with the PLATFORM_HAS_CUSTOM_COMMANDS define, but I don't see any usage of it in the code. The problem is that we don't have the DP available at that time...

@dragonmux
Copy link
Member

The way that this is done for other Nordic parts and others that implement similar kinds of access control is using a prepare function that detects the conditions for protection, and registers a fake target that when attached to, does the unlocking operation, or that when attached to can have mon erase_mass run on the target to do the unlocking operation.

You cannot run the erase before doing a scan not just because you won't have the DP, but because you won't even know what protocol to talk to the target or what the scan chain looks like.

The RP2040 support has a kind of an example of how to go about what we're suggesting, if married with the nRF51/52 logic for determining protection. Note that you can have the detection occur before doing target_s *t = target_new(); and returning early if not protected to avoid registering the "target" in the case there is no protection in play. The LPC55xx support provides an example of how to do all this at the DP level rather than AP, as a true DP prepare function.

NB: Platforms are, in the context of BMD, things on which the firmware can run, not debug targets. It would be a target-specific command, not a platform command.

@zyp
Copy link
Contributor

zyp commented Dec 26, 2024

I think you might be overthinking the problem, handling CTRL-AP ERASEALL the same way as it already is in nRF52 and nRF54L should be sufficient.

The typical workflow when you encounter a locked target is like this:

  • First you do a mon swd_scan that only returns e.g. Nordic nRF53 Access Port (protected).
  • To unlock the target, you run attach 1, mon erase_mass, detach.
  • Then you do a new mon swd_scan which now returns both CPUs in addition to the access port, and now you can attach and debug like usual.

@canatella
Copy link

@dragonmux , @zyp: It just feels a bit convoluted in regards to other tools. The Nordic tools, you just pass a flag and it does its thing. Same for probe-rs.

What I did as a prototype for now is to define a custom command mon recover enable which just sets a static global variable to true in the target code. And when probing, if this variable is true, I just first check for the protection and run the erase all operation to restore access if needed. It feels a bit more user friendly. As a developer I can just set that in my .gdbinit and forget about it. It's simpler and easier to script then having to scan, notice that it's protected, run the mass erase command and rescan.

But I don't want to change things for the sake of it neither. If you think the fake target is more inline with the bmp workflow, I can do that.

On the other hand, if you do feel that the global command could make the workflow easier, I'm willing to do the work, add a bit of infrastructure code so that it can be used in other targets and update the other nrf target to work like this, I still have some nrf52 boards somewhere.

@dragonmux
Copy link
Member

There are a couple of considerations at play here - first, other tools tend to be desktop-only programs while BMD runs as firmware first and foremost with a strict Flash constraint (128kiB for BMP); so many decisions about how things work are done to take that into account. Second is that because BMD is generally run as firmware and set-and-forget, being disconnected from and connected to new targets constantly without restart, any global state must be unsurprising in nature.

We'd strongly suggest that a global that when run against a protected part just obliterates w/e was in Flash is extremely surprising, especially if, say, you set that global a week ago, forgot, and then went on to scan a part which you were wanting to do forensics on or otherwise analyse - you'd have just shot your foot clean off because of some global state which the probe will retain.

This kind of thing is why it's done with a faked target so you have to consciously make the decision to erase everything. This is why other targets supported have commands to "enable dangerous commands" and such. Note that, in the flow where instead of having to mon erase_mass just connecting to the target erases, you would only need to scan, connect, scan, connect - the second time through would be with the erased part.

Essentially what we're saying is that the philosophy is that any time you would do something destructive, it must be a conscious decision to avoid accidental damage, particularly if the user is doing exploratory stuff such as for failure analysis. This is the only counter we have to the very long runtimes probes see in the wild between restarts. All probe-side settings are essentially sticky.

@canatella
Copy link

The implementation of the custom command probably doesn't use more memory than the fake target code. And for the long running scenario, you are right, it shouldn't create any surprise, but then resetting the variable after each use would do just that. But I don't really care, it's basically the same thing anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
New Target New debug target
Projects
None yet
Development

No branches or pull requests

4 participants