Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sotp.c Source File

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