Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permission Control functionalities esp32s3 (IDFGH-14747) #15486

Open
3 tasks done
plamendc opened this issue Feb 27, 2025 · 1 comment
Open
3 tasks done

Permission Control functionalities esp32s3 (IDFGH-14747) #15486

plamendc opened this issue Feb 27, 2025 · 1 comment
Labels
Status: Opened Issue is new Type: Bug bugs in IDF

Comments

@plamendc
Copy link

plamendc commented Feb 27, 2025

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

5.0.7

Espressif SoC revision.

esp32s3

Operating System used.

Windows

How did you build your project?

Command line with Make

If you are using Windows, please specify command line type.

CMD

Development Kit.

esp32s3

Power Supply used.

USB

What is the expected behavior?

I am trying to implement a memory protection functionally for my project. I have several partitions: SSBL, factory and application. During normal operation the code first goes into SSBL than boots the factory/application.

What is the actual behavior?

It works like that, but when I try to implement the PMS functionality to select partitions and set access control for each of them, I can't boot any partition following SSBL. The memory protection algorithm is located in my SSBL.

Steps to reproduce.

This is my SSBL code:

/*

  • We arrive here after the ROM bootloader finished loading this second stage bootloader from flash.

  • The hardware is mostly uninitialized, flash cache is down and the app CPU is in reset.

  • We do have a stack, so we can do the initialization in C.
    /
    void attribute((noreturn)) call_start_cpu0(void)
    {
    tReprogFlag
    pReprogFlag = (tReprogFlag*) REPROGRAMMING_STRUCT_BASE_ADDR;
    esp_image_metadata_t img_meta;
    uint32_t calculatedCrcValue = 0;
    bool noMainApp = false;
    bool verifiedFAC = false;
    bool verifiedOTA[2] = {false, false};

    /* 1. Hardware initialization */
    if (bootloader_init() != ESP_OK) {
    bootloader_reset();
    }

#ifdef CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
// If this boot is a wake up from the deep sleep then go to the short way,
// try to load the application which worked before deep sleep.
// It skips a lot of checks due to it was done before (while first boot).
bootloader_utility_load_boot_image_from_deep_sleep();
// If it is not successful try to load an application as usual.
#endif

/* 2. Select the number of boot partition */
bootloader_state_t bs = {0};

/* 2.1 Load partition table */
if (!bootloader_utility_load_partition_table(&bs)) {
    ESP_LOGE(TAG, "load partition table error!");
    bootloader_reset();
}

/* 3. Verify factory image checksum */
verifiedFAC = (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &bs.factory, &img_meta) == ESP_OK);
ESP_LOGI(TAG, "Image FCTRY verified: %d", verifiedFAC);

ESP_LOGI(TAG, "Should never arrive here!");

/* 4. Evaluate BootFlag */
calculatedCrcValue = esp_rom_crc32_le(REPROGRAMMING_STRUCT_CRC_INIT, (uint8_t const *)pReprogFlag, REPROG_FLAG_CRC_DATA_LEN);
ESP_LOGD(TAG, "calculated CRC: 0x%08X", calculatedCrcValue);
ESP_LOGD(TAG, "reprFlCrc:      0x%08X", pReprogFlag->reprFlCrc);
ESP_LOGD(TAG, "pReprogFlag addr: 0x%08X", pReprogFlag);
ESP_LOGD(TAG, "magicNum: 0x%08X", pReprogFlag->magicNum);
ESP_LOGD(TAG, "reprogFlag: 0x%08X", pReprogFlag->reprogFlag);
ESP_LOGD(TAG, "resetReasonFlag: 0x%08lX", pReprogFlag->resetReasonFlag);

bool bootAppl = false;
if (pReprogFlag->reprFlCrc == calculatedCrcValue) {
    ESP_LOGI(TAG, "The CRC of Reprogramming flag structure valid!");
    switch(pReprogFlag->reprogFlag)
    {
        case REPROGRAMMING_FLAG_APPL:
            ESP_LOGI(TAG, "APPL start is requested.");
            bootAppl = true;
            break;

        default:
            ESP_LOGI(TAG, "Default boot image to factory.");
            /* load KSC2N Factory */
            break;
    }
}
else {
    /* Boot application start flag is invalid. Proceed first to factory */
    ESP_LOGW(TAG, "The CRC of Reprogramming flag structure is invalid.");

    /* Try to boot into application, if factory is not verified. */
    bootAppl = (verifiedFAC == false);
}

