Merge branch 'espressif:release/v5.5' into release/v5.5

This commit is contained in:
Jason2866
2025-12-27 19:07:02 +01:00
committed by GitHub
101 changed files with 2725 additions and 277 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ variables:
GIT_FETCH_EXTRA_FLAGS: "--no-recurse-submodules --prune --prune-tags"
# we're using .cache folder for caches
GIT_CLEAN_FLAGS: -ffdx -e .cache/
LATEST_GIT_TAG: v5.5.1
LATEST_GIT_TAG: v5.5.2
SUBMODULE_FETCH_TOOL: "tools/ci/ci_fetch_submodule.py"
# by default we will fetch all submodules
@@ -111,6 +111,10 @@ esp_err_t esp_ble_gap_start_advertising(esp_ble_adv_params_t *adv_params)
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (adv_params == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_ACT_START_ADV;
@@ -171,6 +175,10 @@ esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (remote_device == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_ACT_SET_PKT_DATA_LEN;
@@ -182,6 +190,9 @@ esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_
esp_err_t esp_ble_gap_addr_create_static(esp_bd_addr_t rand_addr)
{
if (rand_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
// Static device address: First two bits are '11', rest is random
rand_addr[0] = 0xC0 | (esp_random() & 0x3F);
for (int i = 1; i < 6; i++) {
@@ -192,6 +203,9 @@ esp_err_t esp_ble_gap_addr_create_static(esp_bd_addr_t rand_addr)
esp_err_t esp_ble_gap_addr_create_nrpa(esp_bd_addr_t rand_addr)
{
if (rand_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
// Non-resolvable private address: First two bits are '00', rest is random
rand_addr[0] = (esp_random() & 0x3F);
for (int i = 1; i < 6; i++) {
@@ -207,6 +221,10 @@ esp_err_t esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr)
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (rand_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_ACT_SET_RAND_ADDRESS;
@@ -239,7 +257,7 @@ esp_err_t esp_ble_gap_add_device_to_resolving_list(esp_bd_addr_t peer_addr, uint
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (addr_type > BLE_ADDR_TYPE_RANDOM ||!peer_addr || (addr_type && ((peer_addr[0] & 0xC0) != 0xC0))) {
if (addr_type > BLE_ADDR_TYPE_RANDOM || !peer_addr || !peer_irk || (addr_type && ((peer_addr[0] & 0xC0) != 0xC0))) {
return ESP_ERR_INVALID_ARG;
}
@@ -357,6 +375,10 @@ esp_err_t esp_ble_gap_set_prefer_conn_params(esp_bd_addr_t bd_addr,
return ESP_ERR_INVALID_STATE;
}
if (bd_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (ESP_BLE_IS_VALID_PARAM(min_conn_int, ESP_BLE_CONN_INT_MIN, ESP_BLE_CONN_INT_MAX) &&
ESP_BLE_IS_VALID_PARAM(max_conn_int, ESP_BLE_CONN_INT_MIN, ESP_BLE_CONN_INT_MAX) &&
ESP_BLE_IS_VALID_PARAM(supervision_tout, ESP_BLE_CONN_SUP_TOUT_MIN, ESP_BLE_CONN_SUP_TOUT_MAX) &&
@@ -424,6 +446,9 @@ esp_err_t esp_ble_gap_get_local_used_addr(esp_bd_addr_t local_used_addr, uint8_t
LOG_ERROR("%s, bluedroid status error", __func__);
return ESP_FAIL;
}
if (local_used_addr == NULL || addr_type == NULL) {
return ESP_ERR_INVALID_ARG;
}
if(!BTM_BleGetCurrentAddress(local_used_addr, addr_type)) {
return ESP_FAIL;
}
@@ -436,13 +461,6 @@ uint8_t *esp_ble_resolve_adv_data_by_type( uint8_t *adv_data, uint16_t adv_data_
return NULL;
}
if (((type < ESP_BLE_AD_TYPE_FLAG) || (type > ESP_BLE_AD_TYPE_128SERVICE_DATA)) &&
(type != ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE)) {
LOG_ERROR("The advertising data type is not defined, type = %x", type);
*length = 0;
return NULL;
}
if (adv_data_len == 0) {
*length = 0;
return NULL;
@@ -495,6 +513,10 @@ esp_err_t esp_ble_gap_read_rssi(esp_bd_addr_t remote_addr)
return ESP_ERR_INVALID_STATE;
}
if (remote_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_ACT_READ_RSSI;
@@ -645,6 +667,10 @@ esp_err_t esp_ble_set_encryption(esp_bd_addr_t bd_addr, esp_ble_sec_act_t sec_ac
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (bd_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_SET_ENCRYPTION_EVT;
@@ -662,6 +688,10 @@ esp_err_t esp_ble_gap_security_rsp(esp_bd_addr_t bd_addr, bool accept)
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (bd_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_SECURITY_RSP_EVT;
@@ -680,6 +710,10 @@ esp_err_t esp_ble_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t pas
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (bd_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_PASSKEY_REPLY_EVT;
@@ -698,6 +732,10 @@ esp_err_t esp_ble_confirm_reply(esp_bd_addr_t bd_addr, bool accept)
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (bd_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_CONFIRM_REPLY_EVT;
@@ -712,6 +750,11 @@ esp_err_t esp_ble_remove_bond_device(esp_bd_addr_t bd_addr)
{
btc_msg_t msg = {0};
btc_ble_gap_args_t arg;
if (bd_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_REMOVE_BOND_DEV_EVT;
@@ -757,6 +800,10 @@ esp_err_t esp_ble_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t *TK, uint8_t len)
return ESP_ERR_INVALID_ARG;
}
if (bd_addr == NULL || TK == NULL) {
return ESP_ERR_INVALID_ARG;
}
btc_msg_t msg = {0};
btc_ble_gap_args_t arg;
@@ -775,7 +822,7 @@ esp_err_t esp_ble_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t *TK, uint8_t len)
esp_err_t esp_ble_sc_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t p_c[16], uint8_t p_r[16])
{
if (!p_c || !p_r) {
if (!bd_addr || !p_c || !p_r) {
return ESP_ERR_INVALID_ARG;
}
@@ -836,6 +883,10 @@ esp_err_t esp_ble_gap_disconnect(esp_bd_addr_t remote_device)
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (remote_device == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_DISCONNECT_EVT;
@@ -864,6 +915,10 @@ esp_err_t esp_gap_ble_set_channels(esp_gap_ble_channels channels)
return ESP_ERR_INVALID_STATE;
}
if (channels == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_SET_AFH_CHANNELS;
@@ -173,6 +173,10 @@ esp_err_t esp_ble_gattc_enh_open(esp_gatt_if_t gattc_if, esp_ble_gatt_creat_conn
#if (BLE_42_FEATURE_SUPPORT == TRUE)
esp_err_t esp_ble_gattc_open(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, esp_ble_addr_type_t remote_addr_type, bool is_direct)
{
if (remote_bda == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_ble_gatt_creat_conn_params_t creat_conn_params = {0};
memcpy(creat_conn_params.remote_bda, remote_bda, ESP_BD_ADDR_LEN);
creat_conn_params.remote_addr_type = remote_addr_type;
@@ -187,6 +191,10 @@ esp_err_t esp_ble_gattc_open(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, e
#if (BLE_50_FEATURE_SUPPORT == TRUE)
esp_err_t esp_ble_gattc_aux_open(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, esp_ble_addr_type_t remote_addr_type, bool is_direct)
{
if (remote_bda == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_ble_gatt_creat_conn_params_t creat_conn_params = {0};
memcpy(creat_conn_params.remote_bda, remote_bda, ESP_BD_ADDR_LEN);
creat_conn_params.remote_addr_type = remote_addr_type;
@@ -521,6 +529,10 @@ esp_err_t esp_ble_gattc_read_multiple(esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (read_multi == NULL) {
return ESP_ERR_INVALID_ARG;
}
tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(conn_id);
if (!gatt_check_connection_state_by_tcb(p_tcb)) {
LOG_WARN("%s, The connection not created.", __func__);
@@ -557,6 +569,10 @@ esp_err_t esp_ble_gattc_read_multiple_variable(esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (read_multi == NULL) {
return ESP_ERR_INVALID_ARG;
}
tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(conn_id);
if (!gatt_check_connection_state_by_tcb(p_tcb)) {
LOG_WARN("%s, The connection not created.", __func__);
@@ -810,6 +826,10 @@ esp_err_t esp_ble_gattc_register_for_notify (esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (server_bda == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (handle == 0) {
return ESP_GATT_INVALID_HANDLE;
}
@@ -832,6 +852,10 @@ esp_err_t esp_ble_gattc_unregister_for_notify (esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (server_bda == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (handle == 0) {
return ESP_GATT_INVALID_HANDLE;
}
@@ -852,6 +876,10 @@ esp_err_t esp_ble_gattc_cache_refresh(esp_bd_addr_t remote_bda)
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (remote_bda == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GATTC;
msg.act = BTC_GATTC_ACT_CACHE_REFRESH;
@@ -867,6 +895,10 @@ esp_err_t esp_ble_gattc_cache_clean(esp_bd_addr_t remote_bda)
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (remote_bda == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GATTC;
msg.act = BTC_GATTC_ACT_CACHE_CLEAN;
@@ -882,6 +914,10 @@ esp_err_t esp_ble_gattc_cache_assoc(esp_gatt_if_t gattc_if, esp_bd_addr_t src_ad
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (src_addr == NULL || assoc_addr == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GATTC;
msg.act = BTC_GATTC_ACT_CACHE_ASSOC;
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -78,6 +78,10 @@ esp_err_t esp_ble_gatts_create_service(esp_gatt_if_t gatts_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (service_id == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GATTS;
msg.act = BTC_GATTS_ACT_CREATE_SERVICE;
@@ -98,6 +102,10 @@ esp_err_t esp_ble_gatts_create_attr_tab(const esp_gatts_attr_db_t *gatts_attr_db
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (gatts_attr_db == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (max_nb_attr > ESP_GATT_ATTR_HANDLE_MAX) {
LOG_ERROR("The number of attribute should not be greater than CONFIG_BT_GATT_MAX_SR_ATTRIBUTES\n");
return ESP_ERR_INVALID_ARG;
@@ -143,6 +151,10 @@ esp_err_t esp_ble_gatts_add_char(uint16_t service_handle, esp_bt_uuid_t *char_
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (char_uuid == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* parameter validation check */
status = esp_ble_gatts_add_char_desc_param_check(char_val, control);
if (status != ESP_OK){
@@ -183,6 +195,10 @@ esp_err_t esp_ble_gatts_add_char_descr (uint16_t service_handle,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (descr_uuid == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* parameter validation check */
status = esp_ble_gatts_add_char_desc_param_check(char_descr_val, control);
if (status != ESP_OK){
@@ -344,6 +360,10 @@ esp_gatt_status_t esp_ble_gatts_get_attr_value(uint16_t attr_handle, uint16_t *l
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (length == NULL || value == NULL) {
return ESP_GATT_INVALID_PDU;
}
if (attr_handle == ESP_GATT_ILLEGAL_HANDLE) {
*length = 0;
return ESP_GATT_INVALID_HANDLE;
@@ -359,6 +379,10 @@ esp_err_t esp_ble_gatts_open(esp_gatt_if_t gatts_if, esp_bd_addr_t remote_bda, b
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (remote_bda == NULL) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GATTS;
msg.act = BTC_GATTS_ACT_OPEN;
@@ -241,7 +241,7 @@ void BTA_GATTS_AddCharacteristic (UINT16 service_id, const tBT_UUID * p_char_u
p_buf->attr_val.attr_max_len = attr_val->attr_max_len;
p_buf->attr_val.attr_val = (uint8_t *)osi_malloc(len);
if(p_buf->attr_val.attr_val != NULL){
memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, attr_val->attr_len);
memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, len);
}
}
@@ -411,6 +411,14 @@ void BTA_GATTS_StopService(UINT16 service_id)
void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id, UINT16 data_len,
UINT8 *p_data, BOOLEAN need_confirm)
{
/* Validate data length against buffer size */
if (data_len > BTA_GATT_MAX_ATTR_LEN) {
APPL_TRACE_ERROR("GATT indication data too large: %u > %u",
data_len, BTA_GATT_MAX_ATTR_LEN);
return;
}
tBTA_GATTS_API_INDICATION *p_buf;
UINT16 len = sizeof(tBTA_GATTS_API_INDICATION);
@@ -89,6 +89,20 @@ void BTA_HdDisable(void)
******************************************************************************/
extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO *p_app_info, tBTA_HD_QOS_INFO *p_in_qos, tBTA_HD_QOS_INFO *p_out_qos)
{
/* Validate descriptor length before copying */
if (p_app_info->descriptor.dl_len > BTA_HD_APP_DESCRIPTOR_LEN) {
APPL_TRACE_ERROR("HID descriptor too large: %u > %u",
p_app_info->descriptor.dl_len, BTA_HD_APP_DESCRIPTOR_LEN);
return;
}
/* Validate descriptor data pointer */
if (p_app_info->descriptor.dl_len > 0 && p_app_info->descriptor.dsc_list == NULL) {
APPL_TRACE_ERROR("HID descriptor data NULL but length > 0: %u", p_app_info->descriptor.dl_len);
return;
}
tBTA_HD_REGISTER_APP *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_REGISTER_APP *)osi_malloc(sizeof(tBTA_HD_REGISTER_APP))) != NULL) {
@@ -158,6 +172,13 @@ extern void BTA_HdSendReport(tBTA_HD_REPORT *p_report)
__func__, p_report->len, BTA_HD_REPORT_LEN);
return;
}
/* Validate report data pointer */
if (p_report->len > 0 && p_report->p_data == NULL) {
APPL_TRACE_ERROR("HID report data pointer NULL but length > 0: %d", p_report->len);
return;
}
if ((p_buf = (tBTA_HD_SEND_REPORT *)osi_malloc(sizeof(tBTA_HD_SEND_REPORT))) != NULL) {
p_buf->hdr.event = BTA_HD_API_SEND_REPORT_EVT;
p_buf->use_intr = p_report->use_intr;
@@ -263,6 +263,18 @@ void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data, UINT8 *p_report,
UINT16 xx, yy, key_idx = 0;
UINT8 this_report[BTA_HH_MAX_RPT_CHARS];
/* Validate report length before processing */
if (report_len > BTA_HH_MAX_RPT_CHARS) {
APPL_TRACE_ERROR("HID report length exceeds maximum: %u > %u",
report_len, BTA_HH_MAX_RPT_CHARS);
return;
}
if (report_len == 0 || p_report == NULL) {
APPL_TRACE_ERROR("Invalid HID report data");
return;
}
#if BTA_HH_DEBUG
APPL_TRACE_DEBUG("bta_hh_parse_keybd_rpt: (report=%p, report_len=%d) called",
p_report, report_len);
@@ -463,7 +475,7 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status)
if (bta_hh_cb.p_cback) {
(*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
/* all connections are down, no waiting for diconnect */
/* all connections are down, no waiting for disconnect */
memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
}
}
@@ -16,7 +16,7 @@
#if (SMP_INCLUDED == TRUE)
//the maximum number of bonded devices
#define BONED_DEVICES_MAX_COUNT (BTM_SEC_MAX_DEVICE_RECORDS)
#define BONED_DEVICES_MAX_COUNT (BTM_SEC_MAX_BONDS)
static void _btc_storage_save(void)
{
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -40,7 +40,7 @@ bt_status_t btc_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr,
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
/* device not in bond list and exceed the maximum number of bonded devices, delete the inactive bonded device */
if (btc_storage_get_num_all_bond_devices() >= BTM_SEC_MAX_DEVICE_RECORDS && !btc_config_has_section(bdstr)) {
if (btc_storage_get_num_all_bond_devices() >= BTM_SEC_MAX_BONDS && !btc_config_has_section(bdstr)) {
const btc_config_section_iter_t *iter = btc_config_section_begin();
const btc_config_section_iter_t *remove_iter = iter;
/* find the first device(the last node) */
@@ -57,7 +57,7 @@ bt_status_t btc_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr,
// delete config info
if (btc_config_remove_section(remove_section)) {
BTC_TRACE_WARNING("exceeded the maximum nubmer of bonded devices, delete the first device info : %02x:%02x:%02x:%02x:%02x:%02x",
BTC_TRACE_WARNING("exceeded the maximum number of bonded devices, delete the first device info : %02x:%02x:%02x:%02x:%02x:%02x",
bd_addr.address[0], bd_addr.address[1], bd_addr.address[2], bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
}
}
@@ -141,8 +141,8 @@ static bt_status_t btc_in_fetch_bonded_devices(int add)
continue;
}
dev_cnt ++;
/* if the number of device stored in nvs not exceed to BTM_SEC_MAX_DEVICE_RECORDS, load it */
if (dev_cnt <= BTM_SEC_MAX_DEVICE_RECORDS) {
/* if the number of device stored in nvs not exceed to BTM_SEC_MAX_BONDS, load it */
if (dev_cnt <= BTM_SEC_MAX_BONDS) {
if (btc_config_exist(name, BTC_STORAGE_LINK_KEY_TYPE_STR) && btc_config_exist(name, BTC_STORAGE_PIN_LENGTH_STR) &&
btc_config_exist(name, BTC_STORAGE_SC_SUPPORT) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_STR)) {
/* load bt device */
@@ -1132,11 +1132,11 @@
/* The number of security records for peer devices. 15 AS Default*/
#ifndef BTM_SEC_MAX_DEVICE_RECORDS
#if (UC_BT_SMP_MAX_BONDS < UC_BT_ACL_CONNECTIONS)
#define BTM_SEC_MAX_DEVICE_RECORDS UC_BT_ACL_CONNECTIONS
#else
#define BTM_SEC_MAX_DEVICE_RECORDS UC_BT_SMP_MAX_BONDS
#define BTM_SEC_MAX_DEVICE_RECORDS (UC_BT_SMP_MAX_BONDS + UC_BT_ACL_CONNECTIONS)
#endif
#ifndef BTM_SEC_MAX_BONDS
#define BTM_SEC_MAX_BONDS UC_BT_SMP_MAX_BONDS
#endif
#if BTA_SDP_INCLUDED
@@ -508,9 +508,10 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet)
STREAM_TO_UINT8(length, stream);
}
if ((length + hdr_size) != packet->len) {
HCI_TRACE_ERROR("Wrong packet length type=%d hdr_len=%d pd_len=%d "
"pkt_len=%d", type, hdr_size, length, packet->len);
// Prevents integer wrap-around when calculating (length + hdr_size).
if (length != (packet->len - hdr_size)) {
HCI_TRACE_ERROR("%s: SECURITY: parameter length (%d) exceeds packet bounds (%d)",
__func__, length, packet->len - hdr_size);
osi_free(packet);
return;
}
+8 -4
View File
@@ -452,10 +452,12 @@ static bool filter_incoming_event(BT_HDR *packet)
STREAM_TO_UINT8(hci_host_env.command_credits, stream);
STREAM_TO_UINT16(opcode, stream);
wait_entry = get_waiting_command(opcode);
metadata = (hci_cmd_metadata_t *)(wait_entry->data);
if (!wait_entry) {
HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode);
} else if (metadata->command_complete_cb) {
goto intercepted;
}
metadata = (hci_cmd_metadata_t *)(wait_entry->data);
if (metadata->command_complete_cb) {
metadata->command_complete_cb(packet, metadata->context);
#if (BLE_50_FEATURE_SUPPORT == TRUE)
BlE_SYNC *sync_info = btsnd_hcic_ble_get_sync_info();
@@ -482,10 +484,12 @@ static bool filter_incoming_event(BT_HDR *packet)
// If a command generates a command status event, it won't be getting a command complete event
wait_entry = get_waiting_command(opcode);
metadata = (hci_cmd_metadata_t *)(wait_entry->data);
if (!wait_entry) {
HCI_TRACE_WARNING("%s command status event with no matching command. opcode: 0x%x", __func__, opcode);
} else if (metadata->command_status_cb) {
goto intercepted;
}
metadata = (hci_cmd_metadata_t *)(wait_entry->data);
if (metadata->command_status_cb) {
metadata->command_status_cb(status, &metadata->command, metadata->context);
}
@@ -164,7 +164,7 @@ static void parse_ble_read_buffer_size_response_v2 (
uint8_t *iso_pkt_num_ptr)
{
uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_BUFFER_SZIE_V2, 3 /* bytes after */);
uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_BUFFER_SZIE_V2, 6 /* bytes after: 2+1+2+1 */);
assert(stream != NULL);
STREAM_TO_UINT16(*data_size_ptr, stream);
STREAM_TO_UINT8(*acl_buffer_count_ptr, stream);
@@ -161,6 +161,13 @@ static void reassemble_and_dispatch(BT_HDR *packet)
osi_free(partial_packet);
}
/* Check for integer overflow in length calculation */
if (l2cap_length > (UINT16_MAX - L2CAP_HEADER_SIZE - HCI_ACL_PREAMBLE_SIZE)) {
HCI_TRACE_ERROR("L2CAP length too large: %u", l2cap_length);
osi_free(packet);
return;
}
uint16_t full_length = l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE;
if (full_length <= packet->len) {
if (full_length < packet->len) {
@@ -200,6 +207,20 @@ static void reassemble_and_dispatch(BT_HDR *packet)
packet->offset += HCI_ACL_PREAMBLE_SIZE; // skip ACL preamble
packet->len -= HCI_ACL_PREAMBLE_SIZE;
// CVE-2020-0022 (BlueFrag) Fix: Prevent integer underflow
if (partial_packet->offset > partial_packet->len) {
HCI_TRACE_ERROR("%s offset exceeds expected length. Dropping packet.\n", __func__);
osi_free(packet);
return;
}
if (packet->len > UINT16_MAX - partial_packet->offset) {
HCI_TRACE_ERROR("%s: packet->len too large, would overflow. Dropping packet.\n", __func__);
osi_free(packet);
return;
}
uint16_t projected_offset = partial_packet->offset + packet->len;
if (projected_offset > partial_packet->len) { // len stores the expected length
HCI_TRACE_ERROR("%s got packet which would exceed expected length of %d. Truncating.\n", __func__, partial_packet->len);
@@ -1704,6 +1704,9 @@ tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk)
#if (SMP_INCLUDED == TRUE)
void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable)
{
#if BLE_INCLUDED == TRUE
l2cble_notify_le_connection(bd_addr);
#endif // BLE_INCLUDED == TRUE
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
BOOLEAN enc_cback;
@@ -1254,6 +1254,11 @@ void btm_ble_adv_set_terminated_evt(tBTM_BLE_ADV_TERMINAT *params)
return;
}
if (params->adv_handle >= MAX_BLE_ADV_INSTANCE) {
BTM_TRACE_ERROR("%s, Invalid adv_handle %d, max is %d.", __func__, params->adv_handle, MAX_BLE_ADV_INSTANCE);
return;
}
// adv terminated due to connection, save the adv handle and connection handle
if(params->status == 0x00) {
adv_record[params->adv_handle].ter_con_handle = params->conn_handle;
@@ -3112,6 +3112,13 @@ void btm_ble_cache_adv_data(BD_ADDR bda, tBTM_INQ_RESULTS *p_cur, UINT8 data_len
p_cur->scan_rsp_len = 0;
}
/* Additional validation to prevent potential integer overflow */
if (data_len > BTM_BLE_CACHE_ADV_DATA_MAX) {
BTM_TRACE_ERROR("BLE advertising data length exceeds maximum: %u > %u",
data_len, BTM_BLE_CACHE_ADV_DATA_MAX);
return;
}
if (data_len > 0) {
p_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len];
if((data_len + p_le_inq_cb->adv_len) <= BTM_BLE_CACHE_ADV_DATA_MAX) {
@@ -104,7 +104,7 @@ tGAP_CLCB *gap_ble_find_clcb_by_conn_id(UINT16 conn_id)
}
}
return p_clcb;
return NULL;
}
/*******************************************************************************
@@ -126,10 +126,10 @@ tGAP_CLCB *gap_clcb_alloc (BD_ADDR bda)
memset(p_clcb, 0, sizeof(tGAP_CLCB));
p_clcb->in_use = TRUE;
memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
break;
return p_clcb;
}
}
return p_clcb;
return NULL;
}
/*******************************************************************************
@@ -665,6 +665,12 @@ static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS
switch (op_type) {
case GATT_UUID_GAP_PREF_CONN_PARAM:
GAP_TRACE_EVENT ("GATT_UUID_GAP_PREF_CONN_PARAM");
/* Verify sufficient data length before reading connection parameters */
if (p_data->att_value.len < 8) {
GAP_TRACE_ERROR ("GATT_UUID_GAP_PREF_CONN_PARAM: insufficient data length %d", p_data->att_value.len);
gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
break;
}
/* Extract the peripheral preferred connection parameters and save them */
STREAM_TO_UINT16 (min, pp);
@@ -679,7 +685,8 @@ static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS
case GATT_UUID_GAP_DEVICE_NAME:
GAP_TRACE_EVENT ("GATT_UUID_GAP_DEVICE_NAME\n");
len = (UINT16)strlen((char *)pp);
/* Use att_value.len instead of strlen to avoid reading beyond buffer */
len = p_data->att_value.len;
if (len > GAP_CHAR_DEV_NAME_SIZE) {
len = GAP_CHAR_DEV_NAME_SIZE;
}
@@ -687,6 +694,12 @@ static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS
break;
case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
/* Verify sufficient data length */
if (p_data->att_value.len < 1) {
GAP_TRACE_ERROR ("GATT_UUID_GAP_CENTRAL_ADDR_RESOL: insufficient data length");
gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
break;
}
gap_ble_cl_op_cmpl(p_clcb, TRUE, 1, pp);
break;
}
@@ -148,7 +148,7 @@ UINT16 GAP_ConnOpen (const char *p_serv_name, UINT8 service_id, BOOLEAN is_serve
memcpy (&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN);
} else if (!is_server) {
/* remore addr is not specified and is not a server -> bad */
/* remote addr is not specified and is not a server -> bad */
return (GAP_INVALID_HANDLE);
}
@@ -775,7 +775,9 @@ static void gap_checks_con_flags (tGAP_CCB *p_ccb)
if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) {
p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
if (p_ccb->p_callback) {
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
}
}
}
@@ -933,7 +935,9 @@ static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
gap_checks_con_flags (p_ccb);
} else {
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
if (p_ccb->p_callback) {
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
}
gap_release_ccb (p_ccb);
}
}
@@ -964,7 +968,9 @@ static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
L2CA_DISCONNECT_RSP (l2cap_cid);
}
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
if (p_ccb->p_callback) {
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
}
gap_release_ccb (p_ccb);
}
@@ -997,7 +1003,9 @@ static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
p_ccb->rx_queue_size, p_msg->len);
*/
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
if (p_ccb->p_callback) {
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
}
} else {
osi_free (p_msg);
}
@@ -1030,7 +1038,9 @@ static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested)
p_ccb->is_congested = is_congested;
event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED;
p_ccb->p_callback (p_ccb->gap_handle, event);
if (p_ccb->p_callback) {
p_ccb->p_callback (p_ccb->gap_handle, event);
}
if (!is_congested) {
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != NULL) {
@@ -33,7 +33,7 @@
#define GATT_HDR_FIND_TYPE_VALUE_LEN 21
#define GATT_OP_CODE_SIZE 1
/**********************************************************************
** ATT protocl message building utility *
** ATT protocol message building utility *
***********************************************************************/
/*******************************************************************************
**
@@ -285,57 +285,89 @@ BT_HDR *attp_build_opcode_cmd(UINT8 op_code)
** Returns None.
**
*******************************************************************************/
BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
UINT16 offset, UINT16 len, UINT8 *p_data)
BT_HDR *attp_build_value_cmd(UINT16 payload_size, UINT8 op_code,
UINT16 handle, UINT16 offset,
UINT16 len, UINT8 *p_data)
{
BT_HDR *p_buf = NULL;
UINT8 *p, *pp, pair_len, *p_pair_len;
BT_HDR *p_buf = NULL;
UINT8 *p = NULL, *pp = NULL, *p_pair_len = NULL;
size_t pair_len = 0;
size_t size_now = 1; /* track current buffer size including op_code */
if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) {
p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
#define CHECK_SIZE() \
do { \
if (size_now > payload_size) { \
GATT_TRACE_ERROR("payload size too small"); \
osi_free(p_buf); \
return NULL; \
} \
} while (0)
UINT8_TO_STREAM (p, op_code);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = 1;
/* allocate buffer with extra space for L2CAP offset */
p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
if (!p_buf) return NULL;
if (op_code == GATT_RSP_READ_BY_TYPE) {
p_pair_len = p;
pair_len = len + 2;
UINT8_TO_STREAM (p, pair_len);
p_buf->len += 1;
}
if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ && op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) {
UINT16_TO_STREAM (p, handle);
p_buf->len += 2;
p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
CHECK_SIZE();
UINT8_TO_STREAM(p, op_code);
p_buf->offset = L2CAP_MIN_OFFSET;
/* handle Read By Type response: reserve space for pair_len */
if (op_code == GATT_RSP_READ_BY_TYPE) {
p_pair_len = p++;
pair_len = len + 2; /* handle(2 bytes) + value length */
size_now += 1;
CHECK_SIZE();
/* pair_len will be backfilled after value is written */
}
/* write handle if needed */
if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ &&
op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) {
size_now += 2;
CHECK_SIZE();
UINT16_TO_STREAM(p, handle);
}
/* write offset for prepare write requests */
if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE) {
size_now += 2;
CHECK_SIZE();
UINT16_TO_STREAM(p, offset);
}
/* write value data, ensure it does not exceed payload_size */
if (len > 0 && p_data != NULL) {
if (payload_size - size_now < len) {
len = payload_size - size_now;
if (op_code == GATT_RSP_READ_BY_TYPE) {
pair_len = len + 2;
}
GATT_TRACE_WARNING("attribute value too long, truncated to %d", len);
}
if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE ) {
UINT16_TO_STREAM (p, offset);
p_buf->len += 2;
}
size_now += len;
CHECK_SIZE();
if(payload_size < GATT_DEF_BLE_MTU_SIZE || payload_size > GATT_MAX_MTU_SIZE) {
GATT_TRACE_ERROR("invalid payload_size %d", payload_size);
ARRAY_TO_STREAM(p, p_data, len);
}
/* backfill pair_len for Read By Type response */
if (op_code == GATT_RSP_READ_BY_TYPE) {
if (pair_len > UINT8_MAX) {
GATT_TRACE_ERROR("pair_len > UINT8_MAX");
osi_free(p_buf);
return NULL;
}
if (len > 0 && p_data != NULL) {
/* ensure data not exceed MTU size */
if (payload_size - p_buf->len < len) {
len = payload_size - p_buf->len;
/* update handle value pair length */
if (op_code == GATT_RSP_READ_BY_TYPE) {
*p_pair_len = (len + 2);
}
GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
}
ARRAY_TO_STREAM (p, p_data, len);
p_buf->len += len;
}
*p_pair_len = (UINT8)pair_len;
}
/* update buffer length */
p_buf->len = (UINT16)size_now;
#undef CHECK_SIZE
return p_buf;
}
@@ -462,7 +494,7 @@ BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg)
** Description This function sends the server response or indication message
** to client.
**
** Parameter p_tcb: pointer to the connecton control block.
** Parameter p_tcb: pointer to the connection control block.
** p_msg: pointer to message parameters structure.
**
** Returns GATT_SUCCESS if successfully sent; otherwise error code.
@@ -66,7 +66,7 @@ static const UINT16 disc_type_to_uuid[GATT_DISC_MAX] = {
0 /* no type filtering for DISC_CHAR_DSCPT */
};
// Use for GATTC discover infomation print
// Use for GATTC discover information print
#define GATT_DISC_INFO(fmt, args...) {if (gatt_cb.auto_disc == FALSE) BT_PRINT_I("BT_GATT", fmt, ## args);}
/*******************************************************************************
@@ -604,7 +604,7 @@ void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op
GATT_TRACE_DEBUG("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len);
if (len < GATT_PREP_WRITE_RSP_MIN_LEN) {
if ((len < GATT_PREP_WRITE_RSP_MIN_LEN) || ((len - 4) > GATT_MAX_ATTR_LEN)) {
GATT_TRACE_ERROR("illegal prepare write response length, discard");
gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value);
return;
@@ -701,7 +701,7 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code,
}
p_tcb->ind_count = 0;
/* should notify all registered client with the handle value notificaion/indication
/* should notify all registered client with the handle value notification/indication
Note: need to do the indication count and start timer first then do callback
*/
for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
@@ -800,7 +800,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8
handle_len = 4;
}
value_len -= handle_len; /* substract the handle pairs bytes */
value_len -= handle_len; /* subtract the handle pairs bytes */
len -= 1;
while (len >= (handle_len + value_len)) {
@@ -887,7 +887,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8
gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
}
return;
} else { /* discover characterisitic */
} else { /* discover characteristic */
STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p);
STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle)) {
@@ -979,7 +979,7 @@ void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */
len + offset < GATT_MAX_ATTR_LEN) {
GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d",
GATT_TRACE_DEBUG("full pkt issue read blob for remaining bytes old offset=%d len=%d new offset=%d",
offset, len, p_clcb->counter);
gatt_act_read(p_clcb, p_clcb->counter);
} else { /* end of request, send callback */
@@ -1039,20 +1039,23 @@ tGATT_STATUS gatts_write_attr_value_by_handle(tGATT_SVC_DB *p_db,
return GATT_APP_RSP;
}
if ((p_attr->p_value != NULL) &&
(p_attr->p_value->attr_val.attr_max_len >= offset + len) &&
p_attr->p_value->attr_val.attr_val != NULL) {
memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len);
p_attr->p_value->attr_val.attr_len = len + offset;
return GATT_SUCCESS;
} else if (p_attr->p_value && p_attr->p_value->attr_val.attr_max_len < offset + len){
GATT_TRACE_DEBUG("Remote device try to write with a length larger then attribute's max length\n");
return GATT_INVALID_ATTR_LEN;
} else if ((p_attr->p_value == NULL) || (p_attr->p_value->attr_val.attr_val == NULL)){
if (p_attr->p_value == NULL || p_attr->p_value->attr_val.attr_val == NULL) {
GATT_TRACE_ERROR("Error in %s, line=%d, %s should not be NULL here\n", __func__, __LINE__, \
(p_attr->p_value == NULL) ? "p_value" : "attr_val.attr_val");
return GATT_UNKNOWN_ERROR;
}
/* Check for integer overflow: offset + len must not overflow UINT16
* and must not exceed attr_max_len */
if (offset > p_attr->p_value->attr_val.attr_max_len ||
len > p_attr->p_value->attr_val.attr_max_len - offset) {
GATT_TRACE_DEBUG("Remote device try to write with a length larger than attribute's max length\n");
return GATT_INVALID_ATTR_LEN;
}
memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len);
p_attr->p_value->attr_val.attr_len = offset + len;
return GATT_SUCCESS;
}
p_attr = (tGATT_ATTR16 *)p_attr->p_next;
@@ -377,6 +377,9 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason)
#endif ///BLE_INCLUDED == TRUE
status = FALSE;
} else {
#if (BLE_INCLUDED == TRUE)
tL2C_LINK_STATE link_state_temp = p_lcb->link_state;
#endif // (BLE_INCLUDED == TRUE)
/* There can be a case when we rejected PIN code authentication */
/* otherwise save a new reason */
if (btm_cb.acl_disc_reason != HCI_ERR_HOST_REJECT_SECURITY) {
@@ -471,46 +474,54 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason)
p_lcb->p_pending_ccb = NULL;
#if (BLE_INCLUDED == TRUE)
if(reason == HCI_ERR_CONN_FAILED_ESTABLISHMENT && p_lcb->transport == BT_TRANSPORT_LE) {
#if (GATTC_CONNECT_RETRY_EN == TRUE)
if(p_lcb->link_role == HCI_ROLE_MASTER && p_lcb->retry_create_con < GATTC_CONNECT_RETRY_COUNT) {
L2CAP_TRACE_DEBUG("master retry connect, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason);
p_lcb->retry_create_con ++;
// create connection retry
if (l2cu_create_conn(p_lcb, BT_TRANSPORT_LE)) {
btm_acl_removed (p_lcb->remote_bd_addr, BT_TRANSPORT_LE);
lcb_is_free = FALSE; /* still using this lcb */
} else {
L2CAP_TRACE_ERROR("master retry connect failed");
}
}
#endif // (GATTC_CONNECT_RETRY_EN == TRUE)
if(p_lcb->transport == BT_TRANSPORT_LE) {
// for legacy adv, adv restart in gatt_le_connect_cback->gatt_cleanup_upon_disc->BTM_Recovery_Pre_State
if (reason == HCI_ERR_CONN_FAILED_ESTABLISHMENT) {
#if (BLE_50_FEATURE_SUPPORT == TRUE)
#if (BLE_50_EXTEND_ADV_EN == TRUE)
if(btm_ble_inter_get() && p_lcb->link_role == HCI_ROLE_SLAVE) {
p_lcb->retry_create_con ++;
L2CAP_TRACE_DEBUG("slave restart extend adv, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason);
tBTM_STATUS start_adv_status = BTM_BleStartExtAdvRestart(handle);
if (start_adv_status != BTM_SUCCESS) {
L2CAP_TRACE_ERROR("slave restart extend adv failed (err 0x%x)", start_adv_status);
#if (BLE_42_FEATURE_SUPPORT == TRUE)
#if (BLE_42_ADV_EN == TRUE)
if(!btm_ble_inter_get() && p_lcb->link_role == HCI_ROLE_SLAVE) {
L2CAP_TRACE_DEBUG("slave resatrt adv, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason);
tBTM_STATUS start_adv_status = btm_ble_start_adv();
if (start_adv_status != BTM_SUCCESS) {
L2CAP_TRACE_ERROR("slave resatrt adv failed (err 0x%x)", start_adv_status);
}
}
#endif // #if (BLE_42_ADV_EN == TRUE)
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
}
#endif // #if (BLE_50_EXTEND_ADV_EN == TRUE)
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
// try to reconnect for master
if ((reason == HCI_ERR_CONN_FAILED_ESTABLISHMENT) || (link_state_temp == LST_CONNECTING)) {
#if (BLE_42_FEATURE_SUPPORT == TRUE)
#if (BLE_42_ADV_EN == TRUE)
if(!btm_ble_inter_get() && p_lcb->link_role == HCI_ROLE_SLAVE) {
p_lcb->retry_create_con ++;
L2CAP_TRACE_DEBUG("slave resatrt adv, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason);
tBTM_STATUS start_adv_status = btm_ble_start_adv();
if (start_adv_status != BTM_SUCCESS) {
L2CAP_TRACE_ERROR("slave resatrt adv failed (err 0x%x)", start_adv_status);
#if (GATTC_CONNECT_RETRY_EN == TRUE)
if(p_lcb->link_role == HCI_ROLE_MASTER && p_lcb->retry_create_con < GATTC_CONNECT_RETRY_COUNT) {
L2CAP_TRACE_DEBUG("master retry connect, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason);
p_lcb->retry_create_con ++;
// create connection retry
if (l2cu_create_conn(p_lcb, BT_TRANSPORT_LE)) {
btm_acl_removed (p_lcb->remote_bd_addr, BT_TRANSPORT_LE);
lcb_is_free = FALSE; /* still using this lcb */
} else {
L2CAP_TRACE_ERROR("master retry connect failed");
}
}
#endif // (GATTC_CONNECT_RETRY_EN == TRUE)
}
#endif // #if (BLE_42_ADV_EN == TRUE)
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
// try to restart extended adv for slave
if ((reason == HCI_ERR_CONN_FAILED_ESTABLISHMENT) || (link_state_temp == LST_DISCONNECTED)) {
#if (BLE_50_FEATURE_SUPPORT == TRUE)
#if (BLE_50_EXTEND_ADV_EN == TRUE)
if(btm_ble_inter_get() && p_lcb->link_role == HCI_ROLE_SLAVE) {
L2CAP_TRACE_DEBUG("slave restart extend adv, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason);
tBTM_STATUS start_adv_status = BTM_BleStartExtAdvRestart(handle);
if (start_adv_status != BTM_SUCCESS) {
L2CAP_TRACE_ERROR("slave restart extend adv failed (err 0x%x)", start_adv_status);
}
}
#endif // #if (BLE_50_EXTEND_ADV_EN == TRUE)
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
}
}
@@ -197,7 +197,7 @@ enum {
};
typedef UINT8 tSMP_BR_STATE;
/* random and encrption activity state */
/* random and encryption activity state */
enum {
SMP_GEN_COMPARE = 1,
SMP_GEN_CONFIRM,
@@ -363,6 +363,9 @@ extern tSMP_CB *smp_cb_ptr;
/* Functions provided by att_main.c */
extern void smp_init (void);
/* SMP command sizes per spec - defined in smp_utils.c */
extern const UINT8 smp_cmd_size_per_spec[];
/* smp main */
extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data);
@@ -156,15 +156,31 @@ static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN conne
static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
{
tSMP_CB *p_cb = &smp_cb;
UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
UINT8 cmd ;
UINT8 *p;
UINT8 cmd;
SMP_TRACE_EVENT ("\nSMDBG l2c %s\n", __FUNCTION__);
/* Validate packet length before accessing data to prevent out-of-bounds read */
if (p_buf->len < 1) {
SMP_TRACE_WARNING ("Ignore empty SMP packet (len=%d)\n", p_buf->len);
osi_free (p_buf);
return;
}
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
STREAM_TO_UINT8(cmd, p);
/* sanity check */
if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x\n", cmd);
SMP_TRACE_WARNING ("Ignore received command with RESERVED code 0x%02x\n", cmd);
osi_free (p_buf);
return;
}
/* Validate command length to prevent out-of-bounds read in handler functions */
if (p_buf->len != smp_cmd_size_per_spec[cmd]) {
SMP_TRACE_WARNING ("Ignore SMP cmd 0x%02x with invalid length %d (expected %d)\n",
cmd, p_buf->len, smp_cmd_size_per_spec[cmd]);
osi_free (p_buf);
return;
}
@@ -55,7 +55,7 @@
#define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/)
/* SMP command sizes per spec */
static const UINT8 smp_cmd_size_per_spec[] = {
const UINT8 smp_cmd_size_per_spec[] = {
0,
SMP_PAIRING_REQ_SIZE, /* 0x01: pairing request */
SMP_PAIRING_REQ_SIZE, /* 0x02: pairing response */
@@ -15,7 +15,7 @@ extern "C" {
/** Minor version number (x.X.x) */
#define ESP_IDF_VERSION_MINOR 5
/** Patch version number (x.x.X) */
#define ESP_IDF_VERSION_PATCH 1
#define ESP_IDF_VERSION_PATCH 2
/**
* Macro to convert IDF version number into an integer
@@ -1,3 +1,2 @@
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_HEX=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0
+21 -20
View File
@@ -7,6 +7,7 @@
#include <sys/param.h>
#include <inttypes.h>
#include <string.h>
#include <assert.h>
#include "sdkconfig.h"
#include "esp_check.h"
#include "esp_log.h"
@@ -17,25 +18,31 @@
#include "esp_private/mspi_timing_tuning.h"
#include "esp_private/esp_clk_utils.h"
// Not directly divide to avoid truncation issue
// DIG-498
#if CONFIG_IDF_TARGET_ESP32P4
#define BELOW_FREQ_THRESHOLD(freq) ((freq) < CONFIG_SPIRAM_SPEED)
#elif CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 || CONFIG_IDF_TARGET_ESP32H4
#define BELOW_FREQ_THRESHOLD(freq) ((freq) * 8 < CONFIG_SPIRAM_SPEED)
#endif
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
void esp_clk_utils_mspi_speed_mode_sync_before_cpu_freq_switching(uint32_t target_cpu_src_freq, uint32_t target_cpu_freq)
{
#if MSPI_TIMING_LL_FLASH_CPU_CLK_SRC_BINDED
(void) target_cpu_freq;
/* For ESP32S3, the clock source of MSPI is same as the CPU. When CPU use XTAL as clock source, we need to sync the
* MSPI speed mode. */
if (target_cpu_src_freq <= clk_ll_xtal_load_freq_mhz()) {
mspi_timing_change_speed_mode_cache_safe(true);
}
#elif CONFIG_IDF_TARGET_ESP32P4
(void) target_cpu_src_freq;
/**
* Workaround for ESP32P4,
* f_cpu >= f_mspi
#elif SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED && CONFIG_SPIRAM
/* On chips with AXI bus, currently there is a restriction that AXI frequency (usually equals to a portion of CPU
* frequency) needs to be greater than or equal to MSPI PSRAM frequency to avoid writing MSPI FIFO overflow.
*/
if (((target_cpu_freq) < CONFIG_ESPTOOLPY_FLASHFREQ_VAL)
#if CONFIG_SPIRAM
|| ((target_cpu_freq) < CONFIG_SPIRAM_SPEED)
#endif
) {
if (BELOW_FREQ_THRESHOLD(target_cpu_freq)) {
// Before switching to low speed mode, verify CPU frequency meets the constraint
assert(target_cpu_freq >= mspi_timing_get_psram_low_speed_freq_mhz());
mspi_timing_change_speed_mode_cache_safe(true);
}
#else
@@ -51,17 +58,11 @@ void esp_clk_utils_mspi_speed_mode_sync_after_cpu_freq_switching(uint32_t target
if (target_cpu_src_freq > clk_ll_xtal_load_freq_mhz()) {
mspi_timing_change_speed_mode_cache_safe(false);
}
#elif CONFIG_IDF_TARGET_ESP32P4
(void) target_cpu_src_freq;
/**
* Workaround for ESP32P4,
* f_cpu >= f_mspi
#elif SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED && CONFIG_SPIRAM
/* On chips with AXI bus, currently there is a restriction that AXI frequency (usually equals to a portion of CPU
* frequency) needs to be greater than or equal to MSPI PSRAM frequency to avoid writing MSPI FIFO overflow.
*/
if (((target_cpu_freq) >= CONFIG_ESPTOOLPY_FLASHFREQ_VAL)
#if CONFIG_SPIRAM
&& ((target_cpu_freq) >= CONFIG_SPIRAM_SPEED)
#endif
) {
if (!BELOW_FREQ_THRESHOLD(target_cpu_freq)) {
mspi_timing_change_speed_mode_cache_safe(false);
}
#else
@@ -276,6 +276,15 @@ void sleep_retention_do_extra_retention(bool backup_or_restore);
void sleep_retention_do_system_retention(bool backup_or_restore);
#endif
#if SOC_PM_SUPPORT_PMU_MODEM_STATE
/**
* @brief Software trigger REGDMA to do phy linked list retention
*
* @param backup_or_restore true for backup register context to memory
* or false for restore to register from memory
*/
void sleep_retention_do_phy_retention(bool backup_or_restore);
#endif /*SOC_PM_SUPPORT_PMU_MODEM_STATE */
#endif // SOC_PAU_SUPPORTED
#ifdef __cplusplus
@@ -24,6 +24,12 @@ extern "C" {
*/
void mspi_timing_enter_low_speed_mode(bool control_spi1);
/**
* @brief Get PSRAM frequency in low speed mode (MHz)
* @return PSRAM frequency in MHz when in low speed mode
*/
uint32_t mspi_timing_get_psram_low_speed_freq_mhz(void);
/**
* @brief Make MSPI work under the frequency as users set, may add certain delays to MSPI RX direction to meet timing requirements.
* @param control_spi1 Select whether to control SPI1. For tuning, we need to use SPI1. After tuning (during startup stage), let the flash driver to control SPI1
@@ -54,7 +60,6 @@ void mspi_timing_psram_tuning(void);
*/
void mspi_timing_set_pin_drive_strength(void);
#ifdef __cplusplus
}
#endif
@@ -481,6 +481,11 @@ void mspi_timing_psram_tuning(void)
/*------------------------------------------------------------------------------
* APIs to make SPI0 (and SPI1) FLASH work for high/low freq
*----------------------------------------------------------------------------*/
uint32_t mspi_timing_get_psram_low_speed_freq_mhz(void)
{
return 20;
}
void mspi_timing_enter_low_speed_mode(bool control_spi1)
{
#if MSPI_TIMING_LL_FLASH_CLK_SRC_CHANGEABLE
@@ -500,14 +505,14 @@ void mspi_timing_enter_low_speed_mode(bool control_spi1)
* Should be extended to other no-timing-tuning chips if needed. e.g.:
* we still need to turn down Flash / PSRAM clock speed at a certain period of time
*/
mspi_timing_config_set_flash_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
mspi_timing_config_set_psram_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
#endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
uint32_t low_speed_freq_mhz = mspi_timing_get_psram_low_speed_freq_mhz();
mspi_timing_config_set_flash_clock(low_speed_freq_mhz, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
mspi_timing_config_set_psram_clock(low_speed_freq_mhz, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
mspi_timing_flash_config_clear_tuning_regs(control_spi1);
mspi_timing_psram_config_clear_tuning_regs(control_spi1);
#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
#endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
}
/**
@@ -568,10 +573,24 @@ void mspi_timing_change_speed_mode_cache_safe(bool switch_down)
if (switch_down) {
//enter MSPI low speed mode, extra delays should be removed
#if CONFIG_IDF_TARGET_ESP32C5
// ESP32-C5 needs to perform encrypted flash writes even when CPU frequency is reduced.
// Since encrypted writes use SPI1, we need to configure SPI1 timing registers as well
// during runtime frequency switching to ensure proper operation.
mspi_timing_enter_low_speed_mode(true);
#else
mspi_timing_enter_low_speed_mode(false);
#endif
} else {
//enter MSPI high speed mode, extra delays should be considered
#if CONFIG_IDF_TARGET_ESP32C5
// ESP32-C5 needs to perform encrypted flash writes even when CPU frequency is reduced.
// Since encrypted writes use SPI1, we need to configure SPI1 timing registers as well
// during runtime frequency switching to ensure proper operation.
mspi_timing_enter_high_speed_mode(true);
#else
mspi_timing_enter_high_speed_mode(false);
#endif
}
#if SOC_CACHE_FREEZE_SUPPORTED
+2 -4
View File
@@ -173,10 +173,8 @@ __attribute__((unused)) void sleep_modem_wifi_modem_state_deinit(void)
void IRAM_ATTR sleep_modem_wifi_do_phy_retention(bool restore)
{
if (restore) {
pau_regdma_trigger_modem_link_restore();
} else {
pau_regdma_trigger_modem_link_backup();
sleep_retention_do_phy_retention(!restore);
if (!restore) {
s_sleep_modem.wifi.modem_state_phy_done = 1;
}
}
+3
View File
@@ -2754,6 +2754,9 @@ static SLEEP_FN_ATTR uint32_t get_power_down_flags(void)
// TOP power domain depends on the RTC_PERIPH power domain on ESP32C6, RTC_PERIPH should only be disabled when the TOP domain is down.
pd_flags &= ~RTC_SLEEP_PD_RTC_PERIPH;
}
#elif CONFIG_IDF_TARGET_ESP32C5
// TODO: [ESP32C5] PM-642 RNG module depends on LP PERIPH domain, force it on temporary.
pd_flags &= ~RTC_SLEEP_PD_RTC_PERIPH;
#endif
return pd_flags;
}
@@ -1005,3 +1005,23 @@ void IRAM_ATTR sleep_retention_do_system_retention(bool backup_or_restore)
}
}
#endif
#if SOC_PM_SUPPORT_PMU_MODEM_STATE
void IRAM_ATTR sleep_retention_do_phy_retention(bool backup_or_restore)
{
/* since the PHY link and other module links are within the sleep-retention entry (4) context
* add mutex protection to avoid data race.
*/
#if SOC_PM_PAU_REGDMA_COMMON_PHY_LINK_ENTRY
_lock_acquire_recursive(&s_retention.lock);
#endif
if (backup_or_restore) {
pau_regdma_trigger_modem_link_backup();
} else {
pau_regdma_trigger_modem_link_restore();
}
#if SOC_PM_PAU_REGDMA_COMMON_PHY_LINK_ENTRY
_lock_release_recursive(&s_retention.lock);
#endif
}
#endif /*SOC_PM_SUPPORT_PMU_MODEM_STATE */
+13 -2
View File
@@ -1,10 +1,21 @@
idf_build_get_property(target IDF_TARGET)
set(priv_requires esp_system esp_driver_gpio esp_timer)
if(${target} STREQUAL "linux")
return() # This component is not supported by the POSIX/Linux simulator
endif()
idf_component_register(SRCS "pm_locks.c" "pm_trace.c" "pm_impl.c"
set(srcs "pm_locks.c" "pm_trace.c" "pm_impl.c")
if(CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED)
list(APPEND srcs "pm_c5_flash_freq_limit.c")
endif()
if(${target} STREQUAL "esp32c5")
# pm_c5_flash_freq_limit.c needs spi_flash header when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled
list(APPEND priv_requires spi_flash)
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS include
PRIV_REQUIRES esp_system esp_driver_gpio esp_timer
PRIV_REQUIRES "${priv_requires}"
LDFRAGMENTS linker.lf)
+8
View File
@@ -210,4 +210,12 @@ menu "Power Management"
NOTE: Enabling these callbacks may change sleep duration calculations based on time spent in callback and
hence it is highly recommended to keep them as short as possible
config PM_WORKAROUND_FREQ_LIMIT_ENABLED
bool
default y if SPI_FLASH_FREQ_LIMIT_C5_240MHZ
help
Workaround for frequency limit during encrypted flash writes.
Only enabled when SPI_FLASH_FREQ_LIMIT_C5_240MHZ is enabled.
This is an internal configuration, automatically set based on SPI Flash configuration.
endmenu # "Power Management"
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,7 +15,6 @@
#include "soc/rtc.h"
#include "esp_pm.h"
#include "esp_timer.h"
#include "sdkconfig.h"
#ifdef __cplusplus
@@ -26,11 +25,11 @@ extern "C" {
* This is an enum of possible power modes supported by the implementation
*/
typedef enum {
PM_MODE_LIGHT_SLEEP,//!< Light sleep
PM_MODE_APB_MIN, //!< Idle (no CPU frequency or APB frequency locks)
PM_MODE_APB_MAX, //!< Maximum APB frequency mode
PM_MODE_CPU_MAX, //!< Maximum CPU frequency mode
PM_MODE_COUNT //!< Number of items
PM_MODE_LIGHT_SLEEP, //!< Light sleep
PM_MODE_APB_MIN, //!< Idle (no CPU frequency or APB frequency locks)
PM_MODE_APB_MAX, //!< Maximum APB frequency mode
PM_MODE_CPU_MAX, //!< Maximum CPU frequency mode
PM_MODE_COUNT //!< Number of items
} pm_mode_t;
/**
@@ -141,8 +140,18 @@ esp_err_t esp_pm_register_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
*/
esp_err_t esp_pm_unregister_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
/**
* @brief Initialize flash frequency limit
*
* This function initializes the flash frequency limit.
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled.
*/
void esp_pm_flash_freq_limit_init(void);
#ifdef CONFIG_PM_PROFILING
#define WITH_PROFILING
#include "esp_timer.h"
#endif
#ifdef WITH_PROFILING
@@ -0,0 +1,59 @@
/*
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
/**
* @brief Initialize and pre-calculate forced CPU_MAX frequency configuration (private function for spi_flash)
*
* This function pre-calculates and stores the forced CPU_MAX frequency configuration
* based on the given frequency limit. The configuration is computed once during
* initialization and reused during runtime for better performance.
*
* @param limit_freq_mhz Frequency limit in MHz
* @note This is a private function, only for use by spi_flash component.
* @note Must be called during initialization before esp_pm_impl_cpu_max_freq_force().
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is enabled.
*/
void esp_pm_impl_cpu_max_freq_force_init(uint32_t limit_freq_mhz);
/**
* @brief Force CPU_MAX frequency to pre-configured limit (private function for spi_flash)
*
* This function activates the pre-configured forced CPU_MAX frequency limit.
* When forced, all reads of CPU_MAX frequency will use the pre-configured value
* instead of the configured value.
*
* @note This is a private function, only for use by spi_flash component.
* @note The forced frequency configuration must be pre-calculated during initialization.
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is enabled.
*/
void esp_pm_impl_cpu_max_freq_force(void);
/**
* @brief Unforce CPU_MAX frequency (private function for spi_flash)
*
* This function removes the forced CPU_MAX frequency, allowing the configured
* value to be used again.
* @note This is a private function, only for use by spi_flash component.
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is enabled.
*/
void esp_pm_impl_cpu_max_freq_unforce(void);
#endif // CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
#ifdef __cplusplus
}
#endif
+168
View File
@@ -0,0 +1,168 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
//This file implements esp_flash_freq_limit_cb and esp_flash_freq_unlimit_cb callbacks to limit and unlimit CPU
//frequency when encrypted flash writes are performed.
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_rom_sys.h"
#include "soc/chip_revision.h"
#include "soc/rtc.h"
#include "hal/efuse_hal.h"
#include "esp_private/pm_impl_freq_limit.h"
#include "esp_private/spi_flash_freq_limit_cbs.h"
#include "esp_private/esp_clk_utils.h"
/**
* @brief Get the frequency limit for flash encryption lock based on chip revision
*
* @return uint32_t Frequency limit (MHz)
*
* Logic:
* - v1.2+: limit to 160MHz
* - v1.0: limit to 80MHz
*/
static uint32_t IRAM_ATTR get_encrypt_lock_freq_limit(void)
{
unsigned int chip_revision = efuse_hal_chip_revision();
if (ESP_CHIP_REV_ABOVE(chip_revision, 102)) {
return 160;
} else {
return 80;
}
}
void esp_pm_flash_freq_limit_init(void)
{
uint32_t limit_freq_mhz = get_encrypt_lock_freq_limit();
ESP_EARLY_LOGW("spi_flash", "CPU frequency is set to 240MHz. esp_flash_write_encrypted() will automatically limit CPU frequency to %dMHz during execution.", limit_freq_mhz);
#ifdef CONFIG_PM_ENABLE
/* Pre-calculate and store forced frequency configuration during initialization.
* This is done here to avoid runtime calculation overhead in lock/unlock functions.
*/
esp_pm_impl_cpu_max_freq_force_init(limit_freq_mhz);
#endif
}
#if !CONFIG_PM_ENABLE
/* Saved original frequency for !PM_ENABLE case (0 means no change was made) */
static uint32_t s_saved_freq_mhz = 0;
// Switch CPU frequency with all necessary synchronization (for !PM_ENABLE case)
// Similar to do_switch() but without PM-specific state management
static void IRAM_ATTR esp_pm_impl_switch_cpu_freq(const rtc_cpu_freq_config_t *old_config, const rtc_cpu_freq_config_t *new_config)
{
if (new_config->freq_mhz != old_config->freq_mhz) {
//No need to run on_freq_update for ccount, since that's not supported on C5.
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
/* Synchronize MSPI speed mode before CPU frequency switching */
esp_clk_utils_mspi_speed_mode_sync_before_cpu_freq_switching(new_config->source_freq_mhz, new_config->freq_mhz);
#endif
//Not taking s_time_update_lock since C5 have fixed divider for systimer
rtc_clk_cpu_freq_set_config_fast(new_config);
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
/* Synchronize MSPI speed mode after CPU frequency switching */
esp_clk_utils_mspi_speed_mode_sync_after_cpu_freq_switching(new_config->source_freq_mhz, new_config->freq_mhz);
#endif
}
}
/**
* @brief Limit CPU frequency to target frequency (for !PM_ENABLE case only)
*
* This function automatically reads the current CPU frequency, saves it,
* and switches to the target frequency if current frequency is higher.
* The original frequency can be restored by calling unlimit_cpu_freq().
*
* @param target_freq_mhz Target frequency limit in MHz
* @note limit->unlimit cannot be nested, and this function must not be called concurrently
* @note This is a private function, only for use by spi_flash component.
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is not set.
*/
static void IRAM_ATTR limit_cpu_freq(uint32_t target_freq_mhz)
{
/* PM not enabled, directly switch frequency and save original frequency */
rtc_cpu_freq_config_t old_config, new_config;
rtc_clk_cpu_freq_get_config(&old_config);
if (old_config.freq_mhz > target_freq_mhz) {
s_saved_freq_mhz = old_config.freq_mhz;
if (rtc_clk_cpu_freq_mhz_to_config(target_freq_mhz, &new_config)) {
/* Use PM implementation function to switch frequency with all necessary synchronization */
esp_pm_impl_switch_cpu_freq(&old_config, &new_config);
const unsigned wait_clock_stable_us = 10;
esp_rom_delay_us(wait_clock_stable_us);
}
} else {
s_saved_freq_mhz = 0; /* No change needed */
}
}
/**
* @brief Unlimit CPU frequency, restoring to original frequency (for !PM_ENABLE case only)
*
* This function restores the CPU frequency to the value saved by
* limit_cpu_freq(). If no frequency change was made, this function
* does nothing.
*
* @note limit->unlimit cannot be nested, and this function must not be called concurrently
* @note This is a private function, only for use by spi_flash component.
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is not set.
*/
static void IRAM_ATTR unlimit_cpu_freq(void)
{
/* PM not enabled, restore to original frequency */
if (s_saved_freq_mhz > 0) {
rtc_cpu_freq_config_t old_config, new_config;
rtc_clk_cpu_freq_get_config(&old_config);
if (rtc_clk_cpu_freq_mhz_to_config(s_saved_freq_mhz, &new_config)) {
/* Use PM implementation function to switch frequency with all necessary synchronization */
esp_pm_impl_switch_cpu_freq(&old_config, &new_config);
const unsigned wait_clock_stable_us = 10;
esp_rom_delay_us(wait_clock_stable_us);
}
}
/* If s_saved_freq_mhz == 0, no change was made, so no need to restore */
s_saved_freq_mhz = 0;
}
#endif // !CONFIG_PM_ENABLE
void IRAM_ATTR esp_flash_freq_limit_cb(void)
{
/* Limit the frequency */
#ifdef CONFIG_PM_ENABLE
/* PM enabled, use force mechanism */
esp_pm_impl_cpu_max_freq_force();
#else
/* PM not enabled, use limit mechanism */
uint32_t limit_freq_mhz = get_encrypt_lock_freq_limit();
/* Call PM implementation function to limit CPU frequency.
* This function automatically reads current frequency, saves it, and switches to target frequency.
*/
limit_cpu_freq(limit_freq_mhz);
#endif
}
void IRAM_ATTR esp_flash_freq_unlimit_cb(void)
{
/* Restore the frequency */
#ifdef CONFIG_PM_ENABLE
/* PM enabled, use unforce mechanism */
esp_pm_impl_cpu_max_freq_unforce();
#else
/* PM not enabled, use unlimit mechanism */
/* Call PM implementation function to unlimit CPU frequency.
* This function restores the original frequency saved by limit_cpu_freq().
*/
unlimit_cpu_freq();
#endif
}
+91 -7
View File
@@ -10,6 +10,7 @@
#include <stdint.h>
#include <sys/lock.h>
#include <sys/param.h>
#include <assert.h>
#include "sdkconfig.h"
#include "esp_attr.h"
@@ -34,6 +35,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/portmacro.h"
#if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
#include "xtensa_timer.h"
#include "xtensa/core-macros.h"
@@ -42,6 +44,7 @@
#include "esp_private/pm_impl.h"
#include "esp_private/pm_trace.h"
#include "esp_private/esp_timer_private.h"
#include "esp_timer.h"
#include "esp_private/esp_clk.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/sleep_cpu.h"
@@ -51,7 +54,7 @@
#include "esp_private/esp_clk_utils.h"
#include "esp_sleep.h"
#include "esp_memory_utils.h"
#include "esp_rom_sys.h"
#if SOC_PERIPH_CLK_CTRL_SHARED
#define HP_UART_SRC_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
@@ -168,6 +171,16 @@ static esp_pm_lock_handle_t s_rtos_lock_handle[CONFIG_FREERTOS_NUMBER_OF_CORES];
*/
static rtc_cpu_freq_config_t s_cpu_freq_by_mode[PM_MODE_COUNT];
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
/* Forced CPU_MAX frequency configuration.
* s_cpu_max_freq_forced indicates whether CPU_MAX frequency is forced.
* s_cpu_max_freq_force_config stores the forced frequency configuration.
* Protected by s_switch_lock, same as s_cpu_freq_by_mode.
*/
static bool s_cpu_max_freq_forced = false;
static rtc_cpu_freq_config_t s_cpu_max_freq_force_config;
#endif
/* Whether automatic light sleep is enabled */
static bool s_light_sleep_en = false;
@@ -393,6 +406,32 @@ static esp_err_t esp_pm_sleep_configure(const esp_pm_config_t *config)
return err;
}
/**
* @brief Get frequency configuration for a given mode, considering forced frequency
*
* This function returns a pointer to the frequency configuration for the given mode.
* For PM_MODE_CPU_MAX, if s_cpu_max_freq_forced is true, it returns
* a pointer to s_cpu_max_freq_force_config. Otherwise, it returns a pointer to
* s_cpu_freq_by_mode[mode].
*
* @param mode Power mode to get configuration for
* @note Must be called with s_switch_lock held
* @note Must be in IRAM when called from ISR context (e.g., do_switch)
* @return rtc_cpu_freq_config_t* Pointer to frequency configuration for the given mode
*/
static inline IRAM_ATTR rtc_cpu_freq_config_t *get_cpu_freq_config_by_mode(pm_mode_t mode)
{
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
if (mode == PM_MODE_CPU_MAX && s_cpu_max_freq_forced) {
return &s_cpu_max_freq_force_config;
} else {
return &s_cpu_freq_by_mode[mode];
}
#else
return &s_cpu_freq_by_mode[mode];
#endif
}
esp_err_t esp_pm_configure(const void* vconfig)
{
#ifndef CONFIG_PM_ENABLE
@@ -642,18 +681,19 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
s_is_switching = true;
bool config_changed = s_config_changed;
s_config_changed = false;
portENTER_CRITICAL_ISR(&s_cpu_freq_switch_lock[core_id]);
portEXIT_CRITICAL_ISR(&s_switch_lock);
rtc_cpu_freq_config_t new_config = s_cpu_freq_by_mode[new_mode];
rtc_cpu_freq_config_t new_config = *get_cpu_freq_config_by_mode(new_mode);
rtc_cpu_freq_config_t old_config;
if (!config_changed) {
old_config = s_cpu_freq_by_mode[s_mode];
old_config = *get_cpu_freq_config_by_mode(s_mode);
} else {
rtc_clk_cpu_freq_get_config(&old_config);
}
portENTER_CRITICAL_ISR(&s_cpu_freq_switch_lock[core_id]);
portEXIT_CRITICAL_ISR(&s_switch_lock);
if (new_config.freq_mhz != old_config.freq_mhz) {
uint32_t old_ticks_per_us = old_config.freq_mhz;
uint32_t new_ticks_per_us = new_config.freq_mhz;
@@ -866,6 +906,7 @@ void vApplicationSleep( TickType_t xExpectedIdleTime )
void esp_pm_impl_dump_stats(FILE* out)
{
pm_time_t time_in_mode[PM_MODE_COUNT];
uint32_t freq_mhz_by_mode[PM_MODE_COUNT];
portENTER_CRITICAL_ISR(&s_switch_lock);
memcpy(time_in_mode, s_time_in_mode, sizeof(time_in_mode));
@@ -875,6 +916,10 @@ void esp_pm_impl_dump_stats(FILE* out)
bool light_sleep_en = s_light_sleep_en;
uint32_t light_sleep_counts = s_light_sleep_counts;
uint32_t light_sleep_reject_counts = s_light_sleep_reject_counts;
// Read all frequency configs while holding s_switch_lock
for (int i = 0; i < PM_MODE_COUNT; ++i) {
freq_mhz_by_mode[i] = get_cpu_freq_config_by_mode(i)->freq_mhz;
}
portEXIT_CRITICAL_ISR(&s_switch_lock);
time_in_mode[cur_mode] += now - last_mode_change_time;
@@ -888,7 +933,7 @@ void esp_pm_impl_dump_stats(FILE* out)
}
fprintf(out, "%-8s %-3"PRIu32"M%-7s %-10lld %-2d%%\n",
s_mode_names[i],
s_cpu_freq_by_mode[i].freq_mhz,
freq_mhz_by_mode[i],
"", //Empty space to align columns
time_in_mode[i],
(int) (time_in_mode[i] * 100 / now));
@@ -905,7 +950,7 @@ int esp_pm_impl_get_cpu_freq(pm_mode_t mode)
int freq_mhz;
if (mode >= PM_MODE_LIGHT_SLEEP && mode < PM_MODE_COUNT) {
portENTER_CRITICAL(&s_switch_lock);
freq_mhz = s_cpu_freq_by_mode[mode].freq_mhz;
freq_mhz = get_cpu_freq_config_by_mode(mode)->freq_mhz;
portEXIT_CRITICAL(&s_switch_lock);
} else {
abort();
@@ -1051,3 +1096,42 @@ void esp_pm_impl_waiti(void)
esp_cpu_wait_for_intr();
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
}
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED && CONFIG_PM_ENABLE
void esp_pm_impl_cpu_max_freq_force_init(uint32_t limit_freq_mhz)
{
// Pre-calculate frequency config (done outside critical section)
rtc_cpu_freq_config_t force_config;
bool res = rtc_clk_cpu_freq_mhz_to_config(limit_freq_mhz, &force_config);
assert(res && "Failed to convert forced CPU_MAX frequency to config");
// Store the pre-calculated config in critical section
portENTER_CRITICAL(&s_switch_lock);
s_cpu_max_freq_force_config = force_config;
portEXIT_CRITICAL(&s_switch_lock);
}
void IRAM_ATTR esp_pm_impl_cpu_max_freq_force(void)
{
portENTER_CRITICAL_SAFE(&s_switch_lock);
// Activate pre-configured forced frequency (no calculation needed at runtime)
s_cpu_max_freq_forced = true;
s_config_changed = true;
portEXIT_CRITICAL_SAFE(&s_switch_lock);
do_switch(PM_MODE_CPU_MAX);
const unsigned wait_clock_stable_us = 10;
esp_rom_delay_us(wait_clock_stable_us);
}
void IRAM_ATTR esp_pm_impl_cpu_max_freq_unforce(void)
{
portENTER_CRITICAL_SAFE(&s_switch_lock);
s_cpu_max_freq_forced = false;
s_config_changed = true;
portEXIT_CRITICAL_SAFE(&s_switch_lock);
do_switch(PM_MODE_CPU_MAX);
const unsigned wait_clock_stable_us = 10;
esp_rom_delay_us(wait_clock_stable_us);
}
#endif // CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED && CONFIG_PM_ENABLE
@@ -20,6 +20,13 @@ choice ESP_DEFAULT_CPU_FREQ_MHZ
# Please see SoC Errata document for details.
depends on !SECURE_FLASH_ENC_ENABLED
bool "240 MHz"
help
When 240MHz is selected, esp_flash_write_encrypted() will automatically limit CPU frequency during
execution:
- v1.2 and above chips: limited to 160MHz
- v1.0 and below chips: limited to 80MHz
When 160MHz or lower is selected, no frequency limiting occurs during encrypted writes. Please refer to
the ESP32-C5 SoC Errata document for more details.
endchoice
config ESP_DEFAULT_CPU_FREQ_MHZ
+4 -1
View File
@@ -33,7 +33,7 @@
#include "private/esp_coexist_internal.h"
#endif
#if CONFIG_PM_ENABLE
#if CONFIG_PM_ENABLE || CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
#include "esp_pm.h"
#include "esp_private/pm_impl.h"
#endif
@@ -122,6 +122,9 @@ ESP_SYSTEM_INIT_FN(init_flash, CORE, BIT(0), 130)
#endif // CONFIG_SPI_FLASH_BROWNOUT_RESET
// The log library will call the registered callback function to check if the cache is disabled.
esp_log_util_set_cache_enabled_cb(spi_flash_cache_enabled);
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
esp_pm_flash_freq_limit_init();
#endif // CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
return ESP_OK;
}
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -43,6 +43,7 @@
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
#define PARLIO_LL_TX_VALID_MAX_DELAY 32767
#define PARLIO_LL_SUPPORT_TX_EOF_FROM_DMA 1 // Support to treat DMA EOF as TX unit EOF
#endif
#ifdef __cplusplus
@@ -1259,6 +1259,10 @@ config SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR
bool
default y
config SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED
bool
default y
config SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
bool
default y
@@ -1739,6 +1743,10 @@ config SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC
int
default 4
config SOC_PM_PAU_REGDMA_COMMON_PHY_LINK_ENTRY
bool
default y
config SOC_PM_PMU_MIN_SLP_SLOW_CLK_CYCLE_FIXED
bool
default y
@@ -484,6 +484,7 @@
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1)
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
#define SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED (1)
#define SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY (1)
#define SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED 1
@@ -668,6 +669,7 @@
#define SOC_PM_PAU_LINK_NUM (5)
#define SOC_PM_PAU_REGDMA_LINK_CONFIGURABLE (1)
#define SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC (4) // The range of values for the link index is [0, SOC_PM_PAU_LINK_NUM)
#define SOC_PM_PAU_REGDMA_COMMON_PHY_LINK_ENTRY (1)
#define SOC_PM_PMU_MIN_SLP_SLOW_CLK_CYCLE_FIXED (1)
@@ -859,6 +859,10 @@ config SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR
bool
default y
config SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED
bool
default y
config SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
bool
default y
@@ -348,6 +348,7 @@
#define SOC_SPI_MEM_SUPPORT_WRAP (1)
#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1)
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
#define SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED (1)
#define SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY (1)
#define SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED 1
@@ -267,6 +267,10 @@ config SOC_SPI_MEM_SUPPORT_WRAP
bool
default y
config SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED
bool
default y
config SOC_MEMSPI_SRC_FREQ_64M_SUPPORTED
bool
default y
@@ -414,6 +414,7 @@
#define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_CHECK_SUS (1)
#define SOC_SPI_MEM_SUPPORT_WRAP (1)
#define SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED (1)
#define SOC_MEMSPI_SRC_FREQ_64M_SUPPORTED 1
#define SOC_MEMSPI_SRC_FREQ_32M_SUPPORTED 1
@@ -1659,6 +1659,10 @@ config SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP
bool
default y
config SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED
bool
default y
config SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR
bool
default y
@@ -609,6 +609,7 @@
#define SOC_MEMSPI_TIMING_TUNING_BY_DQS (1)
#define SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY (1)
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
#define SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED (1)
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT (1)
@@ -604,6 +604,7 @@ typedef union {
* task.
*/
uint32_t out_etm_en_chn: 1;
uint32_t reserved_7: 1;
/** out_data_burst_mode_sel_chn : R/W; bitpos: [9:8]; default: 1;
* Configures max burst size for TX channeln.
* 2'b00: single
+7
View File
@@ -465,4 +465,11 @@ menu "SPI Flash driver"
application is not using flash encryption feature and is in need of some additional
memory from IRAM region (~1KB) then this config can be disabled.
config SPI_FLASH_FREQ_LIMIT_C5_240MHZ
bool
default y if IDF_TARGET_ESP32C5 && ESP_DEFAULT_CPU_FREQ_MHZ_240
help
Enable frequency limit workaround for encrypted flash writes on ESP32-C5 at 240MHz default CPU frequency.
This is an internal configuration, automatically set based on target chip and CPU frequency.
endmenu
+79 -21
View File
@@ -148,15 +148,6 @@ static const char io_mode_str[][IO_STR_LEN] = {
_Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the io_mode_str should be consistent with the esp_flash_io_mode_t defined in spi_flash_types.h");
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
static esp_err_t spiflash_start_default(esp_flash_t *chip);
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err);
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip);
static esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
#endif // !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
typedef struct {
esp_err_t (*start)(esp_flash_t *chip);
esp_err_t (*end)(esp_flash_t *chip, esp_err_t err);
@@ -164,19 +155,70 @@ typedef struct {
esp_err_t (*flash_end_flush_cache)(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
} rom_spiflash_api_func_t;
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
#if CONFIG_SPI_FLASH_ROM_IMPL
extern rom_spiflash_api_func_t *esp_flash_api_funcs;
#define rom_spiflash_api_funcs esp_flash_api_funcs
#else
#define rom_spiflash_api_funcs esp_flash_api_funcs_patched_ptr
#endif
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
// API funcs case 1 & 2
static esp_err_t spiflash_start_default(esp_flash_t *chip);
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err);
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip);
static esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
// These functions can be placed in the ROM. For now we use the code in IDF.
DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = {
DRAM_ATTR static rom_spiflash_api_func_t esp_flash_api_funcs_patched = {
.start = spiflash_start_default,
.end = spiflash_end_default,
.chip_check = check_chip_pointer_default,
.flash_end_flush_cache = flash_end_flush_cache,
};
DRAM_ATTR rom_spiflash_api_func_t *rom_spiflash_api_funcs = &default_spiflash_rom_api;
#else
extern rom_spiflash_api_func_t *esp_flash_api_funcs;
#define rom_spiflash_api_funcs esp_flash_api_funcs
# if !CONFIG_SPI_FLASH_ROM_IMPL
// API funcs case 1: Not using ROM - define our own pointer and all functions
DRAM_ATTR static rom_spiflash_api_func_t *esp_flash_api_funcs_patched_ptr = &esp_flash_api_funcs_patched;
# else // CONFIG_SPI_FLASH_ROM_IMPL
// API funcs case 2: Using ROM APIs but patch all api_funcs by updating esp_flash_api_funcs from ROM
void esp_flash_rom_api_funcs_init(void)
{
// Point esp_flash_api_funcs to our default structure
esp_flash_api_funcs = &esp_flash_api_funcs_patched;
}
# endif // CONFIG_SPI_FLASH_ROM_IMPL
#else // CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
// Using ROM implementation
# if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
// API funcs case 3: Using ROM APIs but patch start function to support flags parameter
static esp_err_t spiflash_start_default(esp_flash_t *chip);
DRAM_ATTR static rom_spiflash_api_func_t esp_flash_api_funcs_patched;
// Copy ROM structure to RAM and patch start function to support flags
void esp_flash_rom_api_funcs_init(void)
{
rom_spiflash_api_func_t *rom_ptr = esp_flash_api_funcs;
memcpy(&esp_flash_api_funcs_patched, rom_ptr, sizeof(rom_spiflash_api_func_t));
esp_flash_api_funcs_patched.start = spiflash_start_default;
esp_flash_api_funcs = &esp_flash_api_funcs_patched;
}
# else
// API funcs case 4: Using All ROM APIs directly
void esp_flash_rom_api_funcs_init(void)
{
// Do nothing
}
# endif // CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
#endif // !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
/* Static function to notify OS of a new SPI flash operation.
@@ -184,11 +226,13 @@ extern rom_spiflash_api_func_t *esp_flash_api_funcs;
If returns an error result, caller must abort. If returns ESP_OK, caller must
call rom_spiflash_api_funcs->end() before returning.
*/
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
static esp_err_t spiflash_start_default(esp_flash_t *chip)
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV || CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
//Avoid constprop issue that place this function into flash.
__attribute__((optimize("O0"))) //IDF-14941
static esp_err_t spiflash_start_core(esp_flash_t *chip, uint32_t flags)
{
if (chip->os_func != NULL && chip->os_func->start != NULL) {
esp_err_t err = chip->os_func->start(chip->os_func_data);
esp_err_t err = chip->os_func->start(chip->os_func_data, flags);
if (err != ESP_OK) {
return err;
}
@@ -197,6 +241,13 @@ static esp_err_t spiflash_start_default(esp_flash_t *chip)
return ESP_OK;
}
static esp_err_t spiflash_start_default(esp_flash_t *chip)
{
return spiflash_start_core(chip, 0);
}
#endif //!CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV || CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
/* Static function to notify OS that SPI flash operation is complete.
*/
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err)
@@ -1248,13 +1299,20 @@ esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
}
#endif //CONFIG_SPI_FLASH_ROM_IMPL
#if !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV)
// use `esp_flash_write_encrypted` ROM version on chips later than C3 and S3
FORCE_INLINE_ATTR esp_err_t s_encryption_write_lock(esp_flash_t *chip) {
#if !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV) || CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
// use `esp_flash_write_encrypted` ROM version on chips later than C3, S3
// For ESP32-C5, use IDF implementation when CPU frequency is 240MHz (calling start() with arg is required)
FORCE_INLINE_ATTR esp_err_t s_encryption_write_lock(esp_flash_t *chip)
{
#if CONFIG_IDF_TARGET_ESP32S2
esp_crypto_dma_lock_acquire();
#endif //CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
// Use start_core with LIMIT_CPU_FREQ flag to trigger freq_limit_lock in OS layer
return spiflash_start_core(chip, ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ);
#else
return rom_spiflash_api_funcs->start(chip);
#endif
}
FORCE_INLINE_ATTR esp_err_t s_encryption_write_unlock(esp_flash_t *chip) {
@@ -1506,7 +1564,7 @@ esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t addres
}
return rom_esp_flash_write_encrypted(chip, address, buffer, length);
}
#endif // !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV)
#endif // !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV) || CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
//init suspend mode cmd, uses internal.
esp_err_t esp_flash_suspend_cmd_init(esp_flash_t* chip)
+25 -1
View File
@@ -142,6 +142,19 @@ esp_flash_t *esp_flash_default_chip = NULL;
#endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND
#endif // Other target
// Dynamic flash configuration is only needed when:
// 1. Frequency limit workaround is enabled (CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ)
// 2. Flash frequency requires timing tuning (80MHz or 120MHz, i.e., > 40MHz)
// 3. CPU frequency reduction will trigger MSPI timing tuning to enter low speed mode
// This happens when: SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED && CONFIG_SPIRAM &&
// (target_cpu_freq < CONFIG_SPIRAM_SPEED)
// Note: The runtime check for CPU freq < PSRAM speed is done in clk_utils.c,
// which calls mspi_timing_change_speed_mode_cache_safe(true) to enter low speed mode.
// For ESP32-C5, if PSRAM is enabled and CPU freq < PSRAM speed, timing tuning will be disabled.
#define C5_NEEDS_DYNAMIC_CONFIG (CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ && CONFIG_SPIRAM && \
(CONFIG_ESPTOOLPY_FLASHFREQ_80M || CONFIG_ESPTOOLPY_FLASHFREQ_120M))
static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool cs_use_iomux, int cs_id)
{
//Not using spicommon_cs_initialize since we don't want to put the whole
@@ -157,7 +170,7 @@ static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_f
//To avoid the panic caused by flash data line conflicts during cs line
//initialization, disable the cache temporarily
chip->os_func->start(chip->os_func_data);
chip->os_func->start(chip->os_func_data, 0);
gpio_hal_input_enable(&gpio_hal, cs_io_num);
if (cs_use_iomux) {
gpio_hal_func_sel(&gpio_hal, cs_io_num, spics_func);
@@ -547,6 +560,16 @@ esp_err_t esp_flash_init_default_chip(void)
if (err != ESP_OK) {
return err;
}
#if C5_NEEDS_DYNAMIC_CONFIG
err = memspi_host_init_c5_dynamic_config(&esp_flash_default_host);
if (err != ESP_OK) {
return err;
}
#endif
#if CONFIG_SPI_FLASH_ROM_IMPL
esp_flash_rom_api_funcs_init();
#endif // CONFIG_SPI_FLASH_ROM_IMPL
// ROM TODO: account for non-standard default pins in efuse
// ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here
@@ -608,6 +631,7 @@ esp_err_t esp_flash_app_init(void)
spi_flash_init_lock();
spi_flash_guard_set(&g_flash_guard_default_ops);
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
esp_flash_reset_counters();
#endif
+7 -1
View File
@@ -37,11 +37,17 @@ typedef struct {
* risk.
*/
typedef struct {
/**
* Flags for start function
*/
/** Limit CPU frequency during flash operations (ESP32-C5 only, 240MHz).
*/
#define ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ BIT(0)
/**
* Called before commencing any flash operation. Does not need to be
* recursive (ie is called at most once for each call to 'end').
*/
esp_err_t (*start)(void *arg);
esp_err_t (*start)(void *arg, uint32_t flags);
/** Called after completing any flash operation. */
esp_err_t (*end)(void *arg);
@@ -117,6 +117,16 @@ esp_err_t esp_flash_app_disable_os_functions(esp_flash_t* chip);
*/
esp_err_t esp_flash_set_dangerous_write_protection(esp_flash_t *chip, const bool protect);
#if CONFIG_SPI_FLASH_ROM_IMPL
/**
* @brief Initialize ROM API functions structure
*
* This function initializes the ROM API functions structure, either by pointing
* to a custom structure or by patching the ROM structure in RAM.
*/
void esp_flash_rom_api_funcs_init(void);
#endif // CONFIG_SPI_FLASH_ROM_IMPL
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "esp_flash.h"
#include "esp_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
/**
* @brief Callback to limit CPU frequency for flash encryption writes (ESP32-C5 only, 240MHz)
*
* This function limits CPU frequency to <= 160MHz during encrypted flash writes.
* It should be called before starting an encrypted flash write operation.
*
* @note This is an internal function, not exposed to users.
* @note This function is placed in IRAM (implementation uses IRAM_ATTR).
* @note This function is called from spi_flash_os_func_app.c::spi1_start() after cache
* and scheduler locks are acquired. As a result, there is no concurrency concern
* and no need for internal locking or reference counting.
*/
void esp_flash_freq_limit_cb(void);
/**
* @brief Callback to unlimit CPU frequency after flash encryption writes (ESP32-C5 only, 240MHz)
*
* This function restores the CPU frequency after an encrypted flash write operation.
* It should be called after completing an encrypted flash write operation.
*
* @note This is an internal function, not exposed to users.
* @note This function is placed in IRAM (implementation uses IRAM_ATTR).
* @note This function is called from spi_flash_os_func_app.c::spi1_end() before cache
* and scheduler locks are released. As a result, there is no concurrency concern
* and no need for internal locking or reference counting.
*/
void esp_flash_freq_unlimit_cb(void);
#endif // CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
#ifdef __cplusplus
}
#endif
@@ -48,6 +48,17 @@ typedef spi_flash_hal_context_t memspi_host_inst_t;
*/
esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_config_t *cfg);
/**
* Initialize the memory SPI host for ESP32-C5 dynamic configuration.
*
* @param host Pointer to the host structure.
*
* @note This function is available only when CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ is defined.
* @note This function can only be called once at startup, after memspi_host_init_pointers() is called.
* @return always return ESP_OK
*/
esp_err_t memspi_host_init_c5_dynamic_config(memspi_host_inst_t *host);
/*******************************************************************************
* NOTICE
* Rest part of this file are part of the HAL layer
@@ -161,7 +172,7 @@ int memspi_host_read_data_slicer(spi_flash_host_inst_t *host, uint32_t address,
/**
* @brief Slicer for write data used in non-encrypted regions. This slicer limit the length to the
* maximum size the host supports, and truncate if the write data lie accross the page boundary
* maximum size the host supports, and truncate if the write data lie across the page boundary
* (256 bytes)
*
* @param address Flash address to write
+5 -2
View File
@@ -45,12 +45,15 @@ entries:
if SPI_FLASH_VERIFY_WRITE = y:
esp_flash_api: s_verify_write (noflash)
if SPI_FLASH_ROM_IMPL = n || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV = y:
if SPI_FLASH_ROM_IMPL = n || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV = y || SPI_FLASH_FREQ_LIMIT_C5_240MHZ = y:
esp_flash_api: spiflash_start_default (noflash)
esp_flash_api: spiflash_start_core (noflash)
esp_flash_api: esp_flash_write_encrypted (noflash)
if SPI_FLASH_ROM_IMPL = n || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV = y:
esp_flash_api: spiflash_end_default (noflash)
esp_flash_api: check_chip_pointer_default (noflash)
esp_flash_api: flash_end_flush_cache (noflash)
esp_flash_api: esp_flash_write_encrypted (noflash)
if SPI_FLASH_ROM_IMPL = n:
esp_flash_api: esp_flash_get_size (noflash)
+54 -3
View File
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "spi_flash_defs.h"
#include "memspi_host_driver.h"
@@ -12,12 +13,13 @@
#include "esp_private/cache_utils.h"
#include "esp_flash_partitions.h"
#include "esp_memory_utils.h"
#include "hal/mspi_ll.h"
#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64
#define SPI_FLASH_HAL_MAX_READ_BYTES 64
DRAM_ATTR static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER();
DRAM_ATTR static spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER();
#if SOC_MEMSPI_IS_INDEPENDENT
extern void spi_flash_hal_gpspi_poll_cmd_done(spi_flash_host_inst_t *host);
@@ -71,9 +73,9 @@ esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_
}
#if SOC_MEMSPI_IS_INDEPENDENT
if (cfg->host_id == SPI1_HOST)
if (cfg->host_id == SPI1_HOST) {
host->inst.driver = &esp_flash_default_host;
else {
} else {
host->inst.driver = &esp_flash_gpspi_host;
}
#else
@@ -253,3 +255,52 @@ int memspi_host_read_data_slicer(spi_flash_host_inst_t *host, uint32_t address,
}
#endif // CONFIG_SPI_FLASH_ROM_IMPL
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
// Dynamic flash configuration based on timing tuning state:
// 1. The timing tuning system automatically sets core clock and timing parameters (including din_mode/num, etc.).
// It also generates configurations such as clock configuration and dummy configuration for driver use.
// Without calling this function, the driver gets these configurations during initialization and uses them forever.
// The timing tuning provides clock configuration (frequency division) and dummy count.
// 2. When dynamic configuration is needed, call this function. The function supports two states:
// - Timing tuned state (high speed): Restore the values generated by the timing tuning system to the driver,
// as if there was no frequency reduction.
// - Without timing tuning state (low speed): Set configuration to maximum frequency (40 MHz on C5), dummy=0.
static uint32_t s_high_speed_clock_reg;
static uint32_t s_high_speed_extra_dummy;
ESP_STATIC_ASSERT(MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT == 80);
#define LOW_SPEED_DIV (MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT/40)
static esp_err_t spi_flash_hal_device_config_c5(spi_flash_host_inst_t *host)
{
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
// Note: SPI0 and SPI1 have separate TIMING_CALI_REG registers, but SPI0's register reflects the timing tuning state
// since SPI0 and SPI1 share din_mode/din_num registers and timing tuning is configured on SPI0
uint32_t timing_cali_reg = REG_READ(SPI_MEM_TIMING_CALI_REG(MSPI_TIMING_LL_MSPI_ID_0));
bool is_low_speed = !(timing_cali_reg & SPI_MEM_TIMING_CALI_M);
if (is_low_speed) {
// Low speed mode: Set to safe division, dummy=0
uint32_t low_speed_clock_reg = mspi_timing_ll_calculate_clock_reg(LOW_SPEED_DIV);
ctx->clock_conf.spimem = low_speed_clock_reg;
ctx->extra_dummy = 0;
} else {
// High speed mode: Restore timing tuning values
ctx->clock_conf.spimem = s_high_speed_clock_reg;
ctx->extra_dummy = s_high_speed_extra_dummy;
}
return spi_flash_hal_device_config(host);
}
esp_err_t memspi_host_init_c5_dynamic_config(memspi_host_inst_t *host)
{
assert(s_high_speed_clock_reg == 0 && s_high_speed_extra_dummy == 0);
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
s_high_speed_clock_reg = ctx->clock_conf.spimem;
s_high_speed_extra_dummy = ctx->extra_dummy;
esp_flash_default_host.dev_config = spi_flash_hal_device_config_c5;
return ESP_OK;
}
#endif
+31 -6
View File
@@ -20,9 +20,12 @@
#include "esp_rom_sys.h"
#include "esp_private/spi_flash_os.h"
#include "esp_private/cache_utils.h"
#include "esp_private/spi_share_hw_ctrl.h"
// For C5 encrypted write workaround
// Functions are only available when CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ is true
#include "esp_private/spi_flash_freq_limit_cbs.h"
#define SPI_FLASH_CACHE_NO_DISABLE (CONFIG_SPI_FLASH_AUTO_SUSPEND || (CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA) || CONFIG_APP_BUILD_TYPE_RAM)
static const char TAG[] = "spi_flash";
@@ -53,6 +56,7 @@ typedef struct {
bool no_protect; //to decide whether to check protected region (for the main chip) or not.
uint32_t acquired_since_us; // Time since last explicit yield()
uint32_t released_since_us; // Time since last end() (implicit yield)
uint32_t start_flags; // Flags passed to start() function, used to determine if freq_limit was called
} app_func_arg_t;
static inline void on_spi_released(app_func_arg_t* ctx);
@@ -90,21 +94,27 @@ static IRAM_ATTR esp_err_t release_spi_bus_lock(void *arg)
return spi_bus_lock_acquire_end(((app_func_arg_t *)arg)->dev_lock);
}
static esp_err_t spi23_start(void *arg){
static esp_err_t spi23_start(void *arg, uint32_t flags)
{
(void)flags;
esp_err_t ret = acquire_spi_bus_lock(arg);
on_spi_acquired((app_func_arg_t*)arg);
return ret;
}
static esp_err_t spi23_end(void *arg){
static esp_err_t spi23_end(void *arg)
{
esp_err_t ret = release_spi_bus_lock(arg);
on_spi_released((app_func_arg_t*)arg);
return ret;
}
static IRAM_ATTR esp_err_t spi1_start(void *arg)
static IRAM_ATTR esp_err_t spi1_start(void *arg, uint32_t flags)
{
esp_err_t ret = ESP_OK;
app_func_arg_t* ctx = (app_func_arg_t*)arg;
ctx->start_flags = flags;
/**
* There are three ways for ESP Flash API lock:
* 1. spi bus lock, this is used when SPI1 is shared with GPSPI Master Driver
@@ -136,13 +146,28 @@ static IRAM_ATTR esp_err_t spi1_start(void *arg)
}
#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
on_spi_acquired((app_func_arg_t*)arg);
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
if (flags & ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ) {
esp_flash_freq_limit_cb();
}
#endif
on_spi_acquired(ctx);
return ret;
}
static IRAM_ATTR esp_err_t spi1_end(void *arg)
{
esp_err_t ret = ESP_OK;
app_func_arg_t* ctx = (app_func_arg_t*)arg;
// Call freq_limit_unlock if needed, before releasing the lock
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
uint32_t flags = ctx->start_flags;
if (flags & ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ) {
esp_flash_freq_unlimit_cb();
}
#endif
/**
* There are three ways for ESP Flash API lock, see `spi1_start`
@@ -166,7 +191,7 @@ static IRAM_ATTR esp_err_t spi1_end(void *arg)
}
#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
on_spi_released((app_func_arg_t*)arg);
on_spi_released(ctx);
return ret;
}
@@ -15,7 +15,7 @@
#include "hal/cache_ll.h"
#include "soc/soc_caps.h"
static IRAM_ATTR esp_err_t start(void *arg)
static IRAM_ATTR esp_err_t start(void *arg, uint32_t flags)
{
#if SOC_BRANCH_PREDICTOR_SUPPORTED
//branch predictor will start cache request as well
@@ -15,6 +15,15 @@ components/spi_flash/test_apps/esp_flash:
- esp_driver_spi
- esptool_py # Some flash related kconfigs are listed here.
components/spi_flash/test_apps/esp_flash_freq_limit:
enable:
- if: IDF_TARGET == "esp32c5"
depends_components:
- spi_flash
- esp_pm
- esp_driver_gptimer
- esp_hw_support
components/spi_flash/test_apps/esp_flash_stress:
disable:
- if: IDF_TARGET == "esp32h4"
@@ -0,0 +1,17 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.22)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on
# esptool_py as we set CONFIG_ESPTOOLPY_... options.
set(COMPONENTS main esptool_py)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_esp_flash_freq_limit)
message(STATUS "Checking memspi registers are not read-write by half-word")
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
check_register_rw_half_word(SOC_MODULES "spi_mem*" "spi1_mem*"
HAL_MODULES "spimem_flash")
@@ -0,0 +1,2 @@
| Supported Targets | ESP32-C5 |
| ----------------- | -------- |
@@ -0,0 +1,9 @@
set(srcs "test_app_main.c"
"test_esp_flash_freq_limit.c")
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES unity test_utils spi_flash esp_pm bootloader_support freertos esp_timer
esp_driver_gptimer esp_hw_support esp_psram
WHOLE_ARCHIVE)
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_utils.h"
#define TEST_MEMORY_LEAK_THRESHOLD (700)
void setUp(void)
{
unity_utils_record_free_mem();
}
void tearDown(void)
{
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
}
void app_main(void)
{
unity_run_menu();
}
@@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
factory, 0, 0, 0x10000, 1M
flash_test, data, fat, , 700K
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 factory, 0, 0, 0x10000, 1M
5 flash_test, data, fat, , 700K
@@ -0,0 +1,24 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'pm_disabled_240mhz',
'pm_disabled_160mhz',
'pm_enabled_240mhz',
'pm_enabled_160mhz',
'pm_disabled_240mhz_xip_psram',
'pm_enabled_240mhz_xip_psram',
'pm_enabled_240mhz_xip_psram_rom_impl',
],
indirect=True,
)
@idf_parametrize('target', ['esp32c5'], indirect=['target'])
def test_esp_flash_freq_limit(dut: Dut) -> None:
dut.run_all_single_board_cases(group='esp_flash_freq_limit', timeout=10)
@@ -0,0 +1,2 @@
CONFIG_PM_ENABLE=n
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
@@ -0,0 +1,2 @@
CONFIG_PM_ENABLE=n
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
@@ -0,0 +1,8 @@
CONFIG_PM_ENABLE=n
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_HW_INIT=y
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_SPIRAM_SPEED_80M=y
@@ -0,0 +1,6 @@
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_PM_ENABLE=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
@@ -0,0 +1,6 @@
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_PM_ENABLE=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
@@ -0,0 +1,12 @@
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_PM_ENABLE=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_HW_INIT=y
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_SPIRAM_SPEED_80M=y
@@ -0,0 +1,13 @@
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_PM_ENABLE=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_HW_INIT=y
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPI_FLASH_ROM_IMPL=y
@@ -0,0 +1,2 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
@@ -325,7 +325,7 @@ The waveform of the external clock input is shown below:
.. note::
Due to hardware limitations, the bitstream generated by the BitScrambler cannot change the length compared to the original bitstream, otherwise transmission blocking or data loss may occur.
Due to hardware limitations, on chip versions prior to rev3.0, the bitstream generated by the bitscrambler must have the same length as the original bitstream, otherwise transmission blocking or data loss may occur.
:cpp:func:`parlio_tx_unit_decorate_bitscrambler` and :cpp:func:`parlio_tx_unit_undecorate_bitscrambler` need to be used in pairs. When deleting the TX unit, you need to call :cpp:func:`parlio_tx_unit_undecorate_bitscrambler` first to remove the BitScrambler.
@@ -59,3 +59,8 @@ Peripherals
- The new and legacy drivers are not compatible and must not be used together. Mixing them will trigger warnings during startup, and may even cause crashes and system reboots. To suppress this compatibility check, you may enable the configuration option :ref:`CONFIG_TWAI_SKIP_LEGACY_CONFLICT_CHECK`.
- The legacy driver will no longer receive new features, such as TWAI FD (Flexible Data-rate) support.
SPI Flash Driver
----------------
- New argument ``flags`` is added to ``esp_flash_os_functions_t::start``. Caller and implementer should handle this argument properly.
@@ -325,7 +325,7 @@ TX 单元可以选择各种不同的时钟源,其中外部时钟源较为特
.. note::
由于硬件限制,使用比特调节器生成的比特流与原本比特流相比,长度不能发生变化,否则可能会发生传输阻塞或数据丢失。
由于硬件限制,在 rev3.0 之前的芯片版本上,使用比特调节器生成的比特流与原本比特流相比,长度不能发生变化,否则可能会发生传输阻塞或数据丢失。
:cpp:func:`parlio_tx_unit_decorate_bitscrambler`:cpp:func:`parlio_tx_unit_undecorate_bitscrambler` 需要成对使用。在删除 TX 单元时,需要先调用 :cpp:func:`parlio_tx_unit_undecorate_bitscrambler` 移除比特调节器。
@@ -59,3 +59,8 @@
- 新旧驱动不互相兼容,不可混合使用,否则将在启动时打印警告,甚至崩溃并重启。可打开配置项 :ref:`CONFIG_TWAI_SKIP_LEGACY_CONFLICT_CHECK` 以屏蔽该检查。
- 旧版驱动将不再添加新特性(如 TWAIFD)的支持。
SPI flash 驱动
--------------
- ``esp_flash_os_functions_t::start`` 新增了一个参数 ``flags``。调用者和实现者应正确处理此参数。
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -126,14 +126,24 @@ void esp_receive_apple_data_source(uint8_t *message, uint16_t message_len)
switch (Command_id)
{
case CommandIDGetNotificationAttributes: {
// Security fix: Check minimum message length before accessing message[1..4]
if (message_len < 5) {
ESP_LOGE(BLE_ANCS_TAG, "Message too short for NotificationAttributes");
break;
}
uint32_t NotificationUID = (message[1]) | (message[2]<< 8) | (message[3]<< 16) | (message[4] << 24);
uint32_t remian_attr_len = message_len - 5;
uint8_t *attrs = &message[5];
ESP_LOGI(BLE_ANCS_TAG, "recevice Notification Attributes response Command_id %d NotificationUID %" PRIu32, Command_id, NotificationUID);
while(remian_attr_len > 0) {
// Security fix: Need at least 3 bytes for AttributeID(1) + len(2)
if (remian_attr_len < 3) {
ESP_LOGE(BLE_ANCS_TAG, "Incomplete attribute header");
break;
}
uint8_t AttributeID = attrs[0];
uint16_t len = attrs[1] | (attrs[2] << 8);
if(len > (remian_attr_len -3)) {
if(len > (remian_attr_len - 3)) {
ESP_LOGE(BLE_ANCS_TAG, "data error");
break;
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -31,6 +31,8 @@
#define ADV_CONFIG_FLAG (1 << 0)
#define SCAN_RSP_CONFIG_FLAG (1 << 1)
#define INVALID_HANDLE 0
#define ANCS_CMD_BUFFER_MAX_SIZE 600
static uint8_t adv_config_done = 0;
static bool get_service = false;
static esp_gattc_char_elem_t *char_elem_result = NULL;
@@ -168,15 +170,26 @@ esp_noti_attr_list_t p_attr[8] = {
void esp_get_notification_attributes(uint8_t *notificationUID, uint8_t num_attr, esp_noti_attr_list_t *p_attr)
{
uint8_t cmd[600] = {0};
uint8_t cmd[ANCS_CMD_BUFFER_MAX_SIZE] = {0};
uint32_t index = 0;
cmd[0] = CommandIDGetNotificationAttributes;
index ++;
memcpy(&cmd[index], notificationUID, ESP_NOTIFICATIONUID_LEN);
index += ESP_NOTIFICATIONUID_LEN;
while(num_attr > 0) {
// Security fix: Check buffer boundary before writing
if (index >= ANCS_CMD_BUFFER_MAX_SIZE) {
ESP_LOGE(BLE_ANCS_TAG, "Command buffer overflow in get_notification_attributes");
return;
}
cmd[index ++] = p_attr->noti_attribute_id;
if (p_attr->attribute_len > 0) {
// Need 2 more bytes for attribute_len
if ((index + 2) > ANCS_CMD_BUFFER_MAX_SIZE) {
ESP_LOGE(BLE_ANCS_TAG, "Command buffer overflow in get_notification_attributes");
return;
}
cmd[index ++] = p_attr->attribute_len;
cmd[index ++] = (p_attr->attribute_len << 8);
}
@@ -195,8 +208,15 @@ void esp_get_notification_attributes(uint8_t *notificationUID, uint8_t num_attr,
void esp_get_app_attributes(uint8_t *appidentifier, uint16_t appidentifier_len, uint8_t num_attr, uint8_t *p_app_attrs)
{
uint8_t buffer[600] = {0};
uint8_t buffer[ANCS_CMD_BUFFER_MAX_SIZE] = {0};
uint32_t index = 0;
// Security fix: Check buffer boundary before memcpy
if ((1 + appidentifier_len + num_attr) > ANCS_CMD_BUFFER_MAX_SIZE) {
ESP_LOGE(BLE_ANCS_TAG, "Buffer overflow in get_app_attributes");
return;
}
buffer[0] = CommandIDGetAppAttributes;
index ++;
memcpy(&buffer[index], appidentifier, appidentifier_len);
@@ -215,7 +235,7 @@ void esp_get_app_attributes(uint8_t *appidentifier, uint16_t appidentifier_len,
void esp_perform_notification_action(uint8_t *notificationUID, uint8_t ActionID)
{
uint8_t buffer[600] = {0};
uint8_t buffer[ANCS_CMD_BUFFER_MAX_SIZE] = {0};
uint32_t index = 0;
buffer[0] = CommandIDPerformNotificationAction;
index ++;
@@ -517,6 +537,12 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
esp_get_notification_attributes(notificationUID, sizeof(p_attr)/sizeof(esp_noti_attr_list_t), p_attr);
}
} else if (param->notify.handle == gl_profile_tab[PROFILE_A_APP_ID].data_source_handle) {
if ((data_buffer.len + param->notify.value_len) > sizeof(data_buffer.buffer)) {
ESP_LOGE(BLE_ANCS_TAG, "Data source buffer overflow detected, discarding data");
memset(data_buffer.buffer, 0, sizeof(data_buffer.buffer));
data_buffer.len = 0;
break;
}
memcpy(&data_buffer.buffer[data_buffer.len], param->notify.value, param->notify.value_len);
data_buffer.len += param->notify.value_len;
if (param->notify.value_len == (gl_profile_tab[PROFILE_A_APP_ID].MTU_size - 3)) {
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -21,6 +21,7 @@
#include "esp_eddystone_protocol.h"
#include "esp_eddystone_api.h"
#define EDDYSTONE_URL_BUF_SIZE 100
/* Declare static functions */
static esp_err_t esp_eddystone_uid_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res);
@@ -101,18 +102,33 @@ static esp_err_t esp_eddystone_uid_received(const uint8_t* buf, uint8_t len, esp
static char* esp_eddystone_resolve_url_scheme(const uint8_t *url_start, const uint8_t *url_end)
{
int pos = 0;
static char url_buf[100] = {0};
static char url_buf[EDDYSTONE_URL_BUF_SIZE] = {0};
const uint8_t *p = url_start;
int written;
pos += sprintf(&url_buf[pos], "%s", eddystone_url_prefix[*p++]);
// Security fix: Use snprintf instead of sprintf to prevent buffer overflow
written = snprintf(&url_buf[pos], EDDYSTONE_URL_BUF_SIZE - pos, "%s", eddystone_url_prefix[*p++]);
if (written < 0 || written >= (EDDYSTONE_URL_BUF_SIZE - pos)) {
url_buf[EDDYSTONE_URL_BUF_SIZE - 1] = '\0';
return url_buf;
}
pos += written;
for (; p <= url_end; p++) {
if (esp_eddystone_is_char_invalid((*p))) {
pos += sprintf(&url_buf[pos], "%s", eddystone_url_encoding[*p]);
} else {
pos += sprintf(&url_buf[pos], "%c", *p);
if (pos >= EDDYSTONE_URL_BUF_SIZE - 1) {
break;
}
if (esp_eddystone_is_char_invalid((*p))) {
written = snprintf(&url_buf[pos], EDDYSTONE_URL_BUF_SIZE - pos, "%s", eddystone_url_encoding[*p]);
} else {
written = snprintf(&url_buf[pos], EDDYSTONE_URL_BUF_SIZE - pos, "%c", *p);
}
if (written < 0 || written >= (EDDYSTONE_URL_BUF_SIZE - pos)) {
break;
}
pos += written;
}
url_buf[EDDYSTONE_URL_BUF_SIZE - 1] = '\0';
return url_buf;
}
@@ -277,20 +277,25 @@ static bool store_wr_buffer(esp_ble_gatts_cb_param_t *p_data)
ESP_LOGI(GATTS_TABLE_TAG, "malloc error %s %d", __func__, __LINE__);
return false;
}
temp_spp_recv_data_node_p1->len = p_data->write.len;
temp_spp_recv_data_node_p1->next_node = NULL;
temp_spp_recv_data_node_p1->node_buff = (uint8_t *)malloc(p_data->write.len);
if (temp_spp_recv_data_node_p1->node_buff == NULL) {
ESP_LOGI(GATTS_TABLE_TAG, "malloc error %s %d\n", __func__, __LINE__);
// Security fix: Free the node and return false to prevent memory leak
free(temp_spp_recv_data_node_p1);
temp_spp_recv_data_node_p1 = NULL;
return false;
}
memcpy(temp_spp_recv_data_node_p1->node_buff, p_data->write.value, p_data->write.len);
// Security fix: Link to list only after successful allocation
if(temp_spp_recv_data_node_p2 != NULL){
temp_spp_recv_data_node_p2->next_node = temp_spp_recv_data_node_p1;
}
temp_spp_recv_data_node_p1->len = p_data->write.len;
SppRecvDataBuff.buff_size += p_data->write.len;
temp_spp_recv_data_node_p1->next_node = NULL;
temp_spp_recv_data_node_p1->node_buff = (uint8_t *)malloc(p_data->write.len);
temp_spp_recv_data_node_p2 = temp_spp_recv_data_node_p1;
if (temp_spp_recv_data_node_p1->node_buff == NULL) {
ESP_LOGI(GATTS_TABLE_TAG, "malloc error %s %d\n", __func__, __LINE__);
temp_spp_recv_data_node_p1->len = 0;
} else {
memcpy(temp_spp_recv_data_node_p1->node_buff,p_data->write.value,p_data->write.len);
}
SppRecvDataBuff.buff_size += p_data->write.len;
if(SppRecvDataBuff.node_num == 0){
SppRecvDataBuff.first_node = temp_spp_recv_data_node_p1;
@@ -16,7 +16,6 @@
//#define SUPPORT_HEARTBEAT
//#define SPP_DEBUG_MODE
#define spp_sprintf(s,...) sprintf((char*)(s), ##__VA_ARGS__)
#define SPP_DATA_MAX_LEN (512)
#define SPP_CMD_MAX_LEN (20)
#define SPP_STATUS_MAX_LEN (20)
@@ -282,7 +282,8 @@ void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare
}
}
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
// Security fix: Use calloc to ensure memory is zero-initialized
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)calloc(1, sizeof(esp_gatt_rsp_t));
if (gatt_rsp) {
gatt_rsp->attr_value.len = param->write.len;
gatt_rsp->attr_value.handle = param->write.handle;
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -131,8 +131,24 @@ static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = {
};
static void ble_init_adv_data(const char *name)
{
int len = strlen(name);
uint8_t raw_adv_data[len+5];
if (name == NULL) {
ESP_LOGE(BT_BLE_COEX_TAG, "ble_init_adv_data: name is NULL");
return;
}
size_t len = strlen(name);
// ADV data max is 31 bytes; overhead is 5 bytes (Flags: 3, Name header: 2)
#define ADV_DATA_MAX_LEN 31
#define ADV_DATA_OVERHEAD 5
if (len > (ADV_DATA_MAX_LEN - ADV_DATA_OVERHEAD)) {
ESP_LOGW(BT_BLE_COEX_TAG, "ADV name too long (%d), truncating to %d", (int)len, ADV_DATA_MAX_LEN - ADV_DATA_OVERHEAD);
len = ADV_DATA_MAX_LEN - ADV_DATA_OVERHEAD;
}
uint8_t raw_adv_data[ADV_DATA_MAX_LEN];
size_t adv_data_len = len + ADV_DATA_OVERHEAD;
//flag
raw_adv_data[0] = 2;
raw_adv_data[1] = ESP_BT_EIR_TYPE_FLAGS;
@@ -140,16 +156,14 @@ static void ble_init_adv_data(const char *name)
//adv name
raw_adv_data[3] = len + 1;
raw_adv_data[4] = ESP_BLE_AD_TYPE_NAME_CMPL;
for (int i = 0;i < len;i++)
{
raw_adv_data[i+5] = *(name++);
}
memcpy(&raw_adv_data[5], name, len);
//The length of adv data must be less than 31 bytes
esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data));
esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, adv_data_len);
if (raw_adv_ret){
ESP_LOGE(BT_BLE_COEX_TAG, "config raw adv data failed, error code = 0x%x ", raw_adv_ret);
}
esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_adv_data, sizeof(raw_adv_data));
esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_adv_data, adv_data_len);
if (raw_scan_ret){
ESP_LOGE(BT_BLE_COEX_TAG, "config raw scan rsp data failed, error code = 0x%x", raw_scan_ret);
}
@@ -41,6 +41,7 @@
struct blufi_security {
#define DH_SELF_PUB_KEY_LEN 128
#define DH_PARAM_LEN_MAX 1024
uint8_t self_public_key[DH_SELF_PUB_KEY_LEN];
#define SHARE_KEY_LEN 128
uint8_t share_key[SHARE_KEY_LEN];
@@ -83,6 +84,13 @@ void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_da
switch (type) {
case SEC_TYPE_DH_PARAM_LEN:
blufi_sec->dh_param_len = ((data[1]<<8)|data[2]);
// Security fix: Limit DH param length to prevent DoS via large memory allocation
if (blufi_sec->dh_param_len == 0 || blufi_sec->dh_param_len > DH_PARAM_LEN_MAX) {
BLUFI_ERROR("%s, invalid dh param len %d\n", __func__, blufi_sec->dh_param_len);
blufi_sec->dh_param_len = 0;
btc_blufi_report_error(ESP_BLUFI_DH_PARAM_ERROR);
return;
}
if (blufi_sec->dh_param) {
free(blufi_sec->dh_param);
blufi_sec->dh_param = NULL;
@@ -278,6 +278,9 @@ static void handle_bt_device_result(struct disc_res_param *disc_res)
GAP_DBG_PRINTF(", %s: ", gap_bt_prop_type_names[prop->type]);
}
if (prop->type == ESP_BT_GAP_DEV_PROP_BDNAME) {
if (prop->val == NULL) {
continue;
}
name = (uint8_t *)prop->val;
name_len = strlen((const char *)name);
GAP_DBG_PRINTF("%s", (const char *)name);
@@ -164,7 +164,7 @@ void hid_demo_task(void *pvParameters)
printf("] srv 0x%03x, ", r->bt.cod.service);
print_uuid(&r->bt.uuid);
printf(", ");
if (strncmp(r->name, remote_device_name, strlen(remote_device_name)) == 0) {
if (r->name && strncmp(r->name, remote_device_name, strlen(remote_device_name)) == 0) {
break;
}
}
@@ -175,7 +175,7 @@ void hid_demo_task(void *pvParameters)
}
#if CONFIG_BT_HID_HOST_ENABLED
if (cr && strncmp(cr->name, remote_device_name, strlen(remote_device_name)) == 0) {
if (cr && cr->name && strncmp(cr->name, remote_device_name, strlen(remote_device_name)) == 0) {
esp_hidh_dev_open(cr->bda, cr->transport, cr->ble.addr_type);
}
#else
+1 -1
View File
@@ -1,5 +1,5 @@
set(IDF_VERSION_MAJOR 5)
set(IDF_VERSION_MINOR 5)
set(IDF_VERSION_PATCH 1)
set(IDF_VERSION_PATCH 2)
set(ENV{IDF_VERSION} "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}")

Some files were not shown because too many files have changed in this diff Show More