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