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 pal_rtos.c Source File

pal_rtos.c

00001 /*******************************************************************************
00002  * Copyright 2016, 2017 ARM Ltd.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may 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,
00012  * WITHOUT 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 #include <stdio.h>
00018 #include "pal.h"
00019 #include "pal_plat_rtos.h"
00020 #include "sotp.h"
00021 
00022 //! Store the last saved time in SOTP (ram) for quick access
00023 PAL_PRIVATE uint64_t g_lastSavedTimeInSec = 0;
00024 
00025 //! static variables for Random functionality.
00026 //! CTR-DRBG context to be used for generating random numbers from given seed
00027 static palCtrDrbgCtxHandle_t s_ctrDRBGCtx = NULLPTR;
00028 
00029 PAL_PRIVATE palStatus_t pal_setWeakTimeForward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime);
00030 PAL_PRIVATE palStatus_t pal_setWeakTimeBackward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime);
00031 
00032 static uint64_t g_palDeviceBootTimeInSec = 0;
00033 
00034 /*
00035  * Here we define const keys for RoT derivation algorithm.
00036  * Must be 16 characters or less
00037  */
00038 #define PAL_STORAGE_SIGNATURE_128_BIT_KEY  "RoTStorageSgn128"
00039 #define PAL_STORAGE_ENCRYPTION_128_BIT_KEY "RoTStorageEnc128"
00040 #define PAL_STORAGE_ENCRYPTION_256_BIT_KEY "StorageEnc256HMACSHA256SIGNATURE"
00041 
00042 PAL_PRIVATE bool palRTOSInitialized = false;
00043 
00044 #if (PAL_SIMULATE_RTOS_REBOOT == 1)
00045     #include <unistd.h>
00046     extern char *program_invocation_name;
00047 #endif
00048 
00049 #define PAL_NOISE_WAIT_FOR_WRITERS_DELAY_MILLI_SEC 1
00050 #define PAL_NOISE_BITS_TO_BYTES(x) (x / CHAR_BIT)
00051 
00052 typedef struct palNoise
00053 {
00054     int32_t buffer[PAL_NOISE_BUFFER_LEN];
00055     volatile uint32_t bitCountAllocated;
00056     volatile uint32_t bitCountActual;
00057     volatile uint32_t numWriters;
00058     volatile bool isReading;
00059 } palNoise_t;
00060 
00061 PAL_PRIVATE palNoise_t g_noise;
00062 
00063 palStatus_t pal_noiseWriteBuffer(int32_t* buffer, uint16_t lenBits, uint16_t* bitsWritten); // forward declaration
00064 palStatus_t pal_noiseRead(int32_t buffer[PAL_NOISE_BUFFER_LEN], bool partial, uint16_t* bitsRead); // forward declaration
00065 
00066 #if PAL_USE_HW_TRNG
00067     PAL_PRIVATE palThreadID_t g_trngThreadID = NULLPTR;
00068 #endif
00069 
00070 extern palStatus_t pal_plat_CtrDRBGGenerateWithAdditional(palCtrDrbgCtxHandle_t ctx, unsigned char* out, size_t len, unsigned char* additional, size_t additionalLen);
00071 
00072 //Error Translation from SOTP module to PAL
00073 PAL_PRIVATE palStatus_t pal_osSotpErrorTranslation(sotp_result_e err)
00074 {
00075     palStatus_t ret;
00076     switch(err)
00077     {
00078         case SOTP_BAD_VALUE:
00079             ret = PAL_ERR_INVALID_ARGUMENT ;
00080             break;
00081 
00082         case SOTP_BUFF_TOO_SMALL:
00083             ret = PAL_ERR_BUFFER_TOO_SMALL ;
00084             break;
00085 
00086         case SOTP_BUFF_NOT_ALIGNED:
00087             ret = PAL_ERR_RTOS_BUFFER_NOT_ALIGNED ;
00088             break;
00089 
00090         case SOTP_READ_ERROR:
00091         case SOTP_DATA_CORRUPT:
00092         case SOTP_OS_ERROR:
00093         default:
00094             ret = PAL_ERR_GENERIC_FAILURE;
00095             break;
00096     }
00097     return ret;
00098 }
00099 
00100 palStatus_t pal_RTOSInitialize(void* opaqueContext)
00101 {
00102     palStatus_t status = PAL_SUCCESS;
00103     if (palRTOSInitialized)
00104     {
00105         return status;
00106     }
00107 
00108     status = pal_plat_RTOSInitialize (opaqueContext);
00109     if (PAL_SUCCESS == status)
00110     {
00111         memset(g_noise.buffer, 0, PAL_NOISE_SIZE_BYTES);
00112         g_noise.bitCountActual = g_noise.bitCountAllocated = 0;
00113         g_noise.numWriters = 0;
00114         g_noise.isReading = false;
00115 #if PAL_USE_HW_TRNG
00116         g_trngThreadID = NULLPTR;
00117 #endif
00118         palRTOSInitialized = true;
00119     }
00120     else
00121     {
00122         PAL_LOG(ERR, "pal_RTOSInitialize: pal_plat_RTOSInitialize failed, status=%" PRIx32 "\n", status);
00123     }
00124     return status;
00125 }
00126 
00127 palStatus_t pal_RTOSDestroy(void)
00128 {
00129     palStatus_t status = PAL_ERR_NOT_INITIALIZED ;
00130     if (!palRTOSInitialized)
00131     {
00132         return status;
00133     }
00134 
00135 #if PAL_USE_HW_TRNG
00136     if (NULLPTR != g_trngThreadID)
00137     {
00138         if (PAL_SUCCESS != pal_osThreadTerminate(&g_trngThreadID))
00139         {
00140             PAL_LOG(ERR, "pal_RTOSDestroy: failed to terminate trng noise thread\n");
00141         }
00142     }
00143 #endif
00144 
00145     if (NULLPTR != s_ctrDRBGCtx)
00146     {
00147         status = pal_CtrDRBGFree(&s_ctrDRBGCtx);
00148         if (PAL_SUCCESS != status)
00149         {
00150             PAL_LOG(ERR, "pal_RTOSDestroy: pal_CtrDRBGFree failed, status=%" PRIx32 "\n", status);
00151         }
00152     }
00153 
00154     status = pal_plat_RTOSDestroy ();
00155     if (PAL_SUCCESS != status)
00156     {
00157         PAL_LOG(ERR, "pal_RTOSDestroy: pal_plat_RTOSDestroy failed, status=%" PRIx32 "\n", status);
00158     }
00159     palRTOSInitialized = false;
00160     return status;
00161 }
00162 
00163 void pal_osReboot(void)
00164 {
00165     PAL_LOG(INFO, "pal_osReboot\r\n");
00166 #if (PAL_USE_APPLICATION_REBOOT)
00167     pal_plat_osApplicationReboot ();
00168 #else
00169     //Simulator is currently for Linux only
00170     #if (PAL_SIMULATE_RTOS_REBOOT == 1)
00171         const char *argv[] = {"0" , 0};
00172         char *const envp[] = { 0 };
00173         argv[0] = program_invocation_name;
00174 
00175         PAL_LOG(INFO, "pal_osReboot -> simulated reboot with execve(%s).\r\n", argv[0]);
00176   
00177         if (-1 == execve(argv[0], (char **)argv , envp))
00178         {
00179             PAL_LOG(ERR,"child process execve failed [%s]",argv[0]);
00180         }
00181     #else
00182         PAL_LOG(INFO, "Rebooting the system\r\n");
00183         pal_plat_osReboot ();
00184     #endif
00185 #endif
00186 }
00187 
00188 uint64_t pal_osKernelSysTick(void)
00189 {
00190     static uint64_t lastValue = 0;
00191     static uint64_t wraparoundsDetected = 0;
00192     const uint64_t one = 1;
00193     uint64_t tics = pal_plat_osKernelSysTick ();
00194     uint64_t tmp = tics + (wraparoundsDetected << 32);
00195 
00196     if (tmp < lastValue) //erez's "wraparound algorithm" if we detect a wrap around add 1 to the higher 32 bits
00197     {
00198         tmp = tmp + (one << 32);
00199         wraparoundsDetected++;
00200     }
00201     lastValue = tmp;
00202     return (uint64_t)tmp;
00203 }
00204 
00205 uint64_t pal_osKernelSysTickMicroSec(uint64_t microseconds)
00206 {
00207     uint64_t result;
00208     result = pal_plat_osKernelSysTickMicroSec (microseconds);
00209     return result;
00210 }
00211 
00212 uint64_t pal_osKernelSysMilliSecTick(uint64_t sysTicks)
00213 {
00214     uint64_t result = 0;
00215     uint64_t osTickFreq = pal_plat_osKernelSysTickFrequency ();
00216     if ((sysTicks) && (osTickFreq)) // > 0
00217     {
00218         result = (uint64_t)((sysTicks) * PAL_TICK_TO_MILLI_FACTOR / osTickFreq); //convert ticks per second to milliseconds
00219     }
00220 
00221     return result;
00222 }
00223 
00224 uint64_t pal_osKernelSysTickFrequency(void)
00225 {
00226     uint64_t result;
00227     result = pal_plat_osKernelSysTickFrequency ();
00228     return result;
00229 }
00230 
00231 palStatus_t pal_osThreadCreateWithAlloc(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, palThreadLocalStore_t* store, palThreadID_t* threadID)
00232 {
00233     PAL_VALIDATE_ARGUMENTS((NULL == function) || (PAL_osPrioritylast < priority) || (PAL_osPriorityError == priority) || (0 == stackSize) || (NULL == threadID));
00234     if (store)
00235     {
00236         PAL_LOG(ERR, "thread storage in not supported\n");
00237         return PAL_ERR_NOT_SUPPORTED ;
00238     }
00239     palStatus_t status = pal_plat_osThreadCreate (function, funcArgument, priority, stackSize, threadID);
00240     return status;
00241 }
00242 
00243 palStatus_t pal_osThreadTerminate(palThreadID_t* threadID)
00244 {
00245     PAL_VALIDATE_ARGUMENTS ((NULL == threadID) || (PAL_INVALID_THREAD == *threadID));
00246     palStatus_t status = pal_plat_osThreadTerminate (threadID);
00247     return status;
00248 }
00249 
00250 palThreadID_t pal_osThreadGetId(void)
00251 {
00252     palThreadID_t threadID = pal_plat_osThreadGetId ();
00253     return threadID;
00254 }
00255 
00256 palStatus_t pal_osDelay(uint32_t milliseconds)
00257 {
00258     palStatus_t status;
00259     status = pal_plat_osDelay (milliseconds);
00260     return status;
00261 }
00262 
00263 palStatus_t pal_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID)
00264 {
00265     PAL_VALIDATE_ARGUMENTS(NULL == timerID || NULL == function);
00266     palStatus_t status;
00267     status = pal_plat_osTimerCreate (function, funcArgument, timerType, timerID);
00268     return status;
00269 }
00270 
00271 palStatus_t pal_osTimerStart(palTimerID_t timerID, uint32_t millisec)
00272 {
00273     PAL_VALIDATE_ARGUMENTS (NULLPTR == timerID);
00274     palStatus_t status;
00275     if (0 == millisec)
00276     {
00277         return PAL_ERR_RTOS_VALUE ;
00278     }
00279     status = pal_plat_osTimerStart (timerID, millisec);
00280     return status;
00281 }
00282 
00283 palStatus_t pal_osTimerStop(palTimerID_t timerID)
00284 {
00285     PAL_VALIDATE_ARGUMENTS(NULLPTR == timerID);
00286     palStatus_t status;
00287     status = pal_plat_osTimerStop (timerID);
00288     return status;
00289 }
00290 
00291 palStatus_t pal_osTimerDelete(palTimerID_t* timerID)
00292 {
00293     PAL_VALIDATE_ARGUMENTS(NULL == timerID || NULLPTR == *timerID);
00294     palStatus_t status;
00295     status = pal_plat_osTimerDelete (timerID);
00296     return status;
00297 }
00298 
00299 palStatus_t pal_osMutexCreate(palMutexID_t* mutexID)
00300 {
00301     PAL_VALIDATE_ARGUMENTS(NULL == mutexID);
00302     palStatus_t status;
00303     status = pal_plat_osMutexCreate (mutexID);
00304     return status;
00305 }
00306 
00307 palStatus_t pal_osMutexWait(palMutexID_t mutexID, uint32_t millisec)
00308 {
00309     PAL_VALIDATE_ARGUMENTS((NULLPTR == mutexID));
00310     palStatus_t status;
00311     status = pal_plat_osMutexWait (mutexID, millisec);
00312     return status;
00313 }
00314 
00315 palStatus_t pal_osMutexRelease(palMutexID_t mutexID)
00316 {
00317     PAL_VALIDATE_ARGUMENTS(NULLPTR == mutexID);
00318     palStatus_t status;
00319     status = pal_plat_osMutexRelease (mutexID);
00320     return status;
00321 }
00322 
00323 palStatus_t pal_osMutexDelete(palMutexID_t* mutexID)
00324 {
00325     PAL_VALIDATE_ARGUMENTS(NULL == mutexID || NULLPTR == *mutexID);
00326     palStatus_t status;
00327     status = pal_plat_osMutexDelete (mutexID);
00328     return status;
00329 }
00330 
00331 palStatus_t pal_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID)
00332 {
00333     PAL_VALIDATE_ARGUMENTS(NULL == semaphoreID);
00334     palStatus_t status;
00335     status = pal_plat_osSemaphoreCreate (count, semaphoreID);
00336     return status;
00337 }
00338 
00339 palStatus_t pal_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec,  int32_t* countersAvailable)
00340 {
00341     PAL_VALIDATE_ARGUMENTS(NULLPTR == semaphoreID);
00342     palStatus_t status;
00343     status = pal_plat_osSemaphoreWait (semaphoreID, millisec, countersAvailable);
00344     return status;
00345 }
00346 
00347 palStatus_t pal_osSemaphoreRelease(palSemaphoreID_t semaphoreID)
00348 {
00349     PAL_VALIDATE_ARGUMENTS(NULLPTR == semaphoreID);
00350     palStatus_t status;
00351     status = pal_plat_osSemaphoreRelease (semaphoreID);
00352     return status;
00353 }
00354 
00355 palStatus_t pal_osSemaphoreDelete(palSemaphoreID_t* semaphoreID)
00356 {
00357     PAL_VALIDATE_ARGUMENTS(NULL == semaphoreID || NULLPTR == *semaphoreID);
00358     palStatus_t status;
00359     status = pal_plat_osSemaphoreDelete (semaphoreID);
00360     return status;
00361 }
00362 
00363 
00364 int32_t pal_osAtomicIncrement(int32_t* valuePtr, int32_t increment)
00365 {
00366     PAL_VALIDATE_ARGUMENTS(NULL == valuePtr);
00367     int32_t result;
00368     result = pal_plat_osAtomicIncrement (valuePtr, increment);
00369     return result;
00370 }
00371 
00372 
00373 PAL_PRIVATE uint64_t pal_sysTickTimeToSec()
00374 {
00375     uint64_t sysTicksFromBoot = pal_osKernelSysTick();
00376     uint64_t secFromBoot = pal_osKernelSysMilliSecTick(sysTicksFromBoot) / PAL_MILLI_PER_SECOND;
00377 
00378     return secFromBoot;
00379 }
00380 
00381 uint64_t pal_osGetTime(void)
00382 {
00383     uint64_t curSysTimeInSec = 0;
00384     if (0 < g_palDeviceBootTimeInSec) //time was previously set
00385     {
00386         uint64_t secFromBoot = pal_sysTickTimeToSec();
00387         curSysTimeInSec = g_palDeviceBootTimeInSec + secFromBoot; //boot time in sec + sec passed since boot
00388 
00389         if((curSysTimeInSec > g_lastSavedTimeInSec) && (curSysTimeInSec - g_lastSavedTimeInSec > PAL_LAST_SAVED_TIME_LATENCY_SEC))
00390         {
00391             sotp_result_e status = SOTP_SUCCESS;
00392             status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&curSysTimeInSec);
00393             if (SOTP_SUCCESS != status)
00394             {
00395                 PAL_LOG(ERR,"SOTP set time failed \n");  
00396             }
00397             else
00398             {
00399                 g_lastSavedTimeInSec = curSysTimeInSec;
00400             }
00401                      
00402         }
00403     }
00404 
00405     return curSysTimeInSec;
00406 }
00407 
00408 palStatus_t pal_osSetTime(uint64_t seconds)
00409 {
00410     palStatus_t status = PAL_SUCCESS;
00411     if(0 == seconds)
00412     {
00413         g_palDeviceBootTimeInSec = 0;
00414     }
00415     else if (seconds < (uint64_t)PAL_MIN_SEC_FROM_EPOCH)
00416     {
00417         status = PAL_ERR_INVALID_TIME ;
00418     }
00419     else
00420     {
00421         uint64_t secFromBoot = pal_sysTickTimeToSec();
00422         g_palDeviceBootTimeInSec = seconds - secFromBoot; //update device boot time
00423     }
00424 
00425     return status;
00426 }
00427 
00428 
00429 
00430 #if PAL_USE_HW_TRNG
00431 PAL_PRIVATE void pal_trngNoiseThreadFunc(void const* arg)
00432 {
00433     uint8_t buf[PAL_NOISE_SIZE_BYTES] PAL_PTR_ADDR_ALIGN_UINT8_TO_UINT32 = { 0 };
00434     size_t trngBytesRead = 0;
00435     uint16_t noiseBitsWritten = 0;
00436     palStatus_t status;
00437     while (true)
00438     {
00439         status = pal_plat_osRandomBuffer (buf, PAL_NOISE_SIZE_BYTES, &trngBytesRead);
00440         if ((0 < trngBytesRead) && ((PAL_SUCCESS == status) || (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status)))
00441         {
00442             noiseBitsWritten = 0;
00443             status = pal_noiseWriteBuffer((int32_t*)buf, (trngBytesRead * CHAR_BIT), &noiseBitsWritten);            
00444         }
00445         pal_osDelay(PAL_NOISE_TRNG_THREAD_DELAY_MILLI_SEC);
00446     }
00447 }
00448 #endif // PAL_USE_HW_TRNG
00449 
00450 
00451 // this function generates drbg with the possibility of adding noise as additional input to the drbg function.
00452 PAL_PRIVATE palStatus_t pal_generateDrbgWithNoiseAttempt(palCtrDrbgCtxHandle_t drbgContext, uint8_t* outBuffer, bool partial, size_t numBytesToGenerate)
00453 {
00454     uint16_t bitsRead = 0;
00455     int32_t buffer[PAL_NOISE_BUFFER_LEN] = { 0 };
00456     palStatus_t status = pal_noiseRead(buffer, partial, &bitsRead);
00457     if (PAL_SUCCESS == status)
00458     {
00459         status = pal_plat_CtrDRBGGenerateWithAdditional(drbgContext, (unsigned char*)outBuffer, numBytesToGenerate, (unsigned char*)buffer, (size_t)PAL_NOISE_BITS_TO_BYTES(bitsRead));
00460     }
00461     else
00462     {
00463         status = pal_CtrDRBGGenerate(drbgContext, (unsigned char*)outBuffer, numBytesToGenerate);
00464     }
00465     return status;
00466 }
00467 
00468 palStatus_t pal_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes)
00469 {
00470     PAL_VALIDATE_ARGUMENTS (NULL == randomBuf);
00471 
00472     palStatus_t status = PAL_ERR_GENERIC_FAILURE;
00473     if (palRTOSInitialized == true)
00474     {
00475         if (NULLPTR == s_ctrDRBGCtx)
00476         {
00477             uint32_t sotpCounter = 0;
00478             uint8_t buf[(PAL_INITIAL_RANDOM_SIZE * 2 + sizeof(sotpCounter))] PAL_PTR_ADDR_ALIGN_UINT8_TO_UINT32 = { 0 }; // space for 48 bytes short term + 48 bytes long term + 4 counter bytes (note this buffer will also be used to collect TRNG noise)
00479             const uint16_t sotpLenBytes = PAL_INITIAL_RANDOM_SIZE + sizeof(sotpCounter); // the max number of bytes expected to be read/written form/to sotp, note that sotpCounter will probably be empty the 1st time data is read from sotp
00480             uint32_t* ptrSotpRead = (uint32_t*)&buf; // pointer to the memory address in buf which will point to the data that will be read from sotp
00481             uint32_t* ptrSotpWrite = (uint32_t*)&buf[PAL_INITIAL_RANDOM_SIZE]; // pointer to the memory address in buf which will point to the data which needs to be written back to sotp
00482             uint32_t* ptrSotpCounterRead = ptrSotpWrite; // pointer to the memory address in buf which will point to the counter read from sotp
00483             uint32_t* ptrSotpCounterWrite = (uint32_t*)&buf[PAL_INITIAL_RANDOM_SIZE * 2]; // pointer to the memory address in buf which will point to the incremented counter which will be written back to sotp
00484             uint16_t sotpBytesRead = 0, noiseBitsWrittern = 0;
00485             size_t trngBytesRead = 0;
00486             palCtrDrbgCtxHandle_t longCtrDRBGCtx = NULLPTR; // long term drbg context            
00487             palStatus_t tmpStatus;
00488             sotp_result_e sotpResult = sotp_get(SOTP_TYPE_RANDOM_SEED, sotpLenBytes, ptrSotpRead, &sotpBytesRead); // read 48 drbg bytes + 4 counter bytes
00489             if (SOTP_SUCCESS == sotpResult)
00490             {
00491                 if ((PAL_INITIAL_RANDOM_SIZE != sotpBytesRead) && (sotpLenBytes != sotpBytesRead))
00492                 {
00493                     status = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
00494                     PAL_LOG(ERR, "Invalid number of bytes read from sotp, bytes read=%" PRIu16, sotpBytesRead);
00495                     goto finish;
00496                 }
00497                 status = pal_CtrDRBGInit(&longCtrDRBGCtx, ptrSotpRead, PAL_INITIAL_RANDOM_SIZE); // initialize long term drbg with the seed that was read from sotp
00498                 if (PAL_SUCCESS != status)
00499                 {
00500                     PAL_LOG(ERR, "Failed to initialize long term drbg context, status=%" PRIx32 "\n", status);
00501                     goto finish;
00502                 }
00503                 memcpy((void*)&sotpCounter, (void*)ptrSotpCounterRead, sizeof(sotpCounter)); // read the counter from the buffer (sotp data) to local var
00504 #if PAL_USE_HW_TRNG
00505                 memset((void*)buf, 0, sizeof(buf));                
00506                 status = pal_plat_osRandomBuffer (buf, PAL_NOISE_SIZE_BYTES, &trngBytesRead);
00507                 if ((PAL_SUCCESS == status) || (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status))
00508                 {
00509                     if (0 < trngBytesRead)
00510                     {
00511                         tmpStatus = pal_noiseWriteBuffer((int32_t*)buf, (trngBytesRead * CHAR_BIT), &noiseBitsWrittern); // write whatever was collected from trng to the noise buffer
00512                         PAL_LOG(DBG, "Write trng to noise buffer, status=%" PRIx32 ", bits writtern=%" PRIu16 "\n", tmpStatus, noiseBitsWrittern);
00513                     }
00514                 }
00515                 else
00516                 {
00517                     PAL_LOG(ERR, "Read from TRNG failed, status=%" PRIx32 "\n", status);
00518                 }                
00519 #endif // PAL_USE_HW_TRNG
00520                 memset((void*)buf, 0, sizeof(buf));
00521                 status = pal_generateDrbgWithNoiseAttempt(longCtrDRBGCtx, buf, true, (PAL_INITIAL_RANDOM_SIZE * 2)); // generate 96 bytes, the 1st 48 bytes will be used for short term drbg and the other 48 bytes will be used for long term drbg
00522                 if (PAL_SUCCESS != status)
00523                 {
00524                     PAL_LOG(ERR, "Failed to gererate drbg long term and short term seeds, status=%" PRIx32 "\n", status);
00525                     goto drbg_cleanup;
00526                 }
00527                 sotpCounter++; // increment counter before writting it back to sotp
00528                 memcpy((void*)ptrSotpCounterWrite, (void*)&sotpCounter, sizeof(sotpCounter)); // copy the incremented counter to the last 4 bytes of the buffer
00529                 sotpResult = sotp_set(SOTP_TYPE_RANDOM_SEED, sotpLenBytes, ptrSotpWrite); // write 48 long term drbg bytes + 4 counter bytes
00530                 if (SOTP_SUCCESS != sotpResult)
00531                 {
00532                     PAL_LOG(ERR, "Failed to write to sotp, sotp result=%d", sotpResult);
00533                     status = PAL_ERR_GENERIC_FAILURE;
00534                 }                
00535 drbg_cleanup:
00536                 {
00537                     tmpStatus = pal_CtrDRBGFree(&longCtrDRBGCtx);
00538                     if (PAL_SUCCESS != tmpStatus)
00539                     {
00540                         PAL_LOG(ERR, "Failed to free long term drbg context, status=%" PRIx32 "\n", tmpStatus);
00541                     }
00542                     longCtrDRBGCtx = NULLPTR;                    
00543                     if (PAL_SUCCESS != status)
00544                     {
00545                         goto finish;
00546                     }
00547 #if PAL_USE_HW_TRNG
00548                     status = pal_osThreadCreateWithAlloc(pal_trngNoiseThreadFunc, NULL, PAL_osPriorityReservedTRNG, PAL_NOISE_TRNG_THREAD_STACK_SIZE, NULL, &g_trngThreadID);
00549                     if (PAL_SUCCESS != status)
00550                     {
00551                         PAL_LOG(ERR, "Failed to create noise trng thread, status=%" PRIx32 "\n", tmpStatus);
00552                     }
00553 #endif // PAL_USE_HW_TRNG
00554                 }
00555             }
00556             else if (SOTP_NOT_FOUND == sotpResult)
00557             {
00558 #if PAL_USE_HW_TRNG
00559                 memset((void*)buf, 0, sizeof(buf));
00560                 uint8_t* seedPtr = buf;
00561                 size_t randomCounterBytes = 0;
00562                 do
00563                 {
00564                     status = pal_plat_osRandomBuffer (seedPtr, PAL_INITIAL_RANDOM_SIZE - randomCounterBytes, &trngBytesRead);
00565                     if (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status)
00566                     {
00567                         pal_osDelay(PAL_TRNG_COLLECT_DELAY_MILLI_SEC); // sleep to let the device to collect random data.
00568                         randomCounterBytes += trngBytesRead;
00569                         seedPtr += trngBytesRead;
00570                     }
00571                 } while (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status);
00572 #endif // PAL_USE_HW_TRNG
00573             }
00574             if (PAL_SUCCESS != status)
00575             {
00576                 goto finish;
00577             }
00578             status = pal_CtrDRBGInit(&s_ctrDRBGCtx, (void*)buf, PAL_INITIAL_RANDOM_SIZE);
00579             if (PAL_SUCCESS != status)
00580             {
00581                 PAL_LOG(ERR, "Failed to initialize short term drbg context, status=%" PRIx32 "\n", status);
00582                 goto finish;
00583             }
00584         }
00585         status = pal_generateDrbgWithNoiseAttempt(s_ctrDRBGCtx, randomBuf, false, bufSizeBytes);
00586         if (PAL_SUCCESS != status)
00587         {
00588             PAL_LOG(ERR, "Failed to gererate random, status=%" PRIx32 "\n", status);
00589         }
00590     }
00591     else
00592     {
00593         return PAL_ERR_NOT_INITIALIZED ;
00594     }
00595 finish:
00596     return status;
00597 }
00598 
00599 palStatus_t pal_osRandom32bit(uint32_t *random)
00600 {
00601     palStatus_t status = PAL_SUCCESS;
00602 
00603     PAL_VALIDATE_ARGUMENTS(NULL == random);
00604         
00605     status = pal_osRandomBuffer((uint8_t*)random, sizeof(uint32_t));
00606     return status;
00607 }
00608 
00609 
00610 PAL_PRIVATE palStatus_t pal_osGetRoT(uint8_t * key,size_t keyLenBytes)
00611 {
00612     palStatus_t palStatus = PAL_SUCCESS;
00613 #if (PAL_USE_HW_ROT)
00614     palStatus = pal_plat_osGetRoTFromHW (key, keyLenBytes);
00615 #else
00616     sotp_result_e sotpStatus = SOTP_SUCCESS;
00617     uint16_t actual_size;
00618     sotpStatus = sotp_get(SOTP_TYPE_ROT, keyLenBytes, (uint32_t *)key, &actual_size);
00619     if (SOTP_NOT_FOUND == sotpStatus) 
00620     {
00621         palStatus = pal_osRandomBuffer(key , keyLenBytes);
00622         if (PAL_SUCCESS == palStatus) 
00623         {
00624             sotpStatus = sotp_set(SOTP_TYPE_ROT,keyLenBytes, (uint32_t *)key);
00625         }
00626     }
00627     if (SOTP_SUCCESS != sotpStatus)
00628     {
00629         palStatus = pal_osSotpErrorTranslation(sotpStatus);
00630     }
00631 #endif
00632     return palStatus;
00633 }
00634 
00635 palStatus_t pal_osGetDeviceKey(palDevKeyType_t keyType, uint8_t *key, size_t keyLenBytes)
00636 {
00637     palStatus_t status = PAL_SUCCESS;
00638     uint8_t rotBuffer[PAL_DEVICE_KEY_SIZE_IN_BYTES] __attribute__ ((aligned(4))) = {0};
00639 
00640     
00641     PAL_VALIDATE_CONDITION_WITH_ERROR(((keyLenBytes < PAL_DEVICE_KEY_SIZE_IN_BYTES) || ((palOsStorageHmacSha256  == keyType) && (keyLenBytes < PAL_SHA256_DEVICE_KEY_SIZE_IN_BYTES))),PAL_ERR_BUFFER_TOO_SMALL )
00642 
00643     PAL_VALIDATE_CONDITION_WITH_ERROR ((NULL == key),PAL_ERR_NULL_POINTER )
00644 
00645     status = pal_osGetRoT(rotBuffer, keyLenBytes);
00646     if (PAL_SUCCESS == status)
00647     {   // Logic of RoT according to key type using 128 bit strong Key Derivation Algorithm
00648 
00649 #if (PAL_DEVICE_KEY_DERIVATION_BACKWARD_COMPATIBILITY_CALC == 1) //calculate the key derivation in an old way
00650         switch(keyType)
00651         {
00652             case palOsStorageEncryptionKey128Bit:
00653             {
00654                 //USE strong KDF here!
00655                 status = pal_cipherCMAC((const unsigned char*)PAL_STORAGE_ENCRYPTION_128_BIT_KEY, PAL_DEVICE_KEY_SIZE_IN_BITS, (const unsigned char *)rotBuffer, PAL_DEVICE_KEY_SIZE_IN_BYTES, key);
00656                 break;
00657             }
00658             case palOsStorageSignatureKey128Bit :
00659             {
00660                 //USE strong KDF here!
00661                 status = pal_cipherCMAC((const unsigned char *)PAL_STORAGE_SIGNATURE_128_BIT_KEY, PAL_DEVICE_KEY_SIZE_IN_BITS, (const unsigned char *)rotBuffer, PAL_DEVICE_KEY_SIZE_IN_BYTES, key);
00662                 break;
00663             }
00664             case palOsStorageHmacSha256 :
00665             {
00666                 size_t outputLenInBytes = 0;
00667                 status = pal_mdHmacSha256((const unsigned char *)PAL_STORAGE_ENCRYPTION_256_BIT_KEY, PAL_SHA256_DEVICE_KEY_SIZE_IN_BYTES, (const unsigned char*)rotBuffer, PAL_DEVICE_KEY_SIZE_IN_BYTES, key, &outputLenInBytes);
00668                 break;
00669             }
00670             default:
00671                 status = PAL_ERR_GET_DEV_KEY ;
00672         } //switch end
00673 #else //calculate the key derivation in a new way
00674         switch(keyType)
00675         {
00676             case palOsStorageEncryptionKey128Bit:
00677             {
00678                 //USE strong KDF here!
00679                 status = pal_cipherCMAC((const unsigned char*)rotBuffer, PAL_DEVICE_KEY_SIZE_IN_BITS, (const unsigned char *)PAL_STORAGE_ENCRYPTION_128_BIT_KEY, PAL_DEVICE_KEY_SIZE_IN_BYTES, key);
00680                 break;
00681             }
00682             case palOsStorageSignatureKey128Bit :
00683             {
00684                 //USE strong KDF here!
00685                 status = pal_cipherCMAC((const unsigned char*)rotBuffer, PAL_DEVICE_KEY_SIZE_IN_BITS, (const unsigned char *)PAL_STORAGE_SIGNATURE_128_BIT_KEY, PAL_DEVICE_KEY_SIZE_IN_BYTES, key);                
00686                 break;
00687             }
00688             case palOsStorageHmacSha256 :
00689             {
00690                 size_t outputLenInBytes = 0;
00691                 status = pal_mdHmacSha256((const unsigned char*)rotBuffer, PAL_DEVICE_KEY_SIZE_IN_BYTES, (const unsigned char *)PAL_STORAGE_ENCRYPTION_256_BIT_KEY, PAL_SHA256_DEVICE_KEY_SIZE_IN_BYTES, key, &outputLenInBytes);                
00692                 break;
00693             }
00694             default:
00695                 status = PAL_ERR_GET_DEV_KEY ;
00696         } //switch end
00697 #endif        
00698 
00699     } // outer if
00700     else
00701     {
00702         status = PAL_ERR_GET_DEV_KEY ;
00703     }
00704 
00705     return status;
00706 
00707 }
00708 
00709 palStatus_t pal_initTime(void)
00710 {
00711     uint64_t rtcTime = 0;
00712     uint64_t sotpGetTime = 0, sotpLastTimeBack = 0;
00713     palStatus_t ret = PAL_SUCCESS;
00714     sotp_result_e status = SOTP_SUCCESS;
00715     uint16_t actualLenBytes = 0;
00716 
00717     status = sotp_get(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t*)&sotpGetTime, &actualLenBytes);
00718     if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
00719     {
00720         ret = pal_osSotpErrorTranslation(status);
00721     }
00722     else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
00723     {
00724         ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
00725     }
00726 
00727     status = sotp_get(SOTP_TYPE_LAST_TIME_BACK, sizeof(uint64_t), (uint32_t*)&sotpLastTimeBack, &actualLenBytes);
00728     if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
00729     {
00730         ret = pal_osSotpErrorTranslation(status);
00731     }
00732     else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
00733     {
00734         ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
00735     }
00736 
00737     if (sotpLastTimeBack > sotpGetTime)
00738     {//Enter here only when reset occurs during set weak or strong time
00739         status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&sotpLastTimeBack);
00740         if (SOTP_SUCCESS != status)
00741         {
00742             ret = pal_osSotpErrorTranslation(status);
00743         }
00744         sotpGetTime = sotpLastTimeBack;
00745     }
00746     g_lastSavedTimeInSec = sotpGetTime;
00747 
00748 #if (PAL_USE_HW_RTC)
00749     if (PAL_SUCCESS == ret)
00750     {
00751         ret = pal_plat_osGetRtcTime(&rtcTime);
00752     }
00753 #endif
00754 
00755     if (PAL_SUCCESS == ret)
00756     {//set the max time as boot time of the device
00757        pal_osSetTime(PAL_MAX(rtcTime, sotpGetTime));
00758     }
00759     return ret;
00760 }
00761 
00762 
00763 palStatus_t pal_osSetStrongTime(uint64_t setNewTimeInSeconds)
00764 {
00765     palStatus_t ret = PAL_SUCCESS;
00766 
00767     uint64_t getSotpTimeValue = 0;
00768     uint16_t actualLenBytes = 0;
00769     sotp_result_e status = SOTP_SUCCESS;
00770     
00771 #if (PAL_USE_HW_RTC)
00772     //RTC Time Latency
00773     if (PAL_SUCCESS == ret)
00774     {
00775         uint64_t getRtcTimeValue = 0;
00776         ret = pal_plat_osGetRtcTime(&getRtcTimeValue);
00777         if (PAL_SUCCESS == ret)
00778         {
00779             if(llabs(setNewTimeInSeconds - getRtcTimeValue) > PAL_MINIMUM_RTC_LATENCY_SEC)
00780             {
00781                 ret = pal_plat_osSetRtcTime(setNewTimeInSeconds);
00782             }
00783         }
00784     }
00785 #endif
00786 
00787     status = sotp_get(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&getSotpTimeValue, &actualLenBytes);
00788     if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
00789     {
00790         ret = pal_osSotpErrorTranslation(status);
00791     }
00792     else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
00793     {
00794         ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
00795     }    
00796     else if (((setNewTimeInSeconds > getSotpTimeValue) && (setNewTimeInSeconds - getSotpTimeValue > PAL_MINIMUM_SOTP_FORWARD_LATENCY_SEC)) //Forward Time
00797             || ((setNewTimeInSeconds < getSotpTimeValue) && (getSotpTimeValue - setNewTimeInSeconds > PAL_MINIMUM_SOTP_BACKWARD_LATENCY_SEC))) //Backward Time
00798     {
00799         status = sotp_set(SOTP_TYPE_LAST_TIME_BACK, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
00800         if (SOTP_SUCCESS != status)
00801         {
00802             ret = pal_osSotpErrorTranslation(status);
00803         }
00804         else
00805         {            
00806             status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
00807             if (SOTP_SUCCESS != status)
00808             {
00809                 ret = pal_osSotpErrorTranslation(status);
00810             }
00811             g_lastSavedTimeInSec = setNewTimeInSeconds;
00812         }
00813     }
00814 
00815     if(PAL_SUCCESS == ret)
00816     {
00817        ret = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
00818     }
00819 
00820     return ret;
00821 }
00822 
00823 PAL_PRIVATE palStatus_t pal_setWeakTimeForward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime)
00824 {
00825     sotp_result_e status = SOTP_SUCCESS;
00826     palStatus_t ret = PAL_SUCCESS;
00827 
00828     ret = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
00829 #if (PAL_USE_HW_RTC)
00830     //RTC Time Forward
00831     if (PAL_SUCCESS == ret)
00832     {
00833         uint64_t getRtcTimeValue = 0;
00834         ret = pal_plat_osGetRtcTime(&getRtcTimeValue);
00835         if (PAL_SUCCESS == ret)
00836         {
00837             if((setNewTimeInSeconds > getRtcTimeValue) && (setNewTimeInSeconds - getRtcTimeValue > PAL_MINIMUM_RTC_LATENCY_SEC))
00838             {
00839                 ret = pal_plat_osSetRtcTime(setNewTimeInSeconds);
00840             }
00841         }
00842     }
00843 #endif// (PAL_USE_HW_RTC)
00844 
00845     if ((setNewTimeInSeconds - currentOsTime > PAL_MINIMUM_SOTP_FORWARD_LATENCY_SEC) && (PAL_SUCCESS == ret))
00846     {//SOTP time forward
00847         status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
00848         if (SOTP_SUCCESS != status)
00849         {
00850             ret = pal_osSotpErrorTranslation(status);
00851         }
00852         else
00853         {
00854             g_lastSavedTimeInSec = setNewTimeInSeconds;
00855         }
00856     }
00857     return ret;
00858 }
00859 
00860 PAL_PRIVATE palStatus_t pal_setWeakTimeBackward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime)
00861 {
00862     uint64_t getSotpTimeValue = 0;
00863     uint16_t actualLenBytes = 0;
00864     sotp_result_e status = SOTP_SUCCESS;
00865     palStatus_t ret = PAL_SUCCESS;
00866 
00867     status = sotp_get(SOTP_TYPE_LAST_TIME_BACK, sizeof(uint64_t), (uint32_t *)&getSotpTimeValue, &actualLenBytes);
00868     if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
00869     {
00870         ret = pal_osSotpErrorTranslation(status);
00871     }
00872     else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
00873     {
00874         ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
00875     }
00876     else if (setNewTimeInSeconds > getSotpTimeValue)
00877     {
00878         if ((setNewTimeInSeconds - getSotpTimeValue) / PAL_RATIO_SECONDS_PER_DAY  > (currentOsTime - setNewTimeInSeconds))
00879         {
00880             status = sotp_set(SOTP_TYPE_LAST_TIME_BACK, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
00881             if (SOTP_SUCCESS != status)
00882             {
00883                 ret = pal_osSotpErrorTranslation(status);
00884             }
00885             else
00886             {               
00887                 status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
00888                 if (SOTP_SUCCESS != status)
00889                 {
00890                     ret = pal_osSotpErrorTranslation(status);
00891                 }
00892                 else
00893                 {
00894                     g_lastSavedTimeInSec = setNewTimeInSeconds;
00895                     ret = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
00896                 }
00897             }
00898         }
00899     }
00900 
00901     return ret;
00902 }
00903 
00904 palStatus_t pal_osSetWeakTime(uint64_t setNewTimeInSeconds)
00905 {
00906     uint64_t getSotpTimeValue = 0;
00907     uint16_t actualLenBytes = 0;
00908     sotp_result_e status = SOTP_SUCCESS;
00909     palStatus_t ret = PAL_SUCCESS;
00910     uint64_t getOsTimeValue = 0;
00911     
00912     getOsTimeValue = pal_osGetTime(); //get current system time
00913 
00914     if (setNewTimeInSeconds > getOsTimeValue)
00915     {//Time Forward
00916         ret = pal_setWeakTimeForward(setNewTimeInSeconds, getOsTimeValue);
00917     }
00918     else if (getOsTimeValue > setNewTimeInSeconds)
00919     {//Time Backward
00920         ret = pal_setWeakTimeBackward(setNewTimeInSeconds, getOsTimeValue);
00921     }
00922 
00923     if(PAL_SUCCESS == ret)
00924     {
00925         getSotpTimeValue = 0;
00926         status = sotp_get(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&getSotpTimeValue, &actualLenBytes);
00927         if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
00928         {
00929             ret = pal_osSotpErrorTranslation(status);
00930         }
00931         else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
00932         {
00933             ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
00934         }
00935         else if ((setNewTimeInSeconds > getSotpTimeValue) && (setNewTimeInSeconds - getSotpTimeValue > PAL_MINIMUM_STORAGE_LATENCY_SEC))
00936         {
00937             status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
00938             if (SOTP_SUCCESS != status)
00939             {
00940                 ret = pal_osSotpErrorTranslation(status);
00941             }
00942             else
00943             {
00944                 g_lastSavedTimeInSec = setNewTimeInSeconds;
00945             }
00946         }
00947     }
00948     return ret;
00949 }
00950 
00951 /*! Write a value (either all or specific bits) to the global noise buffer
00952 *
00953 * @param[in] data The value containing the bits to be written.
00954 * @param[in] startBit The index of the first bit to be written, valid values are 0-31.
00955 * @param[in] lenBits The number of bits that should be written (startBit+lenBits must be less than 32).
00956 * @param[out] bitsWritten The number of bits that were actually written.
00957 *
00958 * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure.
00959 */
00960 palStatus_t pal_noiseWriteValue(const int32_t* data, uint8_t startBit, uint8_t lenBits, uint8_t* bitsWritten)
00961 {
00962     PAL_VALIDATE_ARGUMENTS((NULL == data) || (PAL_INT32_BITS - 1 < startBit) || (PAL_INT32_BITS < lenBits + startBit) || (NULL == bitsWritten));
00963 
00964     palStatus_t status = PAL_SUCCESS;
00965     uint16_t incrementedBitCount;
00966     uint8_t currentIndex, occupiedBitsInCurrentIndex, availableBitsInCurrentIndex;
00967     uint32_t mask, value;
00968 
00969     *bitsWritten = 0;
00970     if (PAL_NOISE_SIZE_BITS == g_noise.bitCountActual)
00971     {
00972         return PAL_ERR_RTOS_NOISE_BUFFER_FULL ;
00973     }
00974 
00975     pal_osAtomicIncrement((int32_t*)(&g_noise.numWriters), 1); // increment number of writers
00976     if (g_noise.isReading) // if we're in read mode then discard & exit
00977     {
00978         status = PAL_ERR_RTOS_NOISE_BUFFER_IS_READING ;
00979         goto finish;
00980     }
00981 
00982     incrementedBitCount = (uint16_t)pal_osAtomicIncrement((int32_t*)(&g_noise.bitCountAllocated), lenBits); // reserve space in the array
00983     if (PAL_NOISE_SIZE_BITS < incrementedBitCount) // we want to write more bits than are available in the (entire) buffer
00984     {
00985         lenBits -= incrementedBitCount - PAL_NOISE_SIZE_BITS; // max number of bits that are avialable for writing
00986         if ((int8_t)lenBits <= 0) // we don't have any available bits for writing
00987         {
00988             status = PAL_ERR_RTOS_NOISE_BUFFER_FULL ;
00989             goto finish;
00990         }
00991         incrementedBitCount = PAL_NOISE_SIZE_BITS;
00992     }
00993 
00994     currentIndex = (incrementedBitCount - lenBits) / PAL_INT32_BITS; // the current index in the array
00995     occupiedBitsInCurrentIndex = (incrementedBitCount - lenBits) % PAL_INT32_BITS; // how many bits are already occupied (with either 0 or 1) in the current index
00996     availableBitsInCurrentIndex = PAL_INT32_BITS - occupiedBitsInCurrentIndex; // how many bits are available in the current index
00997 
00998     if (lenBits > availableBitsInCurrentIndex) // we want to write more bits than are available in the current index so we need to split the bits
00999     {
01000         mask = ((((int32_t)1) << availableBitsInCurrentIndex) - 1) << startBit; // mask to isolate the wanted bits
01001         value = *data & mask;
01002         if (((int8_t)(startBit - occupiedBitsInCurrentIndex)) > 0)
01003         {
01004             value = value >> (startBit - occupiedBitsInCurrentIndex);
01005         }
01006         else if (((int8_t)(startBit - occupiedBitsInCurrentIndex)) < 0)
01007         {
01008             value = value << (occupiedBitsInCurrentIndex - startBit);
01009         }
01010         pal_osAtomicIncrement(&g_noise.buffer[currentIndex], value); // write the 1st part of the splitted bits to the current index of the noise buffer
01011         *bitsWritten = availableBitsInCurrentIndex;
01012         lenBits -= availableBitsInCurrentIndex; // how many bits remain to be written
01013         startBit += availableBitsInCurrentIndex;
01014         mask = ((((int32_t)1) << lenBits) - 1) << startBit; // mask for the remaining bits that have not been written yet
01015         value = *data & mask;
01016         value = value >> startBit; // since we're writting to the next index we start at bit 0
01017         pal_osAtomicIncrement(&g_noise.buffer[currentIndex + 1], value); // write the 2nd part of the splitted bits to the next index of the noise buffer
01018         *bitsWritten += lenBits;
01019     }
01020     else // we have enough available bits for the current index (no need to split the bits)
01021     {
01022         mask = ((((int64_t)1) << lenBits) - 1) << startBit; // int64_t in case we want all the 32 bits
01023         value = *data & mask;
01024         if (((int8_t)(startBit - occupiedBitsInCurrentIndex)) > 0)
01025         {
01026             value = value >> (startBit - occupiedBitsInCurrentIndex);
01027         }
01028         else if (((int8_t)(startBit - occupiedBitsInCurrentIndex)) < 0)
01029         {
01030             value = value << (occupiedBitsInCurrentIndex - startBit);
01031         }
01032         pal_osAtomicIncrement(&g_noise.buffer[currentIndex], value); // write the bits to the current index of the noise buffer
01033         *bitsWritten = lenBits;
01034     }
01035     pal_osAtomicIncrement((int32_t*)(&g_noise.bitCountActual) , *bitsWritten); // increment how many bits were actually written    
01036 finish:
01037     pal_osAtomicIncrement((int32_t*)(&g_noise.numWriters), -1); // decrement number of writers
01038     return status;
01039 }
01040 
01041 /*! Write values to the global noise buffer
01042 *
01043 * @param[in] buffer The buffer which contains the values to be written.
01044 * @param[in] lenBits The number of bits that should be written.
01045 * @param[out] bitsWritten The number of bits that were actually written.
01046 *
01047 * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure.
01048 */
01049 palStatus_t pal_noiseWriteBuffer(int32_t* buffer, uint16_t lenBits, uint16_t* bitsWritten)
01050 {
01051     PAL_VALIDATE_ARGUMENTS((NULL == buffer) || (PAL_NOISE_SIZE_BITS < lenBits) || (NULL == bitsWritten));
01052 
01053     palStatus_t status;
01054     uint8_t idx, bitsToWrite;
01055     uint16_t totalBitsWritten;
01056 
01057     idx = 0;
01058     totalBitsWritten = 0;
01059     do
01060     {
01061         bitsToWrite = (lenBits > PAL_INT32_BITS) ? PAL_INT32_BITS : lenBits; // we can write a max number of 32 bits at a time
01062         status = pal_noiseWriteValue(&buffer[idx], 0, bitsToWrite, (uint8_t*)bitsWritten);
01063         lenBits -= bitsToWrite;
01064         idx++;
01065         totalBitsWritten += *bitsWritten;
01066     } while ((PAL_SUCCESS == status) && (bitsToWrite == *bitsWritten) && lenBits); // exit if there was an error, or the noise buffer has no more space, or all bits were written
01067 
01068     *bitsWritten = totalBitsWritten;
01069     if (0 < totalBitsWritten)
01070     {
01071         status = PAL_SUCCESS;
01072     }
01073     return status;
01074 }
01075 
01076 /*! Read values from the global noise buffer
01077 *
01078 * @param[out] buffer The output buffer which will contain the noise data collected.
01079 * @param[in] partial When true read what was collected so far, otherwise read only if the noise buffer is full.
01080 * @param[out] bitsRead he number of bits that were actually read.
01081 *
01082 * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure.
01083 */
01084 palStatus_t pal_noiseRead(int32_t buffer[PAL_NOISE_BUFFER_LEN], bool partial, uint16_t* bitsRead)
01085 {
01086     PAL_VALIDATE_ARGUMENTS((NULL == buffer) || (NULL == bitsRead));
01087 
01088     static uint32_t numOfNoiseReaders = 0; // allow only one reader at a time (no concurrent reads)
01089     palStatus_t status = PAL_SUCCESS;
01090     uint8_t numBytesToRead, numReadersLocal;
01091     uint16_t bitCountActual = (uint16_t)g_noise.bitCountActual;
01092     numReadersLocal = (uint8_t)pal_osAtomicIncrement((int32_t*)(&numOfNoiseReaders), 1); // increment number of readers
01093     *bitsRead = 0;
01094     if (1 != numReadersLocal) // single reader
01095     {
01096         PAL_LOG(DBG, "noise cannot read by multiple readers\n");
01097         status = PAL_ERR_RTOS_NOISE_BUFFER_EMPTY ;
01098         goto finish;
01099     }
01100     
01101     if ((CHAR_BIT > bitCountActual) || (!partial && (PAL_NOISE_SIZE_BITS != bitCountActual))) // exit if less than 1 byte was written or if we want a full read and not all bits were written
01102     {
01103         status = (CHAR_BIT > bitCountActual) ? PAL_ERR_RTOS_NOISE_BUFFER_EMPTY  : PAL_ERR_RTOS_NOISE_BUFFER_NOT_FULL ;
01104         goto finish;
01105     }
01106 
01107     g_noise.isReading = true; // set mode to reading so that no more writes will be allowed
01108     while (g_noise.numWriters) // wait for currently executing writers to finish (relevant only for partial read)
01109     {
01110         pal_osDelay(PAL_NOISE_WAIT_FOR_WRITERS_DELAY_MILLI_SEC);
01111     }
01112     bitCountActual = (uint16_t)g_noise.bitCountActual; // this may occur if we waited for the writers to finish writing, meaning we might have a few more bits (relevant only for partial read)
01113     numBytesToRead = (uint8_t)PAL_NOISE_BITS_TO_BYTES(bitCountActual);    
01114     memcpy((void*)buffer, (void*)g_noise.buffer, numBytesToRead); // copy noise buffer to output buffer
01115     *bitsRead = (numBytesToRead * CHAR_BIT); // set out param of how many bits were actually read
01116     memset((void*)g_noise.buffer, 0, PAL_NOISE_SIZE_BYTES); // reset the noise buffer
01117     g_noise.bitCountActual = g_noise.bitCountAllocated = 0; // reset counters
01118     g_noise.isReading = false; // exit read mode so that writters will be able to continue writting
01119     PAL_LOG(DBG, "noise read %" PRIu8 " bits\n", *bitsRead);
01120 finish:
01121     pal_osAtomicIncrement((int32_t*)(&numOfNoiseReaders), -1); // decrement number of readers
01122     return status;
01123 }