Simple interface for Mbed Cloud Client

Dependents:  

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 
00018 #include "pal.h"
00019 #include "pal_plat_rtos.h"
00020 #include "sotp.h"
00021 
00022 #if PAL_UNIQUE_THREAD_PRIORITY   
00023     // An array of PAL thread priorities.
00024     // This array holds a boolean for each thread priority.
00025     // If the value is true then it means that the priority is in use.
00026     // The mapping between the priorities and the index in the array is as follow:
00027     // g_palThreadPriorities[0]  --> PAL_osPriorityIdle
00028     // g_palThreadPriorities[1]  --> PAL_osPriorityLow
00029     // g_palThreadPriorities[2]  --> PAL_osPriorityReservedTRNG
00030     // g_palThreadPriorities[3]  --> PAL_osPriorityBelowNormal
00031     // g_palThreadPriorities[4]  --> PAL_osPriorityNormal
00032     // g_palThreadPriorities[5]  --> PAL_osPriorityAboveNormal
00033     // g_palThreadPriorities[6]  --> PAL_osPriorityReservedDNS
00034     // g_palThreadPriorities[7]  --> PAL_osPriorityReservedSockets
00035     // g_palThreadPriorities[8]  --> PAL_osPriorityHigh
00036     // g_palThreadPriorities[9]  --> PAL_osPriorityReservedHighResTimer
00037     // g_palThreadPriorities[10] --> PAL_osPriorityRealtime
00038     PAL_PRIVATE bool g_threadPriorities[PAL_NUMBER_OF_THREAD_PRIORITIES];
00039 #endif //PAL_UNIQUE_THREAD_PRIORITY
00040 
00041 // thread structure (used by service layer)
00042 typedef struct palThreadWrapper
00043 {
00044     palThreadData_t threadData; // structure containing information about the thread
00045     palThreadServiceBridge_t bridge; // structure containing a function pointer which should always point to threadBridgeFunction & a pointer to palThreadData_t
00046 } palThreadWrapper_t;
00047 
00048 PAL_PRIVATE palMutexID_t g_threadsMutex = NULLPTR; // threads mutex
00049 PAL_PRIVATE uint32_t g_threadIdCounter = 0; // threads counter used for palThreadID generation
00050 PAL_PRIVATE palThreadWrapper_t g_threadsArray[(PAL_MAX_NUMBER_OF_THREADS + 1)] = {{{ 0 }}}; // threads array (+1 for the current thread)
00051 PAL_PRIVATE void threadSetDefaultValues(palThreadData_t* threadData); // forward declaration
00052 PAL_PRIVATE palThreadID_t generatePALthreadID(uint32_t threadWrapperIndex); // forward declaration
00053 
00054 //! Store the last saved time in SOTP (ram) for quick access
00055 PAL_PRIVATE uint64_t g_lastSavedTimeInSec = 0;
00056 
00057 //! static variables for Random functionality.
00058 //! CTR-DRBG context to be used for generating random numbers from given seed
00059 static palCtrDrbgCtxHandle_t s_ctrDRBGCtx = NULLPTR;
00060 
00061 PAL_PRIVATE palStatus_t pal_setWeakTimeForward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime);
00062 PAL_PRIVATE palStatus_t pal_setWeakTimeBackward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime);
00063 
00064 static uint64_t g_palDeviceBootTimeInSec = 0;
00065 
00066 /*
00067  * Here we define const keys for RoT derivation algorithm.
00068  * Must be 16 characters or less
00069  */
00070 #define PAL_STORAGE_SIGNATURE_128_BIT_KEY  "RoTStorageSgn128"
00071 #define PAL_STORAGE_ENCRYPTION_128_BIT_KEY "RoTStorageEnc128"
00072 #define PAL_STORAGE_ENCRYPTION_256_BIT_KEY "StorageEnc256HMACSHA256SIGNATURE"
00073 
00074 PAL_PRIVATE bool palRTOSInitialized = false;
00075 
00076 #if (PAL_SIMULATE_RTOS_REBOOT == 1)
00077      #include <unistd.h> 
00078     extern char *program_invocation_name;
00079 #endif
00080 
00081 #define PAL_NOISE_WAIT_FOR_WRITERS_DELAY_MILLI_SEC 1
00082 #define PAL_NOISE_BITS_TO_BYTES(x) (x / CHAR_BIT)
00083 
00084 typedef struct palNoise
00085 {
00086     int32_t buffer[PAL_NOISE_BUFFER_LEN];
00087     volatile uint16_t bitCountAllocated;
00088     volatile uint16_t bitCountActual;
00089     volatile uint8_t numWriters;
00090     volatile bool isReading;
00091 } palNoise_t;
00092 
00093 PAL_PRIVATE palNoise_t g_noise;
00094 
00095 palStatus_t pal_noiseWriteBuffer(int32_t* buffer, uint16_t lenBits, uint16_t* bitsWritten); // forward declaration
00096 palStatus_t pal_noiseRead(int32_t buffer[PAL_NOISE_BUFFER_LEN], bool partial, uint16_t* bitsRead); // forward declaration
00097 
00098 extern palStatus_t pal_plat_CtrDRBGGenerateWithAdditional(palCtrDrbgCtxHandle_t ctx, unsigned char* out, size_t len, unsigned char* additional, size_t additionalLen);
00099 
00100 //Error Translation from SOTP module to PAL
00101 PAL_PRIVATE palStatus_t pal_osSotpErrorTranslation(sotp_result_e err)
00102 {
00103     palStatus_t ret;
00104     switch(err)
00105     {
00106         case SOTP_BAD_VALUE:
00107             ret = PAL_ERR_INVALID_ARGUMENT ;
00108             break;
00109 
00110         case SOTP_BUFF_TOO_SMALL:
00111             ret = PAL_ERR_BUFFER_TOO_SMALL ;
00112             break;
00113 
00114         case SOTP_BUFF_NOT_ALIGNED:
00115             ret = PAL_ERR_RTOS_BUFFER_NOT_ALIGNED ;
00116             break;
00117 
00118         case SOTP_READ_ERROR:
00119         case SOTP_DATA_CORRUPT:
00120         case SOTP_OS_ERROR:
00121         default:
00122             ret = PAL_ERR_GENERIC_FAILURE;
00123             break;
00124     }
00125     return ret;
00126 }
00127 
00128 palStatus_t pal_RTOSInitialize(void* opaqueContext)
00129 {
00130     palStatus_t status = PAL_SUCCESS;
00131     if (palRTOSInitialized)
00132     {
00133         return status;
00134     }
00135 
00136     status = pal_osMutexCreate(&g_threadsMutex);
00137     if(PAL_SUCCESS == status)
00138     {
00139         status = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER);
00140         if (PAL_SUCCESS == status)
00141         {
00142 #if PAL_UNIQUE_THREAD_PRIORITY
00143             memset(g_threadPriorities, 0, sizeof(g_threadPriorities)); // mark all priorities as available
00144 #endif // PAL_UNIQUE_THREAD_PRIORITY
00145             for (uint32_t i = 0; i <= PAL_MAX_NUMBER_OF_THREADS; ++i) // note the '<=' since g_threadsArray has PAL_MAX_NUMBER_OF_THREADS + 1 for the implicit thread
00146             {
00147                 threadSetDefaultValues(&(g_threadsArray[i].threadData));
00148             }
00149             // add the currently running thread
00150             g_threadsArray[0].threadData.palThreadID = generatePALthreadID(0);
00151             g_threadsArray[0].threadData.osThreadID = pal_plat_osThreadGetId ();
00152 
00153             status = pal_osMutexRelease(g_threadsMutex);
00154             if (PAL_SUCCESS == status)
00155             {
00156                 status = pal_plat_RTOSInitialize (opaqueContext);
00157                 if (PAL_SUCCESS == status)
00158                 {
00159                     memset(g_noise.buffer, 0, PAL_NOISE_SIZE_BYTES);
00160                     g_noise.bitCountActual = g_noise.bitCountAllocated = 0;
00161                     g_noise.numWriters = 0;
00162                     g_noise.isReading = false;
00163                     palRTOSInitialized = true;
00164                 }
00165             }
00166         }
00167     }
00168     return status;
00169 }
00170 
00171 palStatus_t pal_RTOSDestroy(void)
00172 {
00173     palStatus_t status = PAL_SUCCESS;
00174     uint32_t i;
00175     if (palRTOSInitialized)
00176     {
00177         palStatus_t status = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER);
00178         if (PAL_SUCCESS == status)
00179         {
00180             for (i = 1; i <= PAL_MAX_NUMBER_OF_THREADS; ++i) // terminate running threads, note skipping the (1st) thread
00181             {                                                // note the '<=' since g_threadsArray has PAL_MAX_NUMBER_OF_THREADS + 1 for the implicit thread
00182                 if (NULLPTR != g_threadsArray[i].threadData.palThreadID)
00183                 {
00184                     pal_osThreadTerminate(&(g_threadsArray[i].threadData.palThreadID));
00185                 }
00186             }            
00187             status = pal_osMutexRelease(g_threadsMutex);
00188             if (PAL_SUCCESS != status)
00189             {
00190                 PAL_LOG(ERR, "pal_RTOSDestroy: mutex release failed\n");
00191             }
00192         }
00193         else
00194         {
00195             PAL_LOG(ERR, "pal_RTOSDestroy: mutex wait failed\n");
00196         }
00197 
00198         status = pal_osMutexDelete(&g_threadsMutex);
00199         if (PAL_SUCCESS != status)
00200         {
00201             PAL_LOG(ERR, "pal_RTOSDestroy: mutex delete failed\n");
00202         }
00203 
00204         if (NULLPTR != s_ctrDRBGCtx)
00205         {
00206             status = pal_CtrDRBGFree(&s_ctrDRBGCtx);
00207             if (PAL_SUCCESS != status)
00208             {
00209                 PAL_LOG(ERR, "pal_RTOSDestroy: pal_CtrDRBGFree failed\n");
00210             }
00211         }
00212 
00213         status = pal_plat_RTOSDestroy ();
00214         if (PAL_SUCCESS != status)
00215         {
00216             PAL_LOG(ERR, "pal_RTOSDestroy: pal_plat_RTOSDestroy failed\n");
00217         }        
00218         palRTOSInitialized = false;
00219     }
00220     else
00221     {
00222         status = PAL_ERR_NOT_INITIALIZED ;
00223     }
00224     return status;
00225 }
00226 
00227 
00228 void pal_osReboot(void)
00229 {
00230     //Simulator is currently for Linux only
00231     #if (PAL_SIMULATE_RTOS_REBOOT == 1)
00232         const char *argv[] = {"0" , 0};
00233         char *const envp[] = { 0 };
00234         argv[0] = program_invocation_name;
00235         if (-1 == execve(argv[0], (char **)argv , envp))
00236         {
00237             PAL_LOG(ERR,"child process execve failed [%s]",argv[0]);
00238         }
00239     #else
00240         pal_plat_osReboot ();
00241     #endif
00242 }
00243 
00244 uint64_t pal_osKernelSysTick(void)
00245 {
00246     static uint64_t lastValue = 0;
00247     static uint64_t wraparoundsDetected = 0;
00248     const uint64_t one = 1;
00249     uint64_t tics = pal_plat_osKernelSysTick ();
00250     uint64_t tmp = tics + (wraparoundsDetected << 32);
00251 
00252     if (tmp < lastValue) //erez's "wraparound algorithm" if we detect a wrap around add 1 to the higher 32 bits
00253     {
00254         tmp = tmp + (one << 32);
00255         wraparoundsDetected++;
00256     }
00257     lastValue = tmp;
00258     return (uint64_t)tmp;
00259 }
00260 
00261 uint64_t pal_osKernelSysTickMicroSec(uint64_t microseconds)
00262 {
00263     uint64_t result;
00264     result = pal_plat_osKernelSysTickMicroSec (microseconds);
00265     return result;
00266 }
00267 
00268 uint64_t pal_osKernelSysMilliSecTick(uint64_t sysTicks)
00269 {
00270     uint64_t result = 0;
00271     uint64_t osTickFreq = pal_plat_osKernelSysTickFrequency ();
00272     if ((sysTicks) && (osTickFreq)) // > 0
00273     {
00274         result = (uint64_t)((sysTicks) / osTickFreq * PAL_TICK_TO_MILLI_FACTOR); //convert ticks per second to milliseconds
00275     }
00276 
00277     return result;
00278 }
00279 
00280 uint64_t pal_osKernelSysTickFrequency(void)
00281 {
00282     uint64_t result;
00283     result = pal_plat_osKernelSysTickFrequency ();
00284     return result;
00285 }
00286 
00287 inline PAL_PRIVATE void threadSetDefaultValues(palThreadData_t* threadData)
00288 {
00289     threadData->palThreadID = NULLPTR;
00290     threadData->osThreadID  = NULLPTR;
00291     threadData->store  = NULL;
00292     threadData->palPriority  = PAL_osPriorityError;
00293     threadData->osPriority  = 0;
00294     threadData->stackSize  = 0;
00295     threadData->userFunction  = NULL;
00296     threadData->userFunctionArg  = NULL;
00297     threadData->portData  = NULL;
00298 }
00299 
00300 PAL_PRIVATE void threadCleanup(palThreadData_t* threadData)
00301 {
00302 #if PAL_UNIQUE_THREAD_PRIORITY
00303     g_threadPriorities[(threadData->palPriority )] = false; // mark the priority as available
00304 #endif // PAL_UNIQUE_THREAD_PRIORITY
00305     threadSetDefaultValues(threadData);
00306 }
00307 
00308 PAL_PRIVATE palStatus_t findThreadData(palThreadID_t* threadID, palThreadData_t** threadData)
00309 {
00310     palStatus_t status = PAL_ERR_RTOS_ERROR_BASE ;
00311     uint32_t index;
00312     PAL_VALIDATE_ARGUMENTS((NULLPTR == threadID) || (PAL_INVALID_THREAD == *threadID));   
00313 
00314     index = PAL_GET_THREAD_INDEX(*threadID);
00315     if ((PAL_MAX_NUMBER_OF_THREADS >= index) && (g_threadsArray[index].threadData.palThreadID == *threadID))
00316     {
00317         *threadData = &(g_threadsArray[index].threadData);
00318         status = PAL_SUCCESS;
00319     }
00320     return status;
00321 }
00322 
00323 PAL_PRIVATE void threadBridgeFunction(palThreadData_t* threadData)
00324 {
00325     palThreadData_t* tempThreadData = NULL;
00326     palThreadID_t localPalThreadID = NULLPTR; // local copy - will be used after mutex release
00327     palThreadFuncPtr localUserFunction = NULL; // local copy - will be used after mutex release
00328     void* localUserFunctionArg = NULL; // local copy - will be used after mutex release
00329     palStatus_t status;
00330 
00331     status = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER); // enter critical section
00332     if (PAL_SUCCESS != status)
00333     {
00334         goto mutex_wait_err;
00335     }
00336     
00337     status = findThreadData(&(threadData->palThreadID), &tempThreadData);
00338     if (PAL_SUCCESS == status) // thread still exists, i.e. it has NOT been terminated by API call
00339     {
00340         if (NULLPTR == tempThreadData->osThreadID ) // may happen (on some systems) when the created thread has higher priority than the current thread & is immediately executed
00341         {
00342             tempThreadData->osThreadID  = pal_plat_osThreadGetId ();
00343         }
00344         localPalThreadID = tempThreadData->palThreadID;
00345         localUserFunction = tempThreadData->userFunction ;
00346         localUserFunctionArg = tempThreadData->userFunctionArg ;
00347     }
00348     
00349     status = pal_osMutexRelease(g_threadsMutex); // exit critical section
00350     if (PAL_SUCCESS != status)
00351     {
00352         goto mutex_release_err;
00353     }
00354     
00355     if (NULLPTR == localPalThreadID)
00356     {
00357         // thread has been requested for termination, note that some operating systems don't terminate the thread immediately
00358         goto finish;
00359     }
00360     
00361     localUserFunction(localUserFunctionArg); // invoke user function with user function argument (local copies since we're not under mutex lock anymore)
00362     
00363     status = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER); // enter critical section
00364     if (PAL_SUCCESS != status)
00365     {
00366         goto mutex_wait_err;
00367     }
00368     
00369     tempThreadData = NULL;
00370     status = findThreadData(&localPalThreadID, &tempThreadData);
00371     if (PAL_SUCCESS == status) // thread still exists, i.e. it has NOT been terminated by API call
00372     {
00373         status = pal_plat_osThreadDataCleanup (tempThreadData); // platform clean up
00374         threadCleanup(tempThreadData);
00375         if (PAL_SUCCESS != status)
00376         {
00377             PAL_LOG(ERR, "threadBridgeFunction: pal_plat_osThreadDataCleanup failed\n");
00378         }
00379     }
00380 
00381     status = pal_osMutexRelease(g_threadsMutex); // exit critical section
00382     if (PAL_SUCCESS != status)
00383     {
00384         goto mutex_release_err;
00385     }
00386     goto finish;
00387 
00388 mutex_wait_err:
00389     {
00390         PAL_LOG(ERR, "threadBridgeFunction: mutex wait failed\n");
00391         goto finish;
00392     }
00393 mutex_release_err:
00394     {
00395         PAL_LOG(ERR, "threadBridgeFunction: mutex release failed\n");
00396         goto finish;
00397     }
00398 finish:
00399     return;
00400 }
00401 
00402 PAL_PRIVATE palStatus_t allocateThreadWrapper(palThreadWrapper_t** threadWrapper, uint32_t* threadWrapperIndex)
00403 {
00404     palStatus_t status = PAL_ERR_RTOS_RESOURCE ;
00405     for (uint32_t i = 1; i <= PAL_MAX_NUMBER_OF_THREADS; ++i) // note skipping 1st index since it's being used for the implicit thread set in pal_RTOSInitialize
00406     {                                                         // note the '<=' since g_threadsArray has PAL_MAX_NUMBER_OF_THREADS + 1 for the implicit thread
00407         if (NULLPTR == g_threadsArray[i].threadData.palThreadID)
00408         {
00409             *threadWrapper = &g_threadsArray[i];
00410             *threadWrapperIndex = i;
00411             status = PAL_SUCCESS;
00412             break;
00413         }
00414     }
00415     return status;
00416 }
00417 
00418 inline PAL_PRIVATE palThreadID_t generatePALthreadID(uint32_t threadWrapperIndex)
00419 {
00420     // 24 bits for thread counter + lower 8 bits for thread index
00421     ++g_threadIdCounter;
00422     palThreadID_t threadID = (palThreadID_t)((threadWrapperIndex + (g_threadIdCounter << 8)));
00423     return threadID;
00424 }
00425 
00426 PAL_PRIVATE palStatus_t threadCreate(palThreadFuncPtr function, void* functionArg, palThreadPriority_t priority, uint32_t stackSize, palThreadLocalStore_t* store,
00427     palThreadID_t* threadID)
00428 {
00429     palStatus_t status, tempStatus;
00430     palThreadWrapper_t* threadWrapper = NULL;
00431     uint32_t threadWrapperIndex;
00432     palThreadID_t localPalThreadID;
00433     palThreadID_t localOsThreadID = NULLPTR;
00434     palThreadData_t* tempThreadData = NULL;
00435     int16_t translatedPriority;
00436 
00437     PAL_VALIDATE_ARGUMENTS((NULL == function) || (PAL_osPriorityRealtime  < priority) || (PAL_osPriorityError == priority) || (0 == stackSize) || (NULL == threadID));
00438 
00439     *threadID = PAL_INVALID_THREAD;
00440     translatedPriority = pal_plat_osThreadTranslatePriority (priority);
00441     tempStatus = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER);
00442     if (PAL_SUCCESS != tempStatus)
00443     {
00444         goto mutex_wait_err;
00445     }
00446 
00447 #if PAL_UNIQUE_THREAD_PRIORITY
00448     if (g_threadPriorities[priority]) // requested thread priority already occupied
00449     {
00450         status = PAL_ERR_RTOS_PRIORITY ;
00451         tempStatus = pal_osMutexRelease(g_threadsMutex);
00452         if (PAL_SUCCESS != tempStatus)
00453         {
00454             goto mutex_release_err;
00455         }
00456         goto finish;
00457     }
00458     g_threadPriorities[priority] = true;
00459 #endif // PAL_UNIQUE_THREAD_PRIORITY
00460 
00461     status = allocateThreadWrapper(&threadWrapper, &threadWrapperIndex);
00462     if (PAL_SUCCESS != status)
00463     {
00464         PAL_LOG(ERR, "threadCreate: thread wrapper allocation failed\n");
00465         tempStatus = pal_osMutexRelease(g_threadsMutex);
00466         if (PAL_SUCCESS != tempStatus)
00467         {
00468             goto mutex_release_err;
00469         }
00470         goto finish;
00471     }
00472 
00473     localPalThreadID = generatePALthreadID(threadWrapperIndex);
00474     threadWrapper->bridge.function = threadBridgeFunction; // this is the (service layer) thread function invoked by the port via the bridge
00475     threadWrapper->bridge.threadData = &(threadWrapper->threadData);
00476     threadWrapper->threadData.palThreadID = localPalThreadID;
00477     threadWrapper->threadData.store = store;
00478     threadWrapper->threadData.palPriority = priority;
00479     threadWrapper->threadData.osPriority = translatedPriority;
00480     threadWrapper->threadData.stackSize = stackSize;
00481     threadWrapper->threadData.userFunction = function;
00482     threadWrapper->threadData.userFunctionArg = functionArg;    
00483     status = pal_plat_osThreadDataInitialize (&(threadWrapper->threadData.portData), threadWrapper->threadData.osPriority, threadWrapper->threadData.stackSize);
00484     if (PAL_SUCCESS != status)
00485     {
00486         threadCleanup(&(threadWrapper->threadData));
00487         PAL_LOG(ERR, "threadCreate: pal_plat_osThreadDataInitialize failed\n");
00488         tempStatus = pal_osMutexRelease(g_threadsMutex);
00489         if (PAL_SUCCESS != tempStatus)
00490         {
00491             goto mutex_release_err;
00492         }
00493         goto finish;
00494     }
00495 
00496     tempStatus = pal_osMutexRelease(g_threadsMutex);
00497     if (PAL_SUCCESS != tempStatus)
00498     {
00499         goto mutex_release_err;
00500     }
00501         
00502     status = pal_plat_osThreadRun (&(threadWrapper->bridge), &localOsThreadID); // note that we're not under a mutex lock anymore
00503     
00504     tempStatus = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER);
00505     if (PAL_SUCCESS != tempStatus)
00506     {
00507         goto mutex_wait_err;
00508     }
00509 
00510     tempStatus = findThreadData(&localPalThreadID, &tempThreadData);
00511     if ((PAL_SUCCESS == tempStatus) && (PAL_SUCCESS == status)) // thread still exists & pal_plat_osThreadRun was successful
00512     {
00513         if (NULLPTR == tempThreadData->osThreadID )
00514         {
00515             tempThreadData->osThreadID  = localOsThreadID;
00516         }
00517         *threadID = localPalThreadID;
00518     }
00519     else if ((PAL_SUCCESS == tempStatus) && (PAL_SUCCESS != status)) // thread still exists & pal_plat_osThreadRun was not successful
00520     {
00521         threadCleanup(tempThreadData);
00522     }
00523     else if ((PAL_SUCCESS != tempStatus) && (PAL_SUCCESS == status)) // thread does not exist (either finished or terminated) & pal_plat_osThreadRun was successful
00524     {
00525         *threadID = localPalThreadID;
00526     }
00527     else
00528     {
00529         // note: this should never happen because if we're here then it means that pal_plat_osThreadRun was not successful and also that the thread data does not exist any more
00530         //       meaning it has been cleaned up already, this should not be possible since the thread was not supposed to run (pal_plat_osThreadRun failed) and pal_osThreadTerminate
00531         //       is not possible since the user does not have the palThreadID yet which is an output parameter of this function
00532         PAL_LOG(ERR, "threadCreate: pal_plat_osThreadRun was not successful but the thread was not found");
00533     }
00534         
00535     tempStatus = pal_osMutexRelease(g_threadsMutex);
00536     if (PAL_SUCCESS != tempStatus)
00537     {
00538         goto mutex_release_err;
00539     }
00540     goto finish;
00541 
00542 mutex_wait_err:
00543     {
00544         status = tempStatus;
00545         PAL_LOG(ERR, "threadCreate: mutex wait failed\n");
00546         goto finish;
00547     }
00548 mutex_release_err:
00549     {
00550         status = tempStatus;
00551         PAL_LOG(ERR, "threadCreate: mutex release failed\n");
00552         goto finish;
00553     }
00554 finish:
00555     return status;
00556 }
00557 
00558 
00559 palStatus_t pal_osThreadCreateWithAlloc(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, palThreadLocalStore_t* store, palThreadID_t* threadID)
00560 {
00561     palStatus_t status = threadCreate(function, funcArgument, priority, stackSize, store, threadID);
00562     return status;
00563 }
00564 
00565 palStatus_t pal_osThreadTerminate(palThreadID_t* threadID)
00566 {
00567     PAL_VALIDATE_ARGUMENTS ((NULL == threadID) || (PAL_INVALID_THREAD == *threadID));
00568 
00569     palThreadData_t* threadData = NULL;
00570     palStatus_t status;
00571     palStatus_t mutexStatus = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER);
00572     if (PAL_SUCCESS == mutexStatus)
00573     {
00574         status = findThreadData(threadID, &threadData);
00575         if (PAL_SUCCESS == status) // thread has not finished yet
00576         {
00577             status = pal_plat_osThreadTerminate (threadData);
00578             if (PAL_SUCCESS == status)
00579             {
00580                 threadCleanup(threadData);
00581             }
00582             else
00583             {
00584                 PAL_LOG(ERR, "pal_osThreadTerminate: pal_plat_osThreadTerminate failed\n");
00585             }
00586         }
00587         else // thread was not found, it either never existed or already finished
00588         {
00589             status = PAL_SUCCESS;
00590         }
00591 
00592         mutexStatus = pal_osMutexRelease(g_threadsMutex);
00593         if (PAL_SUCCESS != mutexStatus)
00594         {
00595             status = mutexStatus;
00596             PAL_LOG(ERR, "pal_osThreadTerminate: mutex release failed\n");
00597         }
00598     }
00599     else
00600     {
00601         status = mutexStatus;
00602         PAL_LOG(ERR, "pal_osThreadTerminate: mutex wait failed\n");
00603     }
00604     return status;
00605 }
00606 
00607 palThreadID_t pal_osThreadGetId(void)
00608 {
00609     palThreadID_t palThreadID = PAL_INVALID_THREAD;
00610     palThreadID_t osThreadID;
00611     uint32_t i;
00612     palStatus_t status = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER);
00613     if (PAL_SUCCESS == status)
00614     {
00615         osThreadID = pal_plat_osThreadGetId ();
00616         for (i = 0; i <= PAL_MAX_NUMBER_OF_THREADS; ++i) // search the threads array, note the '<=' since g_threadsArray has PAL_MAX_NUMBER_OF_THREADS + 1 for the implicit thread
00617         {
00618             if ((NULLPTR != g_threadsArray[i].threadData.palThreadID) && (g_threadsArray[i].threadData.osThreadID == osThreadID))
00619             {
00620                 palThreadID = g_threadsArray[i].threadData.palThreadID;
00621                 break;
00622             }
00623         }        
00624         status = pal_osMutexRelease(g_threadsMutex);
00625         if (PAL_SUCCESS != status)
00626         {
00627             PAL_LOG(ERR, "pal_osThreadGetId: mutex release failed\n");
00628         }
00629     }
00630     else
00631     {
00632         PAL_LOG(ERR, "pal_osThreadGetId: mutex wait failed\n");
00633     }
00634     return palThreadID;
00635 }
00636 
00637 palThreadLocalStore_t* pal_osThreadGetLocalStore(void)
00638 {
00639     palThreadID_t palThreadID;
00640     palThreadData_t* threadData = NULL;
00641     palThreadLocalStore_t* store = NULL;
00642     palStatus_t status = pal_osMutexWait(g_threadsMutex, PAL_RTOS_WAIT_FOREVER);
00643     if (PAL_SUCCESS == status)
00644     {
00645         palThreadID = pal_osThreadGetId(); // find the palThreadID for the current thread
00646         if (PAL_INVALID_THREAD != palThreadID)
00647         {
00648             status = findThreadData(&palThreadID, &threadData);
00649             if (PAL_SUCCESS == status)
00650             {
00651                 store = threadData->store ;
00652             }
00653         }
00654         status = pal_osMutexRelease(g_threadsMutex);
00655         if (PAL_SUCCESS != status)
00656         {
00657             PAL_LOG(ERR, "pal_osThreadGetLocalStore: mutex release failed\n");
00658         }
00659     }
00660     else
00661     {
00662         PAL_LOG(ERR, "pal_osThreadGetLocalStore: mutex wait failed\n");
00663     }
00664     return store;
00665 }
00666 
00667 palStatus_t pal_osDelay(uint32_t milliseconds)
00668 {
00669     palStatus_t status;
00670     status = pal_plat_osDelay (milliseconds);
00671     return status;
00672 }
00673 
00674 palStatus_t pal_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID)
00675 {
00676     PAL_VALIDATE_ARGUMENTS(NULL == timerID || NULL == function);
00677     palStatus_t status;
00678     status = pal_plat_osTimerCreate (function, funcArgument, timerType, timerID);
00679     return status;
00680 }
00681 
00682 palStatus_t pal_osTimerStart(palTimerID_t timerID, uint32_t millisec)
00683 {
00684     PAL_VALIDATE_ARGUMENTS (NULLPTR == timerID);
00685     palStatus_t status;
00686     if (0 == millisec)
00687     {
00688         return PAL_ERR_RTOS_VALUE ;
00689     }
00690     status = pal_plat_osTimerStart (timerID, millisec);
00691     return status;
00692 }
00693 
00694 palStatus_t pal_osTimerStop(palTimerID_t timerID)
00695 {
00696     PAL_VALIDATE_ARGUMENTS(NULLPTR == timerID);
00697     palStatus_t status;
00698     status = pal_plat_osTimerStop (timerID);
00699     return status;
00700 }
00701 
00702 palStatus_t pal_osTimerDelete(palTimerID_t* timerID)
00703 {
00704     PAL_VALIDATE_ARGUMENTS(NULL == timerID || NULLPTR == *timerID);
00705     palStatus_t status;
00706     status = pal_plat_osTimerDelete (timerID);
00707     return status;
00708 }
00709 
00710 palStatus_t pal_osMutexCreate(palMutexID_t* mutexID)
00711 {
00712     PAL_VALIDATE_ARGUMENTS(NULL == mutexID);
00713     palStatus_t status;
00714     status = pal_plat_osMutexCreate (mutexID);
00715     return status;
00716 }
00717 
00718 palStatus_t pal_osMutexWait(palMutexID_t mutexID, uint32_t millisec)
00719 {
00720     PAL_VALIDATE_ARGUMENTS((NULLPTR == mutexID));
00721     palStatus_t status;
00722     status = pal_plat_osMutexWait (mutexID, millisec);
00723     return status;
00724 }
00725 
00726 palStatus_t pal_osMutexRelease(palMutexID_t mutexID)
00727 {
00728     PAL_VALIDATE_ARGUMENTS(NULLPTR == mutexID);
00729     palStatus_t status;
00730     status = pal_plat_osMutexRelease (mutexID);
00731     return status;
00732 }
00733 
00734 palStatus_t pal_osMutexDelete(palMutexID_t* mutexID)
00735 {
00736     PAL_VALIDATE_ARGUMENTS(NULL == mutexID || NULLPTR == *mutexID);
00737     palStatus_t status;
00738     status = pal_plat_osMutexDelete (mutexID);
00739     return status;
00740 }
00741 
00742 palStatus_t pal_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID)
00743 {
00744     PAL_VALIDATE_ARGUMENTS(NULL == semaphoreID);
00745     palStatus_t status;
00746     status = pal_plat_osSemaphoreCreate (count, semaphoreID);
00747     return status;
00748 }
00749 
00750 palStatus_t pal_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec,  int32_t* countersAvailable)
00751 {
00752     PAL_VALIDATE_ARGUMENTS(NULLPTR == semaphoreID);
00753     palStatus_t status;
00754     status = pal_plat_osSemaphoreWait (semaphoreID, millisec, countersAvailable);
00755     return status;
00756 }
00757 
00758 palStatus_t pal_osSemaphoreRelease(palSemaphoreID_t semaphoreID)
00759 {
00760     PAL_VALIDATE_ARGUMENTS(NULLPTR == semaphoreID);
00761     palStatus_t status;
00762     status = pal_plat_osSemaphoreRelease (semaphoreID);
00763     return status;
00764 }
00765 
00766 palStatus_t pal_osSemaphoreDelete(palSemaphoreID_t* semaphoreID)
00767 {
00768     PAL_VALIDATE_ARGUMENTS(NULL == semaphoreID || NULLPTR == *semaphoreID);
00769     palStatus_t status;
00770     status = pal_plat_osSemaphoreDelete (semaphoreID);
00771     return status;
00772 }
00773 
00774 
00775 int32_t pal_osAtomicIncrement(int32_t* valuePtr, int32_t increment)
00776 {
00777     PAL_VALIDATE_ARGUMENTS(NULL == valuePtr);
00778     int32_t result;
00779     result = pal_plat_osAtomicIncrement (valuePtr, increment);
00780     return result;
00781 }
00782 
00783 
00784 PAL_PRIVATE uint64_t pal_sysTickTimeToSec()
00785 {
00786     uint64_t sysTicksFromBoot = pal_osKernelSysTick();
00787     uint64_t secFromBoot = pal_osKernelSysMilliSecTick(sysTicksFromBoot) / PAL_MILLI_PER_SECOND;
00788 
00789     return secFromBoot;
00790 }
00791 
00792 uint64_t pal_osGetTime(void)
00793 {
00794     uint64_t curSysTimeInSec = 0;
00795     if (0 < g_palDeviceBootTimeInSec) //time was previously set
00796     {
00797         uint64_t secFromBoot = pal_sysTickTimeToSec();
00798         curSysTimeInSec = g_palDeviceBootTimeInSec + secFromBoot; //boot time in sec + sec passed since boot
00799 
00800         if((curSysTimeInSec > g_lastSavedTimeInSec) && (curSysTimeInSec - g_lastSavedTimeInSec > PAL_LAST_SAVED_TIME_LATENCY_SEC))
00801         {
00802             sotp_result_e status = SOTP_SUCCESS;
00803             status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&curSysTimeInSec);
00804             if (SOTP_SUCCESS != status)
00805             {
00806                 PAL_LOG(ERR,"SOTP set time failed \n");  
00807             }
00808             else
00809             {
00810                 g_lastSavedTimeInSec = curSysTimeInSec;
00811             }
00812                      
00813         }
00814     }
00815 
00816     return curSysTimeInSec;
00817 }
00818 
00819 palStatus_t pal_osSetTime(uint64_t seconds)
00820 {
00821     palStatus_t status = PAL_SUCCESS;
00822     if(0 == seconds)
00823     {
00824         g_palDeviceBootTimeInSec = 0;
00825     }
00826     else if (seconds < (uint64_t)PAL_MIN_SEC_FROM_EPOCH)
00827     {
00828         status = PAL_ERR_INVALID_TIME ;
00829     }
00830     else
00831     {
00832         uint64_t secFromBoot = pal_sysTickTimeToSec();
00833         g_palDeviceBootTimeInSec = seconds - secFromBoot; //update device boot time
00834     }
00835 
00836     return status;
00837 }
00838 
00839 
00840 
00841 #if PAL_USE_HW_TRNG
00842 PAL_PRIVATE void pal_trngNoiseThreadFunc(void const* arg)
00843 {
00844     uint8_t buf[PAL_NOISE_SIZE_BYTES] PAL_PTR_ADDR_ALIGN_UINT8_TO_UINT32 = { 0 };
00845     size_t trngBytesRead = 0;
00846     uint16_t noiseBitsWritten = 0;
00847     palStatus_t status;
00848     while (true)
00849     {
00850         status = pal_plat_osRandomBuffer (buf, PAL_NOISE_SIZE_BYTES, &trngBytesRead);
00851         if ((0 < trngBytesRead) && ((PAL_SUCCESS == status) || (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status)))
00852         {
00853             noiseBitsWritten = 0;
00854             status = pal_noiseWriteBuffer((int32_t*)buf, (trngBytesRead * CHAR_BIT), &noiseBitsWritten);
00855             PAL_LOG(DBG, "noise trng thread wrote %" PRIu16 " bits, status=%" PRIx32 "\n", noiseBitsWritten, status);
00856         }
00857         pal_osDelay(PAL_NOISE_TRNG_THREAD_DELAY_MILLI_SEC);
00858     }
00859 }
00860 #endif // PAL_USE_HW_TRNG
00861 
00862 
00863 // this function generates drbg with the possibility of adding noise as additional input to the drbg function.
00864 PAL_PRIVATE palStatus_t pal_generateDrbgWithNoiseAttempt(palCtrDrbgCtxHandle_t drbgContext, uint8_t* outBuffer, bool partial, size_t numBytesToGenerate)
00865 {
00866     uint16_t bitsRead = 0;
00867     int32_t buffer[PAL_NOISE_BUFFER_LEN] = { 0 };
00868     palStatus_t status = pal_noiseRead(buffer, partial, &bitsRead);
00869     if (PAL_SUCCESS == status)
00870     {
00871         status = pal_plat_CtrDRBGGenerateWithAdditional(drbgContext, (unsigned char*)outBuffer, numBytesToGenerate, (unsigned char*)buffer, (size_t)PAL_NOISE_BITS_TO_BYTES(bitsRead));
00872     }
00873     else
00874     {
00875         status = pal_CtrDRBGGenerate(drbgContext, (unsigned char*)outBuffer, numBytesToGenerate);
00876     }
00877     return status;
00878 }
00879 
00880 palStatus_t pal_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes)
00881 {
00882     PAL_VALIDATE_ARGUMENTS (NULL == randomBuf);
00883 
00884     palStatus_t status = PAL_ERR_GENERIC_FAILURE;
00885     if (palRTOSInitialized == true)
00886     {
00887         if (NULLPTR == s_ctrDRBGCtx)
00888         {
00889             uint32_t sotpCounter = 0;
00890             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)
00891             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
00892             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
00893             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
00894             uint32_t* ptrSotpCounterRead = ptrSotpWrite; // pointer to the memory address in buf which will point to the counter read from sotp
00895             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
00896             uint16_t sotpBytesRead = 0, noiseBitsWrittern = 0;
00897             size_t trngBytesRead = 0;
00898             palCtrDrbgCtxHandle_t longCtrDRBGCtx = NULLPTR; // long term drbg context            
00899             palStatus_t tmpStatus;
00900             sotp_result_e sotpResult = sotp_get(SOTP_TYPE_RANDOM_SEED, sotpLenBytes, ptrSotpRead, &sotpBytesRead); // read 48 drbg bytes + 4 counter bytes
00901             if (SOTP_SUCCESS == sotpResult)
00902             {
00903                 if ((PAL_INITIAL_RANDOM_SIZE != sotpBytesRead) && (sotpLenBytes != sotpBytesRead))
00904                 {
00905                     status = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
00906                     PAL_LOG(ERR, "Invalid number of bytes read from sotp, bytes read=%" PRIu16, sotpBytesRead);
00907                     goto finish;
00908                 }
00909                 status = pal_CtrDRBGInit(&longCtrDRBGCtx, ptrSotpRead, PAL_INITIAL_RANDOM_SIZE); // initialize long term drbg with the seed that was read from sotp
00910                 if (PAL_SUCCESS != status)
00911                 {
00912                     PAL_LOG(ERR, "Failed to initialize long term drbg context, status=%" PRIx32 "\n", status);
00913                     goto finish;
00914                 }
00915                 memcpy((void*)&sotpCounter, (void*)ptrSotpCounterRead, sizeof(sotpCounter)); // read the counter from the buffer (sotp data) to local var
00916 #if PAL_USE_HW_TRNG
00917                 memset((void*)buf, 0, sizeof(buf));                
00918                 status = pal_plat_osRandomBuffer (buf, PAL_NOISE_SIZE_BYTES, &trngBytesRead);
00919                 if ((PAL_SUCCESS == status) || (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status))
00920                 {
00921                     if (0 < trngBytesRead)
00922                     {
00923                         tmpStatus = pal_noiseWriteBuffer((int32_t*)buf, (trngBytesRead * CHAR_BIT), &noiseBitsWrittern); // write whatever was collected from trng to the noise buffer
00924                         PAL_LOG(DBG, "Write trng to noise buffer, status=%" PRIx32 ", bits writtern=%" PRIu16 "\n", tmpStatus, noiseBitsWrittern);
00925                     }
00926                 }
00927                 else
00928                 {
00929                     PAL_LOG(ERR, "Read from TRNG failed, status=%" PRIx32 "\n", status);
00930                 }                
00931 #endif // PAL_USE_HW_TRNG
00932                 memset((void*)buf, 0, sizeof(buf));
00933                 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
00934                 if (PAL_SUCCESS != status)
00935                 {
00936                     PAL_LOG(ERR, "Failed to gererate drbg long term and short term seeds, status=%" PRIx32 "\n", status);
00937                     goto drbg_cleanup;
00938                 }
00939                 sotpCounter++; // increment counter before writting it back to sotp
00940                 memcpy((void*)ptrSotpCounterWrite, (void*)&sotpCounter, sizeof(sotpCounter)); // copy the incremented counter to the last 4 bytes of the buffer
00941                 sotpResult = sotp_set(SOTP_TYPE_RANDOM_SEED, sotpLenBytes, ptrSotpWrite); // write 48 long term drbg bytes + 4 counter bytes
00942                 if (SOTP_SUCCESS != sotpResult)
00943                 {
00944                     PAL_LOG(ERR, "Failed to write to sotp, sotp result=%d", sotpResult);
00945                     status = PAL_ERR_GENERIC_FAILURE;
00946                 }                
00947 drbg_cleanup:
00948                 {
00949                     tmpStatus = pal_CtrDRBGFree(&longCtrDRBGCtx);
00950                     if (PAL_SUCCESS != tmpStatus)
00951                     {
00952                         PAL_LOG(ERR, "Failed to free long term drbg context, status=%" PRIx32 "\n", tmpStatus);
00953                     }
00954                     longCtrDRBGCtx = NULLPTR;                    
00955                     if (PAL_SUCCESS != status)
00956                     {
00957                         goto finish;
00958                     }
00959 #if PAL_USE_HW_TRNG
00960                     palThreadID_t trngThreadId = NULLPTR;
00961                     tmpStatus = pal_osThreadCreateWithAlloc(pal_trngNoiseThreadFunc, NULL, PAL_osPriorityReservedTRNG, PAL_NOISE_TRNG_THREAD_STACK_SIZE, NULL, &trngThreadId);
00962                     if (PAL_SUCCESS != tmpStatus)
00963                     {
00964                         PAL_LOG(ERR, "Failed to create noise trng thread, status=%" PRIx32 "\n", tmpStatus);
00965                     }
00966 #endif // PAL_USE_HW_TRNG
00967                 }
00968             }
00969             else if (SOTP_NOT_FOUND == sotpResult)
00970             {
00971 #if PAL_USE_HW_TRNG
00972                 memset((void*)buf, 0, sizeof(buf));
00973                 uint8_t* seedPtr = buf;
00974                 size_t randomCounterBytes = 0;
00975                 do
00976                 {
00977                     status = pal_plat_osRandomBuffer (seedPtr, PAL_INITIAL_RANDOM_SIZE - randomCounterBytes, &trngBytesRead);
00978                     if (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status)
00979                     {
00980                         pal_osDelay(PAL_TRNG_COLLECT_DELAY_MILLI_SEC); // sleep to let the device to collect random data.
00981                         randomCounterBytes += trngBytesRead;
00982                         seedPtr += trngBytesRead;
00983                     }
00984                 } while (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status);
00985 #endif // PAL_USE_HW_TRNG
00986             }
00987             if (PAL_SUCCESS != status)
00988             {
00989                 goto finish;
00990             }
00991             status = pal_CtrDRBGInit(&s_ctrDRBGCtx, (void*)buf, PAL_INITIAL_RANDOM_SIZE);
00992             if (PAL_SUCCESS != status)
00993             {
00994                 PAL_LOG(ERR, "Failed to initialize short term drbg context, status=%" PRIx32 "\n", status);
00995                 goto finish;
00996             }
00997         }
00998         status = pal_generateDrbgWithNoiseAttempt(s_ctrDRBGCtx, randomBuf, false, bufSizeBytes);
00999         if (PAL_SUCCESS != status)
01000         {
01001             PAL_LOG(ERR, "Failed to gererate random, status=%" PRIx32 "\n", status);
01002         }
01003     }
01004     else
01005     {
01006         return PAL_ERR_NOT_INITIALIZED ;
01007     }
01008 finish:
01009     return status;
01010 }
01011 
01012 palStatus_t pal_osRandom32bit(uint32_t *random)
01013 {
01014     palStatus_t status = PAL_SUCCESS;
01015 
01016     PAL_VALIDATE_ARGUMENTS(NULL == random);
01017         
01018     status = pal_osRandomBuffer((uint8_t*)random, sizeof(uint32_t));
01019     return status;
01020 }
01021 
01022 
01023 PAL_PRIVATE palStatus_t pal_osGetRoT(uint8_t * key,size_t keyLenBytes)
01024 {
01025     palStatus_t palStatus = PAL_SUCCESS;
01026 #if (PAL_USE_HW_ROT)
01027     palStatus = pal_plat_osGetRoTFromHW (key, keyLenBytes);
01028 #else
01029     sotp_result_e sotpStatus = SOTP_SUCCESS;
01030     uint16_t actual_size;
01031     sotpStatus = sotp_get(SOTP_TYPE_ROT, keyLenBytes, (uint32_t *)key, &actual_size);
01032     if (SOTP_NOT_FOUND == sotpStatus) 
01033     {
01034         palStatus = pal_osRandomBuffer(key , keyLenBytes);
01035         if (PAL_SUCCESS == palStatus) 
01036         {
01037             sotpStatus = sotp_set(SOTP_TYPE_ROT,keyLenBytes, (uint32_t *)key);
01038         }
01039     }
01040     if (SOTP_SUCCESS != sotpStatus)
01041     {
01042         palStatus = pal_osSotpErrorTranslation(sotpStatus);
01043     }
01044 #endif
01045     return palStatus;
01046 }
01047 
01048 palStatus_t pal_osGetDeviceKey(palDevKeyType_t keyType, uint8_t *key, size_t keyLenBytes)
01049 {
01050     palStatus_t status = PAL_SUCCESS;
01051     uint8_t rotBuffer[PAL_DEVICE_KEY_SIZE_IN_BYTES] __attribute__ ((aligned(4))) = {0};
01052 
01053     
01054     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 )
01055 
01056     PAL_VALIDATE_CONDITION_WITH_ERROR ((NULL == key),PAL_ERR_NULL_POINTER )
01057 
01058     status = pal_osGetRoT(rotBuffer, keyLenBytes);
01059     if (PAL_SUCCESS == status)
01060     {   // Logic of RoT according to key type using 128 bit strong Key Derivation Algorithm
01061 
01062 #if (PAL_DEVICE_KEY_DERIVATION_BACKWARD_COMPATIBILITY_CALC == 1) //calculate the key derivation in an old way
01063         switch(keyType)
01064         {
01065             case palOsStorageEncryptionKey128Bit:
01066             {
01067                 //USE strong KDF here!
01068                 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);
01069                 break;
01070             }
01071             case palOsStorageSignatureKey128Bit :
01072             {
01073                 //USE strong KDF here!
01074                 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);
01075                 break;
01076             }
01077             case palOsStorageHmacSha256 :
01078             {
01079                 size_t outputLenInBytes = 0;
01080                 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);
01081                 break;
01082             }
01083             default:
01084                 status = PAL_ERR_GET_DEV_KEY ;
01085         } //switch end
01086 #else //calculate the key derivation in a new way
01087         switch(keyType)
01088         {
01089             case palOsStorageEncryptionKey128Bit:
01090             {
01091                 //USE strong KDF here!
01092                 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);
01093                 break;
01094             }
01095             case palOsStorageSignatureKey128Bit :
01096             {
01097                 //USE strong KDF here!
01098                 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);                
01099                 break;
01100             }
01101             case palOsStorageHmacSha256 :
01102             {
01103                 size_t outputLenInBytes = 0;
01104                 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);                
01105                 break;
01106             }
01107             default:
01108                 status = PAL_ERR_GET_DEV_KEY ;
01109         } //switch end
01110 #endif        
01111 
01112     } // outer if
01113     else
01114     {
01115         status = PAL_ERR_GET_DEV_KEY ;
01116     }
01117 
01118     return status;
01119 
01120 }
01121 
01122 palStatus_t pal_initTime(void)
01123 {
01124     uint64_t rtcTime = 0;
01125     uint64_t sotpGetTime = 0, sotpLastTimeBack = 0;
01126     palStatus_t ret = PAL_SUCCESS;
01127     sotp_result_e status = SOTP_SUCCESS;
01128     uint16_t actualLenBytes = 0;
01129 
01130     status = sotp_get(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t*)&sotpGetTime, &actualLenBytes);
01131     if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
01132     {
01133         ret = pal_osSotpErrorTranslation(status);
01134     }
01135     else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
01136     {
01137         ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
01138     }
01139 
01140     status = sotp_get(SOTP_TYPE_LAST_TIME_BACK, sizeof(uint64_t), (uint32_t*)&sotpLastTimeBack, &actualLenBytes);
01141     if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
01142     {
01143         ret = pal_osSotpErrorTranslation(status);
01144     }
01145     else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
01146     {
01147         ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
01148     }
01149 
01150     if (sotpLastTimeBack > sotpGetTime)
01151     {//Enter here only when reset occurs during set weak or strong time
01152         status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&sotpLastTimeBack);
01153         if (SOTP_SUCCESS != status)
01154         {
01155             ret = pal_osSotpErrorTranslation(status);
01156         }
01157         sotpGetTime = sotpLastTimeBack;
01158     }
01159     g_lastSavedTimeInSec = sotpGetTime;
01160 
01161 #if (PAL_USE_HW_RTC)
01162     if (PAL_SUCCESS == ret)
01163     {
01164         ret = pal_plat_osGetRtcTime(&rtcTime);
01165     }
01166 #endif
01167 
01168     if (PAL_SUCCESS == ret)
01169     {//set the max time as boot time of the device
01170        pal_osSetTime(PAL_MAX(rtcTime, sotpGetTime));
01171     }
01172     return ret;
01173 }
01174 
01175 
01176 palStatus_t pal_osSetStrongTime(uint64_t setNewTimeInSeconds)
01177 {
01178     palStatus_t ret = PAL_SUCCESS;
01179 
01180     uint64_t getSotpTimeValue = 0;
01181     uint16_t actualLenBytes = 0;
01182     sotp_result_e status = SOTP_SUCCESS;
01183     
01184 #if (PAL_USE_HW_RTC)
01185     //RTC Time Latency
01186     if (PAL_SUCCESS == ret)
01187     {
01188         uint64_t getRtcTimeValue = 0;
01189         ret = pal_plat_osGetRtcTime(&getRtcTimeValue);
01190         if (PAL_SUCCESS == ret)
01191         {
01192             if(llabs(setNewTimeInSeconds - getRtcTimeValue) > PAL_MINIMUM_RTC_LATENCY_SEC)
01193             {
01194                 ret = pal_plat_osSetRtcTime(setNewTimeInSeconds);
01195             }
01196         }
01197     }
01198 #endif
01199 
01200     status = sotp_get(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&getSotpTimeValue, &actualLenBytes);
01201     if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
01202     {
01203         ret = pal_osSotpErrorTranslation(status);
01204     }
01205     else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
01206     {
01207         ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
01208     }    
01209     else if (((setNewTimeInSeconds > getSotpTimeValue) && (setNewTimeInSeconds - getSotpTimeValue > PAL_MINIMUM_SOTP_FORWARD_LATENCY_SEC)) //Forward Time
01210             || ((setNewTimeInSeconds < getSotpTimeValue) && (getSotpTimeValue - setNewTimeInSeconds > PAL_MINIMUM_SOTP_BACKWARD_LATENCY_SEC))) //Backward Time
01211     {
01212         status = sotp_set(SOTP_TYPE_LAST_TIME_BACK, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
01213         if (SOTP_SUCCESS != status)
01214         {
01215             ret = pal_osSotpErrorTranslation(status);
01216         }
01217         else
01218         {            
01219             status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
01220             if (SOTP_SUCCESS != status)
01221             {
01222                 ret = pal_osSotpErrorTranslation(status);
01223             }
01224             g_lastSavedTimeInSec = setNewTimeInSeconds;
01225         }
01226     }
01227 
01228     if(PAL_SUCCESS == ret)
01229     {
01230        ret = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
01231     }
01232 
01233     return ret;
01234 }
01235 
01236 PAL_PRIVATE palStatus_t pal_setWeakTimeForward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime)
01237 {
01238     sotp_result_e status = SOTP_SUCCESS;
01239     palStatus_t ret = PAL_SUCCESS;
01240 
01241     ret = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
01242 #if (PAL_USE_HW_RTC)
01243     //RTC Time Forward
01244     if (PAL_SUCCESS == ret)
01245     {
01246         uint64_t getRtcTimeValue = 0;
01247         ret = pal_plat_osGetRtcTime(&getRtcTimeValue);
01248         if (PAL_SUCCESS == ret)
01249         {
01250             if((setNewTimeInSeconds > getRtcTimeValue) && (setNewTimeInSeconds - getRtcTimeValue > PAL_MINIMUM_RTC_LATENCY_SEC))
01251             {
01252                 ret = pal_plat_osSetRtcTime(setNewTimeInSeconds);
01253             }
01254         }
01255     }
01256 #endif// (PAL_USE_HW_RTC)
01257 
01258     if ((setNewTimeInSeconds - currentOsTime > PAL_MINIMUM_SOTP_FORWARD_LATENCY_SEC) && (PAL_SUCCESS == ret))
01259     {//SOTP time forward
01260         status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
01261         if (SOTP_SUCCESS != status)
01262         {
01263             ret = pal_osSotpErrorTranslation(status);
01264         }
01265         else
01266         {
01267             g_lastSavedTimeInSec = setNewTimeInSeconds;
01268         }
01269     }
01270     return ret;
01271 }
01272 
01273 PAL_PRIVATE palStatus_t pal_setWeakTimeBackward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime)
01274 {
01275     uint64_t getSotpTimeValue = 0;
01276     uint16_t actualLenBytes = 0;
01277     sotp_result_e status = SOTP_SUCCESS;
01278     palStatus_t ret = PAL_SUCCESS;
01279 
01280     status = sotp_get(SOTP_TYPE_LAST_TIME_BACK, sizeof(uint64_t), (uint32_t *)&getSotpTimeValue, &actualLenBytes);
01281     if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
01282     {
01283         ret = pal_osSotpErrorTranslation(status);
01284     }
01285     else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
01286     {
01287         ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
01288     }
01289     else if (setNewTimeInSeconds > getSotpTimeValue)
01290     {
01291         if ((setNewTimeInSeconds - getSotpTimeValue) / PAL_RATIO_SECONDS_PER_DAY  > (currentOsTime - setNewTimeInSeconds))
01292         {
01293             status = sotp_set(SOTP_TYPE_LAST_TIME_BACK, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
01294             if (SOTP_SUCCESS != status)
01295             {
01296                 ret = pal_osSotpErrorTranslation(status);
01297             }
01298             else
01299             {               
01300                 status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
01301                 if (SOTP_SUCCESS != status)
01302                 {
01303                     ret = pal_osSotpErrorTranslation(status);
01304                 }
01305                 else
01306                 {
01307                     g_lastSavedTimeInSec = setNewTimeInSeconds;
01308                     ret = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
01309                 }
01310             }
01311         }
01312     }
01313 
01314     return ret;
01315 }
01316 
01317 palStatus_t pal_osSetWeakTime(uint64_t setNewTimeInSeconds)
01318 {
01319     uint64_t getSotpTimeValue = 0;
01320     uint16_t actualLenBytes = 0;
01321     sotp_result_e status = SOTP_SUCCESS;
01322     palStatus_t ret = PAL_SUCCESS;
01323     uint64_t getOsTimeValue = 0;
01324     
01325     getOsTimeValue = pal_osGetTime(); //get current system time
01326 
01327     if (setNewTimeInSeconds > getOsTimeValue)
01328     {//Time Forward
01329         ret = pal_setWeakTimeForward(setNewTimeInSeconds, getOsTimeValue);
01330     }
01331     else if (getOsTimeValue > setNewTimeInSeconds)
01332     {//Time Backward
01333         ret = pal_setWeakTimeBackward(setNewTimeInSeconds, getOsTimeValue);
01334     }
01335 
01336     if(PAL_SUCCESS == ret)
01337     {
01338         getSotpTimeValue = 0;
01339         status = sotp_get(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&getSotpTimeValue, &actualLenBytes);
01340         if ((SOTP_SUCCESS != status) && (SOTP_NOT_FOUND != status))
01341         {
01342             ret = pal_osSotpErrorTranslation(status);
01343         }
01344         else if ((sizeof(uint64_t) != actualLenBytes) && (SOTP_NOT_FOUND != status))
01345         {
01346             ret = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
01347         }
01348         else if ((setNewTimeInSeconds > getSotpTimeValue) && (setNewTimeInSeconds - getSotpTimeValue > PAL_MINIMUM_STORAGE_LATENCY_SEC))
01349         {
01350             status = sotp_set(SOTP_TYPE_SAVED_TIME, sizeof(uint64_t), (uint32_t *)&setNewTimeInSeconds);
01351             if (SOTP_SUCCESS != status)
01352             {
01353                 ret = pal_osSotpErrorTranslation(status);
01354             }
01355             else
01356             {
01357                 g_lastSavedTimeInSec = setNewTimeInSeconds;
01358             }
01359         }
01360     }
01361     return ret;
01362 }
01363 
01364 /*! Write a value (either all or specific bits) to the global noise buffer
01365 *
01366 * @param[in] data The value containing the bits to be written.
01367 * @param[in] startBit The index of the first bit to be written, valid values are 0-31.
01368 * @param[in] lenBits The number of bits that should be written (startBit+lenBits must be less than 32).
01369 * @param[out] bitsWritten The number of bits that were actually written.
01370 *
01371 * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure.
01372 */
01373 palStatus_t pal_noiseWriteValue(const int32_t* data, uint8_t startBit, uint8_t lenBits, uint8_t* bitsWritten)
01374 {
01375     PAL_VALIDATE_ARGUMENTS((NULL == data) || (PAL_INT32_BITS - 1 < startBit) || (PAL_INT32_BITS < lenBits + startBit) || (NULL == bitsWritten));
01376 
01377     palStatus_t status = PAL_SUCCESS;
01378     uint16_t incrementedBitCount;
01379     uint8_t currentIndex, occupiedBitsInCurrentIndex, availableBitsInCurrentIndex;
01380     uint32_t mask, value;
01381 
01382     *bitsWritten = 0;
01383     if (PAL_NOISE_SIZE_BITS == g_noise.bitCountActual)
01384     {
01385         return PAL_ERR_RTOS_NOISE_BUFFER_FULL ;
01386     }
01387 
01388     pal_osAtomicIncrement((int32_t*)(&g_noise.numWriters), 1); // increment number of writers
01389     if (g_noise.isReading) // if we're in read mode then discard & exit
01390     {
01391         status = PAL_ERR_RTOS_NOISE_BUFFER_IS_READING ;
01392         goto finish;
01393     }
01394 
01395     incrementedBitCount = (uint16_t)pal_osAtomicIncrement((int32_t*)(&g_noise.bitCountAllocated), lenBits); // reserve space in the array
01396     if (PAL_NOISE_SIZE_BITS < incrementedBitCount) // we want to write more bits than are available in the (entire) buffer
01397     {
01398         lenBits -= incrementedBitCount - PAL_NOISE_SIZE_BITS; // max number of bits that are avialable for writing
01399         if ((int8_t)lenBits <= 0) // we don't have any available bits for writing
01400         {
01401             status = PAL_ERR_RTOS_NOISE_BUFFER_FULL ;
01402             goto finish;
01403         }
01404         incrementedBitCount = PAL_NOISE_SIZE_BITS;
01405     }
01406 
01407     currentIndex = (incrementedBitCount - lenBits) / PAL_INT32_BITS; // the current index in the array
01408     occupiedBitsInCurrentIndex = (incrementedBitCount - lenBits) % PAL_INT32_BITS; // how many bits are already occupied (with either 0 or 1) in the current index
01409     availableBitsInCurrentIndex = PAL_INT32_BITS - occupiedBitsInCurrentIndex; // how many bits are available in the current index
01410 
01411     if (lenBits > availableBitsInCurrentIndex) // we want to write more bits than are available in the current index so we need to split the bits
01412     {
01413         mask = ((((int32_t)1) << availableBitsInCurrentIndex) - 1) << startBit; // mask to isolate the wanted bits
01414         value = *data & mask;
01415         if (((int8_t)(startBit - occupiedBitsInCurrentIndex)) > 0)
01416         {
01417             value = value >> (startBit - occupiedBitsInCurrentIndex);
01418         }
01419         else if (((int8_t)(startBit - occupiedBitsInCurrentIndex)) < 0)
01420         {
01421             value = value << (occupiedBitsInCurrentIndex - startBit);
01422         }
01423         pal_osAtomicIncrement(&g_noise.buffer[currentIndex], value); // write the 1st part of the splitted bits to the current index of the noise buffer
01424         *bitsWritten = availableBitsInCurrentIndex;
01425         lenBits -= availableBitsInCurrentIndex; // how many bits remain to be written
01426         startBit += availableBitsInCurrentIndex;
01427         mask = ((((int32_t)1) << lenBits) - 1) << startBit; // mask for the remaining bits that have not been written yet
01428         value = *data & mask;
01429         value = value >> startBit; // since we're writting to the next index we start at bit 0
01430         pal_osAtomicIncrement(&g_noise.buffer[currentIndex + 1], value); // write the 2nd part of the splitted bits to the next index of the noise buffer
01431         *bitsWritten += lenBits;
01432     }
01433     else // we have enough available bits for the current index (no need to split the bits)
01434     {
01435         mask = ((((int64_t)1) << lenBits) - 1) << startBit; // int64_t in case we want all the 32 bits
01436         value = *data & mask;
01437         if (((int8_t)(startBit - occupiedBitsInCurrentIndex)) > 0)
01438         {
01439             value = value >> (startBit - occupiedBitsInCurrentIndex);
01440         }
01441         else if (((int8_t)(startBit - occupiedBitsInCurrentIndex)) < 0)
01442         {
01443             value = value << (occupiedBitsInCurrentIndex - startBit);
01444         }
01445         pal_osAtomicIncrement(&g_noise.buffer[currentIndex], value); // write the bits to the current index of the noise buffer
01446         *bitsWritten = lenBits;
01447     }
01448     pal_osAtomicIncrement((int32_t*)(&g_noise.bitCountActual), *bitsWritten); // increment how many bits were actually written
01449     PAL_LOG(DBG, "noise added %" PRIu8 " bits\n", *bitsWritten);
01450 finish:
01451     pal_osAtomicIncrement((int32_t*)(&g_noise.numWriters), -1); // decrement number of writers
01452     return status;
01453 }
01454 
01455 /*! Write values to the global noise buffer
01456 *
01457 * @param[in] buffer The buffer which contains the values to be written.
01458 * @param[in] lenBits The number of bits that should be written.
01459 * @param[out] bitsWritten The number of bits that were actually written.
01460 *
01461 * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure.
01462 */
01463 palStatus_t pal_noiseWriteBuffer(int32_t* buffer, uint16_t lenBits, uint16_t* bitsWritten)
01464 {
01465     PAL_VALIDATE_ARGUMENTS((NULL == buffer) || (PAL_NOISE_SIZE_BITS < lenBits) || (NULL == bitsWritten));
01466 
01467     palStatus_t status;
01468     uint8_t idx, bitsToWrite;
01469     uint16_t totalBitsWritten;
01470 
01471     idx = 0;
01472     totalBitsWritten = 0;
01473     do
01474     {
01475         bitsToWrite = (lenBits > PAL_INT32_BITS) ? PAL_INT32_BITS : lenBits; // we can write a max number of 32 bits at a time
01476         status = pal_noiseWriteValue(&buffer[idx], 0, bitsToWrite, (uint8_t*)bitsWritten);
01477         lenBits -= bitsToWrite;
01478         idx++;
01479         totalBitsWritten += *bitsWritten;
01480     } 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
01481 
01482     *bitsWritten = totalBitsWritten;
01483     if (0 < totalBitsWritten)
01484     {
01485         status = PAL_SUCCESS;
01486     }
01487     return status;
01488 }
01489 
01490 /*! Read values from the global noise buffer
01491 *
01492 * @param[out] buffer The output buffer which will contain the noise data collected.
01493 * @param[in] partial When true read what was collected so far, otherwise read only if the noise buffer is full.
01494 * @param[out] bitsRead he number of bits that were actually read.
01495 *
01496 * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure.
01497 */
01498 palStatus_t pal_noiseRead(int32_t buffer[PAL_NOISE_BUFFER_LEN], bool partial, uint16_t* bitsRead)
01499 {
01500     PAL_VALIDATE_ARGUMENTS((NULL == buffer) || (NULL == bitsRead));
01501 
01502     static uint8_t numOfNoiseReaders = 0; // allow only one reader at a time (no concurrent reads)
01503     palStatus_t status = PAL_SUCCESS;
01504     uint8_t numBytesToRead, numReadersLocal;
01505     uint16_t bitCountActual = g_noise.bitCountActual;
01506     numReadersLocal = (uint8_t)pal_osAtomicIncrement((int32_t*)(&numOfNoiseReaders), 1); // increment number of readers
01507     *bitsRead = 0;
01508     if (1 != numReadersLocal) // single reader
01509     {
01510         PAL_LOG(DBG, "noise cannot read by multiple readers\n");
01511         status = PAL_ERR_RTOS_NOISE_BUFFER_EMPTY ;
01512         goto finish;
01513     }
01514     
01515     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
01516     {
01517         status = (CHAR_BIT > bitCountActual) ? PAL_ERR_RTOS_NOISE_BUFFER_EMPTY  : PAL_ERR_RTOS_NOISE_BUFFER_NOT_FULL ;
01518         goto finish;
01519     }
01520 
01521     g_noise.isReading = true; // set mode to reading so that no more writes will be allowed
01522     while (g_noise.numWriters) // wait for currently executing writers to finish (relevant only for partial read)
01523     {
01524         pal_osDelay(PAL_NOISE_WAIT_FOR_WRITERS_DELAY_MILLI_SEC);
01525     }
01526     bitCountActual = 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)
01527     numBytesToRead = (uint8_t)PAL_NOISE_BITS_TO_BYTES(bitCountActual);    
01528     memcpy((void*)buffer, (void*)g_noise.buffer, numBytesToRead); // copy noise buffer to output buffer
01529     *bitsRead = (numBytesToRead * CHAR_BIT); // set out param of how many bits were actually read
01530     memset((void*)g_noise.buffer, 0, PAL_NOISE_SIZE_BYTES); // reset the noise buffer
01531     g_noise.bitCountActual = g_noise.bitCountAllocated = 0; // reset counters
01532     g_noise.isReading = false; // exit read mode so that writters will be able to continue writting
01533     PAL_LOG(DBG, "noise read %" PRIu8 " bits\n", *bitsRead);
01534 finish:
01535     pal_osAtomicIncrement((int32_t*)(&numOfNoiseReaders), -1); // decrement number of readers
01536     return status;
01537 }