mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(partition_table): Add read-only partition flag and functionality
This commit is contained in:
parent
f083570af6
commit
ab1eb37fe8
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -33,6 +33,7 @@ extern "C" {
|
||||
#define PART_SUBTYPE_END 0xff
|
||||
|
||||
#define PART_FLAG_ENCRYPTED (1<<0)
|
||||
#define PART_FLAG_READONLY (1<<1)
|
||||
|
||||
/* The md5sum value is found this many bytes after the ESP_PARTITION_MAGIC_MD5 offset */
|
||||
#define ESP_PARTITION_MD5_OFFSET 16
|
||||
@ -92,6 +93,15 @@ typedef struct {
|
||||
*/
|
||||
esp_err_t esp_partition_table_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions);
|
||||
|
||||
/**
|
||||
* Check whether the region on the main flash is not read-only.
|
||||
*
|
||||
* @param addr Start address of the region
|
||||
* @param size Size of the region
|
||||
*
|
||||
* @return true if the region is safe to write, otherwise false.
|
||||
*/
|
||||
bool esp_partition_is_flash_region_writable(size_t addr, size_t size);
|
||||
|
||||
/**
|
||||
* Check whether the region on the main flash is safe to write.
|
||||
|
@ -34,6 +34,7 @@ typedef int esp_err_t;
|
||||
#define ESP_ERR_INVALID_VERSION 0x10A /*!< Version was invalid */
|
||||
#define ESP_ERR_INVALID_MAC 0x10B /*!< MAC address was invalid */
|
||||
#define ESP_ERR_NOT_FINISHED 0x10C /*!< Operation has not fully completed */
|
||||
#define ESP_ERR_NOT_ALLOWED 0x10D /*!< Operation is not allowed */
|
||||
|
||||
|
||||
#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */
|
||||
|
@ -133,6 +133,9 @@ static const esp_err_msg_t esp_err_msg_table[] = {
|
||||
# endif
|
||||
# ifdef ESP_ERR_NOT_FINISHED
|
||||
ERR_TBL_IT(ESP_ERR_NOT_FINISHED), /* 268 0x10c Operation has not fully completed */
|
||||
# endif
|
||||
# ifdef ESP_ERR_NOT_ALLOWED
|
||||
ERR_TBL_IT(ESP_ERR_NOT_ALLOWED), /* 269 0x10d Operation is not allowed */
|
||||
# endif
|
||||
// components/nvs_flash/include/nvs.h
|
||||
# ifdef ESP_ERR_NVS_BASE
|
||||
|
@ -132,6 +132,7 @@ typedef struct {
|
||||
uint32_t erase_size; /*!< size the erase operation should be aligned to */
|
||||
char label[17]; /*!< partition label, zero-terminated ASCII string */
|
||||
bool encrypted; /*!< flag is set to true if partition is encrypted */
|
||||
bool readonly; /*!< flag is set to true if partition is read-only */
|
||||
} esp_partition_t;
|
||||
|
||||
/**
|
||||
@ -270,6 +271,7 @@ esp_err_t esp_partition_read(const esp_partition_t* partition,
|
||||
* @return ESP_OK, if data was written successfully;
|
||||
* ESP_ERR_INVALID_ARG, if dst_offset exceeds partition size;
|
||||
* ESP_ERR_INVALID_SIZE, if write would go out of bounds of the partition;
|
||||
* ESP_ERR_NOT_ALLOWED, if partition is read-only;
|
||||
* or one of error codes from lower-level flash driver.
|
||||
*/
|
||||
esp_err_t esp_partition_write(const esp_partition_t* partition,
|
||||
@ -322,6 +324,7 @@ esp_err_t esp_partition_read_raw(const esp_partition_t* partition,
|
||||
* @return ESP_OK, if data was written successfully;
|
||||
* ESP_ERR_INVALID_ARG, if dst_offset exceeds partition size;
|
||||
* ESP_ERR_INVALID_SIZE, if write would go out of bounds of the partition;
|
||||
* ESP_ERR_NOT_ALLOWED, if partition is read-only;
|
||||
* or one of the error codes from lower-level flash driver.
|
||||
*/
|
||||
esp_err_t esp_partition_write_raw(const esp_partition_t* partition,
|
||||
@ -341,6 +344,7 @@ esp_err_t esp_partition_write_raw(const esp_partition_t* partition,
|
||||
* @return ESP_OK, if the range was erased successfully;
|
||||
* ESP_ERR_INVALID_ARG, if iterator or dst are NULL;
|
||||
* ESP_ERR_INVALID_SIZE, if erase would go out of bounds of the partition;
|
||||
* ESP_ERR_NOT_ALLOWED, if partition is read-only;
|
||||
* or one of error codes from lower-level flash driver.
|
||||
*/
|
||||
esp_err_t esp_partition_erase_range(const esp_partition_t* partition,
|
||||
|
@ -154,6 +154,7 @@ static esp_err_t load_partitions(void)
|
||||
item->info.type = entry.type;
|
||||
item->info.subtype = entry.subtype;
|
||||
item->info.encrypted = entry.flags & PART_FLAG_ENCRYPTED;
|
||||
item->info.readonly = entry.flags & PART_FLAG_READONLY;
|
||||
item->user_registered = false;
|
||||
|
||||
#if CONFIG_IDF_TARGET_LINUX
|
||||
@ -349,7 +350,6 @@ const esp_partition_t *esp_partition_find_first(esp_partition_type_t type,
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void esp_partition_iterator_release(esp_partition_iterator_t iterator)
|
||||
{
|
||||
// iterator == NULL is okay
|
||||
@ -384,6 +384,7 @@ const esp_partition_t *esp_partition_verify(const esp_partition_t *partition)
|
||||
esp_partition_iterator_release(it);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_register_external(esp_flash_t *flash_chip, size_t offset, size_t size,
|
||||
const char *label, esp_partition_type_t type, esp_partition_subtype_t subtype,
|
||||
const esp_partition_t **out_partition)
|
||||
|
@ -369,6 +369,9 @@ esp_err_t esp_partition_write(const esp_partition_t *partition, size_t dst_offse
|
||||
{
|
||||
assert(partition != NULL && s_spiflash_mem_file_buf != NULL);
|
||||
|
||||
if (partition->readonly) {
|
||||
return ESP_ERR_NOT_ALLOWED;
|
||||
}
|
||||
if (partition->encrypted) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
@ -450,6 +453,9 @@ esp_err_t esp_partition_erase_range(const esp_partition_t *partition, size_t off
|
||||
{
|
||||
assert(partition != NULL);
|
||||
|
||||
if (partition->readonly) {
|
||||
return ESP_ERR_NOT_ALLOWED;
|
||||
}
|
||||
if (offset > partition->size || offset % partition->erase_size != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -64,6 +64,9 @@ esp_err_t esp_partition_write(const esp_partition_t *partition,
|
||||
size_t dst_offset, const void *src, size_t size)
|
||||
{
|
||||
assert(partition != NULL);
|
||||
if (partition->readonly) {
|
||||
return ESP_ERR_NOT_ALLOWED;
|
||||
}
|
||||
if (dst_offset > partition->size) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@ -103,6 +106,9 @@ esp_err_t esp_partition_write_raw(const esp_partition_t *partition,
|
||||
size_t dst_offset, const void *src, size_t size)
|
||||
{
|
||||
assert(partition != NULL);
|
||||
if (partition->readonly) {
|
||||
return ESP_ERR_NOT_ALLOWED;
|
||||
}
|
||||
if (dst_offset > partition->size) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@ -118,6 +124,9 @@ esp_err_t esp_partition_erase_range(const esp_partition_t *partition,
|
||||
size_t offset, size_t size)
|
||||
{
|
||||
assert(partition != NULL);
|
||||
if (partition->readonly) {
|
||||
return ESP_ERR_NOT_ALLOWED;
|
||||
}
|
||||
if (offset > partition->size) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@ -193,9 +202,25 @@ bool esp_partition_check_identity(const esp_partition_t *partition_1, const esp_
|
||||
return false;
|
||||
}
|
||||
|
||||
bool esp_partition_is_flash_region_writable(size_t addr, size_t size)
|
||||
{
|
||||
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
for (; it != NULL; it = esp_partition_next(it)) {
|
||||
const esp_partition_t *p = esp_partition_get(it);
|
||||
if (p->readonly) {
|
||||
if (addr >= p->address && addr < p->address + p->size) {
|
||||
return false;
|
||||
}
|
||||
if (addr < p->address && addr + size > p->address) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool esp_partition_main_flash_region_safe(size_t addr, size_t size)
|
||||
{
|
||||
bool result = true;
|
||||
if (addr <= ESP_PARTITION_TABLE_OFFSET + ESP_PARTITION_TABLE_MAX_LEN) {
|
||||
return false;
|
||||
}
|
||||
@ -206,5 +231,5 @@ bool esp_partition_main_flash_region_safe(size_t addr, size_t size)
|
||||
if (addr < p->address && addr + size > p->address) {
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -8,7 +8,6 @@
|
||||
#include <string.h>
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "vfs_fat_internal.h"
|
||||
#include "diskio_impl.h"
|
||||
@ -29,6 +28,8 @@ typedef struct vfs_fat_spiflash_ctx_t {
|
||||
|
||||
static vfs_fat_spiflash_ctx_t *s_ctx[FF_VOLUMES] = {};
|
||||
|
||||
extern esp_err_t esp_vfs_set_readonly_flag(const char* base_path); // from vfs/vfs.c to set readonly flag in esp_vfs_t struct externally
|
||||
|
||||
static bool s_get_context_id_by_label(const char *label, uint32_t *out_id)
|
||||
{
|
||||
vfs_fat_spiflash_ctx_t *p_ctx = NULL;
|
||||
@ -160,6 +161,10 @@ esp_err_t esp_vfs_fat_spiflash_mount_rw_wl(const char* base_path,
|
||||
assert(ctx_id != FF_VOLUMES);
|
||||
s_ctx[ctx_id] = ctx;
|
||||
|
||||
if (data_partition->readonly) {
|
||||
esp_vfs_set_readonly_flag(base_path);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
fail:
|
||||
@ -296,6 +301,11 @@ esp_err_t esp_vfs_fat_spiflash_mount_ro(const char* base_path,
|
||||
ret = ESP_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (data_partition->readonly) {
|
||||
esp_vfs_set_readonly_flag(base_path);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
fail:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -76,6 +76,11 @@ public:
|
||||
return size;
|
||||
}
|
||||
|
||||
bool get_readonly() override
|
||||
{
|
||||
return partition.readonly;
|
||||
}
|
||||
|
||||
const esp_partition_t partition;
|
||||
|
||||
private:
|
||||
|
@ -135,6 +135,7 @@ typedef struct nvs_opaque_iterator_t *nvs_iterator_t;
|
||||
* - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
|
||||
* - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is no space for a new entry or there are too many different
|
||||
* namespaces (maximum allowed different namespaces: 254)
|
||||
* - ESP_ERR_NOT_ALLOWED if the NVS partition is read-only and mode is NVS_READWRITE
|
||||
* - other error codes from the underlying storage driver
|
||||
*/
|
||||
esp_err_t nvs_open(const char* namespace_name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle);
|
||||
@ -166,6 +167,7 @@ esp_err_t nvs_open(const char* namespace_name, nvs_open_mode_t open_mode, nvs_ha
|
||||
* - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
|
||||
* - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is no space for a new entry or there are too many different
|
||||
* namespaces (maximum allowed different namespaces: 254)
|
||||
* - ESP_ERR_NOT_ALLOWED if the NVS partition is read-only and mode is NVS_READWRITE
|
||||
* - other error codes from the underlying storage driver
|
||||
*/
|
||||
esp_err_t nvs_open_from_partition(const char *part_name, const char* namespace_name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle);
|
||||
|
@ -222,6 +222,7 @@ protected:
|
||||
* - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and
|
||||
* mode is NVS_READONLY
|
||||
* - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints
|
||||
* - ESP_ERR_NOT_ALLOWED if the NVS partition is read-only and mode is NVS_READWRITE
|
||||
* - other error codes from the underlying storage driver
|
||||
*
|
||||
* @return unique pointer of an nvs handle on success, an empty unique pointer otherwise
|
||||
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include "nvs_partition.hpp"
|
||||
@ -74,4 +66,9 @@ uint32_t NVSPartition::get_size()
|
||||
return mESPPartition->size;
|
||||
}
|
||||
|
||||
bool NVSPartition::get_readonly()
|
||||
{
|
||||
return mESPPartition->readonly;
|
||||
}
|
||||
|
||||
} // nvs
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -99,6 +99,11 @@ public:
|
||||
*/
|
||||
uint32_t get_size() override;
|
||||
|
||||
/**
|
||||
* @return true if the partition is read-only.
|
||||
*/
|
||||
bool get_readonly() override;
|
||||
|
||||
protected:
|
||||
const esp_partition_t* mESPPartition;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -192,6 +192,11 @@ esp_err_t NVSPartitionManager::open_handle(const char *part_name,
|
||||
return ESP_ERR_NVS_PART_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (open_mode == NVS_READWRITE && const_cast<Partition*>(sHandle->getPart())->get_readonly()) {
|
||||
return ESP_ERR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t err = sHandle->createOrOpenNamespace(ns_name, open_mode == NVS_READWRITE, nsIndex);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef PARTITION_HPP_
|
||||
#define PARTITION_HPP_
|
||||
@ -52,6 +44,11 @@ public:
|
||||
* Return the partition size in bytes.
|
||||
*/
|
||||
virtual uint32_t get_size() = 0;
|
||||
|
||||
/**
|
||||
* Return true if the partition is read-only.
|
||||
*/
|
||||
virtual bool get_readonly() = 0;
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "nvs_partition.hpp"
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
@ -27,6 +19,7 @@ public:
|
||||
assert(partition_name);
|
||||
assert(flash_emu);
|
||||
assert(size);
|
||||
readonly = false;
|
||||
}
|
||||
|
||||
const char *get_partition_name() override
|
||||
@ -101,6 +94,11 @@ public:
|
||||
return size;
|
||||
}
|
||||
|
||||
bool get_readonly() override
|
||||
{
|
||||
return readonly;
|
||||
}
|
||||
|
||||
private:
|
||||
const char *partition_name;
|
||||
|
||||
@ -109,6 +107,8 @@ private:
|
||||
uint32_t address;
|
||||
|
||||
uint32_t size;
|
||||
|
||||
bool readonly;
|
||||
};
|
||||
|
||||
struct PartitionEmulationFixture {
|
||||
|
@ -7,7 +7,7 @@
|
||||
# See https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/partition-tables.html
|
||||
# for explanation of partition table structure and uses.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import division, print_function, unicode_literals
|
||||
@ -32,7 +32,7 @@ SECURE_NONE = None
|
||||
SECURE_V1 = 'v1'
|
||||
SECURE_V2 = 'v2'
|
||||
|
||||
__version__ = '1.2'
|
||||
__version__ = '1.3'
|
||||
|
||||
APP_TYPE = 0x00
|
||||
DATA_TYPE = 0x01
|
||||
@ -341,7 +341,8 @@ class PartitionDefinition(object):
|
||||
# dictionary maps flag name (as used in CSV flags list, property name)
|
||||
# to bit set in flags words in binary format
|
||||
FLAGS = {
|
||||
'encrypted': 0
|
||||
'encrypted': 0,
|
||||
'readonly': 1
|
||||
}
|
||||
|
||||
# add subtypes for the 16 OTA slot values ("ota_XX, etc.")
|
||||
@ -355,6 +356,7 @@ class PartitionDefinition(object):
|
||||
self.offset = None
|
||||
self.size = None
|
||||
self.encrypted = False
|
||||
self.readonly = False
|
||||
|
||||
@classmethod
|
||||
def from_csv(cls, line, line_no):
|
||||
@ -454,6 +456,11 @@ class PartitionDefinition(object):
|
||||
critical("WARNING: Partition has name '%s' which is a partition subtype, but this partition has "
|
||||
'non-matching type 0x%x and subtype 0x%x. Mistake in partition table?' % (self.name, self.type, self.subtype))
|
||||
|
||||
always_rw_data_subtypes = [SUBTYPES[DATA_TYPE]['ota'], SUBTYPES[DATA_TYPE]['coredump']]
|
||||
if self.type == TYPES['data'] and self.subtype in always_rw_data_subtypes and self.readonly is True:
|
||||
raise ValidationError(self, "'%s' partition of type %s and subtype %s is always read-write and cannot be read-only" %
|
||||
(self.name, self.type, self.subtype))
|
||||
|
||||
STRUCT_FORMAT = b'<2sBBLL16sL'
|
||||
|
||||
@classmethod
|
||||
|
@ -3,7 +3,7 @@
|
||||
# parttool is used to perform partition level operations - reading,
|
||||
# writing, erasing and getting info about the partition.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
from __future__ import division, print_function
|
||||
|
||||
@ -16,7 +16,7 @@ import tempfile
|
||||
|
||||
import gen_esp32part as gen
|
||||
|
||||
__version__ = '2.0'
|
||||
__version__ = '2.1'
|
||||
|
||||
COMPONENTS_PATH = os.path.expandvars(os.path.join('$IDF_PATH', 'components'))
|
||||
ESPTOOL_PY = os.path.join(COMPONENTS_PATH, 'esptool_py', 'esptool', 'esptool.py')
|
||||
@ -159,10 +159,13 @@ class ParttoolTarget():
|
||||
self._call_esptool(['read_flash', str(partition.offset), str(partition.size), output] + self.esptool_read_args)
|
||||
|
||||
def write_partition(self, partition_id, input):
|
||||
self.erase_partition(partition_id)
|
||||
|
||||
partition = self.get_partition_info(partition_id)
|
||||
|
||||
if partition.readonly:
|
||||
raise Exception(f'"{partition.name}" partition is read-only')
|
||||
|
||||
self.erase_partition(partition_id)
|
||||
|
||||
with open(input, 'rb') as input_file:
|
||||
content_len = len(input_file.read())
|
||||
|
||||
@ -209,7 +212,8 @@ def _get_partition_info(target, partition_id, info):
|
||||
'subtype': '{}'.format(p.subtype),
|
||||
'offset': '0x{:x}'.format(p.offset),
|
||||
'size': '0x{:x}'.format(p.size),
|
||||
'encrypted': '{}'.format(p.encrypted)
|
||||
'encrypted': '{}'.format(p.encrypted),
|
||||
'readonly': '{}'.format(p.readonly)
|
||||
}
|
||||
for i in info:
|
||||
infos += [info_dict[i]]
|
||||
@ -269,7 +273,8 @@ def main():
|
||||
|
||||
print_partition_info_subparser = subparsers.add_parser('get_partition_info', help='get partition information', parents=[partition_selection_parser])
|
||||
print_partition_info_subparser.add_argument('--info', help='type of partition information to get',
|
||||
choices=['name', 'type', 'subtype', 'offset', 'size', 'encrypted'], default=['offset', 'size'], nargs='+')
|
||||
choices=['name', 'type', 'subtype', 'offset', 'size', 'encrypted', 'readonly'],
|
||||
default=['offset', 'size'], nargs='+')
|
||||
print_partition_info_subparser.add_argument('--part_list', help='Get a list of partitions suitable for a given type', action='store_true')
|
||||
|
||||
args = parser.parse_args()
|
||||
@ -329,10 +334,10 @@ def main():
|
||||
# Create the operation table and execute the operation
|
||||
common_args = {'target':target, 'partition_id':partition_id}
|
||||
parttool_ops = {
|
||||
'erase_partition':(_erase_partition, []),
|
||||
'read_partition':(_read_partition, ['output']),
|
||||
'write_partition':(_write_partition, ['input']),
|
||||
'get_partition_info':(_get_partition_info, ['info'])
|
||||
'erase_partition': (_erase_partition, []),
|
||||
'read_partition': (_read_partition, ['output']),
|
||||
'write_partition': (_write_partition, ['input']),
|
||||
'get_partition_info': (_get_partition_info, ['info'])
|
||||
}
|
||||
|
||||
(op, op_args) = parttool_ops[args.operation]
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -47,25 +47,26 @@ DRAM_ATTR static const char TAG[] = "spi_flash";
|
||||
/* CHECK_WRITE_ADDRESS macro to fail writes which land in the
|
||||
bootloader, partition table, or running application region.
|
||||
*/
|
||||
#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
|
||||
#define CHECK_WRITE_ADDRESS(CHIP, ADDR, SIZE)
|
||||
#else /* FAILS or ABORTS */
|
||||
#define CHECK_WRITE_ADDRESS(CHIP, ADDR, SIZE) do { \
|
||||
if (CHIP && CHIP->os_func->region_protected && CHIP->os_func->region_protected(CHIP->os_func_data, ADDR, SIZE)) { \
|
||||
UNSAFE_WRITE_ADDRESS; \
|
||||
} \
|
||||
#define CHECK_WRITE_ADDRESS(CHIP, ADDR, SIZE) do { \
|
||||
if (CHIP && CHIP->os_func->region_protected) { \
|
||||
esp_err_t ret = CHIP->os_func->region_protected(CHIP->os_func_data, ADDR, SIZE); \
|
||||
if (ret == ESP_ERR_NOT_ALLOWED) { \
|
||||
return ret; /* ESP_ERR_NOT_ALLOWED from read-only partition check */ \
|
||||
} else if (ret != ESP_OK) { \
|
||||
UNSAFE_WRITE_ADDRESS; /* FAILS or ABORTS */ \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
#endif // CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
|
||||
|
||||
/* Convenience macro for beginning of all API functions.
|
||||
* Check the return value of `rom_spiflash_api_funcs->chip_check` is correct,
|
||||
* and the chip supports the operation in question.
|
||||
*/
|
||||
#define VERIFY_CHIP_OP(op) do { \
|
||||
#define VERIFY_CHIP_OP(op) do { \
|
||||
if (err != ESP_OK) return err; \
|
||||
if (chip->chip_drv->op == NULL) { \
|
||||
return ESP_ERR_FLASH_UNSUPPORTED_CHIP; \
|
||||
} \
|
||||
if (chip->chip_drv->op == NULL) { \
|
||||
return ESP_ERR_FLASH_UNSUPPORTED_CHIP; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -191,6 +191,7 @@ esp_err_t esp_flash_read_unique_chip_id(esp_flash_t *chip, uint64_t *out_id);
|
||||
* @return
|
||||
* - ESP_OK on success,
|
||||
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
|
||||
* - ESP_ERR_NOT_ALLOWED if a read-only partition is present.
|
||||
* - Other flash error code if operation failed.
|
||||
*/
|
||||
esp_err_t esp_flash_erase_chip(esp_flash_t *chip);
|
||||
@ -211,6 +212,7 @@ esp_err_t esp_flash_erase_chip(esp_flash_t *chip);
|
||||
* @return
|
||||
* - ESP_OK on success,
|
||||
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
|
||||
* - ESP_ERR_NOT_ALLOWED if the address range (start -- start + len) overlaps with a read-only partition address space
|
||||
* - Other flash error code if operation failed.
|
||||
*/
|
||||
esp_err_t esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len);
|
||||
@ -316,9 +318,10 @@ esp_err_t esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint
|
||||
* There are no alignment constraints on buffer, address or length.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success,
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL, bad write, this will be detected only when CONFIG_SPI_FLASH_VERIFY_WRITE is enabled
|
||||
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
|
||||
* - ESP_ERR_NOT_ALLOWED if the address range (address -- address + length) overlaps with a read-only partition address space
|
||||
* - Other flash error code if operation failed.
|
||||
*/
|
||||
esp_err_t esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
|
||||
@ -337,6 +340,7 @@ esp_err_t esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t addres
|
||||
* - ESP_FAIL: bad write, this will be detected only when CONFIG_SPI_FLASH_VERIFY_WRITE is enabled
|
||||
* - ESP_ERR_NOT_SUPPORTED: encrypted write not supported for this chip.
|
||||
* - ESP_ERR_INVALID_ARG: Either the address, buffer or length is invalid.
|
||||
* - ESP_ERR_NOT_ALLOWED if the address range (address -- address + length) overlaps with a read-only partition address space
|
||||
*/
|
||||
esp_err_t esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length);
|
||||
|
||||
|
@ -206,15 +206,20 @@ static IRAM_ATTR void release_buffer_malloc(void* arg, void *temp_buf)
|
||||
|
||||
static IRAM_ATTR esp_err_t main_flash_region_protected(void* arg, size_t start_addr, size_t size)
|
||||
{
|
||||
if (!esp_partition_is_flash_region_writable(start_addr, size)) {
|
||||
return ESP_ERR_NOT_ALLOWED;
|
||||
}
|
||||
#if !CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
|
||||
if (((app_func_arg_t*)arg)->no_protect || esp_partition_main_flash_region_safe(start_addr, size)) {
|
||||
//ESP_OK = 0, also means protected==0
|
||||
return ESP_OK;
|
||||
} else {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
#endif // !CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static IRAM_ATTR void main_flash_op_status(uint32_t op_status)
|
||||
{
|
||||
bool is_erasing = op_status & SPI_FLASH_OS_IS_ERASING_STATUS_FLAG;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -402,8 +402,24 @@ esp_err_t esp_spiffs_gc(const char* partition_label, size_t size_to_gc)
|
||||
esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf)
|
||||
{
|
||||
assert(conf->base_path);
|
||||
|
||||
esp_err_t err = esp_spiffs_init(conf);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int index;
|
||||
if (esp_spiffs_by_label(conf->partition_label, &index) != ESP_OK) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
int vfs_flags = ESP_VFS_FLAG_CONTEXT_PTR;
|
||||
if (_efs[index]->partition->readonly) {
|
||||
vfs_flags |= ESP_VFS_FLAG_READONLY_FS;
|
||||
}
|
||||
|
||||
const esp_vfs_t vfs = {
|
||||
.flags = ESP_VFS_FLAG_CONTEXT_PTR,
|
||||
.flags = vfs_flags,
|
||||
.write_p = &vfs_spiffs_write,
|
||||
.lseek_p = &vfs_spiffs_lseek,
|
||||
.read_p = &vfs_spiffs_read,
|
||||
@ -433,16 +449,6 @@ esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf)
|
||||
#endif // CONFIG_VFS_SUPPORT_DIR
|
||||
};
|
||||
|
||||
esp_err_t err = esp_spiffs_init(conf);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int index;
|
||||
if (esp_spiffs_by_label(conf->partition_label, &index) != ESP_OK) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
strlcat(_efs[index]->base_path, conf->base_path, ESP_VFS_PATH_MAX + 1);
|
||||
err = esp_vfs_register(conf->base_path, &vfs, _efs[index]);
|
||||
if (err != ESP_OK) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -53,6 +53,11 @@ extern "C" {
|
||||
*/
|
||||
#define ESP_VFS_FLAG_CONTEXT_PTR 1
|
||||
|
||||
/**
|
||||
* Flag which indicates that FS is located on read-only partition.
|
||||
*/
|
||||
#define ESP_VFS_FLAG_READONLY_FS 2
|
||||
|
||||
/*
|
||||
* @brief VFS identificator used for esp_vfs_register_with_id()
|
||||
*/
|
||||
@ -91,7 +96,7 @@ typedef struct
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int flags; /*!< ESP_VFS_FLAG_CONTEXT_PTR or ESP_VFS_FLAG_DEFAULT */
|
||||
int flags; /*!< ESP_VFS_FLAG_CONTEXT_PTR and/or ESP_VFS_FLAG_READONLY_FS or ESP_VFS_FLAG_DEFAULT */
|
||||
union {
|
||||
ssize_t (*write_p)(void* p, int fd, const void * data, size_t size); /*!< Write with context pointer */
|
||||
ssize_t (*write)(int fd, const void * data, size_t size); /*!< Write without context pointer */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -270,6 +270,29 @@ esp_err_t esp_vfs_unregister_fd(esp_vfs_id_t vfs_id, int fd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set ESP_VFS_FLAG_READONLY_FS read-only flag for a registered virtual filesystem
|
||||
* for given path prefix. Should be only called from the esp_vfs_*filesystem* register
|
||||
* or helper mount functions where vfs_t is not available to set the read-only
|
||||
* flag directly (e.g. esp_vfs_fat_spiflash_mount_rw_wl).
|
||||
*/
|
||||
esp_err_t esp_vfs_set_readonly_flag(const char* base_path)
|
||||
{
|
||||
const size_t base_path_len = strlen(base_path);
|
||||
for (size_t i = 0; i < s_vfs_count; ++i) {
|
||||
vfs_entry_t* vfs = s_vfs[i];
|
||||
if (vfs == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (base_path_len == vfs->path_prefix_len &&
|
||||
memcmp(base_path, vfs->path_prefix, vfs->path_prefix_len) == 0) {
|
||||
vfs->vfs.flags |= ESP_VFS_FLAG_READONLY_FS;
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
const vfs_entry_t *get_vfs_for_index(int index)
|
||||
{
|
||||
if (index < 0 || index >= s_vfs_count) {
|
||||
@ -401,6 +424,12 @@ const vfs_entry_t* get_vfs_for_path(const char* path)
|
||||
ret = (*pvfs->vfs.func)(__VA_ARGS__);\
|
||||
}
|
||||
|
||||
#define CHECK_VFS_READONLY_FLAG(flags) \
|
||||
if (flags & ESP_VFS_FLAG_READONLY_FS) { \
|
||||
__errno_r(r) = EROFS; \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
int esp_vfs_open(struct _reent *r, const char * path, int flags, int mode)
|
||||
{
|
||||
const vfs_entry_t *vfs = get_vfs_for_path(path);
|
||||
@ -408,6 +437,14 @@ int esp_vfs_open(struct _reent *r, const char * path, int flags, int mode)
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int acc_mode = flags & O_ACCMODE;
|
||||
int ro_filesystem = vfs->vfs.flags & ESP_VFS_FLAG_READONLY_FS;
|
||||
if (acc_mode != O_RDONLY && ro_filesystem) {
|
||||
__errno_r(r) = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *path_within_vfs = translate_path(vfs, path);
|
||||
int fd_within_vfs;
|
||||
CHECK_AND_CALL(fd_within_vfs, r, vfs, open, path_within_vfs, flags, mode);
|
||||
@ -621,6 +658,9 @@ int esp_vfs_link(struct _reent *r, const char* n1, const char* n2)
|
||||
__errno_r(r) = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK_VFS_READONLY_FLAG(vfs2->vfs.flags);
|
||||
|
||||
const char* path1_within_vfs = translate_path(vfs, n1);
|
||||
const char* path2_within_vfs = translate_path(vfs, n2);
|
||||
int ret;
|
||||
@ -635,6 +675,9 @@ int esp_vfs_unlink(struct _reent *r, const char *path)
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK_VFS_READONLY_FLAG(vfs->vfs.flags);
|
||||
|
||||
const char* path_within_vfs = translate_path(vfs, path);
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, unlink, path_within_vfs);
|
||||
@ -648,11 +691,17 @@ int esp_vfs_rename(struct _reent *r, const char *src, const char *dst)
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK_VFS_READONLY_FLAG(vfs->vfs.flags);
|
||||
|
||||
const vfs_entry_t* vfs_dst = get_vfs_for_path(dst);
|
||||
if (vfs != vfs_dst) {
|
||||
__errno_r(r) = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK_VFS_READONLY_FLAG(vfs_dst->vfs.flags);
|
||||
|
||||
const char* src_within_vfs = translate_path(vfs, src);
|
||||
const char* dst_within_vfs = translate_path(vfs, dst);
|
||||
int ret;
|
||||
@ -753,6 +802,9 @@ int esp_vfs_mkdir(const char* name, mode_t mode)
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK_VFS_READONLY_FLAG(vfs->vfs.flags);
|
||||
|
||||
const char* path_within_vfs = translate_path(vfs, name);
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, mkdir, path_within_vfs, mode);
|
||||
@ -767,6 +819,9 @@ int esp_vfs_rmdir(const char* name)
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK_VFS_READONLY_FLAG(vfs->vfs.flags);
|
||||
|
||||
const char* path_within_vfs = translate_path(vfs, name);
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, rmdir, path_within_vfs);
|
||||
@ -796,6 +851,9 @@ int esp_vfs_truncate(const char *path, off_t length)
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK_VFS_READONLY_FLAG(vfs->vfs.flags);
|
||||
|
||||
const char* path_within_vfs = translate_path(vfs, path);
|
||||
CHECK_AND_CALL(ret, r, vfs, truncate, path_within_vfs, length);
|
||||
return ret;
|
||||
@ -810,6 +868,9 @@ int esp_vfs_ftruncate(int fd, off_t length)
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHECK_VFS_READONLY_FLAG(vfs->vfs.flags);
|
||||
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, ftruncate, local_fd, length);
|
||||
return ret;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -22,7 +22,7 @@ public :
|
||||
WL_Flash();
|
||||
~WL_Flash() override;
|
||||
|
||||
virtual esp_err_t config(wl_config_t *cfg, Partition *flash_drv);
|
||||
virtual esp_err_t config(wl_config_t *cfg, Partition *partition);
|
||||
virtual esp_err_t init();
|
||||
|
||||
size_t get_flash_size() override;
|
||||
|
@ -174,10 +174,12 @@ esp_err_t wl_unmount(wl_handle_t handle)
|
||||
_lock_acquire(&s_instances_lock);
|
||||
result = check_handle(handle, __func__);
|
||||
if (result == ESP_OK) {
|
||||
// We have to flush state of the component
|
||||
result = s_instances[handle].instance->flush();
|
||||
// We use placement new in wl_mount, so call destructor directly
|
||||
Partition *part = s_instances[handle].instance->get_part();
|
||||
// We have to flush state of the component
|
||||
if (!part->is_readonly()) {
|
||||
result = s_instances[handle].instance->flush();
|
||||
}
|
||||
part->~Partition();
|
||||
free(part);
|
||||
s_instances[handle].instance->~WL_Flash();
|
||||
|
@ -166,11 +166,21 @@ If you want the partitions in the partition table to work relative to any placem
|
||||
Flags
|
||||
~~~~~
|
||||
|
||||
Only one flag is currently supported, ``encrypted``. If this field is set to ``encrypted``, this partition will be encrypted if :doc:`/security/flash-encryption` is enabled.
|
||||
Two flags are currently supported, ``encrypted`` and ``readonly``:
|
||||
|
||||
- If ``encrypted`` flag is set, the partition will be encrypted if :doc:`/security/flash-encryption` is enabled.
|
||||
|
||||
.. note::
|
||||
.. note::
|
||||
|
||||
``app`` type partitions will always be encrypted, regardless of whether this flag is set or not.
|
||||
``app`` type partitions will always be encrypted, regardless of whether this flag is set or not.
|
||||
|
||||
- If ``readonly`` flag is set, the partition will be read-only. This flag is only supported for ``data`` type partitions except ``ota``` and ``coredump``` subtypes. This flag can help to protect against the accidental writes to partition that contains critical device specific configuration data, e.g., factory data partition.
|
||||
|
||||
.. note::
|
||||
|
||||
Using C file I/O API to open a file (``fopen```) in any write mode (``w``, ``w+``, ``a``, ``a+``, ``r+``) will fail and return ``NULL``. Using ``open`` with any other flag than ``O_RDONLY`` will fail and return ``-1`` while ``errno`` global variable will be set to ``EACCES``. This is also true for any other POSIX syscall function performing write or erase operations. Opening a handle in read-write mode for NVS on a read-only partition will fail and return :c:macro:`ESP_ERR_NOT_ALLOWED` error code. Using a lower level API like ``esp_partition``, ``spi_flash``, ``wear_levelling``, etc. to write to a read-only partition will result in :c:macro:`ESP_ERR_NOT_ALLOWED` error code.
|
||||
|
||||
You can specify multiple flags by separating them with a colon. For example, ``encrypted:readonly``.
|
||||
|
||||
Generating Binary Partition Table
|
||||
---------------------------------
|
||||
|
@ -591,16 +591,13 @@ components/nvs_flash/src/nvs_handle_locked.cpp
|
||||
components/nvs_flash/src/nvs_handle_locked.hpp
|
||||
components/nvs_flash/src/nvs_item_hash_list.cpp
|
||||
components/nvs_flash/src/nvs_pagemanager.hpp
|
||||
components/nvs_flash/src/nvs_partition.cpp
|
||||
components/nvs_flash/src/nvs_partition_lookup.cpp
|
||||
components/nvs_flash/src/nvs_partition_lookup.hpp
|
||||
components/nvs_flash/src/nvs_platform.hpp
|
||||
components/nvs_flash/src/nvs_test_api.h
|
||||
components/nvs_flash/src/nvs_types.cpp
|
||||
components/nvs_flash/src/partition.hpp
|
||||
components/nvs_flash/test_nvs_host/main.cpp
|
||||
components/nvs_flash/test_nvs_host/sdkconfig.h
|
||||
components/nvs_flash/test_nvs_host/test_fixtures.hpp
|
||||
components/nvs_flash/test_nvs_host/test_intrusive_list.cpp
|
||||
components/protocomm/include/transports/protocomm_console.h
|
||||
components/protocomm/include/transports/protocomm_httpd.h
|
||||
|
@ -74,6 +74,23 @@ tools/test_apps/security/signed_app_no_secure_boot:
|
||||
temporary: true
|
||||
reason: No need to test on all targets
|
||||
|
||||
tools/test_apps/storage/partition_table_readonly:
|
||||
disable_test:
|
||||
- if: IDF_TARGET not in ["esp32", "esp32c3"]
|
||||
reason: these chips should be sufficient for test coverage (Xtensa and RISC-V, single and dual core)
|
||||
disable:
|
||||
- if: CONFIG_NAME == "encrypted"
|
||||
temporary: true
|
||||
reason: there are potential bugs with pytest when using flash encryption and NVS partition with nvs_create_partition_image #TODO: IDF-8300
|
||||
depends_components:
|
||||
- partition_table
|
||||
- spi_flash
|
||||
- esp_partition
|
||||
- nvs_flash
|
||||
- vfs
|
||||
- fatfs
|
||||
- spiffs
|
||||
|
||||
tools/test_apps/system/bootloader_sections:
|
||||
disable:
|
||||
- if: IDF_TARGET == "esp32c2"
|
||||
|
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(test_partition_table_readonly)
|
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
@ -0,0 +1 @@
|
||||
This is a file cointained in the generated filesystem image on the host and flashed to the ESP device
|
@ -0,0 +1,16 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
set(nvs_partition_name nvs_ro)
|
||||
set(nvs_data_csv ../nvs_data.csv)
|
||||
nvs_create_partition_image(${nvs_partition_name} ${nvs_data_csv} FLASH_IN_PROJECT)
|
||||
|
||||
set(image ../filesystem_image)
|
||||
|
||||
set(fatfs_wl_partition_name fatfs_ro)
|
||||
set(fatfs_raw_partition_name fatfs_raw_ro)
|
||||
fatfs_create_spiflash_image(${fatfs_wl_partition_name} ${image} FLASH_IN_PROJECT)
|
||||
fatfs_create_rawflash_image(${fatfs_raw_partition_name} ${image} FLASH_IN_PROJECT)
|
||||
|
||||
set(spiffs_partition_name spiffs_ro)
|
||||
spiffs_create_partition_image(${spiffs_partition_name} ${image} FLASH_IN_PROJECT)
|
359
tools/test_apps/storage/partition_table_readonly/main/main.c
Normal file
359
tools/test_apps/storage/partition_table_readonly/main/main.c
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_attr.h>
|
||||
#include "esp_flash.h"
|
||||
#include <esp_partition.h>
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
static const char* TAG = "test_readonly_partition_feature";
|
||||
|
||||
#define NUM_OF_READONLY_PARTITIONS 4
|
||||
const esp_partition_t* readonly_partitions[NUM_OF_READONLY_PARTITIONS];
|
||||
|
||||
// Partition names
|
||||
const char *nvs_partition_name = "nvs_ro";
|
||||
const char *fatfs_wl_partition_name = "fatfs_ro";
|
||||
const char *fatfs_raw_partition_name = "fatfs_raw_ro";
|
||||
const char *spiffs_partition_name = "spiffs_ro";
|
||||
|
||||
// Mount paths for partitions
|
||||
#define FATFS_WL_BASE_PATH "/fatfs_wl"
|
||||
#define FATFS_RAW_BASE_PATH "/fatfs_raw"
|
||||
#define SPIFFS_BASE_PATH "/spiffs"
|
||||
|
||||
// Handle of the wear levelling library instance
|
||||
static wl_handle_t s_wl_handle = WL_INVALID_HANDLE;
|
||||
|
||||
// Data in each filesystem partition
|
||||
const char* cmp_string = "This is a file cointained in the generated filesystem image on the host and flashed to the ESP device";
|
||||
#define CMP_STRING_LEN 102 // 101 + '\0'
|
||||
|
||||
static void fill_array_of_readonly_data_partitions(void)
|
||||
{
|
||||
// This finds read-only partitions defined in the partition table
|
||||
const esp_partition_t* part_nvs = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
|
||||
ESP_PARTITION_SUBTYPE_ANY, nvs_partition_name);
|
||||
const esp_partition_t* part_fatfs_wl = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
|
||||
ESP_PARTITION_SUBTYPE_ANY, fatfs_wl_partition_name);
|
||||
const esp_partition_t* part_fatfs_raw = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
|
||||
ESP_PARTITION_SUBTYPE_ANY, fatfs_raw_partition_name);
|
||||
const esp_partition_t* part_spiffs = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
|
||||
ESP_PARTITION_SUBTYPE_ANY, spiffs_partition_name);
|
||||
TEST_ASSERT_NOT_NULL(part_nvs); // NULL means partition table set wrong
|
||||
TEST_ASSERT_NOT_NULL(part_fatfs_wl);
|
||||
TEST_ASSERT_NOT_NULL(part_fatfs_raw);
|
||||
TEST_ASSERT_NOT_NULL(part_spiffs);
|
||||
|
||||
readonly_partitions[0] = part_nvs;
|
||||
readonly_partitions[1] = part_fatfs_wl;
|
||||
readonly_partitions[2] = part_fatfs_raw;
|
||||
readonly_partitions[3] = part_spiffs;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define TARGET_CRYPT_CNT_EFUSE ESP_EFUSE_FLASH_CRYPT_CNT
|
||||
#define TARGET_CRYPT_CNT_WIDTH 7
|
||||
#else
|
||||
#define TARGET_CRYPT_CNT_EFUSE ESP_EFUSE_SPI_BOOT_CRYPT_CNT
|
||||
#define TARGET_CRYPT_CNT_WIDTH 3
|
||||
#endif
|
||||
|
||||
static void example_print_flash_encryption_status(void)
|
||||
{
|
||||
uint32_t flash_crypt_cnt = 0;
|
||||
esp_efuse_read_field_blob(TARGET_CRYPT_CNT_EFUSE, &flash_crypt_cnt, TARGET_CRYPT_CNT_WIDTH);
|
||||
printf("FLASH_CRYPT_CNT eFuse value is %" PRIu32 "\n", flash_crypt_cnt);
|
||||
|
||||
esp_flash_enc_mode_t mode = esp_get_flash_encryption_mode();
|
||||
if (mode == ESP_FLASH_ENC_MODE_DISABLED) {
|
||||
printf("Flash encryption feature is disabled\n");
|
||||
} else {
|
||||
printf("Flash encryption feature is enabled in %s mode\n",
|
||||
mode == ESP_FLASH_ENC_MODE_DEVELOPMENT ? "DEVELOPMENT" : "RELEASE");
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
example_print_flash_encryption_status();
|
||||
fill_array_of_readonly_data_partitions();
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
TEST_CASE("Read-only partition - SPI flash API", "[spi_flash]")
|
||||
{
|
||||
esp_err_t err;
|
||||
char buf[11] = {0};
|
||||
const char some_data[] = "0123456789";
|
||||
for (int i = 0; i < NUM_OF_READONLY_PARTITIONS; i++) {
|
||||
const esp_partition_t *part = readonly_partitions[i];
|
||||
// Writing to the SPI flash on address overlapping read-only partition shouldn't be possible
|
||||
// and should return ESP_ERR_NOT_ALLOWED error
|
||||
err = esp_flash_write(part->flash_chip, some_data, part->address, strlen(some_data));
|
||||
ESP_LOGD(TAG, "Writing %u bytes to partition %s at 0x%lx, should return %s and returned %s (0x%x)",
|
||||
strlen(some_data), part->label, part->address, esp_err_to_name(ESP_ERR_NOT_ALLOWED), esp_err_to_name(err), err);
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_ALLOWED, err);
|
||||
|
||||
// Reading the SPI flash on address overlapping read-only partition should be possible without an error
|
||||
TEST_ESP_OK(esp_flash_read(part->flash_chip, &buf, part->address, strlen(some_data)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Read-only partition - Partition API", "[partition]")
|
||||
{
|
||||
esp_err_t err;
|
||||
// Writing to the partition should not be possible and should return ESP_ERR_NOT_ALLOWED error
|
||||
const char some_data[] = "0123456789";
|
||||
for (int i = 0; i < NUM_OF_READONLY_PARTITIONS; i++) {
|
||||
err = esp_partition_write(readonly_partitions[i], 0, some_data, strlen(some_data));
|
||||
ESP_LOGD(TAG, "esp_partition_write on readonly_partitions[%d] should return %s and returned %s (0x%x)",
|
||||
i, esp_err_to_name(ESP_ERR_NOT_ALLOWED), esp_err_to_name(err), err);
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_ALLOWED, err);
|
||||
}
|
||||
|
||||
// Reading the partition should be possible without an error
|
||||
char buf[strlen(some_data)];
|
||||
for (int i = 0; i < NUM_OF_READONLY_PARTITIONS; i++) {
|
||||
err = esp_partition_read(readonly_partitions[i], 0, buf, sizeof(buf));
|
||||
TEST_ESP_OK(err);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Read-only partition - NVS API", "[nvs]")
|
||||
{
|
||||
nvs_handle_t handle;
|
||||
esp_err_t err;
|
||||
|
||||
err = nvs_flash_init_partition(nvs_partition_name);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// NVS partition flagged as read-only should be possible to open in read-only mode
|
||||
err = nvs_open_from_partition(nvs_partition_name, "storage", NVS_READONLY, &handle);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// Read test
|
||||
int32_t i32_val = 0;
|
||||
err = nvs_get_i32(handle, "i32_key", &i32_val);
|
||||
TEST_ESP_OK(err);
|
||||
TEST_ASSERT_EQUAL(-2147483648, i32_val);
|
||||
nvs_close(handle);
|
||||
|
||||
// NVS partition flagged as read-only shouln't be possible to open in read-write mode
|
||||
err = nvs_open_from_partition(nvs_partition_name, "storage", NVS_READWRITE, &handle);
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_ALLOWED, err);
|
||||
nvs_close(handle);
|
||||
}
|
||||
|
||||
void test_c_api_common(const char* base_path)
|
||||
{
|
||||
char hello_txt[64];
|
||||
char new_txt[64];
|
||||
snprintf(hello_txt, sizeof(hello_txt), "%s%s", base_path, "/hello.txt");
|
||||
snprintf(new_txt, sizeof(new_txt), "%s%s", base_path, "/new.txt");
|
||||
|
||||
FILE *f;
|
||||
int fd, status;
|
||||
char buf[CMP_STRING_LEN] = {0};
|
||||
|
||||
// Test write mode is not possible
|
||||
f = fopen(hello_txt, "w");
|
||||
TEST_ASSERT_NULL(f);
|
||||
fd = open(hello_txt, O_CREAT|O_WRONLY, 0666);
|
||||
TEST_ASSERT_EQUAL(-1, fd);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
f = fopen(hello_txt, "w+");
|
||||
TEST_ASSERT_NULL(f);
|
||||
fd = open(hello_txt, O_CREAT|O_RDWR, 0666);
|
||||
TEST_ASSERT_EQUAL(-1, fd);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
f = fopen(hello_txt, "a");
|
||||
TEST_ASSERT_NULL(f);
|
||||
fd = open(hello_txt, O_CREAT|O_WRONLY|O_APPEND, 0666);
|
||||
TEST_ASSERT_EQUAL(-1, fd);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
f = fopen(hello_txt, "a+");
|
||||
TEST_ASSERT_NULL(f);
|
||||
fd = open(hello_txt, O_CREAT|O_RDWR|O_APPEND, 0666);
|
||||
TEST_ASSERT_EQUAL(-1, fd);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
f = fopen(hello_txt, "r+");
|
||||
TEST_ASSERT_NULL(f);
|
||||
fd = open(hello_txt, O_RDWR);
|
||||
TEST_ASSERT_EQUAL(-1, fd);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
fd = creat(new_txt, 0666); // == open(new_txt, O_WRONLY|O_CREAT|O_TRUNC, 0666)
|
||||
TEST_ASSERT_EQUAL(-1, fd);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
status = link(hello_txt, new_txt);
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
status = rename(hello_txt, new_txt);
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
status = unlink(hello_txt);
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
status = truncate(hello_txt, 10);
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
// Test read is still possible
|
||||
fd = open(hello_txt, O_RDONLY);
|
||||
TEST_ASSERT_GREATER_THAN(0, fd);
|
||||
|
||||
status = ftruncate(fd, 10);
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
close(fd);
|
||||
|
||||
f = fopen(hello_txt, "r");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
fread(buf, 1, sizeof(buf) - 1, f);
|
||||
ESP_LOGD(TAG, "Read from file: %s", buf);
|
||||
TEST_ASSERT_EQUAL(0, strcmp(buf, cmp_string));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
char str[] = "Should not be written";
|
||||
fseek(f, 0, SEEK_SET);
|
||||
status = fwrite(str, 1, sizeof(str), f); // Writing should do nothing
|
||||
TEST_ASSERT_EQUAL(0, status);
|
||||
TEST_ASSERT_EQUAL(EBADF, errno);
|
||||
|
||||
fread(buf, 1, sizeof(buf) - 1, f);
|
||||
ESP_LOGD(TAG, "Read from file: %s", buf);
|
||||
TEST_ASSERT_EQUAL(0, strcmp(buf, cmp_string)); // Test if the file content is still the same
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
TEST_CASE("Read-only partition - C file I/O API (using FATFS WL)", "[vfs][fatfs]")
|
||||
{
|
||||
const esp_vfs_fat_mount_config_t mount_config = {
|
||||
.max_files = 4,
|
||||
.format_if_mount_failed = false,
|
||||
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE
|
||||
};
|
||||
|
||||
esp_err_t err;
|
||||
int status;
|
||||
|
||||
err = esp_vfs_fat_spiflash_mount_rw_wl(FATFS_WL_BASE_PATH, fatfs_wl_partition_name, &mount_config, &s_wl_handle);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// FATFS WL itself is read-write capable, but we are restricting it to read-only mode via esp_partition layer
|
||||
// Opening a file in a write mode on read-only partition is checked in vfs
|
||||
|
||||
test_c_api_common(FATFS_WL_BASE_PATH);
|
||||
|
||||
// Test directories
|
||||
DIR *dir;
|
||||
status = mkdir(FATFS_WL_BASE_PATH "/dir1", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
dir = opendir(FATFS_WL_BASE_PATH "/dir1");
|
||||
TEST_ASSERT_NULL(dir);
|
||||
|
||||
status = rmdir(FATFS_WL_BASE_PATH "/dir");
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
dir = opendir(FATFS_WL_BASE_PATH "/dir");
|
||||
TEST_ASSERT_NOT_NULL(dir);
|
||||
closedir(dir);
|
||||
|
||||
TEST_ESP_OK(esp_vfs_fat_spiflash_unmount_rw_wl(FATFS_WL_BASE_PATH, s_wl_handle));
|
||||
}
|
||||
|
||||
TEST_CASE("Read-only partition - C file I/O API (using FATFS RAW)", "[vfs][fatfs]")
|
||||
{
|
||||
const esp_vfs_fat_mount_config_t mount_config = {
|
||||
.max_files = 4,
|
||||
.format_if_mount_failed = false,
|
||||
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE
|
||||
};
|
||||
|
||||
esp_err_t err;
|
||||
int status;
|
||||
|
||||
err = esp_vfs_fat_spiflash_mount_ro(FATFS_RAW_BASE_PATH, fatfs_raw_partition_name, &mount_config);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// FATFS RAW is read-only itself, but esp_parition read-only adds another layer
|
||||
// Opening a file in a write mode on read-only partition is checked in vfs
|
||||
|
||||
test_c_api_common(FATFS_RAW_BASE_PATH);
|
||||
|
||||
// Test directories
|
||||
DIR *dir;
|
||||
status = mkdir(FATFS_RAW_BASE_PATH "/dir1", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
dir = opendir(FATFS_RAW_BASE_PATH "/dir1");
|
||||
TEST_ASSERT_NULL(dir);
|
||||
|
||||
status = rmdir(FATFS_RAW_BASE_PATH "/dir");
|
||||
TEST_ASSERT_EQUAL(-1, status);
|
||||
TEST_ASSERT_EQUAL(EROFS, errno);
|
||||
|
||||
dir = opendir(FATFS_RAW_BASE_PATH "/dir");
|
||||
TEST_ASSERT_NOT_NULL(dir);
|
||||
closedir(dir);
|
||||
|
||||
TEST_ESP_OK(esp_vfs_fat_spiflash_unmount_ro(FATFS_RAW_BASE_PATH, fatfs_raw_partition_name));
|
||||
}
|
||||
|
||||
TEST_CASE("Read-only partition - C file I/O API (using SPIFFS)", "[vfs][spiffs]")
|
||||
{
|
||||
esp_vfs_spiffs_conf_t conf = {
|
||||
.base_path = SPIFFS_BASE_PATH,
|
||||
.partition_label = spiffs_partition_name,
|
||||
.max_files = 5,
|
||||
.format_if_mount_failed = false
|
||||
};
|
||||
|
||||
esp_err_t err;
|
||||
err = esp_vfs_spiffs_register(&conf);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// SPIFFS is read-write capable, but we are restricting it to read-only mode via esp_partition layer
|
||||
|
||||
test_c_api_common(SPIFFS_BASE_PATH);
|
||||
|
||||
// SPIFFS doesn't support directories
|
||||
|
||||
TEST_ESP_OK(esp_vfs_spiffs_unregister(spiffs_partition_name));
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
# Sample csv file
|
||||
key,type,encoding,value
|
||||
storage,namespace,,
|
||||
u8_key,data,u8,255
|
||||
i8_key,data,i8,-128
|
||||
u16_key,data,u16,65535
|
||||
u32_key,data,u32,4294967295
|
||||
i32_key,data,i32,-2147483648
|
||||
str_key,data,string,"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Fusce quis risus justo.
|
||||
Suspendisse egestas in nisi sit amet auctor.
|
||||
Pellentesque rhoncus dictum sodales.
|
||||
In justo erat, viverra at interdum eget, interdum vel dui."
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -0,0 +1,9 @@
|
||||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs_ro, data, nvs, , 0x4000, readonly
|
||||
nvs_key, data, nvs_keys, , 0x1000, encrypted
|
||||
phy_init, data, phy, , 0x1000,
|
||||
factory, app, factory, , 0x60000,
|
||||
fatfs_ro, data, fat, , 528K, readonly
|
||||
fatfs_raw_ro, data, fat, , 528K, encrypted:readonly
|
||||
spiffs_ro, data, spiffs, , 256K, readonly
|
|
@ -0,0 +1,31 @@
|
||||
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'default',
|
||||
],
|
||||
indirect=True)
|
||||
def test_partition_table_readonly(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases(timeout=120)
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.flash_encryption
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'encrypted',
|
||||
],
|
||||
indirect=True)
|
||||
def test_partition_table_readonly_flash_encryption(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases(timeout=120)
|
@ -0,0 +1 @@
|
||||
CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS=y
|
@ -0,0 +1,9 @@
|
||||
CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS=y
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_JTAG=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
|
||||
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
|
@ -0,0 +1,20 @@
|
||||
# General options for additional checks
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
|
||||
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
CONFIG_NVS_ASSERT_ERROR_CHECK=y
|
||||
|
||||
# Disable task watchdog since this app uses an interactive menu
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
|
||||
# SPIFFS configuration
|
||||
CONFIG_SPIFFS_USE_MTIME=n # Disable mtime update as the partition is read-only
|
||||
|
||||
# Custom partition table related
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
|
Loading…
Reference in New Issue
Block a user