leo hendrickson / Mbed OS example-Ethernet-mbed-Cloud-connect
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_plat_time.c Source File

pal_plat_time.c

00001 /*******************************************************************************
00002  * Copyright 2016-2018 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 //! This module implements the Time platform API using the storage_rbp as storage backend
00018 // and optionally setting the system RTC to match the "secure time". Generic idea
00019 // is to prevent attack by setting clock backwards and to have some idea of current
00020 // time across system power cycle, even if the system does not have a battery backed RTC.
00021 
00022 #include "pal.h"
00023 #include "pal_time.h"
00024 #include "pal_plat_time.h"
00025 #include "storage.h"
00026 #include <stdlib.h>
00027 
00028 
00029 #define TRACE_GROUP "PAL"
00030 
00031 PAL_PRIVATE palStatus_t pal_plat_setWeakTimeForward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime);
00032 PAL_PRIVATE palStatus_t pal_plat_setWeakTimeBackward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime);
00033 
00034 static uint64_t g_palDeviceBootTimeInSec = 0;
00035 
00036 palStatus_t pal_plat_initTime(void)
00037 {
00038     uint64_t rtcTime = 0;
00039     uint64_t getTime = 0, lastTimeBack = 0;
00040     palStatus_t  ret = PAL_SUCCESS;
00041     palStatus_t pal_status = PAL_SUCCESS;
00042     size_t actualLenBytes = 0;
00043 
00044     ret = storage_rbp_read(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&getTime, sizeof(uint64_t), &actualLenBytes);
00045     //In case the weak time corrupted (could be due to power failure) :
00046     // 1. Set 0 getTime 
00047     // 2. Rewrite STORAGE_RBP_SAVED_TIME_NAME with 0, to avoid an error in pal_plat_osSetStrongTime later, when the function tries first to read the weak time.
00048     // 3. Avoid error status and continue.
00049     if ((ret != PAL_SUCCESS) && (ret != PAL_ERR_ITEM_NOT_EXIST ))
00050     {
00051         getTime = 0;
00052         //Rewrite weak time to avoid error in pal_plat_osSetStrongTime
00053         ret = storage_rbp_write(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&getTime, sizeof(uint64_t), false);
00054         pal_status = ret;
00055     }
00056 
00057     ret = storage_rbp_read(STORAGE_RBP_LAST_TIME_BACK_NAME, (uint8_t *)&lastTimeBack, sizeof(uint64_t),&actualLenBytes);
00058     //Strong time : avoid error, reset device time and continue
00059     //In case the strong time corrupted (could be due to power failure) : 
00060     //1. Set device time to 0,to enforce the device to update the time against trusted server later.
00061     //2. Set 0 lastTimeBack 
00062     //3. Rewrite STORAGE_RBP_LAST_TIME_BACK_NAME with 0, to avoid an error in pal_plat_osSetWeak later, when the functions could try first to read the strong time.
00063     //4. Set weak time value getTime to 0 , to avoid setting of the value to device time with pal_status = pal_osSetTime(PAL_MAX(rtcTime, getTime)) ,
00064     //   that called in this function later. In case of strong time corruption, we need to keep the device time value - 0.
00065     if ((ret != PAL_SUCCESS) && (ret != PAL_ERR_ITEM_NOT_EXIST ))
00066     {
00067         pal_plat_osSetTime(0); //Set device time to 0
00068         lastTimeBack = 0;
00069         //Rewrite strong time to avoid error in pal_plat_osSetWeak functions
00070         ret = storage_rbp_write(STORAGE_RBP_LAST_TIME_BACK_NAME, (uint8_t *)&lastTimeBack, sizeof(uint64_t), false);
00071         pal_status = ret;
00072         getTime = 0; //to avoid setting of the value to device time with  pal_status = pal_osSetTime(PAL_MAX(rtcTime, getTime))
00073     }
00074 
00075     if (lastTimeBack > getTime)
00076     {//Enter here only when reset occurs during set weak or strong time
00077         ret = storage_rbp_write(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&lastTimeBack, sizeof(uint64_t), false);
00078         if (PAL_SUCCESS != ret)
00079         {
00080             pal_status = ret;
00081         }
00082         getTime = lastTimeBack;
00083     }
00084 
00085 #if (PAL_USE_HW_RTC)
00086     if (PAL_SUCCESS == pal_status)
00087     {
00088         pal_status = pal_plat_osGetRtcTime(&rtcTime);
00089     }
00090 #endif
00091 
00092     if (PAL_SUCCESS == pal_status)
00093     {//set the max time as boot time of the device
00094         pal_status = pal_osSetTime(PAL_MAX(rtcTime, getTime));
00095     }
00096     
00097     return pal_status;
00098 }
00099 
00100 PAL_PRIVATE uint64_t pal_plat_sysTickTimeToSec()
00101 {
00102     uint64_t sysTicksFromBoot = pal_osKernelSysTick();
00103     uint64_t secFromBoot = pal_osKernelSysMilliSecTick(sysTicksFromBoot) / PAL_MILLI_PER_SECOND;
00104 
00105     return secFromBoot;
00106 }
00107 
00108 uint64_t pal_plat_osGetTime(void)
00109 {
00110     uint64_t curSysTimeInSec = 0;
00111     if (0 < g_palDeviceBootTimeInSec) //time was previously set
00112     {
00113         uint64_t secFromBoot = pal_plat_sysTickTimeToSec();
00114         curSysTimeInSec = g_palDeviceBootTimeInSec + secFromBoot; //boot time in sec + sec passed since boot
00115     }
00116 
00117     return curSysTimeInSec;
00118 }
00119 
00120 palStatus_t pal_plat_osSetTime(uint64_t seconds)
00121 {
00122     palStatus_t status = PAL_SUCCESS;
00123     if(0 == seconds)
00124     {
00125         g_palDeviceBootTimeInSec = 0;
00126     }
00127     else if (seconds < (uint64_t)PAL_MIN_SEC_FROM_EPOCH)
00128     {
00129         status = PAL_ERR_INVALID_TIME ;
00130     }
00131     else
00132     {
00133         uint64_t secFromBoot = pal_plat_sysTickTimeToSec();
00134         g_palDeviceBootTimeInSec = seconds - secFromBoot; //update device boot time
00135     }
00136 
00137     return status;
00138 }
00139 
00140 palStatus_t pal_plat_osSetStrongTime(uint64_t setNewTimeInSeconds)
00141 {
00142     palStatus_t ret = PAL_SUCCESS;
00143     palStatus_t pal_status = PAL_SUCCESS;
00144 
00145     uint64_t getTimeValue = 0;
00146     size_t actualLenBytes = 0;
00147 
00148 #if (PAL_USE_HW_RTC)
00149     //RTC Time Latency
00150     if (PAL_SUCCESS == ret)
00151     {
00152         uint64_t getRtcTimeValue = 0;
00153         ret = pal_plat_osGetRtcTime(&getRtcTimeValue);
00154         if (PAL_SUCCESS == ret)
00155         {
00156             if(llabs(setNewTimeInSeconds - getRtcTimeValue) > PAL_MINIMUM_RTC_LATENCY_SEC)
00157             {
00158                 ret = pal_plat_osSetRtcTime(setNewTimeInSeconds);
00159             }
00160         }
00161     }
00162 #endif
00163 
00164     ret = storage_rbp_read(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&getTimeValue, sizeof(uint64_t), &actualLenBytes);
00165     if ((PAL_SUCCESS != ret) && (PAL_ERR_ITEM_NOT_EXIST  != ret))
00166     {
00167         pal_status =  ret;
00168     }
00169     
00170     else if (((setNewTimeInSeconds > getTimeValue) && (setNewTimeInSeconds - getTimeValue > PAL_MINIMUM_FORWARD_LATENCY_SEC)) //Forward Time
00171             || ((setNewTimeInSeconds < getTimeValue) && (getTimeValue - setNewTimeInSeconds > PAL_MINIMUM_BACKWARD_LATENCY_SEC))) //Backward Time
00172     {
00173         ret = storage_rbp_write(STORAGE_RBP_LAST_TIME_BACK_NAME,  (uint8_t *)&setNewTimeInSeconds, sizeof(uint64_t), false);
00174         if (PAL_SUCCESS != ret)
00175         {
00176             pal_status = ret;
00177         }
00178         else
00179         {
00180             pal_status = storage_rbp_write(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&setNewTimeInSeconds, sizeof(uint64_t), false);            
00181         }
00182     }
00183 
00184     if(PAL_SUCCESS == pal_status)
00185     {
00186        pal_status = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
00187     }
00188 
00189     return pal_status;
00190 }
00191 
00192 PAL_PRIVATE palStatus_t pal_plat_setWeakTimeForward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime)
00193 {
00194     palStatus_t ret = PAL_SUCCESS;
00195 
00196     ret = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
00197 #if (PAL_USE_HW_RTC)
00198     //RTC Time Forward
00199     if (PAL_SUCCESS == ret)
00200     {
00201         uint64_t getRtcTimeValue = 0;
00202         ret = pal_plat_osGetRtcTime(&getRtcTimeValue);
00203         if (PAL_SUCCESS == ret)
00204         {
00205             if((setNewTimeInSeconds > getRtcTimeValue) && (setNewTimeInSeconds - getRtcTimeValue > PAL_MINIMUM_RTC_LATENCY_SEC))
00206             {
00207                 ret = pal_plat_osSetRtcTime(setNewTimeInSeconds);
00208             }
00209         }
00210     }
00211 #endif// (PAL_USE_HW_RTC)
00212 
00213     if ((setNewTimeInSeconds - currentOsTime > PAL_MINIMUM_FORWARD_LATENCY_SEC) && (PAL_SUCCESS == ret))
00214     {  //time forward
00215         ret = storage_rbp_write(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&setNewTimeInSeconds, sizeof(uint64_t), false);
00216     }
00217     
00218     return ret;
00219 }
00220 
00221 PAL_PRIVATE palStatus_t pal_plat_setWeakTimeBackward(uint64_t setNewTimeInSeconds, uint64_t currentOsTime)
00222 {
00223     uint64_t getTimeValue = 0;
00224     size_t actualLenBytes = 0;
00225     palStatus_t ret = PAL_SUCCESS;
00226     palStatus_t pal_status = PAL_SUCCESS;
00227 
00228     ret = storage_rbp_read(STORAGE_RBP_LAST_TIME_BACK_NAME, (uint8_t *)&getTimeValue, sizeof(uint64_t), &actualLenBytes);
00229     if ((PAL_SUCCESS != ret) && (PAL_ERR_ITEM_NOT_EXIST  != ret))
00230     {
00231         pal_status = ret;
00232     }
00233     
00234     else if (setNewTimeInSeconds > getTimeValue)
00235     {
00236         if ((setNewTimeInSeconds - getTimeValue) / PAL_RATIO_SECONDS_PER_DAY  > (currentOsTime - setNewTimeInSeconds))
00237         {
00238             ret = storage_rbp_write(STORAGE_RBP_LAST_TIME_BACK_NAME, (uint8_t *)&setNewTimeInSeconds, sizeof(uint64_t), false);
00239             if (PAL_SUCCESS != ret)
00240             {
00241                 pal_status = ret;
00242             }
00243             else
00244             {
00245                 ret = storage_rbp_write(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&setNewTimeInSeconds, sizeof(uint64_t), false);
00246                 if (PAL_SUCCESS == ret)
00247                 {
00248                     pal_status = pal_osSetTime(setNewTimeInSeconds); //Save new time to RAM
00249                 }
00250             }
00251         }
00252     }
00253 
00254     return pal_status;
00255 }
00256 
00257 palStatus_t pal_plat_osSetWeakTime(uint64_t setNewTimeInSeconds)
00258 {
00259     uint64_t getTimeValue = 0;
00260     size_t actualLenBytes = 0;
00261     palStatus_t ret = PAL_SUCCESS;
00262     palStatus_t pal_status = PAL_SUCCESS;
00263     uint64_t getOsTimeValue = 0;
00264 
00265     getOsTimeValue = pal_osGetTime(); //get current system time
00266 
00267     if (setNewTimeInSeconds > getOsTimeValue)
00268     {//Time Forward
00269         ret = pal_plat_setWeakTimeForward(setNewTimeInSeconds, getOsTimeValue);
00270     }
00271     else if (getOsTimeValue > setNewTimeInSeconds)
00272     {//Time Backward
00273         ret = pal_plat_setWeakTimeBackward(setNewTimeInSeconds, getOsTimeValue);
00274     }
00275 
00276     if(PAL_SUCCESS == ret)
00277     {
00278         getTimeValue = 0;
00279         ret = storage_rbp_read(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&getTimeValue, sizeof(uint64_t), &actualLenBytes);
00280         if ((PAL_SUCCESS != ret) && (PAL_ERR_ITEM_NOT_EXIST  != ret))
00281         {
00282             pal_status = ret;
00283         }
00284         else if ((setNewTimeInSeconds > getTimeValue) && (setNewTimeInSeconds - getTimeValue > PAL_MINIMUM_STORAGE_LATENCY_SEC))
00285         {
00286             pal_status = storage_rbp_write(STORAGE_RBP_SAVED_TIME_NAME, (uint8_t *)&setNewTimeInSeconds, sizeof(uint64_t), false);
00287         }
00288     }
00289     
00290     return pal_status;
00291 }
00292