int bootIndex = FACTORY_INDEX;
if (bootAppl) {
    /* Verfiy OTA image checksums */
    verifiedOTA[0] = (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &bs.ota[0], &img_meta) == ESP_OK);
    ESP_LOGI(TAG, "Image OTA[0] verified: %d", verifiedOTA[0]);
    verifiedOTA[1] = (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &bs.ota[1], &img_meta) == ESP_OK);
    ESP_LOGI(TAG, "Image OTA[1] verified: %d", verifiedOTA[1]);

    /* Select boot index for available applications. */
    bootIndex = select_boot_index(&bs, verifiedOTA);
    /* If factory is selected, no applicaiton is available */
    if (bootIndex == FACTORY_INDEX) {
        noMainApp = true;
    }
}

ESP_LOGI(TAG, "Should never arrive here2!");

if ((bootIndex == FACTORY_INDEX) && (!verifiedFAC)) {
    ESP_LOGE(TAG, "Factory image is invalid. No bootable image found.");
    bootloader_halt();
}

/* 6. Reset reprogFlag for next boot (because a reset should always first boot factory and then go to main) */
pReprogFlag->magicNum         = REPROGRAMMING_STRUCT_MAGIC_NUM;
pReprogFlag->reprogFlag       = REPROGRAMMING_FLAG_FCTRY;
pReprogFlag->resetReasonFlag = (noMainApp) ? REPROGRAMMING_REASON_NO_APP : REPROGRAMMING_REASON_RESERVED;
calculatedCrcValue = esp_rom_crc32_le(REPROGRAMMING_STRUCT_CRC_INIT, (uint8_t const *)pReprogFlag, REPROG_FLAG_CRC_DATA_LEN);
pReprogFlag->reprFlCrc        = calculatedCrcValue;
ESP_LOGI(TAG, "Reset Reprogramming flag");

ESP_LOGD(TAG, "calculated CRC: 0x%08X", calculatedCrcValue);
ESP_LOGD(TAG, "reprFlCrc:      0x%08X", pReprogFlag->reprFlCrc);
ESP_LOGD(TAG, "pReprogFlag addr: 0x%08X", pReprogFlag);
ESP_LOGD(TAG, "magicNum: 0x%08X", pReprogFlag->magicNum);
ESP_LOGD(TAG, "reprogFlag: 0x%08X", pReprogFlag->reprogFlag);
ESP_LOGD(TAG, "resetReasonFlag: 0x%08lX", pReprogFlag->resetReasonFlag);

/*** MEMORY PROTECTION ***/
hal_mem_protect_enable(bootIndex);
/*** MEMORY PROTECTION ***/
/* 7. Load the app image for booting */
ESP_LOGI(TAG, "Try to load image: %d (-1: factory | 0/1: main app)", bootIndex);
bootloader_utility_load_boot_image(&bs, bootIndex);

}

My hal driver for PMS:

/**

  • (c) Maschinenfabrik Bernard Krone GmbH, Spelle. All rights reserved.
  • @file: HAL_MEM_PROTECT.c
  • @Date: $LastChangedDate: 20.11.24
  • @author: $LastChangedBy: Plamen Dimitrov
  • @Version: $Revision: 1.0
  • @brief: This file contains the interface for the Memory Protection HAL

*/

