[RTD400HF01 LLD]K312 No HSE secure debug operation

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

[RTD400HF01 LLD]K312 No HSE secure debug operation

[RTD400HF01 LLD]K312 No HSE secure debug operation

[RTD400HF01 LLD]K312 No HSE secure debug operation

1. Abstract

The S32K3 chip has rich encryption functions. For encryption, an independent arm core is even allocated for HSE. HSE firmware needs to be installed separately. For the encryption debug interface, there are usually two ways:

  • Install HSE firmware to do static or dynamic secure
  • Do static secure without installing HSE firmware

The default chip does not install HSE firmware. In order to verify the secure debug, this article will use the RTD400HF01 version on the K312 chip to do static secure debug interface without installing HSE firmware. Other K3 chips are similar.

The outline of this article is as follows:

kerryzhou_0-1737288632768.png

 Fig 1

2. Hardware prepare

For the hardware, you can use any K3 board, such as the K312-EVB development board, or a self-developed board. In order to facilitate chip replacement in this article, an evaluation board with a socket is used:

 

kerryzhou_1-1737288644761.png

 Fig 2

If need to configure to the K312, the board jumper need to do the following configuration:

J92:2-3,J28:2-3 ,J64:2-3  ,J114:2-3,J71:2-3  ,J118:2-3,J57:2-3 ,J72:2-3 ,J99:2-3

3. Secure debug interface

3.1 flash code prepare

    The flash controller of K3 is a PFLASH module. The chip comes with c40asf flash memory. Different K3 chips have different flash sizes and block numbers. Since the flash in the chip cannot implement the RWW function, when doing flash operations, you need to consider RWW and copy the flash operation code to the internal RAM for execution.

    This article will take the LLD routine C40_Ip_Example routine of the RTD400HF01 version as the starting point. Since the RTD400HF01 version does not directly come with the K312 example, you first need to create a new K312 project, and then configure the LLD configuration by yourself. You can refer to the relevant LLD configuration of K344, but you need to pay attention to the clock situation to meet the requirements of K312. This article uses the option B clock mode, the clock is 120Mhz.

The most feasible way to verify the code for successful flash operation is to be able to operate the flash area and the code area in one block. Of course, it is necessary to pay attention to the flash sector and app code to be erased and written. Do not overlap. This can be checked according to the map file. For example:

#define EXAMPLE_SECTOR_START_ADDR       (0x004FE000)

#define EXAMPLE_SECTOR_TEST             (C40_CODE_ARRAY_0_BLOCK_0_S127)

 

kerryzhou_2-1737288663348.png

 Fig 3

   Usually, in order to consider a larger margin, you can directly exceed the maximum hex value compiled, and then take the last sector of the current block to ensure that this address and the compiled size do not overlap in sectors.

    For flash operations considering RWW, there are two methods for RTD500/RTD400. One thing is that it is not enough to just put the Flash operation code into RAM. Here are two methods that can be run, both of which have been tested and can work stably:

3.1.1 flash code copy to RAM and wait the controller is idle

This requires two steps: first put the C40_Ip.c, C40_Ip.h related flash operation code into RAM, then wait for the flash controller to be idle before doing other operations.

(1) Open C40_Ip.c in the RTD/src folder

Two places need to be modified:

Modify the start of the file:     

         #define MEM_43_INFLS_START_SEC_CODE

  to:

        #define MEM_43_INFLS_START_SEC_RAMCODE

  

Modify the file ending area:

    #define MEM_43_INFLS_STOP_SEC_CODE

To :

    #define MEM_43_INFLS_STOP_SEC_RAMCODE

(2)Open C40_Ip.h in the RTD/include folder

Two places need to be modified:

Modify the beginning of the file:

         #define MEM_43_INFLS_START_SEC_CODE

  To :

        #define MEM_43_INFLS_START_SEC_RAMCODE

  

Modify the file ending area:

    #define MEM_43_INFLS_STOP_SEC_CODE

To :

    #define MEM_43_INFLS_STOP_SEC_RAMCODE

The purpose of doing this is to put all the functions in C40_Ip into RAM. After compiling, check the ramcode area in the map file:

kerryzhou_3-1737288680731.png

 Fig 4

As you can see, after the above modification, all relevant C40 functions have been put into the internal RAM.

But please note that if you only do this and directly operate the flash, especially when erasing block0, hard fault will occur. You also need to wait for the FLASH controller to be idle.

Add a code to wait for the FLASH controller to be idle in main, and also put it in RAM. After operating the flash erase or write, call the function that waits for the FLASH controller to be idle. Before operating the flash code, you also need to call :

C40_Ip_SetAsyncMode(FALSE);

Refer to the following code:

#define MEM_43_INFLS_START_SEC_RAMCODE
#include "Mem_43_INFLS_MemMap.h"
void MemInfls_AccessCodeLoadToRam(void);

