项目文件夹

文件
2026-07-13 13:04:25 +08:00

250 行
7.7 KiB
C++

/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <new>
#include <sys/lock.h>
#include "wear_levelling.h"
#include "WL_Config.h"
#include "WL_Ext_Cfg.h"
#include "WL_Flash.h"
#include "WL_Ext_Perf.h"
#include "WL_Ext_Safe.h"
#include "BDL_Access.h"
#ifndef WL_DEFAULT_UPDATERATE
#define WL_DEFAULT_UPDATERATE 16
#endif
#ifndef WL_DEFAULT_TEMP_BUFF_SIZE
#define WL_DEFAULT_TEMP_BUFF_SIZE 32
#endif
#ifndef WL_DEFAULT_WRITE_SIZE
#define WL_DEFAULT_WRITE_SIZE 16
#endif
#ifndef WL_DEFAULT_START_ADDR
#define WL_DEFAULT_START_ADDR 0
#endif
#ifndef WL_CURRENT_VERSION
#define WL_CURRENT_VERSION 2
#endif
static const char *TAG = "wl_blockdev";
/* ========================================================================= */
/* BDL path – standalone WL instance, no wl_handle_t */
/* ========================================================================= */
typedef struct {
WL_Flash *wl_instance;
BDL_Access *bdl_access;
esp_blockdev_handle_t bottom_bdl;
_lock_t lock;
} wl_bdl_ctx_t;
static esp_err_t wl_bdl_read(esp_blockdev_handle_t dev, uint8_t *dst, size_t dst_size,
uint64_t src_addr, size_t len)
{
if (dst_size < len) {
return ESP_ERR_INVALID_ARG;
}
if (src_addr % dev->geometry.read_size != 0 || len % dev->geometry.read_size) {
return ESP_ERR_INVALID_SIZE;
}
wl_bdl_ctx_t *ctx = (wl_bdl_ctx_t *)dev->ctx;
_lock_acquire(&ctx->lock);
esp_err_t ret = ctx->wl_instance->read((size_t)src_addr, dst, len);
_lock_release(&ctx->lock);
return ret;
}
static esp_err_t wl_bdl_write(esp_blockdev_handle_t dev, const uint8_t *src,
uint64_t dst_addr, size_t len)
{
if (dst_addr % dev->geometry.write_size != 0 || len % dev->geometry.write_size) {
return ESP_ERR_INVALID_SIZE;
}
wl_bdl_ctx_t *ctx = (wl_bdl_ctx_t *)dev->ctx;
_lock_acquire(&ctx->lock);
esp_err_t ret = ctx->wl_instance->write((size_t)dst_addr, src, len);
_lock_release(&ctx->lock);
return ret;
}
static esp_err_t wl_bdl_erase(esp_blockdev_handle_t dev, uint64_t start, size_t len)
{
if (start % dev->geometry.erase_size != 0 || len % dev->geometry.erase_size) {
return ESP_ERR_INVALID_SIZE;
}
wl_bdl_ctx_t *ctx = (wl_bdl_ctx_t *)dev->ctx;
_lock_acquire(&ctx->lock);
esp_err_t ret = ctx->wl_instance->erase_range((size_t)start, len);
_lock_release(&ctx->lock);
return ret;
}
static esp_err_t wl_bdl_sync(esp_blockdev_handle_t dev)
{
wl_bdl_ctx_t *ctx = (wl_bdl_ctx_t *)dev->ctx;
_lock_acquire(&ctx->lock);
esp_err_t ret = ctx->wl_instance->flush();
_lock_release(&ctx->lock);
return ret;
}
static esp_err_t wl_bdl_ioctl(esp_blockdev_handle_t dev, const uint8_t cmd, void *args)
{
wl_bdl_ctx_t *ctx = (wl_bdl_ctx_t *)dev->ctx;
if (ctx->bottom_bdl == ESP_BLOCKDEV_HANDLE_INVALID) {
return ESP_ERR_NOT_ALLOWED;
}
if (ctx->bottom_bdl->ops->ioctl == NULL) {
return ESP_ERR_NOT_SUPPORTED;
}
return ctx->bottom_bdl->ops->ioctl(ctx->bottom_bdl, cmd, args);
}
static esp_err_t wl_bdl_release(esp_blockdev_handle_t dev)
{
wl_bdl_ctx_t *ctx = (wl_bdl_ctx_t *)dev->ctx;
if (ctx->wl_instance) {
if (!ctx->bdl_access->is_readonly()) {
ctx->wl_instance->flush();
}
ctx->wl_instance->~WL_Flash();
free(ctx->wl_instance);
}
if (ctx->bdl_access) {
ctx->bdl_access->~BDL_Access();
free(ctx->bdl_access);
}
_lock_close(&ctx->lock);
free(ctx);
free(dev);
return ESP_OK;
}
static const esp_blockdev_ops_t s_wl_bdl_ops = {
.read = wl_bdl_read,
.write = wl_bdl_write,
.erase = wl_bdl_erase,
.sync = wl_bdl_sync,
.ioctl = wl_bdl_ioctl,
.release = wl_bdl_release,
};
esp_err_t wl_get_blockdev(const esp_blockdev_handle_t bdl_bottom_device,
esp_blockdev_handle_t *out_bdl_handle_ptr)
{
if (bdl_bottom_device == ESP_BLOCKDEV_HANDLE_INVALID || out_bdl_handle_ptr == NULL) {
return ESP_ERR_INVALID_ARG;
}
*out_bdl_handle_ptr = ESP_BLOCKDEV_HANDLE_INVALID;
if (bdl_bottom_device->geometry.disk_size > UINT32_MAX) {
ESP_LOGE(TAG, "%s: disk_size 0x%016" PRIx64 " exceeds uint32_t range, "
"WL configuration would be silently truncated",
__func__, bdl_bottom_device->geometry.disk_size);
return ESP_ERR_INVALID_SIZE;
}
esp_err_t result = ESP_OK;
wl_bdl_ctx_t *ctx = (wl_bdl_ctx_t *)calloc(1, sizeof(wl_bdl_ctx_t));
if (!ctx) {
return ESP_ERR_NO_MEM;
}
ctx->bottom_bdl = bdl_bottom_device;
void *access_mem = malloc(sizeof(BDL_Access));
if (!access_mem) {
free(ctx);
return ESP_ERR_NO_MEM;
}
ctx->bdl_access = new (access_mem) BDL_Access(bdl_bottom_device);
void *wl_mem = NULL;
#if CONFIG_WL_SECTOR_SIZE == 512
#if CONFIG_WL_SECTOR_MODE == 1
wl_mem = malloc(sizeof(WL_Ext_Safe));
if (!wl_mem) { result = ESP_ERR_NO_MEM; goto fail; }
ctx->wl_instance = new (wl_mem) WL_Ext_Safe();
#else
wl_mem = malloc(sizeof(WL_Ext_Perf));
if (!wl_mem) { result = ESP_ERR_NO_MEM; goto fail; }
ctx->wl_instance = new (wl_mem) WL_Ext_Perf();
#endif
#endif
#if CONFIG_WL_SECTOR_SIZE == 4096
wl_mem = malloc(sizeof(WL_Flash));
if (!wl_mem) { result = ESP_ERR_NO_MEM; goto fail; }
ctx->wl_instance = new (wl_mem) WL_Flash();
#endif
{
wl_ext_cfg_t cfg;
cfg.wl_partition_start_addr = WL_DEFAULT_START_ADDR;
cfg.wl_partition_size = (uint32_t)bdl_bottom_device->geometry.disk_size;
cfg.wl_page_size = bdl_bottom_device->geometry.erase_size;
cfg.flash_sector_size = bdl_bottom_device->geometry.erase_size;
cfg.wl_update_rate = WL_DEFAULT_UPDATERATE;
cfg.wl_pos_update_record_size = WL_DEFAULT_WRITE_SIZE;
cfg.version = WL_CURRENT_VERSION;
cfg.wl_temp_buff_size = WL_DEFAULT_TEMP_BUFF_SIZE;
cfg.fat_sector_size = CONFIG_WL_SECTOR_SIZE;
result = ctx->wl_instance->config(&cfg, ctx->bdl_access);
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s: config failed, result=0x%x", __func__, result);
goto fail;
}
result = ctx->wl_instance->init();
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s: init failed, result=0x%x", __func__, result);
goto fail;
}
}
{
esp_blockdev_t *dev = (esp_blockdev_t *)calloc(1, sizeof(esp_blockdev_t));
if (!dev) { result = ESP_ERR_NO_MEM; goto fail; }
dev->ctx = ctx;
dev->ops = &s_wl_bdl_ops;
dev->device_flags = bdl_bottom_device->device_flags;
dev->geometry.disk_size = ctx->wl_instance->get_flash_size();
dev->geometry.read_size = bdl_bottom_device->geometry.read_size;
dev->geometry.write_size = bdl_bottom_device->geometry.write_size;
dev->geometry.erase_size = ctx->wl_instance->get_sector_size();
dev->geometry.recommended_read_size = bdl_bottom_device->geometry.recommended_read_size;
dev->geometry.recommended_write_size = bdl_bottom_device->geometry.recommended_write_size;
dev->geometry.recommended_erase_size = ctx->wl_instance->get_sector_size();
_lock_init(&ctx->lock);
*out_bdl_handle_ptr = dev;
}
return ESP_OK;
fail:
if (ctx->wl_instance) { ctx->wl_instance->~WL_Flash(); free(ctx->wl_instance); }
if (ctx->bdl_access) { ctx->bdl_access->~BDL_Access(); free(ctx->bdl_access); }
free(ctx);
return result;
}