Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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