#ifdef __cplusplus
extern "C"
{
#endif

//
/***************** Inclusions **************************/
/
/

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "esp_log.h"
#include "HAL_MEM_PROTECT.h"

/************************/
/***************** Local Macros /
/
/

//write value to register
#define REG_WRITE(_r, _v) do {
(*(volatile uint32_t *)(_r)) = (_v);
} while(0)

//read value from register
#define REG_READ(_r) ({
(*(volatile uint32_t *)(_r));
})

// Correct SYSCON Base Address for Flash
#define SYSCON_BASE 0x60026000

// Flash ACE Registers
#define FLASH_ACE_ATTR_REG(n) (SYSCON_BASE + 0x0028 + (4 * (n))) // Flash ACE Permission Config Register
#define FLASH_ACE_ADDR_REG(n) (SYSCON_BASE + 0x0038 + (4 * (n))) // Flash ACE Starting Address Config Register
#define FLASH_ACE_SIZE_REG(n) (SYSCON_BASE + 0x0048 + (4 * (n))) // Flash ACE Length Config Register

// Define Access Control Attributes (Readable Names for Bits)
#define ATTR_SECURE_READ_ONLY (0b010 << 0) // Secure World: Read-only (W=0, R=1, X=1)
#define ATTR_NON_SECURE_READ_ONLY (0b010 << 3) // Non-Secure World: Read-only (W=0, R=1, X=1)
#define ATTR_SPI1_READ_ONLY (0b01 << 6) // SPI1: Read-only (W=0, R=1)
#define ATTR_FULL_ACCESS (0b11111111) // Full Access (W=1, R=1, X=1)

/*************************/
/***************** Local types /
/
/

// Memory Map Configuration Macros
#define SSBL_START_ADDR 0x00000000
#define SSBL_SIZE 1 // (48 * 1024) // 48KB

#define OTA_0_START_ADDR 0x00020000
#define OTA_0_SIZE 45 // (3072 * 1024) // 3072KB

#define OTA_1_START_ADDR 0x0312000
#define OTA_1_SIZE 45 // (3072 * 1024) // 3072KB

#define FACTORY_START_ADDR 0x00620000
#define FACTORY_SIZE 15 // (1024 * 1024) // 1024KB

#define PROD_START_ADDR 0x00710000
#define PROD_SIZE 1 // (4 * 1024) // 4KB

// Constants for Active OTA Selection
#define OTA_0_ACTIVE 0
#define OTA_1_ACTIVE 1

/*************************/
/***************** Local types /
/
/

// Enum for Memory Regions
enum {
SSBL = 0,
OTA_0,
OTA_1,
FACTORY,
PROD,
NUM_REGIONS // Total number of regions
};

// Memory map structure
typedef struct {
uint32_t start_address; // Starting address of the memory region
uint32_t size; // Size of the memory region
} memory_region_t;

/*********************/
/***************** Local variables /
/
/

// Memory regions defined using macros
const memory_region_t memory_regions[NUM_REGIONS] = {
{SSBL_START_ADDR, SSBL_SIZE}, // SSBL
{OTA_0_START_ADDR, OTA_0_SIZE}, // OTA_0
{OTA_1_START_ADDR, OTA_1_SIZE}, // OTA_1
{FACTORY_START_ADDR, FACTORY_SIZE}, // Factory
{PROD_START_ADDR, PROD_SIZE} // Prod
};

uint8_t counter = 0;

//
/
Local function declarations /
/
/

//
/***************** Interface functions *****************/
/
/

// Configures the Flash memory protection
void hal_mem_protect_enable(int active_ota) {
// Iterate through all memory regions
for (int i = 0; i < NUM_REGIONS; i++) {

    if(i == OTA_0 || i == OTA_1 || i == FACTORY) {

      // Configure the start address and size
      REG_WRITE(FLASH_ACE_ADDR_REG(counter), memory_regions[counter].start_address);  // Set base address
      REG_WRITE(FLASH_ACE_SIZE_REG(counter), memory_regions[counter].size);           // Set size

      ESP_LOGE("PCU", "FLASH ACE ADDR REG: %X, start address: %X", FLASH_ACE_ADDR_REG(counter), memory_regions[counter].start_address);
      ESP_LOGE("PCU", "FLASH ACE SIZE REG: %X, size: %X", FLASH_ACE_SIZE_REG(counter), memory_regions[counter].size);
      
      // Set the access control attributes for Secure, Non-Secure, and SPI1
      uint32_t attr = ATTR_FULL_ACCESS;//ATTR_SPI1_READ_ONLY | ATTR_NON_SECURE_READ_ONLY | ATTR_SECURE_READ_ONLY;
      REG_WRITE(FLASH_ACE_ATTR_REG(counter), attr); // Set attributes
      ESP_LOGE("PCU", "FLASH ACE ATTR REG: %X, attr: %X", FLASH_ACE_ATTR_REG(counter), attr);

      uint32_t value = REG_READ(FLASH_ACE_ADDR_REG(counter));
      ESP_LOGE("PCU", "read FLASH ACE ADDR REG: %X", value);
      value = REG_READ(FLASH_ACE_SIZE_REG(counter));
      ESP_LOGE("PCU", "read FLASH ACE SIZE REG: %X", value);
      value = REG_READ(FLASH_ACE_ATTR_REG(counter));
      ESP_LOGE("PCU", "read FLASH ACE ATTR REG: %X", value);
    }

    counter++;
}

ESP_LOGE("PCU", "Flash memory regions configured with full access for Secure, Non-Secure, and SPI1.");

}

// Enables full access for either SSBL or Factory region
void enable_full_access(int region) {
if (region != SSBL && region != FACTORY) {
ESP_LOGE("PCU", "Invalid region specified. Only SSBL or Factory can be set to full access.");
return;
}

// Enable full access for the specified region
uint32_t full_access_attr = ATTR_FULL_ACCESS; // Full access for all
REG_WRITE(FLASH_ACE_ATTR_REG(region), full_access_attr);

ESP_LOGI("PCU", "Full access enabled for region %s.",
         (region == SSBL) ? "SSBL" : "Factory");

}

//
/
Local function definitions **************/
/
*************/

#ifdef __cplusplus
} /* end of extern "C" */
#endif

