Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
sotp.c
00001 /* 00002 * Copyright (c) 2016 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 // ----------------------------------------------------------- Includes ----------------------------------------------------------- 00018 00019 #include "sotp.h" 00020 00021 #if (SYS_CONF_SOTP == SYS_CONF_SOTP_ENABLED) 00022 00023 #include "sotp_shared_lock.h" 00024 #include "pal.h" 00025 #include <string.h> 00026 #include <stdio.h> 00027 #include "sotp_int.h" 00028 #include "sotp_log.h" 00029 00030 // --------------------------------------------------------- Definitions ---------------------------------------------------------- 00031 00032 #define SOTP_FORMAT_REV 0 00033 00034 #define MEDITATE_TIME_MS 100 00035 00036 #define NUM_WRITE_RETRIES 100 00037 00038 typedef enum { 00039 AREA_STATE_NONE = 0, 00040 AREA_STATE_EMPTY, 00041 AREA_STATE_VALID, 00042 } area_state_e; 00043 00044 #define INITIAL_CRC 0xFFFFFFFF 00045 00046 #ifndef SOTP_PROBE_ONLY 00047 STATIC bool init_done = false; 00048 STATIC int32_t init_attempts = 0; 00049 STATIC uint8_t active_area; 00050 STATIC uint16_t active_area_version; 00051 // Must be aligned to the size of native integer, otherwise atomic add may not work 00052 STATIC uint32_t free_space_offset __attribute__((aligned(8))); 00053 STATIC uint32_t offset_by_type[SOTP_MAX_TYPES]; 00054 STATIC sotp_shared_lock_t write_lock; 00055 00056 00057 // Currently disable OTP feature 00058 #if 0 00059 static const sotp_type_e otp_types[] = 00060 {SOTP_TYPE_FACTORY_DONE, 00061 SOTP_TYPE_ROT, 00062 SOTP_TYPE_TRUSTED_TIME_SRV_ID, 00063 SOTP_TYPE_EXECUTION_MODE}; 00064 #endif 00065 #endif 00066 00067 STATIC palSotpAreaData_t flash_area_params[SOTP_NUM_AREAS]; 00068 00069 // -------------------------------------------------- Local Functions Declaration ---------------------------------------------------- 00070 00071 // -------------------------------------------------- Functions Implementation ---------------------------------------------------- 00072 00073 sotp_result_e sotp_garbage_collection(uint16_t type, uint16_t buf_len_bytes, const uint32_t *buf); 00074 00075 // Safely increment an integer (depending on if we're thread safe or not) 00076 // Parameters : 00077 // value - [IN] Pointer to variable. 00078 // size - [IN] Increment. 00079 // Return : Value after increment. 00080 int32_t safe_increment(int32_t* value, int32_t increment) 00081 { 00082 #ifdef SOTP_THREAD_SAFE 00083 return pal_osAtomicIncrement(value, increment); 00084 #else 00085 *value += increment; 00086 return *value; 00087 #endif 00088 } 00089 00090 // Check whether a buffer is aligned. 00091 // Parameters : 00092 // buf - [IN] Data buffer. 00093 // size - [IN] Alignment size. 00094 // Return : Boolean result. 00095 static inline bool is_buf_aligned(const void *buf, uint32_t size) 00096 { 00097 return (((size_t) buf / size * size) == (size_t) buf); 00098 } 00099 00100 // Pad an address to a specified size. 00101 // Parameters : 00102 // address - [IN] Address. 00103 // size - [IN] Size. 00104 // Return : Padded address. 00105 static inline uint32_t pad_addr(uint32_t address, uint32_t size) 00106 { 00107 return (((address-1) / size) + 1) * size; 00108 } 00109 00110 // Flash access helper functions, using area and offset notations 00111 00112 // Read from flash, given area and offset. 00113 // Parameters : 00114 // area - [IN] Flash area. 00115 // offset - [IN] Offset in area. 00116 // len_bytes - [IN] Length in bytes. 00117 // buf - [IN] Data buffer. 00118 // Return : PAL_SUCCESS on success. Error code otherwise. 00119 palStatus_t sotp_flash_read_area(uint8_t area, uint32_t offset, uint32_t len_bytes, uint32_t *buf) 00120 { 00121 return pal_internalFlashRead(len_bytes, flash_area_params[area].address + offset, buf); 00122 } 00123 00124 #ifndef SOTP_PROBE_ONLY 00125 // Write to flash, given area and offset. 00126 // Parameters : 00127 // area - [IN] Flash area. 00128 // offset - [IN] Offset in area. 00129 // len_bytes - [IN] Length in bytes. 00130 // buf - [IN] Data buffer. 00131 // Return : PAL_SUCCESS on success. Error code otherwise. 00132 palStatus_t sotp_flash_write_area(uint8_t area, uint32_t offset, uint32_t len_bytes, const uint32_t *buf) 00133 { 00134 palStatus_t ret; 00135 int i; 00136 // On some boards, write action can fail due to HW limitations (like critical actions 00137 // that disable all other actions). Just retry until success. 00138 for (i = 0; i < NUM_WRITE_RETRIES; i++) { 00139 ret = pal_internalFlashWrite(len_bytes, flash_area_params[area].address + offset, buf); 00140 if (!ret) { 00141 return ret; 00142 } 00143 pal_osDelay(1); 00144 } 00145 return ret; 00146 } 00147 00148 // Erase a flash area, given area. 00149 // Parameters : 00150 // area - [IN] Flash area. 00151 // Return : PAL_SUCCESS on success. Error code otherwise. 00152 palStatus_t sotp_flash_erase_area(uint8_t area) 00153 { 00154 palStatus_t ret; 00155 int i; 00156 // On some boards, write action can fail due to HW limitations (like critical actions 00157 // that disable all other actions). Just retry until success. 00158 for (i = 0; i < NUM_WRITE_RETRIES; i++) { 00159 ret = pal_internalFlashErase(flash_area_params[area].address, flash_area_params[area].size); 00160 if (!ret) { 00161 return ret; 00162 } 00163 pal_osDelay(1); 00164 } 00165 return ret; 00166 } 00167 #endif 00168 00169 // CRC32 calculation. Supports "rolling" calculation (using the initial value). 00170 // Parameters : 00171 // init_crc - [IN] Initial CRC. 00172 // data_len - [IN] Buffer's data length. 00173 // data_buf - [IN] Data buffer. 00174 // Return : CRC. 00175 STATIC uint32_t crc32(uint32_t init_crc, uint32_t data_len, uint8_t *data_buf) 00176 { 00177 uint32_t i, j; 00178 uint32_t crc, mask; 00179 00180 crc = init_crc; 00181 for (i = 0; i < data_len; i++) { 00182 crc = crc ^ (uint32_t) (data_buf[i]); 00183 for (j = 0; j < 8; j++) { 00184 mask = -(crc & 1); 00185 crc = (crc >> 1) ^ (0xEDB88320 & mask); 00186 } 00187 } 00188 return crc; 00189 } 00190 00191 // Scan start of latest continuous empty area in flash area. 00192 // Parameters : 00193 // area - [IN] Flash area. 00194 // offset - [OUT] Blank chunk offset. 00195 // Return : PAL_SUCCESS on success. Error code otherwise. 00196 STATIC palStatus_t calc_empty_space(uint8_t area, uint32_t *offset) 00197 { 00198 uint32_t buf[32]; 00199 uint8_t *chbuf; 00200 uint32_t i, j; 00201 palStatus_t ret; 00202 00203 *offset = flash_area_params[area].size; 00204 for (i = 0; i < flash_area_params[area].size / sizeof(buf); i++) { 00205 *offset -= sizeof(buf); 00206 ret = sotp_flash_read_area(area, *offset, sizeof(buf), buf); 00207 if (ret != PAL_SUCCESS) 00208 return ret; 00209 chbuf = (uint8_t *) buf; 00210 for (j = sizeof(buf); j > 0; j--) { 00211 if (chbuf[j-1] != SOTP_BLANK_FLASH_VAL) { 00212 *offset += j; 00213 return PAL_SUCCESS; 00214 } 00215 } 00216 } 00217 return PAL_SUCCESS; 00218 } 00219 00220 // Read a record from a given area and offset. 00221 // Parameters : 00222 // area - [IN] Flash area. 00223 // offset - [IN] Record offset. 00224 // buf_len_bytes - [IN] Length of user buffer in byte. 00225 // buf - [IN] User buffer. 00226 // actual_len_bytes 00227 // - [Out] Actual length of returned data. 00228 // validate_only - [IN] Just validate (don't return user data). 00229 // valid - [Out] Is record valid. 00230 // type - [Out] Record type. 00231 // flags - [Out] Record flags. 00232 // next_offset - [Out] If valid, offset of next record. 00233 // Return : PAL_SUCCESS on success. Error code otherwise. 00234 STATIC sotp_result_e read_record(uint8_t area, uint32_t offset, uint16_t buf_len_bytes, uint32_t *buf, 00235 uint16_t *actual_len_bytes, bool validate_only, bool *valid, 00236 uint16_t *type, uint16_t *flags, uint32_t *next_offset) 00237 { 00238 uint32_t int_buf[32]; 00239 uint32_t *buf_ptr; 00240 uint32_t data_len, chunk_len; 00241 palStatus_t pal_ret; 00242 record_header_t header; 00243 uint32_t crc = INITIAL_CRC; 00244 00245 SOTP_LOG_APPEND("read_record area:%d offs:%d len:%d. ", area, offset, buf_len_bytes); 00246 00247 *valid = true; 00248 00249 pal_ret = sotp_flash_read_area(area, offset, sizeof(header), (uint32_t *) &header); 00250 if (pal_ret != PAL_SUCCESS) { 00251 PR_ERR("read_record: sotp_flash_read_area failed with ret 0x%lx\n", pal_ret); 00252 return SOTP_READ_ERROR; 00253 } 00254 00255 crc = crc32(crc, sizeof(header) - sizeof(header.mac), (uint8_t *) &header); 00256 00257 *actual_len_bytes = 0; 00258 *type = header.type_and_flags & ~HEADER_FLAG_MASK; 00259 *flags = header.type_and_flags & HEADER_FLAG_MASK; 00260 00261 if ((*type >= SOTP_MAX_TYPES) && (*type != SOTP_MASTER_RECORD_TYPE)) { 00262 *valid = false; 00263 return SOTP_SUCCESS; 00264 } 00265 00266 data_len = header.length; 00267 offset += sizeof(header); 00268 00269 // In case of validate only enabled, we use our internal buffer for data reading, 00270 // instead of the user one. This allows us to use a smaller buffer, on which CRC 00271 // is continuously calculated. 00272 if (validate_only) { 00273 buf_ptr = int_buf; 00274 buf_len_bytes = sizeof(int_buf); 00275 } 00276 else { 00277 if (data_len > buf_len_bytes) { 00278 offset += data_len; 00279 *actual_len_bytes = data_len; 00280 *next_offset = pad_addr(offset, FLASH_MINIMAL_PROG_UNIT); 00281 return SOTP_BUFF_TOO_SMALL; 00282 } 00283 buf_ptr = buf; 00284 } 00285 00286 while (data_len) { 00287 chunk_len = PAL_MIN(data_len, buf_len_bytes); 00288 pal_ret = sotp_flash_read_area(area, offset, chunk_len, buf_ptr); 00289 if (pal_ret != PAL_SUCCESS) { 00290 PR_ERR("read_record: sotp_flash_read_area failed with ret 0x%lx\n", pal_ret); 00291 return SOTP_READ_ERROR; 00292 } 00293 crc = crc32(crc, chunk_len, (uint8_t *) buf_ptr); 00294 data_len -= chunk_len; 00295 offset += chunk_len; 00296 } 00297 00298 if (header.mac != crc) { 00299 *valid = false; 00300 return SOTP_SUCCESS; 00301 } 00302 00303 *actual_len_bytes = header.length; 00304 *next_offset = pad_addr(offset, FLASH_MINIMAL_PROG_UNIT); 00305 00306 return SOTP_SUCCESS; 00307 } 00308 00309 #ifndef SOTP_PROBE_ONLY 00310 // Write a record in a given area and offset. 00311 // Parameters : 00312 // area - [IN] Flash area. 00313 // offset - [IN] Record offset. 00314 // type - [IN] Record type. 00315 // flags - [IN] Record flags 00316 // data_len - [IN] Record's data length. 00317 // data_buf - [IN] Record's data buffer. 00318 // next_offset - [Out] offset of next record. 00319 // Return : SOTP_SUCCESS on success. Error code otherwise. 00320 STATIC sotp_result_e write_record(uint8_t area, uint32_t offset, uint16_t type, uint16_t flags, 00321 uint32_t data_len, const uint32_t *data_buf, uint32_t *next_offset) 00322 { 00323 record_header_t header; 00324 uint32_t crc = INITIAL_CRC; 00325 palStatus_t pal_ret; 00326 uint32_t write_len; 00327 SOTP_LOG_APPEND("write_record area:%d offs:%d len:%d type:%d. ", area, offset, data_len, type); 00328 00329 header.type_and_flags = type | flags; 00330 header.length = data_len; 00331 header.mac = 0; // Satisfy compiler 00332 crc = crc32(crc, sizeof(header) - sizeof(header.mac), (uint8_t *) &header); 00333 if (data_len) 00334 crc = crc32(crc, data_len, (uint8_t *) data_buf); 00335 header.mac = crc; 00336 00337 pal_ret = sotp_flash_write_area(area, offset, sizeof(header), (uint32_t *)&header); 00338 if (pal_ret != PAL_SUCCESS) { 00339 return SOTP_WRITE_ERROR; 00340 } 00341 00342 if (data_len) { 00343 offset += sizeof(header); 00344 write_len = data_len; 00345 pal_ret = sotp_flash_write_area(area, offset, write_len, data_buf); 00346 if (pal_ret != PAL_SUCCESS) { 00347 return SOTP_WRITE_ERROR; 00348 } 00349 offset += data_len; 00350 } 00351 00352 *next_offset = pad_addr(offset, FLASH_MINIMAL_PROG_UNIT); 00353 return SOTP_SUCCESS; 00354 } 00355 00356 // Write a master record in a given area. 00357 // Parameters : 00358 // area - [IN] Flash area. 00359 // version - [IN] Version. 00360 // next_offset - [Out] offset of next record. 00361 // Return : SOTP_SUCCESS on success. Error code otherwise. 00362 STATIC sotp_result_e write_master_record(uint8_t area, uint16_t version, uint32_t *next_offset) 00363 { 00364 master_record_data_t master_rec; 00365 00366 master_rec.version = version; 00367 master_rec.format_rev = SOTP_FORMAT_REV; 00368 master_rec.reserved = 0; 00369 return write_record(area, 0, SOTP_MASTER_RECORD_TYPE, 0, sizeof(master_rec), 00370 (uint32_t*) &master_rec, next_offset); 00371 } 00372 00373 // Copy a record from a given area and offset to another offset in the other area. 00374 // Parameters : 00375 // from_area - [IN] Flash area to copy from. 00376 // from_offset - [IN] Record offset in current area. 00377 // to_offset - [IN] Record offset in new area. 00378 // next_offset - [Out] Offset of next record in the new area. 00379 // Return : PAL_SUCCESS on success. Error code otherwise. 00380 STATIC sotp_result_e copy_record(uint8_t from_area, uint32_t from_offset, uint32_t to_offset, 00381 uint32_t *next_offset) 00382 { 00383 uint32_t int_buf[32]; 00384 uint32_t data_len, chunk_len; 00385 palStatus_t pal_ret; 00386 record_header_t header; 00387 SOTP_LOG_APPEND("copy_record f_area:%d f_offs:%d t_offs:%d ", 00388 from_area, from_offset, to_offset); 00389 00390 // This function assumes that the source record is valid, so no need to recalculate CRC. 00391 00392 pal_ret = sotp_flash_read_area(from_area, from_offset, sizeof(header), (uint32_t *) &header); 00393 if (pal_ret != PAL_SUCCESS) { 00394 return SOTP_READ_ERROR; 00395 } 00396 00397 SOTP_LOG_APPEND("type %d. ", header.type); 00398 00399 data_len = header.length; 00400 00401 // No need to copy records whose flags indicate deletion 00402 if (header.type_and_flags & DELETE_ITEM_FLAG) { 00403 *next_offset = pad_addr(to_offset, FLASH_MINIMAL_PROG_UNIT); 00404 return SOTP_SUCCESS; 00405 } 00406 00407 // no need to align record size here, as it won't change the outcome of this condition 00408 if (to_offset + sizeof(header) + data_len >= flash_area_params[1-from_area].size) { 00409 return SOTP_FLASH_AREA_TOO_SMALL; 00410 } 00411 00412 pal_ret = sotp_flash_write_area(1-from_area, to_offset, sizeof(header), (uint32_t *)&header); 00413 if (pal_ret != PAL_SUCCESS) { 00414 return SOTP_WRITE_ERROR; 00415 } 00416 00417 from_offset += sizeof(header); 00418 to_offset += sizeof(header); 00419 00420 while (data_len) { 00421 chunk_len = PAL_MIN(data_len, sizeof(int_buf)); 00422 pal_ret = sotp_flash_read_area(from_area, from_offset, chunk_len, int_buf); 00423 if (pal_ret != PAL_SUCCESS) { 00424 return SOTP_READ_ERROR; 00425 } 00426 pal_ret = sotp_flash_write_area(1-from_area, to_offset, chunk_len, int_buf); 00427 if (pal_ret != PAL_SUCCESS) { 00428 return SOTP_WRITE_ERROR; 00429 } 00430 00431 data_len -= chunk_len; 00432 from_offset += chunk_len; 00433 to_offset += chunk_len; 00434 } 00435 00436 *next_offset = pad_addr(to_offset, FLASH_MINIMAL_PROG_UNIT); 00437 return SOTP_SUCCESS; 00438 } 00439 00440 // Perform the garbage collection process. 00441 // Parameters : 00442 // type - [IN] Item's type. 00443 // buf_len_bytes - [IN] Item length in bytes. 00444 // buf - [IN] Pointer to user buffer. 00445 // Return : SOTP_SUCCESS on success. Error code otherwise. 00446 sotp_result_e sotp_garbage_collection(uint16_t type, uint16_t buf_len_bytes, const uint32_t *buf) 00447 { 00448 uint32_t curr_offset, new_area_offset, next_offset; 00449 uint8_t curr_area; 00450 sotp_result_e ret; 00451 00452 SOTP_LOG_CREATE("GC. "); 00453 00454 new_area_offset = sizeof(record_header_t) + sizeof(master_record_data_t); 00455 00456 // If GC is triggered by a set item request, we need to first write that item in the new location, 00457 // otherwise we may either write it twice (if already included), or lose it in case we decide 00458 // to skip it at garbage collection phase (and the system crashes). 00459 if (type != SOTP_NO_TYPE) { 00460 ret = write_record(1 - active_area, new_area_offset, type, 0, buf_len_bytes, buf, &next_offset); 00461 if (ret != SOTP_SUCCESS) { 00462 PR_ERR("sotp_garbage_collection: write_record failed with ret 0x%x\n", ret); 00463 SOTP_LOG_FINALIZE(); 00464 return ret; 00465 } 00466 offset_by_type[type] = new_area_offset | (1-active_area) << (sizeof(offset_by_type[type])*8 - 1); 00467 new_area_offset = next_offset; 00468 } 00469 00470 // Now iterate on all types, and copy the ones who have valid offsets (meaning that they exist) 00471 // to the other area. 00472 for (type = 0; type < SOTP_MAX_TYPES; type++) { 00473 curr_offset = offset_by_type[type]; 00474 curr_area = (uint8_t) (curr_offset >> (sizeof(curr_offset)*8 - 1)); 00475 curr_offset &= ~(1 << (sizeof(curr_offset)*8 - 1)); 00476 if ((!curr_offset) || (curr_area != active_area)) 00477 continue; 00478 ret = copy_record(curr_area, curr_offset, new_area_offset, &next_offset); 00479 if (ret != SOTP_SUCCESS) { 00480 PR_ERR("sotp_garbage_collection: copy_record failed with ret 0x%x\n", ret); 00481 SOTP_LOG_FINALIZE(); 00482 return ret; 00483 } 00484 offset_by_type[type] = new_area_offset | (1-curr_area) << (sizeof(offset_by_type[type])*8 - 1); 00485 new_area_offset = next_offset; 00486 } 00487 00488 // Now write master record, with version incremented by 1. 00489 active_area_version++; 00490 ret = write_master_record(1 - active_area, active_area_version, &next_offset); 00491 if (ret != SOTP_SUCCESS) { 00492 PR_ERR("sotp_garbage_collection: write_master_record failed with ret 0x%x\n", ret); 00493 SOTP_LOG_FINALIZE(); 00494 return ret; 00495 } 00496 00497 free_space_offset = new_area_offset; 00498 00499 // Only now we can switch to the new active area 00500 active_area = 1 - active_area; 00501 00502 // The older area doesn't concern us now. Erase it now. 00503 ret = sotp_flash_erase_area(1 - active_area); 00504 00505 SOTP_LOG_FINALIZE(); 00506 return ret; 00507 } 00508 00509 00510 // Get API logics helper function. Serves both Get & Get item size APIs. 00511 // Parameters : 00512 // type - [IN] Item's type. 00513 // buf_len_bytes - [IN] Item length in bytes. 00514 // buf - [IN] Pointer to user buffer. 00515 // actual_len_bytes - [OUT] Actual length of returned data. 00516 // validate_only - [IN] Just validate (don't return user data). 00517 // Return : SOTP_SUCCESS on success. Error code otherwise. 00518 STATIC sotp_result_e sotp_do_get(uint8_t type, uint16_t buf_len_bytes, uint32_t *buf, uint16_t *actual_len_bytes, 00519 bool validate_only) 00520 { 00521 sotp_result_e ret = SOTP_SUCCESS; 00522 uint32_t record_offset, next_offset; 00523 uint8_t area; 00524 uint16_t read_type, flags; 00525 bool valid; 00526 00527 SOTP_LOG_CREATE("get type:%d len:%d. ", type, buf_len_bytes); 00528 00529 if (!init_done) { 00530 ret = sotp_init(); 00531 if (ret != SOTP_SUCCESS) { 00532 SOTP_LOG_FINALIZE(); 00533 return ret; 00534 } 00535 } 00536 00537 if (type >= SOTP_MAX_TYPES) { 00538 SOTP_LOG_FINALIZE(); 00539 return SOTP_BAD_VALUE; 00540 } 00541 00542 00543 if (!buf) 00544 buf_len_bytes = 0; 00545 00546 if (buf_len_bytes && !is_buf_aligned(buf, sizeof(uint32_t))) { 00547 SOTP_LOG_FINALIZE(); 00548 return SOTP_BUFF_NOT_ALIGNED; 00549 } 00550 00551 // This loop is required for the case we try to perform reading while GC is in progress. 00552 // If so, we have the following cases: 00553 // 1. Record is still in the older area. It will be successfully read. 00554 // 2. Record was already copied to the new area. Now the offset_by_type indicates it. 00555 // So we have two cases here: 00556 // a. Read from new area succeeds. Everything's OK. 00557 // b. Read fails (either physically or CRC error). So we know that if the area taken 00558 // from offset_by_type is different from the active area, a GC is in progress, so 00559 // retry the operation. 00560 for (;;) { 00561 record_offset = offset_by_type[type]; 00562 if (!record_offset) { 00563 SOTP_LOG_FINALIZE(); 00564 return SOTP_NOT_FOUND; 00565 } 00566 00567 area = (uint8_t) (record_offset >> (sizeof(record_offset)*8 - 1)); 00568 record_offset &= ~(1 << (sizeof(record_offset)*8 - 1)); 00569 00570 ret = read_record(area, record_offset, buf_len_bytes, buf, 00571 actual_len_bytes, validate_only, &valid, 00572 &read_type, &flags, &next_offset); 00573 if ((ret == SOTP_SUCCESS) && valid) 00574 break; 00575 // In case area is the same as expected, GC is not in progress and we have a genuine error. 00576 if (area == active_area) { 00577 if (ret == SOTP_SUCCESS) { 00578 ret = SOTP_DATA_CORRUPT; 00579 } 00580 PR_ERR("sotp_do_get: read_record failed with ret 0x%x\n", ret); 00581 SOTP_LOG_FINALIZE(); 00582 return ret; 00583 } 00584 } 00585 00586 SOTP_LOG_FINALIZE(); 00587 return SOTP_SUCCESS; 00588 } 00589 00590 // Start of API functions 00591 00592 bool sotp_is_otp_type(uint32_t type) 00593 { 00594 // Currently disable OTP feature 00595 #if 0 00596 unsigned int i; 00597 for (i = 0; i < sizeof(otp_types) / sizeof(sotp_type_e); i++) { 00598 if (otp_types[i] == type) { 00599 return true; 00600 } 00601 } 00602 #endif 00603 return false; 00604 } 00605 00606 sotp_result_e sotp_get(uint32_t type, uint16_t buf_len_bytes, uint32_t *buf, uint16_t *actual_len_bytes) 00607 { 00608 return sotp_do_get((uint8_t)type, buf_len_bytes, buf, actual_len_bytes, false); 00609 } 00610 00611 sotp_result_e sotp_get_item_size(uint32_t type, uint16_t *actual_len_bytes) 00612 { 00613 return sotp_do_get((uint8_t)type, 0, NULL, actual_len_bytes, true); 00614 } 00615 00616 STATIC sotp_result_e sotp_do_set(uint32_t type, uint16_t buf_len_bytes, const uint32_t *buf, 00617 bool ignore_otp, uint16_t flags) 00618 { 00619 sotp_result_e ret = SOTP_SUCCESS; 00620 uint32_t record_offset, record_size, new_free_space; 00621 uint32_t next_offset; 00622 uint8_t save_active_area; 00623 00624 SOTP_LOG_CREATE("set type:%d len:%d. ", type, buf_len_bytes); 00625 00626 if (!init_done) { 00627 ret = sotp_init(); 00628 if (ret != SOTP_SUCCESS) { 00629 SOTP_LOG_FINALIZE(); 00630 return ret; 00631 } 00632 } 00633 00634 if (type >= SOTP_MAX_TYPES) { 00635 SOTP_LOG_FINALIZE(); 00636 return SOTP_BAD_VALUE; 00637 } 00638 00639 if (!buf) 00640 buf_len_bytes = 0; 00641 00642 if (buf_len_bytes && !is_buf_aligned(buf, sizeof(uint32_t))) { 00643 SOTP_LOG_FINALIZE(); 00644 return SOTP_BUFF_NOT_ALIGNED; 00645 } 00646 00647 if ((flags & DELETE_ITEM_FLAG) && !offset_by_type[type]) { 00648 SOTP_LOG_FINALIZE(); 00649 return SOTP_NOT_FOUND; 00650 } 00651 00652 if (!ignore_otp && sotp_is_otp_type(type) && offset_by_type[(uint8_t)type]) { 00653 SOTP_LOG_FINALIZE(); 00654 return SOTP_ALREADY_EXISTS; 00655 } 00656 00657 // writers do not lock each other exclusively, but can operate in parallel. 00658 // Shared lock is in order to prevent GC from operating (which uses exclusive lock). 00659 if (sotp_sh_lock_shared_lock(write_lock) != SOTP_SHL_SUCCESS) { 00660 PR_ERR("sotp_set: sotp_sh_lock_shared_lock failed\n"); 00661 SOTP_LOG_FINALIZE(); 00662 return SOTP_OS_ERROR; 00663 } 00664 00665 save_active_area = active_area; 00666 record_size = pad_addr(sizeof(record_header_t) + buf_len_bytes, FLASH_MINIMAL_PROG_UNIT); 00667 00668 // Parallel operation of writers is allowed due to this atomic operation. This operation 00669 // produces an offset on which each writer can work separately, without being interrupted 00670 // by the other writer. The only mutual resource here is free_space_offset - which 00671 // gets the correct value because of this atomic increment. 00672 new_free_space = safe_increment((int32_t *) &free_space_offset, record_size); 00673 record_offset = new_free_space - record_size; 00674 00675 // If we cross the area limit, we need to invoke GC. However, we should consider all the cases 00676 // where writers work in parallel, and we only want the FIRST writer to invoke GC. 00677 if (new_free_space >= flash_area_params[active_area].size) { 00678 // In the case we have crossed the limit, but the initial offset was still before the limit, this 00679 // means we are the first writer (common case). Exclusively lock write_lock, and invoke GC. 00680 if (record_offset < flash_area_params[active_area].size) { 00681 if (sotp_sh_lock_promote(write_lock) != SOTP_SHL_SUCCESS) { 00682 SOTP_LOG_FINALIZE(); 00683 return SOTP_OS_ERROR; 00684 } 00685 ret = sotp_garbage_collection((uint8_t)type, buf_len_bytes, buf); 00686 sotp_sh_lock_exclusive_release(write_lock); 00687 SOTP_LOG_FINALIZE(); 00688 return ret; 00689 } 00690 else { 00691 SOTP_LOG_APPEND("S "); 00692 // In the case we have crossed the limit, and the initial offset was also after the limit, 00693 // this means we are not first writer (uncommon case). Just wait for GC to complete. 00694 // then write record. 00695 if (sotp_sh_lock_shared_release(write_lock) != SOTP_SHL_SUCCESS) { 00696 PR_ERR("sotp_set: sotp_sh_lock_shared_release failed\n"); 00697 SOTP_LOG_FINALIZE(); 00698 return SOTP_OS_ERROR; 00699 } 00700 for (;;) { 00701 if (sotp_sh_lock_shared_lock(write_lock) != SOTP_SHL_SUCCESS) { 00702 PR_ERR("sotp_set: sotp_sh_lock_shared_lock failed\n"); 00703 SOTP_LOG_FINALIZE(); 00704 return SOTP_OS_ERROR; 00705 } 00706 if (save_active_area != active_area) { 00707 SOTP_LOG_APPEND("E "); 00708 break; 00709 } 00710 if (sotp_sh_lock_shared_release(write_lock) != SOTP_SHL_SUCCESS) { 00711 PR_ERR("sotp_set: sotp_sh_lock_shared_lock failed\n"); 00712 SOTP_LOG_FINALIZE(); 00713 return SOTP_OS_ERROR; 00714 } 00715 } 00716 new_free_space = safe_increment((int32_t *) &free_space_offset, record_size); 00717 record_offset = new_free_space - free_space_offset; 00718 } 00719 } 00720 00721 // Now write the record 00722 ret = write_record(active_area, record_offset, (uint8_t)type, flags, buf_len_bytes, buf, &next_offset); 00723 if (ret != SOTP_SUCCESS) { 00724 PR_ERR("sotp_set: write_record failed with err code 0x%x\n", ret); 00725 sotp_sh_lock_shared_release(write_lock); 00726 SOTP_LOG_FINALIZE(); 00727 return ret; 00728 } 00729 00730 // Update offset_by_type. High bit indicates area. 00731 if (flags & DELETE_ITEM_FLAG) 00732 offset_by_type[type] = 0; 00733 else 00734 offset_by_type[type] = record_offset | (active_area << (sizeof(offset_by_type[type])*8 - 1)); 00735 00736 if (sotp_sh_lock_shared_release(write_lock) != SOTP_SHL_SUCCESS) { 00737 PR_ERR("sotp_set: sotp_sh_lock_shared_release failed\n"); 00738 SOTP_LOG_FINALIZE(); 00739 return SOTP_OS_ERROR; 00740 } 00741 00742 SOTP_LOG_FINALIZE(); 00743 return SOTP_SUCCESS; 00744 } 00745 00746 sotp_result_e sotp_set(uint32_t type, uint16_t buf_len_bytes, const uint32_t *buf) 00747 { 00748 return sotp_do_set(type, buf_len_bytes, buf, false, 0); 00749 } 00750 00751 #ifdef SOTP_TESTING 00752 00753 sotp_result_e sotp_set_for_testing(uint32_t type, uint16_t buf_len_bytes, const uint32_t *buf) 00754 { 00755 return sotp_do_set(type, buf_len_bytes, buf, true, 0); 00756 } 00757 00758 sotp_result_e sotp_delete(uint32_t type) 00759 { 00760 return sotp_do_set(type, 0, NULL, true, DELETE_ITEM_FLAG); 00761 } 00762 #endif 00763 00764 sotp_result_e sotp_init(void) 00765 { 00766 uint8_t area; 00767 uint16_t type; 00768 uint16_t flags; 00769 palStatus_t pal_ret; 00770 sotp_result_e ret = SOTP_SUCCESS; 00771 #ifdef SOTP_THREAD_SAFE 00772 int32_t init_attempts_val; 00773 #endif 00774 area_state_e area_state[SOTP_NUM_AREAS] = { AREA_STATE_NONE, AREA_STATE_NONE }; 00775 uint32_t free_space_offset_of_area[SOTP_NUM_AREAS] = { 0, 0 }; 00776 uint16_t versions[SOTP_NUM_AREAS] = { 0, 0 }; 00777 uint32_t next_offset; 00778 master_record_data_t master_rec; 00779 uint16_t actual_len_bytes; 00780 bool valid; 00781 00782 if (init_done) 00783 return SOTP_SUCCESS; 00784 00785 // This handles the case that init function is called by more than one thread concurrently. 00786 // Only the one who gets the value of 1 in init_attempts_val will proceed, while others will 00787 // wait until init is finished. 00788 #ifdef SOTP_THREAD_SAFE 00789 init_attempts_val = safe_increment(&init_attempts, 1); 00790 if (init_attempts_val != 1) { 00791 while(!init_done) 00792 pal_osDelay(MEDITATE_TIME_MS); 00793 return SOTP_SUCCESS; 00794 } 00795 #endif 00796 00797 memset(offset_by_type, 0, sizeof(offset_by_type)); 00798 00799 if (sotp_sh_lock_create(&write_lock) != SOTP_SHL_SUCCESS) { 00800 PR_ERR("sotp_init: sotp_sh_lock_create failed\n"); 00801 ret = SOTP_OS_ERROR; 00802 goto init_end; 00803 } 00804 00805 for (area = 0; area < SOTP_NUM_AREAS; area++) { 00806 pal_ret = pal_internalFlashGetAreaInfo(area, &flash_area_params[area]); 00807 if (pal_ret != PAL_SUCCESS) { 00808 PR_ERR("sotp_init: pal_internalFlashGetAreaInfo failed with err code 0x%lx\n", 00809 (unsigned long) pal_ret); 00810 ret = SOTP_OS_ERROR; 00811 goto init_end; 00812 } 00813 00814 // Find start of empty space at the end of the area. This serves for both 00815 // knowing whether the area is empty and for the record traversal at the end. 00816 pal_ret = calc_empty_space(area, &(free_space_offset_of_area[area])); 00817 if (pal_ret != PAL_SUCCESS) { 00818 PR_ERR("sotp_init: calc_empty_space failed with err code 0x%lx\n", 00819 (unsigned long) pal_ret); 00820 ret = SOTP_READ_ERROR; 00821 goto init_end; 00822 } 00823 00824 if (!free_space_offset_of_area[area]) { 00825 area_state[area] = AREA_STATE_EMPTY; 00826 continue; 00827 } 00828 00829 // Check validity of master record 00830 ret = read_record(area, 0, sizeof(master_rec), (uint32_t *) &master_rec, 00831 &actual_len_bytes, false, &valid, 00832 &type, &flags, &next_offset); 00833 if (ret != SOTP_SUCCESS) { 00834 if (ret == SOTP_BUFF_TOO_SMALL) { 00835 // Buf too small error means that we have a corrupt master record - 00836 // treat it as such 00837 valid = false; 00838 } 00839 else { 00840 PR_ERR("sotp_init: read_record failed with err code 0x%x\n", ret); 00841 goto init_end; 00842 } 00843 } 00844 00845 // We have a non valid master record, in a non-empty area. Just erase the area. 00846 if ((!valid) || (type != SOTP_MASTER_RECORD_TYPE)) { 00847 pal_ret = sotp_flash_erase_area(area); 00848 if (pal_ret != PAL_SUCCESS) { 00849 PR_ERR("sotp_init: sotp_flash_erase_area failed with err code 0x%lx\n", 00850 (unsigned long) pal_ret); 00851 ret = SOTP_WRITE_ERROR; 00852 goto init_end; 00853 } 00854 area_state[area] = AREA_STATE_EMPTY; 00855 continue; 00856 } 00857 versions[area] = master_rec.version; 00858 00859 // Place free_space_offset after the master record (for the traversal, 00860 // which takes place after this loop). 00861 free_space_offset = next_offset; 00862 area_state[area] = AREA_STATE_VALID; 00863 00864 // Unless both areas are valid (a case handled later), getting here means 00865 // that we found our active area. 00866 active_area = area; 00867 active_area_version = versions[area]; 00868 } 00869 00870 // In case we have two empty areas, arbitrarily assign 0 to the active one. 00871 if ((area_state[0] == AREA_STATE_EMPTY) && (area_state[1] == AREA_STATE_EMPTY)) { 00872 active_area = 0; 00873 ret = write_master_record(active_area, 1, &free_space_offset); 00874 goto init_end; 00875 } 00876 00877 // In case we have two valid areas, choose the one having the higher version (or 0 00878 // in case of wrap around). Erase the other one. 00879 if ((area_state[0] == AREA_STATE_VALID) && (area_state[1] == AREA_STATE_VALID)) { 00880 if ((versions[0] > versions[1]) || (!versions[0])) 00881 active_area = 0; 00882 else 00883 active_area = 1; 00884 active_area_version = versions[active_area]; 00885 pal_ret = sotp_flash_erase_area(1 - active_area); 00886 if (pal_ret != PAL_SUCCESS) { 00887 PR_ERR("sotp_init: sotp_flash_erase_area failed with err code 0x%lx\n", 00888 (unsigned long) pal_ret); 00889 ret = SOTP_WRITE_ERROR; 00890 goto init_end; 00891 } 00892 } 00893 00894 // Traverse area until reaching the empty space at the end or until reaching a faulty record 00895 while (free_space_offset < free_space_offset_of_area[active_area]) { 00896 ret = read_record(active_area, free_space_offset, 0, NULL, 00897 &actual_len_bytes, true, &valid, 00898 &type, &flags, &next_offset); 00899 if (ret != SOTP_SUCCESS) { 00900 PR_ERR("sotp_init: read_record failed with err code 0x%x\n", ret); 00901 goto init_end; 00902 } 00903 // In case we have a faulty record, this probably means that the system crashed when written. 00904 // Perform a garbage collection, to make the the other area valid. 00905 if (!valid) { 00906 ret = sotp_garbage_collection(SOTP_NO_TYPE, 0, NULL); 00907 break; 00908 } 00909 if (flags & DELETE_ITEM_FLAG) 00910 offset_by_type[type] = 0; 00911 else 00912 offset_by_type[type] = free_space_offset | (active_area << (sizeof(offset_by_type[type])*8 - 1)); 00913 free_space_offset = next_offset; 00914 } 00915 00916 init_end: 00917 init_done = TRUE; 00918 return ret; 00919 } 00920 00921 sotp_result_e sotp_deinit(void) 00922 { 00923 if (init_done) { 00924 sotp_sh_lock_destroy(write_lock); 00925 } 00926 00927 init_attempts = 0; 00928 init_done = false; 00929 00930 return SOTP_SUCCESS; 00931 } 00932 00933 sotp_result_e sotp_reset(void) 00934 { 00935 uint8_t area; 00936 palStatus_t pal_ret; 00937 00938 // Erase both areas, and reinitialize the module. This is totally not thread safe, 00939 // as init doesn't take the case of re-initialization into account. It's OK, as this function 00940 // should only be called in pre-production cases. 00941 for (area = 0; area < SOTP_NUM_AREAS; area++) { 00942 if (!init_done) { 00943 pal_ret = pal_internalFlashGetAreaInfo(area, &flash_area_params[area]); 00944 if (pal_ret != PAL_SUCCESS) 00945 return SOTP_OS_ERROR; 00946 } 00947 pal_ret = sotp_flash_erase_area(area); 00948 if (pal_ret != PAL_SUCCESS) 00949 return SOTP_WRITE_ERROR; 00950 } 00951 00952 sotp_deinit(); 00953 return sotp_init(); 00954 } 00955 00956 #ifdef SOTP_TESTING 00957 00958 sotp_result_e sotp_force_garbage_collection(void) 00959 { 00960 sotp_result_e ret; 00961 00962 if (!init_done) { 00963 ret = sotp_init(); 00964 if (ret != SOTP_SUCCESS) 00965 return ret; 00966 } 00967 00968 if (sotp_sh_lock_exclusive_lock(write_lock) != SOTP_SHL_SUCCESS) { 00969 PR_ERR("sotp_force_garbage_collection: sotp_sh_lock_exclusive_lock failed"); 00970 return SOTP_OS_ERROR; 00971 } 00972 ret = sotp_garbage_collection(SOTP_NO_TYPE, 0, NULL); 00973 sotp_sh_lock_exclusive_release(write_lock); 00974 return ret; 00975 } 00976 #endif 00977 00978 #endif // SOTP_PROBE_ONLY 00979 00980 #if defined(SOTP_PROBE_ONLY) || defined(SOTP_TESTING) 00981 sotp_result_e sotp_probe(uint32_t type, uint16_t buf_len_bytes, uint32_t *buf, uint16_t *actual_len_bytes) 00982 { 00983 00984 uint8_t area; 00985 int sel_area = -1; 00986 uint16_t read_type; 00987 uint16_t flags; 00988 palStatus_t pal_ret; 00989 sotp_result_e ret = SOTP_SUCCESS, save_ret = SOTP_SUCCESS; 00990 uint32_t free_space_offset_of_area = 0; 00991 uint32_t curr_offset = 0, next_offset; 00992 master_record_data_t master_rec; 00993 uint16_t prev_version = 0; 00994 uint16_t tmp_actual_len_bytes; 00995 bool valid; 00996 bool found = 0; 00997 00998 for (area = 0; area < SOTP_NUM_AREAS; area++) { 00999 pal_ret = pal_internalFlashGetAreaInfo(area, &flash_area_params[area]); 01000 if (pal_ret != PAL_SUCCESS) { 01001 PR_ERR("sotp_probe: pal_internalFlashGetAreaInfo failed with err code 0x%lx\n", 01002 (unsigned long) pal_ret); 01003 return SOTP_OS_ERROR; 01004 } 01005 01006 // Check validity of master record 01007 ret = read_record(area, 0, sizeof(master_rec), (uint32_t *) &master_rec, 01008 actual_len_bytes, false, &valid, 01009 &read_type, &flags, &next_offset); 01010 if (ret != SOTP_SUCCESS) { 01011 if (ret == SOTP_BUFF_TOO_SMALL) { 01012 // Buf too small error means that we have a corrupt master record - 01013 // treat it as such, move to next area. 01014 continue; 01015 } 01016 else { 01017 PR_ERR("sotp_probe_type: read_record failed with err code 0x%x\n", ret); 01018 return ret; 01019 } 01020 } 01021 01022 // We have a non valid master record, move to next area. 01023 if ((!valid) || (read_type != SOTP_MASTER_RECORD_TYPE)) { 01024 continue; 01025 } 01026 01027 // Use similar logic of init's way of handling two valid areas (without erasing them of course) 01028 if ((area == 1) && (sel_area > 0)) { 01029 if ((!prev_version) || (prev_version > master_rec.version)) { 01030 // leave selected area as 0 01031 break; 01032 } 01033 } 01034 01035 prev_version = master_rec.version; 01036 curr_offset = next_offset; 01037 sel_area = area; 01038 } 01039 01040 if (sel_area < 0) { 01041 return SOTP_NOT_FOUND; 01042 } 01043 01044 area = (uint8_t) sel_area; 01045 pal_ret = calc_empty_space(area, &free_space_offset_of_area); 01046 if (pal_ret != PAL_SUCCESS) { 01047 PR_ERR("sotp_probe: calc_empty_space failed with err code 0x%lx\n", 01048 (unsigned long) pal_ret); 01049 return SOTP_READ_ERROR; 01050 } 01051 01052 // Traverse area until reaching the empty space at the end or until reaching a faulty record 01053 found = false; 01054 while (curr_offset < free_space_offset_of_area) { 01055 // first just verify, then read to user buffer 01056 ret = read_record(area, curr_offset, 0, NULL, 01057 &tmp_actual_len_bytes, true, &valid, 01058 &read_type, &flags, &next_offset); 01059 if (ret != SOTP_SUCCESS) { 01060 PR_ERR("sotp_probe: read_record failed with err code 0x%x\n", ret); 01061 return ret; 01062 } 01063 if (!valid) { 01064 break; 01065 } 01066 01067 if (read_type == type) { 01068 if (flags & DELETE_ITEM_FLAG) { 01069 found = false; 01070 } 01071 else { 01072 save_ret = read_record(area, curr_offset, buf_len_bytes, buf, 01073 actual_len_bytes, false, &valid, 01074 &read_type, &flags, &next_offset); 01075 found = true; 01076 } 01077 } 01078 curr_offset = next_offset; 01079 } 01080 01081 if (!found) { 01082 return SOTP_NOT_FOUND; 01083 } 01084 01085 return save_ret; 01086 } 01087 #endif 01088 01089 #endif
Generated on Tue Jul 12 2022 19:01:37 by 1.7.2