Open j4cbo opened 2 years ago
Hi @j4cbo, yeah, that's a tricky one without a completely right answer. I think it depends on what you're debugging—ultimately it's something you need to configure. In almost all cases in my experience, the debugger by default reads and writes the actual memory contents, ignoring any cache. Also, the various MEM-APs all reset to HPROT == 0x3 (data access, privileged, nothing else enabled).
In pyocd you can control the HPROT value for memory transactions using the set hprot x
command, and show hprot
to view the current setting. These modify/view the currently selected MEM-AP (set/show mem-ap
), which is independent of the gdbserver's core (not something to worry about if you are only debugging core #0).
To enable cacheable transfers from gdb, you'd run monitor set hprot 0xb
. This can be placed in a connect script if you want cacheable transfers all the time.
I've not heard of a debugger that reads MPU settings and applies them to its own transfers (but I could certainly have missed such a feature!); that's not something the hardware supports automatically. That would be a pretty neat feature, though. But I'm not even sure it would be something that should be enabled by default.
How would such a connect script look like? I have quite a few issues finding the right APIs I'd need to call in pyOCD.
If you're using gdb, you don't need to directly use the pyOCD APIs. Just use the monitor set hprot 0xb
gdb command immediately after gdb connects to pyocd. I'd set this up in config for whatever debugger you're using. For instance, using cortex-debug in VSCode, add it to postAttachCommands
. You can use monitor show hprot
to verify the settings.
If you want to avoid doing this through gdb commands for whatever reason, you can create a user script with containing this snippet:
def did_connect():
target.aps[0].hprot = 0xb
And if using pyOCD via a Python script, mirror the statement inside did_connect()
above using your target object.
Please note that although I've tested that the above commands work and correctly set HPROT, I don't have an easy way to really verify that the D$ contents are being read rather than raw memory contents. No reason to believe it shouldn't work though, at least on Cortex-M7 based devices using the core's built-in D$.
For reference, here are the HPROT bits for Cortex-M devices (show hprot
will also display something like this). Not all bits are implemented on all core/MEM-AP variants; each MEM-AP version implements slightly different sets of these options. For instance, the standard CM3 and CM4 MEM-AP only implements HPROT[1] (privilege, user).
HPROT[0] = 1 data access, 0 instr fetch
HPROT[1] = 1 privilege, 0 user
HPROT[2] = 1 bufferable, 0 non bufferable
HPROT[3] = 1 cacheable/modifable, 0 non cacheable
HPROT[4] = 1 lookup in cache, 0 no cache
HPROT[5] = 1 allocate in cache, 0 no allocate in cache
HPROT[6] = 1 shareable, 0 non shareable
In the above commands, 0xb == data (hprot[0]) | privileged (hprot[1]) | cacheable (hprot[3]).
It appears that when I perform a memory read [edit: on a Cortex-M7, STM32H750] through gdb and
pyocd gdb
, what I get is the actual contents of the backing SRAM, not the view as seen by the CPU - which means that if the D-cache is enabled and I'm reading something in cacheable memory that hasn't been cleaned from the cache, I won't get the right results. This leads to some confusing behavior:Once again I'm not sure what the right fix here is. :( It looks like the AHB-AP allows setting e.g.
HPROT_CACHEABLE
, but it seems like what we actually want forgdb
is to use whichever cacheability settings the CPU would apply, as configured through the MPU if applicable, right?