Simple interface for Mbed Cloud Client

Dependents:  

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