You can see that I have selected the partitions starting addresses, their size and the access control.
Even if set the access control is set to full access, I can't boot my bootloader or application. Please take a look at the logs.

Debug Logs.

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x3 (RTC_SW_SYS_RST),boot:0x29 (SPI_FAST_FLASH_BOOT)
Saved PC:0x403cdf3a
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3980,len:0x216c
load:0x403c9700,len:0x1344
load:0x403cc700,len:0x33fc
entry 0x403c99e0
W (27) boot.esp32s3: eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!
I (43) boot: ESP-IDF v5.0.7-dirty 2nd stage bootloader
I (44) boot: compile time 15:48:58
I (44) boot: Multicore bootloader
I (46) boot: chip revision: v0.1
I (50) qio_mode: Enabling default flash chip QIO
I (55) boot.esp32s3: Boot SPI Speed : 80MHz
I (60) boot.esp32s3: SPI Mode       : QIO
I (65) boot.esp32s3: SPI Flash Size : 16MB
I (70) boot: Enabling RNG early entropy source...
I (75) boot: Partition Table:
I (79) boot: ## Label            Usage          Type ST Offset   Length
I (86) boot:  0 otadata          OTA data         01 00 0000d000 00002000
I (93) boot:  1 reserved         WiFi data        01 02 0000f000 00001000
I (101) boot:  2 ota_0            OTA app          00 10 00010000 00300000
I (108) boot:  3 ota_1            OTA app          00 11 00310000 00300000
I (116) boot:  4 factory          factory app      00 00 00610000 00100000
I (124) boot:  5 prod             Unknown data     01 ff 00710000 00001000
I (131) boot:  6 reserved1        Unknown data     01 ff 00711000 00002000
I (139) boot:  7 safeNVrb0        Unknown data     01 ff 00713000 00010000
I (146) boot:  8 safeNVrb1        Unknown data     01 ff 00723000 00010000
I (154) boot:  9 safeNVrb2        Unknown data     01 ff 00733000 00010000
I (161) boot: 10 config           WiFi data        01 02 00743000 00046000
I (169) boot: 11 shared           WiFi data        01 02 00789000 00003000
I (176) boot: 12 appl             WiFi data        01 02 0078c000 00008000
I (184) boot: 13 coredump         Unknown data     01 03 00794000 00040000
I (192) boot: 14 log              Unknown data     01 ff 007d4000 00040000
I (199) boot: 15 fifo             Unknown data     01 ff 00814000 00100000
I (207) boot: 16 diagtool2        Unknown data     01 ff 00914000 006ea000
I (214) boot: End of partition table
I (321) SSBL: Image FCTRY verified: 1
I (321) SSBL: Should never arrive here!
I (321) SSBL: The CRC of Reprogramming flag structure valid!
I (325) SSBL: Default boot image to factory.
I (329) SSBL: Should never arrive here2!
I (334) SSBL: Reset Reprogramming flag
E (339) PCU: FLASH ACE ADDR REG: 6002603C, start address: 20000
E (345) PCU: FLASH ACE SIZE REG: 6002604C, size: 2D
E (351) PCU: FLASH ACE ATTR REG: 6002602C, attr: FF
E (356) PCU: read FLASH ACE ADDR REG: 20000
E (361) PCU: read FLASH ACE SIZE REG: 2D
E (366) PCU: read FLASH ACE ATTR REG: FF
E (370) PCU: FLASH ACE ADDR REG: 60026040, start address: 312000
E (377) PCU: FLASH ACE SIZE REG: 60026050, size: 2D
E (383) PCU: FLASH ACE ATTR REG: 60026030, attr: FF
E (388) PCU: read FLASH ACE ADDR REG: 312000
E (393) PCU: read FLASH ACE SIZE REG: 2D
E (398) PCU: read FLASH ACE ATTR REG: FF
E (402) PCU: FLASH ACE ADDR REG: 60026044, start address: 620000
E (409) PCU: FLASH ACE SIZE REG: 60026054, size: F
E (414) PCU: FLASH ACE ATTR REG: 60026034, attr: FF
E (420) PCU: read FLASH ACE ADDR REG: 620000
E (425) PCU: read FLASH ACE SIZE REG: F
E (429) PCU: read FLASH ACE ATTR REG: FF
E (434) PCU: Flash memory regions configured with full access for Secure, Non-Secure, and SPI1.
I (443) SSBL: Try to load image: -1 (-1: factory | 0/1: main app)
I (450) esp_image: segment 0: paddr=00610020 vaddr=3c070020 size=2a618h (173592) map
E (480) esp_image: invalid segment length 0xfeebdaed
E (481) boot: Factory app partition is not bootable
I (481) esp_image: segment 0: paddr=00010020 vaddr=3c1b0020 size=7ffe8h (524264) map
E (549) esp_image: invalid segment length 0xfeebdaed
E (549) boot: OTA app partition slot 0 is not bootable
E (549) esp_image: image at 0x310000 has invalid magic byte (nothing flashed here?)
E (557) boot: OTA app partition slot 1 is not bootable
E (563) boot: No bootable app partitions in the partition table

