Cortex-M initial PC LSB must be 0
Market leading real time kernel for 40+ microcontroller architectures
Brought to you by:
gaurav-aws,
rtel
According to the ARM documentation:
Since the instructions must be aligned to half-word or word addresses, the Least Significant Bit (LSB) of the PC is zero. However, when using some of the branch/ memory read instructions to update the PC, you need to set the LSB of the new PC value to 1 to indicate the Thumb state.
Most actual hardware seem to autocorrect this error, but very strict emulators issue a message, for example QEMU reports:
M profile return from interrupt with misaligned PC is UNPREDICTABLE
To fix this, in pxPortInitialiseStack()
you need to mask out the LSB when you create the stack frame used to start a task:
*pxTopOfStack = ((StackType_t) (pxCode)) & (~1); /* PC with LSB=0 */
Regards,
Liviu
Here is a link to the fix I used in my fork. Later I added a similar one for M0.
https://github.com/xpacks/freertos/commit/9fe142e6236ecdac8acee6eb537cc633581d3d69
I have just tried this with the ARM compiler (which is only one of the
too many ARM compilers we support), and the address is passed in to
pxPortInitialiseStack() with the LSB set already - which I think is as
expected. It may be that other compilers don't do that....I would have
to say though - is this really a FreeRTOS bug? We generally have a
policy of creating code for real hardware, and not changing code
specifically for use on emulators, and on real hardware THUMB2 is the
only option for Cortex-M. The old ARM7 ports (ARMv4 architecture) used
to set or clear the LSB explicitly, but the Cortex-M (ARMv7M) ports don't.
Appologies if this appears twice - I don't know what happened to the first post. I originally wrote:
"I have just tried this with the ARM compiler (which is only one of the too many ARM compilers we support), and the address is passed in to pxPortInitialiseStack() with the LSB set already - which I think is as expected. It may be that other compilers don't do that....I would have to say though - is this really a FreeRTOS bug? We generally have a policy of creating code for real hardware, and not changing code specifically for use on emulators, and on real hardware THUMB2 is the only option for Cortex-M. The old ARM7 ports (ARMv4 architecture) used to set or clear the LSB explicitly, but the Cortex-M (ARMv7M) ports don't."
...but now after re-reading your original report thing I misunderstood.
As far as I know the LSB should be set, and the quote from the ARM documentation seems to agree, but your suggested patch seems to clear the LSB. Can you elaborate further?
only "when using some of the branch/ memory read instructions to update the PC, you need to set the LSB", otherwise it should be 0, as for any half-word/word address, and the first part of the statement clearly says so.
to check this, halt to a breakpoint in a handler routine and check the PC, it has the LSB=0.
Last edit: Liviu Ionescu (ilg) 2016-04-05
The PC value in question is only ever loaded into the PC on returning from an interrupt using a bx lr instruction to load an EXC_RETURN value. Looking specifically at that use case in the documentation I read:
"loading an unaligned value from the stack into the PC on an exception return is UNPREDICTABLE."
so it seems you are indeed correct, technically at least. I don't think there are any actual Cortex-M implementations (actual processors) that this is really a problem for, but it does seem to be out of spec, so should be changed in case anythign in the future does have an issue with it.
that's exactly what QEMU is complaining.
the policy of creating code for real hardware is fine, but emulators are still valuable tools, they can spot bugs that otherwise would slip undetected on some implementations and misteriously fail on others.
I did all my testing for CMSIS++ RTOS API running on top of the FreeRTOS scheduler using QEMU, and everything was fine, the Keil CMSIS RTOS validator passed hapilly, just that QEMU issued one error line for each new thread started, which were lots of messages.
after fixing the FreeRTOS code locally, the QEMU errors vanished completely. and, to be sure, I ran the tests on a STM32F407DISCOVERY, and everything is fine :-)
as a side note, this is only the second time I used real hardware for my tests, the other time was when the validator passed for the very first time, to be sure everything is ok.
if you did not use QEMU yet, I highly recommend it for day to day RTOS tests, it is quite accurate and very convenient (I mean the GNU ARM Eclipse QEMU, the original one does not work properly for Cortex-M).
regards,
Liviu
for reference:
http://gnuarmeclipse.github.io/qemu/
a test project that runs nicely on the emulated STM32F407DISCOVERY board, blinking the animated lefs, is presented here:
http://gnuarmeclipse.github.io/tutorials/blinky-arm/