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.
Dependencies: FXAS21002 FXOS8700Q
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 Tue Jul 12 2022 20:21:03 by