More Information.

I followed the specifications specified in section 15.5 in this document: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf

The whole idea was to implement memory protection that while I am in one partition in the code, to disable unwanted access to the other partitions. Perhaps, I am doing something wrong during the configuration of the PMS or perhaps, this functionality is not applicable for my use case.

Also, because some of the segments I want to protect are shorter than 64k, which is the shortest segment fraction, I was wondering whether I can have overlapping memory segments in terms of PMS?

@plamendc plamendc added the Type: Bug bugs in IDF label Feb 27, 2025
@github-actions github-actions bot changed the title Permission Control functionalities esp32s3 Permission Control functionalities esp32s3 (IDFGH-14747) Feb 27, 2025
@espressif-bot espressif-bot added the Status: Opened Issue is new label Feb 27, 2025
@sachin-billore
Copy link
Collaborator

Hi @plamendc ,

  1. Can you confirm that start address and size of the all the flash partitions are 64Kb aligned? From the code snippet it looks like SSBL partition size is not (it’s 48KB).
  2. All the partition size defined are in numbers (SSBL_SIZE = 1, ….) and same is configured in FLASH_ACE_n_SIZE register. Can you please confirm it? If this is the case, it will be invalid configuration.
  3. Are you configuring all the valid permission for Secure World? I think entire code will be executing in secure world, it is not switching to Non-secure world.
  4. Are you configuring and enabling the interrupt for access violation for external memory (Section 15.6.3 in TRM)? If not, can you read control and addr registers (0x88 and 0x8c), to find the location and type of access violation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Opened Issue is new Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

3 participants