0
\$\begingroup\$

I am developing a commercial design on STM32 and am considering porting it to MAX32660 (another ARM MCU) due to the smaller footprint and lower cost for devices having 64KB+ RAM. However, the MAX32660 datasheet does not describe a code readout protection feature. Is there a way to prevent code readout on the MAX32660?

My minimum requirements are:

  • Prevent reading the flash memory from SWDIO or JTAG.
  • Even when the flash is protected, it must still be possible for custom bootloader code on the MAX32660 to overwrite regions of flash, without disturbing the custom bootloader code or the protection of all flash.

Does this feature exist somewhere? Is it documented?

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Have you asked Maxim? What did they say? \$\endgroup\$ Commented Jun 17, 2020 at 1:01
  • \$\begingroup\$ I forgot what the terminology was but there are some preventative measures to make sure no one is able read your code by using fuses to disconnect itself from the chip. Once you upload the code onto the chip, you could then deliberately blow the fuses to prevent any access to the chip. \$\endgroup\$
    – user103380
    Commented Jun 17, 2020 at 1:53
  • \$\begingroup\$ Please contact Maxim Integrated Tech Support. From what I can see publicly there are a lot of security features in the MAX326XX family, of which MAX32660 has the least features (Memory Protection Unit and Secure Boot ROM), but off the top of my head I don't understand exactly what those two features mean. I know most of the people at Maxim HQ Tech Support and several in the Microcontroller group, but I don't have a direct way to forward messages from stackexchange into Maxim's support database. \$\endgroup\$
    – MarkU
    Commented Jun 17, 2020 at 1:56

1 Answer 1

3
\$\begingroup\$

In case of MAX32660 it is not publicly documented, but in case of recently introduced MAX32690 It is documented in user guide (document UG7618; Rev 1) in section Debug Access Port (DAP). Later I googled some magic numbers from the provided algorithm and found that the algorithm is also documented for MAX32665/666 microcontrollers in user guide (document UG6971; Rev 3). Interestingly MCUs use slightly different magic constants and in case of MAX32690 there is also mistake becase Maxim attached wrong diagram. I tried to port algorithm to MAX32660 and it seems that works.

TLDR: Executing following code will lock MAX32660 (and MAX32690):

MXC_FLC0->ctrl = 0x20000000;

// magic values for unlocking FIB
MXC_FLC0->actrl = 0x3a7f5ca3;
MXC_FLC0->actrl = 0xa1e34f20;
MXC_FLC0->actrl = 0x9608b2c1;

// write address
MXC_FLC0->addr = 0x00040030;

// magic values to write (differs per lock/unlock/permlock) operations
MXC_FLC0->data[0] = 0x5A5AA5A5;
MXC_FLC0->data[1] = 0xDA5AA5A5;
MXC_FLC0->data[2] = 0xFFFFFFFF;
MXC_FLC0->data[3] = 0xFFFFFFFF;

MXC_FLC0->ctrl = 0x20000001;
while (MXC_FLC0->ctrl & MXC_F_FLC_CTRL_BUSY) {
    // nop
}
MXC_FLC0->ctrl = 0;
MXC_FLC0->actrl = 0;

MCU locked in this way is single-time unlockable. Maxim MCU has two types of lock:

  • Single-time unlockable: You can lock it onece, then unlock it once and then you can't use it anymore (at least documentation says that)
  • Permanent lock: You can lock it once and then you can't unlock it anymore.

Locking basicaly works by writing to the one-time programmable area referred to as Flash Information Block (FIB). These area si documented and part of it is user-writable (see examples in MSDK: msdk/Examples/MAX32660/Info_Block_Usecase), but locks are in the Maxim-reserved area. In the same area there is unique id which is partially documented even in case of MAX32660 in user guide (document UG6659; Rev 1) in section Information Block Flash Memory.

In most Maxim MCUs FIB begins at address 0x10800000, but in case of MAX32660 it is at 0x00040000. Lock bits begins at offset 0x30. Documentation says that they are one-time programmable bits but practical experiments show that there is more complex logic and basically you can't write any value to them. It seems that invalid write attempts are ignored. Bits are readable after unlocking memory by magic (but documented) constants 0x3a7f5ca3, 0xa1e34f20, 0x9608b2c1. Interestingly magic values which are written to the FIB when locking MCU differs per MCU or at least documentation says that. Magic codes written to the FIB according MCU public documentation are following:

MAX32690:
- Single-time unlockable lock:   0x5A5AA5A5 0x5A5AA5A5 0xFFFFFFFF 0xFFFFFFFF !!!!
- Single-time unlockable unlock: 0x00000000 0xFFFFFFFF 0xFFFFFFFF 0x00000000
- Permanent lock:                0x5A5AA5A5 0x5A5AA5A5 0xFFFFFFFF 0xFFFFFFFF

MAX32665/666:
- Single-time unlockable lock:   0x5A5AA5A5 0x5A5AA5A5 0x5A5AA5A5 0xDA5AA5A5
- Single-time unlockable unlock: 0x00000000 0x00000000 0x00000000 0x00000000
- Permanent lock:                0x5A5AA5A5 0x5A5AA5A5 0x5A5AA5A5 0x5A5AA5A5

Note that values according to MAX32690 documentation codes for single-time unlockable and permanent lock are the same. This is mistake confirmed by Maxim Tech Support and in case of single-time unlockable lock second value should be 0xDA5AA5A5 instead of 0x5A5AA5A5.

I originally tried to lock MAX32660 using MAX32690 approach (which I found first), but it seems that more correct is MAX32665/666 approach. I made testing firmware which allows me to trigger lock procedures over UART and also allows me to execute memory operations. I locked it by writing 0x5A5AA5A5 0x5A5AA5A5 0xFFFFFFFF 0xFFFFFFFF and after power cycling I really lost access to debug port.

MAX32660 Locking

Then I tried it unlock it by MAX32690 procedure but it was unsuccessful. I tried writing 0x00000000 0xFFFFFFFF 0xFFFFFFFF 0x00000000 and interestingly some bytes changed, but not the written value and MCU remained locked. The new value in lock bits was 0x00000000 0xDA5AA5A5 0xFFFFFFFF 0x00000000 which is different value then I wrote to it, and it is also different value to value which was there at the beginning of this step.

MAX32660 Unsuccessfull Unlocking

So I tried unlocking procedure from different MCU. I tried writing all zeroes as MAX32665/666 documentation says, but because my MCU was locked I had to do it manually

MAX32660 Successfull Unlocking

and surprisingly MAX32660 unlocked. Permanent lock I did not tested. But it seems that procedure form MAX32665/666 is correct and may work with MAX32660 also.

References:

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.