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