#define MEM_43_INFLS_STOP_SEC_RAMCODE
#include "Mem_43_INFLS_MemMap.h"
#define MEM_43_INFLS_START_SEC_RAMCODE
#include "Mem_43_INFLS_MemMap.h"
/* @violates @ref fls_flash_c_REF_20 Object/function previously declared */
void MemInfls_AccessCodeLoadToRam(void)
{
#if (C40_IP_TIMEOUT_SUPERVISION_ENABLED == STD_ON)
    uint32 ValueTimeOut = C40_Ip_u32TimeoutTicks;
    uint32 WaitedTicks;
#endif

    /* Start internal erase/program sequence */
    C40_Ip_pFlashBaseAddress->MCR |= FLASH_MCR_EHV_MASK;

    /* Wait until operation finishes or write/erase timeout is reached */
    while (0U == (C40_Ip_pFlashBaseAddress->MCRS & FLASH_MCRS_DONE_MASK))
    {
#if (C40_IP_TIMEOUT_SUPERVISION_ENABLED == STD_ON)
        ValueTimeOut--;
        if (0U == ValueTimeOut)
        {
            break;
        }
#endif
    }

    /* Disable HV to finalize/abort the operation */
    C40_Ip_pFlashBaseAddress->MCR &= ~FLASH_MCR_EHV_MASK;

    /* Wait until done or abort timeout is reached */
    while (0U == (C40_Ip_pFlashBaseAddress->MCRS & FLASH_MCRS_DONE_MASK))
    {
#if (C40_IP_TIMEOUT_SUPERVISION_ENABLED == STD_ON)
        ValueTimeOut--;
        if (0U == ValueTimeOut)
        {
            break;
        }
#endif
    }

#if (C40_IP_TIMEOUT_SUPERVISION_ENABLED == STD_ON)
    /* Update the timeout counter */
    WaitedTicks = C40_Ip_u32TimeoutTicks - ValueTimeOut;
    C40_Ip_u32ElapsedTicks += WaitedTicks;
    C40_Ip_u32CurrentTicks += WaitedTicks;
#endif
}

#define MEM_43_INFLS_STOP_SEC_RAMCODE
#include "Mem_43_INFLS_MemMap.h"

 

 Main code related erase and program is:

#define EXAMPLE_SECTOR_START_ADDR       (0x004FE000)
#define EXAMPLE_SECTOR_TEST              (C40_CODE_ARRAY_0_BLOCK_0_S127)

   C40_Ip_SetAsyncMode(FALSE);
    t_SectorAddr = EXAMPLE_SECTOR_START_ADDR;
    t_SectorNumber = EXAMPLE_SECTOR_TEST;
    /* Unlock sector */
    if (C40_IP_STATUS_SECTOR_PROTECTED == C40_Ip_GetLock(t_SectorNumber))
    {
        C40_Ip_ClearLock(t_SectorNumber, EXAMPLE_MASTER_ID);
    }
    /* Erase sector */
    C40_Ip_MainInterfaceSectorErase(t_SectorNumber, EXAMPLE_MASTER_ID);
    MemInfls_AccessCodeLoadToRam();
    do
    {
        t_ReturnValue = C40_Ip_MainInterfaceSectorEraseStatus();
    }
    while (C40_IP_STATUS_BUSY == t_ReturnValue);
    Example_CheckAssert(t_ReturnValue == C40_IP_STATUS_SUCCESS);

    /* Write data */
    C40_Ip_MainInterfaceWrite(t_SectorAddr, t_BufferSize, TxBuffer, EXAMPLE_MASTER_ID);
    MemInfls_AccessCodeLoadToRam();
    do
    {
        t_ReturnValue = C40_Ip_MainInterfaceWriteStatus();
    }
    while (C40_IP_STATUS_BUSY == t_ReturnValue);
    Example_CheckAssert(t_ReturnValue == C40_IP_STATUS_SUCCESS);

Compile the code, burn the code and test the results as follows:

kerryzhou_4-1737288697242.png

 Fig 5

kerryzhou_5-1737288702884.png

 Fig 6

 

kerryzhou_6-1737288707772.png

 Fig 7

 

3.1.2 link modify the file to RAM

    The above method requires more changes, and special waiting code needs to be added. Here is another method, which can directly modify the link file to directly drop all related .o files into RAM at once, and then for the user program, the RTD driver does not need to modify or add additional code.

Open the project Project_Settings->Linker_Files->linker_flash_s32k312.ld

Two points need to be modified:

(1)  .pflash Modify the following code:

 

    .pflash :
    {
        KEEP(*(.boot_header))
        . = ALIGN(8192);  /* The minimum erase size of C40 Flash IP is 8kb */
        __text_start = .;
        __interrupts_init_start = .;
        KEEP(*(.intc_vector))
        . = ALIGN(4);
        __interrupts_init_end = .;
        KEEP(*(.core_loop))
        . = ALIGN(4);
        *(.startup)
        . = ALIGN(4);
        *(.systeminit)
        . = ALIGN(4);
        *(.text.startup)
        . = ALIGN(4);
        *(EXCLUDE_FILE (*C40_Ip.o *OsIf_Timer.o *OsIf_Timer_System.o) .text)
        *(EXCLUDE_FILE (*C40_Ip.o *OsIf_Timer.o *OsIf_Timer_System.o) .text*)
        . = ALIGN(4);
        *(EXCLUDE_FILE (*C40_Ip.o *OsIf_Timer.o *OsIf_Timer_System.o) .mcal_text)
        . = ALIGN(4);
        *(.acmcu_code_rom)
        . = ALIGN(4);
        __acfls_code_rom_start = .;
        *(.acfls_code_rom)
        . = ALIGN(4);
        __acfls_code_rom_end = .;
        __acmem_43_infls_code_rom_start = .;
        *(.acmem_43_infls_code_rom)
        . = ALIGN(4);
        __acmem_43_infls_code_rom_end = .;
        KEEP(*(.init))
        . = ALIGN(4);
        KEEP(*(.fini))
        . = ALIGN(4);
        *(.rodata)
        *(.rodata*)
        . = ALIGN(4);
        *(.mcal_const_cfg)
        . = ALIGN(4);
        *(.mcal_const)
        . = ALIGN(4);
        __init_table = .;
        KEEP(*(.init_table))
        . = ALIGN(4);
        __zero_table = .;
        KEEP(*(.zero_table))
    } > int_pflash

