Menu

#126 Cortex-M initial PC LSB must be 0

v1.0 (example)
closed-fixed
Richard
None
5
2016-04-05
2016-04-05
No

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

Discussion

  • Liviu Ionescu (ilg)

    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

     
    • Richard Barry

      Richard Barry - 2016-04-05

      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.

       
  • Richard Barry

    Richard Barry - 2016-04-05

    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?

     
  • Liviu Ionescu (ilg)

    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
  • Richard Barry

    Richard Barry - 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.

     
  • Richard Barry

    Richard Barry - 2016-04-05
    • status: open --> closed-fixed
     
  • Liviu Ionescu (ilg)

    "loading an unaligned value from the stack into the PC on an exception return is UNPREDICTABLE."

    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

     

Log in to post a comment.