(2).pflash section add the following code

   .itcm_text : AT(__tcm_code_rom_start)
    {
        . = ALIGN(4);
        __itcm_start__ = .;
        *(.itcm_text*)
        . = ALIGN(4);
        KEEP(*C40_Ip.o (.mcal_text*))
        KEEP(*C40_Ip.o (.text*))
        KEEP(*C40_Ip.o (.text))
        KEEP(*OsIf_Timer.o (.mcal_text*))
        KEEP(*OsIf_Timer.o (.text*))
        KEEP(*OsIf_Timer.o (.text))
        KEEP(*OsIf_Timer_System.o (.mcal_text*))
        KEEP(*OsIf_Timer_System.o (.text*))
        KEEP(*OsIf_Timer_System.o (.text))
        . = ALIGN(4);
        __itcm_end__ = .;
    } > int_itcm

From here, we can see that in fact, not only the C40 code needs to be copied to RAM, but also the OsIf_Timer and OsIf_Timer_System related codes need to be put into RAM.

The test results are the same as those in Figure 5.6.7, and the erase and write actions of the corresponding block0 flash sector can be realized.

3.2  burn key to UTEST 0X1B000080

For secure debug, there are two static key addresses in the UTEST area: 0X1B000080, 0X1B000370.

0X1B000370 is the static encryption key address for use after the HSE firmware is installed. 0X1B000080 is the static encryption key address without HSE firmware.

kerryzhou_7-1737288737117.png

 Fig 8

So the following operation needs to be performed to burn the key to the address of UTEST 0X1B000080. After the above flash preparation, it is very clear to burn the key, but there is no need to erase it. When it is determined that the key address is not all 0XFF, the key operation can be performed directly. The code is as follows:

Generate->include->C40_Ip_Cfg.h

#define C40_IP_MAX_VIRTUAL_SECTOR              (272U)//(271U)

If this is not modified, it will get stuck when executing sector C40_Ip_GetLock.

#define C40_UTEST_ARRAY_0_S000              (272U)    /* 0x1B000000 */
#define FLS_SECTOR_ADDR              0x1B000080U
#define FLS_SECTOR_TEST              C40_UTEST_ARRAY_0_S000
uint8 ADKP_Buffer[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
					   0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15};
    if( (IP_DCM->DCMLCC & 0x77) == 0x33 ) // check LC is CUST_DEL or not
    {
#if 1
    //read the UTEST password data, if 0XFF, write.
    /* Read data */
    t_SectorAddr = FLS_SECTOR_ADDR;
    t_SectorNumber = FLS_SECTOR_TEST;

    t_ReturnValue = C40_Ip_Read(t_SectorAddr, 16, RxBuffer);
    Example_CheckAssert(t_ReturnValue == C40_IP_STATUS_SUCCESS);

    KeyEmptyFlag = 1;
    for(uint32_t i=0; i<16; i++)
    {
    	if(RxBuffer[i] != 0XFF)
    	{
    		KeyEmptyFlag = 0;
    		break;
    	}
    }

    //write ADKP to UTEST, just write once!
    if(KeyEmptyFlag == 1)
    {
        /* Unlock sector */
        if (C40_IP_STATUS_SECTOR_PROTECTED == C40_Ip_GetLock(t_SectorNumber))
        {
            C40_Ip_ClearLock(t_SectorNumber, FLS_MASTER_ID);
        }
        /* Write data */
    	C40_Ip_MainInterfaceWrite(FLS_SECTOR_ADDR, 16, ADKP_Buffer, FLS_MASTER_ID);
    	MemInfls_AccessCodeLoadToRam();//kerry
        do
        {
            t_ReturnValue = C40_Ip_MainInterfaceWriteStatus();
        }
        while (C40_IP_STATUS_BUSY == t_ReturnValue);
        Example_CheckAssert(t_ReturnValue == C40_IP_STATUS_SUCCESS);

        //Power_Ip_PerformReset(&Power_Ip_HwIPsConfigPB);
    }

#endif

Test conditions before Key burning:

kerryzhou_8-1737288749563.png

 Fig 9

Test results after Key burning:

kerryzhou_9-1737288753714.png

 Fig 10

It can be seen that key: HEX 00010203040506070809101112131415 is successfully burned into the UTEST 0X1B000080 area.

3.3 Program IVT lifecyle related flash area

To really make secure debug work, the lifecycle needs to be evolved to non-CUST_DEL and FA. This article tests the evolution of LC to the IN_FIELD stage:

LCW = 0xDADADADA advances LC to OEM_PROD

LCW = 0xBABABABA advances LC to IN_FIELD

The address corresponding to LC (lifecyle) is the offset 0X24 of IVT, and must be 4-byte aligned. You can specify the address of IVT->LC to a flash area, and then burn the corresponding flash value to the IN_FIELD value: 0xBABABABA

Evolution method:

(1) Set the flash address of IVT LC

(2) Write the IN_FIELD value 0xBABABABA to the corresponding flash address

(3) Software reset

After evolution, you can also check whether the evolution is successful by checking the LC slot combination starting from address 0X1B000220 in the UTEST area. Of course, after the evolution is successful, the debug interface will also be locked, which can be unlocked to view. In addition, you can also view the evolved LC results through the DCM_DCMLCC register.

kerryzhou_10-1737288769128.png

 Fig 11

Here are the relevant codes:

(1)Project_Settings->Startup_Code->startup_cm7.s

#define LF_CONFIG_ADDR              (0x00500000U)/*(0)*/
.section ".boot_header","ax"
/*00h*/     .long SBAF_BOOT_MARKER /* IVT marker */
/*04h*/     .long (CM7_0_ENABLE << CM7_0_ENABLE_SHIFT) | (CM7_1_ENABLE << CM7_1_ENABLE_SHIFT) | (CM7_2_ENABLE << CM7_2_ENABLE_SHIFT) /* Boot configuration word */
/*08h*/     .long 0 /* Reserved */
/*0Ch*/     .long CM7_0_VTOR_ADDR /* CM7_0 Start address */
/*10h*/     .long 0 /* Reserved */
/*14h*/     .long CM7_1_VTOR_ADDR /* CM7_1 Start address */
/*18h*/     .long 0 /* Reserved */
/*1Ch*/     .long CM7_2_VTOR_ADDR /* CM7_2 Start address */
/*20h*/     .long 0 /* Reserved */
/*  .long XRDC_CONFIG_ADDR*/ /* XRDC configuration pointer */
/*24h*/     .long LF_CONFIG_ADDR /* Lifecycle configuration pointer */
/*28h*/     .long 0 /* Reserved */

It can be seen that the flash address specified by IVT offset 0X24 is 0X00500000

(2) Add flash0X00500000 area and write code

#define FLS_SECTOR_ADDR_LC			 (0x00500000U)
#define FLS_SECTOR_ADDR_LC_TEST      (C40_CODE_ARRAY_0_BLOCK_1_S128) 
   uint8 lcwValue[8] = {0xBA,0xBA,0xBA,0xBA,0x00,0x00,0x00,0x00};
    t_SectorAddr = FLS_SECTOR_ADDR_LC;
t_SectorNumber = FLS_SECTOR_ADDR_LC_TEST;
 
   t_ReturnValue = C40_Ip_Read(t_SectorAddr, 16, RxBuffer);
    Example_CheckAssert(t_ReturnValue == C40_IP_STATUS_SUCCESS);

    LCEmptyFlag = 1;
    for(uint32_t i=0; i<16; i++)
    {
    	if(RxBuffer[i] != 0XFF)
    	{
    		LCEmptyFlag = 0;
    		break;
    	}
    }

    //write LC, just write once!
    if(LCEmptyFlag == 1)
    {
        if (C40_IP_STATUS_SECTOR_PROTECTED == C40_Ip_GetLock(t_SectorNumber))
        {
            C40_Ip_ClearLock(t_SectorNumber, EXAMPLE_MASTER_ID);
        }
        /* Write data */
    	C40_Ip_MainInterfaceWrite(t_SectorAddr, 8, lcwValue, FLS_MASTER_ID);//IN FIELD
    	MemInfls_AccessCodeLoadToRam();//kerry
        do
        {
            t_ReturnValue = C40_Ip_MainInterfaceWriteStatus();
        }
        while (C40_IP_STATUS_BUSY == t_ReturnValue);
        Example_CheckAssert(t_ReturnValue == C40_IP_STATUS_SUCCESS);
        Power_Ip_PerformReset(&Power_Ip_HwIPsConfigPB);
    }

Of course, it should be noted here that if the corresponding flash address has been written with other values, you must first perform an erase operation before writing, or erase the entire chip once before downloading the code.

The test results are as follows:

Before LC evolution:

The 16 bytes of 0X1B000220 are the location of LC slot1. It can be seen that LC slot1 CUST_DEL corresponds to the Active state: that is, the lower 64 bits are Marked, and the upper 64 bytes are Erased

Mared: 0X55AA_50AF_55AA_50AF

Erased: 0XFFFF_FFFF_FFFF_FFFF

The other LC slot2, LC slot3, LC slot4, LC slot5 are all Erased. Figure 8 and Figure 11 can help understand.

kerryzhou_11-1737288785607.png

 Fig 12

IVT LC  related flash 0X00500000 data result:

kerryzhou_12-1737288789022.png

 Fig 13

3.4 SW reset

The software reset code is as follows:

Power_Ip_PerformReset(&Power_Ip_HwIPsConfigPB);

After the software reset, you can see the PE Multilink connection results as follows:

kerryzhou_13-1737288807077.png

 Fig 14

The results of JLINK locking are as follows:

kerryzhou_14-1737288811935.png

 Fig 15

The results of the Lauterbach lock are as follows:

kerryzhou_15-1737288817213.png

 Fig 16

So far, the K312 debug interface has been encrypted. The following will explain how to decrypt it.

4. unlock debug interface

4.1 PE Multilink unlock

For PE Multilink, the decryption link has been given from the encryption. You can refer to the following link of the PE official website:

https://www.pemicro.com/blog/index.cfm?post_id=216

 for detailed tutorials. You need to download the python script: http://www.pemicro.com/downloads/download_file.cfm?download_id=450

 then unzip and open: \supportFiles_ARM\supportFiles_ARM\NXP\S32K3xx\ authenticate_password_mode.py

kerryzhou_16-1737288836919.png

 Fig17

Save the script, open the computer cmd command window, enter the script path, and enter:

python authenticate_password_mode.py

The decryption result is as follows:

kerryzhou_17-1737288842290.png

 Fig 18

As you can see, the decryption is complete. At this point, you can download a simple project to try, you can directly download the code and enter debug mode. Of course, if the power is turned off and then on again, you need to decrypt again.

In your new app project, please modify the device to the : S32K312-SECUREDEBUG, otherwise, if you just use the S32K312, it will always report the secure issues.

3.2 Lauterbach unlock

Prepare one .cmm file, then change the content to the following content:

Global &SDAP_AUTHSTTS
Global &SDAP_AUTHCTL
Global &SDAP_KEYCHAL_0
Global &SDAP_KEYCHAL_1
Global &SDAP_KEYCHAL_2
Global &SDAP_KEYCHAL_3
Global &SDAP_KEYCHAL_4
Global &SDAP_KEYCHAL_5
Global &SDAP_KEYCHAL_6
Global &SDAP_KEYCHAL_7
GLOBAL &UID0 &UID1
Global &SDAP_AUTHSTTS_Read
GLOBAL &CHAL0 &CHAL1 &CHAL2 &CHAL3 &CHAL4 &CHAL5 &CHAL6 &CHAL7

SYStem.CPU S32K312-M7
sys.mode prepare

&SDAP_BASE_ADDRESS=0x40000700
&SDAP_AUTHSTTS = &SDAP_BASE_ADDRESS
&SDAP_AUTHCTL  = &SDAP_BASE_ADDRESS+0x4

&SDAP_KEYCHAL_0 = &SDAP_BASE_ADDRESS+0x10
&SDAP_KEYCHAL_1 = &SDAP_BASE_ADDRESS+0x14
&SDAP_KEYCHAL_2 = &SDAP_BASE_ADDRESS+0x18
&SDAP_KEYCHAL_3 = &SDAP_BASE_ADDRESS+0x1C
&SDAP_KEYCHAL_4 = &SDAP_BASE_ADDRESS+0x20
&SDAP_KEYCHAL_5 = &SDAP_BASE_ADDRESS+0x24
&SDAP_KEYCHAL_6 = &SDAP_BASE_ADDRESS+0x28
&SDAP_KEYCHAL_7 = &SDAP_BASE_ADDRESS+0x2C

&SDAP_KEYRESP_0 = &SDAP_BASE_ADDRESS+0x40
&SDAP_KEYRESP_1 = &SDAP_BASE_ADDRESS+0x44
&SDAP_KEYRESP_2 = &SDAP_BASE_ADDRESS+0x48
&SDAP_KEYRESP_3 = &SDAP_BASE_ADDRESS+0x4C
&SDAP_KEYRESP_4 = &SDAP_BASE_ADDRESS+0x50
&SDAP_KEYRESP_5 = &SDAP_BASE_ADDRESS+0x54
&SDAP_KEYRESP_6 = &SDAP_BASE_ADDRESS+0x58
&SDAP_KEYRESP_7 = &SDAP_BASE_ADDRESS+0x5C

&SDAP_UID0 = &SDAP_BASE_ADDRESS+0x70
&SDAP_UID1 = &SDAP_BASE_ADDRESS+0x74

&SDAP_DBGENCTRL = &SDAP_BASE_ADDRESS+0x80
&SDAP_SDAAPRSTCTRL = &SDAP_BASE_ADDRESS+0x90
&SDAP_SDAAPGENCTRL0 = &SDAP_BASE_ADDRESS+0xA4
&SDAP_DAP_GEN1_CTRL = &SDAP_BASE_ADDRESS+0xB4

;prepare the key value
;sample adkp_value 5eba18b957523a0c10839b84c481f379
;need byte sway

&arg1 = 0x03020100
&arg2 = 0x07060504
&arg3 = 0x11100908
&arg4 = 0x15141312
&arg5 = 0x00000000
&arg6 = 0x00000000
&arg7 = 0x00000000
&arg8 = 0x00000000

;Enable SDAP Based Debug Authorization
data.set EDBG:&SDAP_SDAAPGENCTRL0 %LE %Long 0x00000001
local &rdata
;&rdata=Data.long(EDBG:&SDAP_AUTHSTTS)&0x00000001
;while &rdata!=0x1
;(
;  &rdata=Data.long(EDBG:&SDAP_AUTHSTTS)&0x00000001
;)

&UID0=Data.long(EDBG:&SDAP_UID0)
&UID1=Data.long(EDBG:&SDAP_UID1)

&CHAL0=Data.long(EDBG:&SDAP_KEYCHAL_0)
&CHAL1=Data.long(EDBG:&SDAP_KEYCHAL_1)
&CHAL2=Data.long(EDBG:&SDAP_KEYCHAL_2)
&CHAL3=Data.long(EDBG:&SDAP_KEYCHAL_3)
&CHAL4=Data.long(EDBG:&SDAP_KEYCHAL_4)
&CHAL5=Data.long(EDBG:&SDAP_KEYCHAL_5)
&CHAL6=Data.long(EDBG:&SDAP_KEYCHAL_6)
&CHAL7=Data.long(EDBG:&SDAP_KEYCHAL_7)

print "UID0 is &UID0"
print "UID1 is &UID1"

data.set EDBG:&SDAP_KEYRESP_0 %LE %Long &arg1
data.set EDBG:&SDAP_KEYRESP_1 %LE %Long &arg2
data.set EDBG:&SDAP_KEYRESP_2 %LE %Long &arg3
data.set EDBG:&SDAP_KEYRESP_3 %LE %Long &arg4
data.set EDBG:&SDAP_KEYRESP_4 %LE %Long &arg5
data.set EDBG:&SDAP_KEYRESP_5 %LE %Long &arg6
data.set EDBG:&SDAP_KEYRESP_6 %LE %Long &arg7
data.set EDBG:&SDAP_KEYRESP_7 %LE %Long &arg8

;Writing SDA AP AUTHCTL.HSEAUTHREQ
data.set EDBG:&SDAP_AUTHCTL %LE %Long 0x00000001

wait 1ms

&SDAP_AUTHSTTS_Read = Data.long(EDBG:&SDAP_AUTHSTTS)
print "SDAP_AUTHSTTS is &SDAP_AUTHSTTS_Read"

local &rdata1

&rdata1 = Data.long(EDBG:&SDAP_AUTHSTTS)&0x60000004
print "rdata1 is &rdata1"

;IF(&SDAP_AUTHSTTS_Read==0x60000005)
IF (&rdata1==0x60000004)
(
  print "debug function check ok, ready to open"

  ;Writing SDA AP DBGENCTRL.GDBGEN and DBGENCTRL.CDBGEN
  data.set EDBG:&SDAP_DBGENCTRL %LE %Long 0x10000010
)
ELSE
(
  PRINT "debug function still closed, please check your security setting and password"
  ENDDO
)

SYStem.Option TRST OFF
SYStem.Option EnReset OFF
SYStem.Option DUALPORT ON

; system.config debugporttype swd

SYSTEM.JTAGclock 10Mhz

SYSTEM.Attach

print "debugger attached, but No flash driver"

break

ENDDO

&arg1 to &arg8 fill in the real used key。

After saving, run the script using Lauderbach trace32, the results are as follows:

kerryzhou_18-1737288860667.png

 Fig 19

kerryzhou_19-1737288865017.png

 Fig 20

kerryzhou_20-1737288869839.png

 Fig 21

As you can see, Lauderbach can be unlocked and mounted, and can directly enter debug mode after downloading new code.

3.3 Segger JLINK unlock

From the current situation, Segger JLINK's non-HSE static unlocking is relatively convenient, because the latest Segger driver has added this function by default, which can directly identify whether it is locked, and then ask for the key value to be entered, and it can be automatically unlocked after entering. The driver version supported by the test is: JLink_V812a, open the JLINK commander, and do the connection action:

kerryzhou_21-1737288886760.png

 Fig 22

kerryzhou_22-1737288890779.png

 Fig 23

As you can see, JLINK has been unlocked successfully.

Of course, some lower-version drivers do not have this automatic lock recognition and require key input. In this case, you can unlock it by directly controlling the SDA_AP register.

The following is my actual command line operation method and results, for reference only:

J-Link>usb
Disconnecting from J-Link...O.K.
Disconnecting from J-Link...O.K.
Connecting to J-Link via USB...O.K.
Firmware: J-Link V11 compiled Dec  4 2024 17:53:35
Hardware version: V11.00
J-Link uptime (since boot): 0d 00h 00m 31s
S/N: 601012430
License(s): RDI, FlashBP, FlashDL, JFlash, GDB
USB speed mode: High speed (480 MBit/s)
VTref=3.315V
Device "S32K312" selected.

Connecting to target via SWD
ConfigTargetSettings() start
ConfigTargetSettings() end - Took 15us
InitTarget() start
SDA_AP detected
Unlocking device if necessary...
  Locked device detected. Proceeding with the unlock procedure...
  Locked S32K3xx device detected.
For proper debugger connection the device needs to be unlocked via an password.
Please specify the password via JLINK_ExecCommand() or by specifying a callback for an external dialog to enter the 16-byte password.
InitTarget() end - Took 7.53s
ConfigTargetSettings() start
ConfigTargetSettings() end - Took 13us
InitTarget() start
SDA_AP detected
Unlocking device if necessary...
  Locked device detected. Proceeding with the unlock procedure...
  Locked S32K3xx device detected.
For proper debugger connection the device needs to be unlocked via an password.
Please specify the password via JLINK_ExecCommand() or by specifying a callback for an external dialog to enter the 16-byte password.
InitTarget() end - Took 1.96s
Error occurred: Could not connect to the target device.
For troubleshooting steps visit: https://wiki.segger.com/J-Link_Troubleshooting
J-Link>WriteDP 2 0X070000FC
Writing DP register 2 = 0x070000FC (0 write repetitions needed)
J-Link>ReadAP 3
Reading AP register 3 = 0x001C0040 (0 read repetitions needed)
J-Link>WriteDP 2 0X07000070
Writing DP register 2 = 0x07000070 (0 write repetitions needed)
J-Link>ReadAP 0
Reading AP register 0 = 0x54030F33 (0 read repetitions needed)
J-Link>ReadAP 1
Reading AP register 1 = 0x23100265 (0 read repetitions needed)
J-Link>WriteDP 2 0x07000040
Writing DP register 2 = 0x07000040 (0 write repetitions needed)
J-Link>WriteAP 0 0x03020100
Writing AP register 0 = 0x03020100 (0 write repetitions needed)
J-Link>WriteAP 1 0X07060504
Writing AP register 1 = 0x07060504 (0 write repetitions needed)
J-Link>WriteAP 2 0X11100908
Writing AP register 2 = 0x11100908 (0 write repetitions needed)
J-Link>WriteAP 3 0X15141312
Writing AP register 3 = 0x15141312 (0 write repetitions needed)
J-Link>WriteDP 2 0X07000050
Writing DP register 2 = 0x07000050 (0 write repetitions needed)
J-Link>WriteAP 0 0X00000000
Writing AP register 0 = 0x00000000 (0 write repetitions needed)
J-Link>WriteAP 1 0X00000000
Writing AP register 1 = 0x00000000 (0 write repetitions needed)
J-Link>WriteAP 2 0X00000000
Writing AP register 2 = 0x00000000 (0 write repetitions needed)
J-Link>WriteAP 3 0X00000000
Writing AP register 3 = 0x00000000 (0 write repetitions needed)
J-Link>WriteDP 2 0X07000040
Writing DP register 2 = 0x07000040 (0 write repetitions needed)
J-Link>ReadAP 0
Reading AP register 0 = 0x03020100 (0 read repetitions needed)
J-Link>ReadAP 1
Reading AP register 1 = 0x07060504 (0 read repetitions needed)
J-Link>ReadAP 2
Reading AP register 2 = 0x11100908 (0 read repetitions needed)
J-Link>ReadAP 3
Reading AP register 3 = 0x15141312 (0 read repetitions needed)
J-Link>WriteDP 2 0x07000000
Writing DP register 2 = 0x07000000 (0 write repetitions needed)
J-Link>WriteAP 1 0X00000001
Writing AP register 1 = 0x00000001 (0 write repetitions needed)
J-Link>WriteDP 2 0x07000000
Writing DP register 2 = 0x07000000 (0 write repetitions needed)
J-Link>ReadAP 0
Reading AP register 0 = 0x60000004 (0 read repetitions needed)
J-Link>connect
Device "S32K312" selected.

Connecting to target via SWD
ConfigTargetSettings() start
ConfigTargetSettings() end - Took 12us
InitTarget() start
SDA_AP detected
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
Checking if debug access is already enabled...
  Debug access is not enabled yet. Performing enable debug access sequence...
  Debug access enabled
Checking if HSE firmware is installed...
  HSE firmware not installed
Checking if Cortex-M7_0 and Cortex-M7_1 are operating in lockstep mode
  Lock step mode disabled or not available
InitTarget() end - Took 16.5ms
Found SW-DP with ID 0x6BA02477
DPIDR: 0x6BA02477
CoreSight SoC-400 or earlier
AP map detection skipped. Manually configured AP map found.
AP[0]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[1]: APB-AP (IDR: Not set, ADDR: 0x00000000)
AP[2]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[3]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[4]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[5]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[6]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[7]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[4]: Skipped ROMBASE read. CoreBaseAddr manually set by user
AP[4]: Core found
CPUID register: 0x411FC272. Implementer code: 0x41 (ARM)
Cache: L1 I/D-cache present
Found Cortex-M7 r1p2, Little endian.
FPUnit: 8 code (BP) slots and 0 literal slots
ROM table scan skipped. CoreBaseAddr manually set by user: 0x40250400
I-Cache L1: 8 KB, 128 Sets, 32 Bytes/Line, 2-Way
D-Cache L1: 8 KB, 64 Sets, 32 Bytes/Line, 4-Way
SetupTarget() start
Initializing ECC RAM...
  RAMCodeAddr: 0x20000000
  RAMInitAddr: 0x20000010
  RAMInitSize: 0x00007FF0
  InitPattern: 0xDEADBEEF
  ECC RAM initialized successfully
Initializing ECC RAM...
  RAMCodeAddr: 0x20000000
  RAMInitAddr: 0x20400000
  RAMInitSize: 0x00004000
  InitPattern: 0xDEADBEEF
  ECC RAM initialized successfully
SetupTarget() end - Took 12.0ms
Memory zones:
  Zone: "Default" Description: Default access mode
Cortex-M7 identified.
J-Link>

It should be noted here that for SDA_AP control, the addresses of the kernel and DAPBUS control are different, which is why the above command line controls the address starting from 0x07000000. It can be seen that the above command line method finally successfully injected the key and unlocked it successfully.

kerryzhou_23-1737288908780.png

 

Fig 24

 

3.4 LC test result after unlock debug

After unlocking, check the UTEST and DCM register values ​​of LC as follows:

kerryzhou_24-1737288922430.png

 

Fig 25

 

kerryzhou_25-1737288925811.png

 

Fig 26

As you can see, it is already in IN_FIELD. The values ​​in the UTEST area also meet the following conditions:

LC slot1 is Inactive,

LC slot2 is Inactive,

LC slot3 is Active,

LC slot4 is Erased,

LC slot5 is Erased,

5. Sumarrize

After the above detailed description, the static encryption of K312's non-HSE firmware is completed, and the use of different emulators: JLINK, PE Mulitlink, lauterbach for decryption is also implemented.

Attachments:

S32K312_C40_Ip_RTD400HF01_flash.zip: flash waiting operation

S32K312_C40_Ip_RTD400HF01_flash_link.zip: link operation file to RAM

S32K312_C40_Ip_RTD400HF01_flash_SJG.zip: secure debug encryption code

S32K312_helloworld_RTD400HF01.zip: application test print helloworld code

When doing this set of functions, I also encountered many pitfalls, which are summarized here.

5.1 Trap1:RTD400/500 flash operation copies to RAM

  When a DFAE first reported this problem, I was still suspecting because after I copied the C40 code to RAM, I could still operate the flash successfully. But later I found that if I changed the erase area to block0, that is, when it was in the same block as the code, although the C40 code was copied to RAM successfully, and the map file was also in the ramcode area, when running it, it would go into hardfault and the error reported was still RWW error:  

 

kerryzhou_26-1737288942488.png

 

Fig 27

After many tests and final summary, we got the conclusion of Chapter 3.1. In fact, the code for processing C40 and OSIF was called without completing the flash operation, which led to the RWW problem. Therefore, after doing flash busy waiting or putting OSIF into RAM, the final test verification was successful.

5.2 Trap 2: Failure to push LC

    After completing the key burning, the test of the flash value IN_FIELD of the LC area specified by IVT was OK, and then reset, even power on again, it can still enter the debug mode smoothly. This situation means that the secure debug is not successful at all. I was stuck at this point for eve one day, looking at the principles, registers, and memory. Finally, I was helpless and went back to the .s file to check the position of IVT. Only then did I find that the IVT and LC position of RTD400 were wrong, and it was actually written to the offset 0X28. After the modification, it was successful, and the emulator reminded that debug had been locked. This point of RTD500 has been fixed.

 

kerryzhou_27-1737288958366.png

 

Fig 28

5.3 Trap 3: Lauterbach unlocking script fails to unlock

This problem is also quite strange, because the same Lauterbach script was successfully unlocked by my colleagues and customers before, but it just couldn't be unlocked when I did it, and it was always locked. Later, After debug the Lauterbach script , we found that there were two points that were stuck, both about challenge is ready, but my chip was not challenge ready. Because this kind of static encryption does not need challenge at all, just take care of the response, so I skipped the challenge check directly later, such as blocking the following code:

&rdata=Data.long(EDBG:&SDAP_AUTHSTTS)&0x00000001
while &rdata!=0x1
(
  &rdata=Data.long(EDBG:&SDAP_AUTHSTTS)&0x00000001
)

Modify the script:

&SDAP_AUTHSTTS_Read = Data.long(EDBG:&SDAP_AUTHSTTS)
print "SDAP_AUTHSTTS is &SDAP_AUTHSTTS_Read"
IF (&SDAP_AUTHSTTS_Read==0x60000005)
(
  print "debug function check ok, ready to open"

  ;Writing SDA AP DBGENCTRL.GDBGEN and DBGENCTRL.CDBGEN
  data.set EDBG:&SDAP_DBGENCTRL %LE %Long 0x10000010
)

To:
&rdata1 = Data.long(EDBG:&SDAP_AUTHSTTS)&0x60000004
print "rdata1 is &rdata1"

;IF(&SDAP_AUTHSTTS_Read==0x60000005)
IF (&rdata1==0x60000004)
(
  print "debug function check ok, ready to open"

  ;Writing SDA AP DBGENCTRL.GDBGEN and DBGENCTRL.CDBGEN
  data.set EDBG:&SDAP_DBGENCTRL %LE %Long 0x10000010
)

That is, the status register does not identify the challenge, and then unlock is working.

Attachments
Comments

For the RTD500 C40 FLASH operation linker method, as RTD500 flash driver also calls the SchM_Mem_43_INFLS related driver, so in the linker file, also need to put the SchM_Mem_43_INFLS.o to RAM.

The related linker file is:

Modify C40_Ip_Example_S32K344 Project_Settings->Linker_Files->Linker_flash_s32k344.ld

 

.pflash :
    {
        KEEP(*(.boot_header))
        . = ALIGN(8192);  /* The minimum erase size of C40 Flash IP is 8kb */
        __text_start = .;
        __interrupts_init_start = .;
        KEEP(*(.intc_vector))
        . = ALIGN(4);
        __interrupts_init_end = .;
        KEEP(*(.core_loop))
        . = ALIGN(4);
        *(.startup)
        . = ALIGN(4);
        *(.systeminit)
        . = ALIGN(4);
        *(.text.startup)
        . = ALIGN(4);
        *(EXCLUDE_FILE (*C40_Ip.o *OsIf_Timer.o *OsIf_Timer_System.o *SchM_Mem_43_INFLS.o) .text)
        *(EXCLUDE_FILE (*C40_Ip.o *OsIf_Timer.o *OsIf_Timer_System.o *SchM_Mem_43_INFLS.o) .text*)
        . = ALIGN(4);
        *(EXCLUDE_FILE (*C40_Ip.o *OsIf_Timer.o *OsIf_Timer_System.o *SchM_Mem_43_INFLS.o) .mcal_text)
        . = ALIGN(4);
        . = ALIGN(4);
        *(.acmcu_code_rom)
        . = ALIGN(4);
        __acfls_code_rom_start = .;
        *(.acfls_code_rom)
        . = ALIGN(4);
        __acfls_code_rom_end = .;
        __acmem_43_infls_code_rom_start = .;
        *(.acmem_43_infls_code_rom)
        . = ALIGN(4);
        __acmem_43_infls_code_rom_end = .;
        KEEP(*(.init))
        . = ALIGN(4);
        KEEP(*(.fini))
        . = ALIGN(4);
        *(.rodata)
        *(.rodata*)
        . = ALIGN(4);
        *(.mcal_const_cfg)
        . = ALIGN(4);
        *(.mcal_const)
        . = ALIGN(4);
        __init_table = .;
        KEEP(*(.init_table))
        . = ALIGN(4);
        __zero_table = .;
        KEEP(*(.zero_table))
    } > int_pflash

   .itcm_text : AT(__tcm_code_rom_start)
    {
        . = ALIGN(4);
        __itcm_start__ = .;
        *(.itcm_text*)
        . = ALIGN(4);
        KEEP(*C40_Ip.o (.mcal_text*))
        KEEP(*C40_Ip.o (.text*))
        KEEP(*C40_Ip.o (.text))
        KEEP(*OsIf_Timer.o (.mcal_text*))
        KEEP(*OsIf_Timer.o (.text*))
        KEEP(*OsIf_Timer.o (.text))
        KEEP(*OsIf_Timer_System.o (.mcal_text*))
        KEEP(*OsIf_Timer_System.o (.text*))
        KEEP(*OsIf_Timer_System.o (.text))
        KEEP(**SchM_Mem_43_INFLS.o (.mcal_text*))
        KEEP(**SchM_Mem_43_INFLS.o (.text*))
        KEEP(**SchM_Mem_43_INFLS.o (.text))
        . = ALIGN(4);
        __itcm_end__ = .;
    } > int_itcm

 

 

Modify C40_Ip_Example_S32K344 main.c 

#define EXAMPLE_SECTOR_START_ADDR (0x004FE000)//(0x00600000U)
#define EXAMPLE_SECTOR_TEST (C40_CODE_ARRAY_0_BLOCK_0_S127)//(C40_CODE_ARRAY_0_BLOCK_2_S256)

Others no modification, test result:

kerryzhou_0-1737344832046.png

 

 

 

 

100% helpful (1/1)
Version history
Last update:
3 weeks ago
Updated by: