public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 0/1] EmbeddedPkg: Fix multiple Virtual RTC issues
@ 2019-02-25 23:52 Pete Batard
  2019-02-25 23:52 ` [PATCH 1/1] " Pete Batard
  0 siblings, 1 reply; 3+ messages in thread
From: Pete Batard @ 2019-02-25 23:52 UTC (permalink / raw)
  To: edk2-devel

This patch fixes multiple issues in VirtualRealTimeClockLib.c:

1. Use of two separate variables (ElapsedSeconds and EpochSeconds) in
   LibGetTime(), where only a single one should have been used.

2. Possible underflow while sustracting TZ/DST offsets in LibSetTime()
   if the user sets a date that is very close to start of epoch.

3. Non substraction of elpased seconds since reset, which would lead to
   the following behaviour in UEFI shell (assuming for this example that
   exactly 5 minutes have elapsed since platform reset):

     Shell> time 12:00:00
     Shell> time
     12:05:01 (LOCAL)

   In other words, setting and immediately reading back the time would
   result in the returned value being offset by the time since reset.

   This last behaviour has been observed (and confirmed fixed) using an
   RPi3 platform.

Regards,

/Pete

Pete Batard (1):
  EmbeddedPkg: Fix multiple Virtual RTC issues

 .../VirtualRealTimeClockLib.c                 | 34 ++++++++++++++-----
 1 file changed, 25 insertions(+), 9 deletions(-)

-- 
2.17.0.windows.1



^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/1] EmbeddedPkg: Fix multiple Virtual RTC issues
  2019-02-25 23:52 [PATCH 0/1] EmbeddedPkg: Fix multiple Virtual RTC issues Pete Batard
@ 2019-02-25 23:52 ` Pete Batard
  2019-02-26  7:36   ` Ard Biesheuvel
  0 siblings, 1 reply; 3+ messages in thread
From: Pete Batard @ 2019-02-25 23:52 UTC (permalink / raw)
  To: edk2-devel

LibGetTime():
- Two variables were used for the epoch, where only one should have been.
- Also harmonize variable name to match the one used in LibSetTime.
LiBSetTime():
- Address possible underflows if time is set to start of epoch.
- Ensure that time being read does actually match time that was manually
  set (plus the time elapsed since), by subtracting number of seconds
  since reset.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Pete Batard <pete@akeo.ie>
---
 EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c | 34 ++++++++++++++------
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c b/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
index 4c354730d02b..5559106b696f 100644
--- a/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
+++ b/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
@@ -54,13 +54,12 @@ LibGetTime (
   )
 {
   EFI_STATUS  Status;
-  UINT32      EpochSeconds;
   INT16       TimeZone;
   UINT8       Daylight;
   UINT64      Freq;
   UINT64      Counter;
   UINT64      Remainder;
-  UINTN       ElapsedSeconds;
+  UINTN       EpochSeconds;
   UINTN       Size;
 
   if (Time == NULL) {
@@ -75,13 +74,13 @@ LibGetTime (
 
   // Get the epoch time from non-volatile storage
   Size = sizeof (UINTN);
-  ElapsedSeconds = 0;
+  EpochSeconds = 0;
   Status = EfiGetVariable (
              (CHAR16 *)mEpochVariableName,
              &gEfiCallerIdGuid,
              NULL,
              &Size,
-             (VOID *)&ElapsedSeconds
+             (VOID *)&EpochSeconds
              );
   // Fall back to compilation-time epoch if not set
   if (EFI_ERROR (Status)) {
@@ -93,7 +92,7 @@ LibGetTime (
     // If you are attempting to use this library on such an environment, please
     // contact the edk2 mailing list, so we can try to add support for it.
     //
-    ElapsedSeconds = BUILD_EPOCH;
+    EpochSeconds = BUILD_EPOCH;
     DEBUG ((
       DEBUG_INFO,
       "LibGetTime: %s non volatile variable was not found - Using compilation time epoch.\n",
@@ -101,7 +100,7 @@ LibGetTime (
       ));
   }
   Counter = GetPerformanceCounter ();
-  ElapsedSeconds += DivU64x64Remainder (Counter, Freq, &Remainder);
+  EpochSeconds += DivU64x64Remainder (Counter, Freq, &Remainder);
 
   // Get the current time zone information from non-volatile storage
   Size = sizeof (TimeZone);
@@ -204,7 +203,7 @@ LibGetTime (
     }
   }
 
-  EpochToEfiTime (ElapsedSeconds, Time);
+  EpochToEfiTime (EpochSeconds, Time);
 
   // Because we use the performance counter, we can fill the Nanosecond attribute
   // provided that the remainder doesn't overflow 64-bit during multiplication.
@@ -240,6 +239,9 @@ LibSetTime (
   )
 {
   EFI_STATUS  Status;
+  UINT64      Freq;
+  UINT64      Counter;
+  UINT64      Remainder;
   UINTN       EpochSeconds;
 
   if (!IsTimeValid (Time)) {
@@ -249,16 +251,30 @@ LibSetTime (
   EpochSeconds = EfiTimeToEpoch (Time);
 
   // Adjust for the correct time zone, i.e. convert to UTC time zone
-  if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
+  if ((Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE)
+      && (EpochSeconds > Time->TimeZone * SEC_PER_MIN)) {
     EpochSeconds -= Time->TimeZone * SEC_PER_MIN;
   }
 
   // Adjust for the correct period
-  if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {
+  if (((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT)
+      && (EpochSeconds > SEC_PER_HOUR)) {
     // Convert to un-adjusted time, i.e. fall back one hour
     EpochSeconds -= SEC_PER_HOUR;
   }
 
+  // Use the performance counter to substract the number of seconds
+  // since platform reset. Without this, setting time from the shell
+  // and immediately reading it back would result in a forward time
+  // offset, of the duration during which the platform has been up.
+  Freq = GetPerformanceCounterProperties (NULL, NULL);
+  if (Freq != 0) {
+    Counter = GetPerformanceCounter ();
+    if (EpochSeconds > DivU64x64Remainder (Counter, Freq, &Remainder)) {
+      EpochSeconds -= DivU64x64Remainder (Counter, Freq, &Remainder);
+    }
+  }
+
   // Save the current time zone information into non-volatile storage
   Status = EfiSetVariable (
              (CHAR16 *)mTimeZoneVariableName,
-- 
2.17.0.windows.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/1] EmbeddedPkg: Fix multiple Virtual RTC issues
  2019-02-25 23:52 ` [PATCH 1/1] " Pete Batard
@ 2019-02-26  7:36   ` Ard Biesheuvel
  0 siblings, 0 replies; 3+ messages in thread
From: Ard Biesheuvel @ 2019-02-26  7:36 UTC (permalink / raw)
  To: Pete Batard; +Cc: edk2-devel@lists.01.org, Leif Lindholm

On Tue, 26 Feb 2019 at 00:52, Pete Batard <pete@akeo.ie> wrote:
>
> LibGetTime():
> - Two variables were used for the epoch, where only one should have been.
> - Also harmonize variable name to match the one used in LibSetTime.
> LiBSetTime():
> - Address possible underflows if time is set to start of epoch.
> - Ensure that time being read does actually match time that was manually
>   set (plus the time elapsed since), by subtracting number of seconds
>   since reset.
>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Pete Batard <pete@akeo.ie>

Thanks Pete

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Pushed as 9ab4ec518882..1342d7679e10
> ---
>  EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c | 34 ++++++++++++++------
>  1 file changed, 25 insertions(+), 9 deletions(-)
>
> diff --git a/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c b/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
> index 4c354730d02b..5559106b696f 100644
> --- a/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
> +++ b/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
> @@ -54,13 +54,12 @@ LibGetTime (
>    )
>  {
>    EFI_STATUS  Status;
> -  UINT32      EpochSeconds;
>    INT16       TimeZone;
>    UINT8       Daylight;
>    UINT64      Freq;
>    UINT64      Counter;
>    UINT64      Remainder;
> -  UINTN       ElapsedSeconds;
> +  UINTN       EpochSeconds;
>    UINTN       Size;
>
>    if (Time == NULL) {
> @@ -75,13 +74,13 @@ LibGetTime (
>
>    // Get the epoch time from non-volatile storage
>    Size = sizeof (UINTN);
> -  ElapsedSeconds = 0;
> +  EpochSeconds = 0;
>    Status = EfiGetVariable (
>               (CHAR16 *)mEpochVariableName,
>               &gEfiCallerIdGuid,
>               NULL,
>               &Size,
> -             (VOID *)&ElapsedSeconds
> +             (VOID *)&EpochSeconds
>               );
>    // Fall back to compilation-time epoch if not set
>    if (EFI_ERROR (Status)) {
> @@ -93,7 +92,7 @@ LibGetTime (
>      // If you are attempting to use this library on such an environment, please
>      // contact the edk2 mailing list, so we can try to add support for it.
>      //
> -    ElapsedSeconds = BUILD_EPOCH;
> +    EpochSeconds = BUILD_EPOCH;
>      DEBUG ((
>        DEBUG_INFO,
>        "LibGetTime: %s non volatile variable was not found - Using compilation time epoch.\n",
> @@ -101,7 +100,7 @@ LibGetTime (
>        ));
>    }
>    Counter = GetPerformanceCounter ();
> -  ElapsedSeconds += DivU64x64Remainder (Counter, Freq, &Remainder);
> +  EpochSeconds += DivU64x64Remainder (Counter, Freq, &Remainder);
>
>    // Get the current time zone information from non-volatile storage
>    Size = sizeof (TimeZone);
> @@ -204,7 +203,7 @@ LibGetTime (
>      }
>    }
>
> -  EpochToEfiTime (ElapsedSeconds, Time);
> +  EpochToEfiTime (EpochSeconds, Time);
>
>    // Because we use the performance counter, we can fill the Nanosecond attribute
>    // provided that the remainder doesn't overflow 64-bit during multiplication.
> @@ -240,6 +239,9 @@ LibSetTime (
>    )
>  {
>    EFI_STATUS  Status;
> +  UINT64      Freq;
> +  UINT64      Counter;
> +  UINT64      Remainder;
>    UINTN       EpochSeconds;
>
>    if (!IsTimeValid (Time)) {
> @@ -249,16 +251,30 @@ LibSetTime (
>    EpochSeconds = EfiTimeToEpoch (Time);
>
>    // Adjust for the correct time zone, i.e. convert to UTC time zone
> -  if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
> +  if ((Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE)
> +      && (EpochSeconds > Time->TimeZone * SEC_PER_MIN)) {
>      EpochSeconds -= Time->TimeZone * SEC_PER_MIN;
>    }
>
>    // Adjust for the correct period
> -  if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {
> +  if (((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT)
> +      && (EpochSeconds > SEC_PER_HOUR)) {
>      // Convert to un-adjusted time, i.e. fall back one hour
>      EpochSeconds -= SEC_PER_HOUR;
>    }
>
> +  // Use the performance counter to substract the number of seconds
> +  // since platform reset. Without this, setting time from the shell
> +  // and immediately reading it back would result in a forward time
> +  // offset, of the duration during which the platform has been up.
> +  Freq = GetPerformanceCounterProperties (NULL, NULL);
> +  if (Freq != 0) {
> +    Counter = GetPerformanceCounter ();
> +    if (EpochSeconds > DivU64x64Remainder (Counter, Freq, &Remainder)) {
> +      EpochSeconds -= DivU64x64Remainder (Counter, Freq, &Remainder);
> +    }
> +  }
> +
>    // Save the current time zone information into non-volatile storage
>    Status = EfiSetVariable (
>               (CHAR16 *)mTimeZoneVariableName,
> --
> 2.17.0.windows.1
>


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-02-26  7:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-02-25 23:52 [PATCH 0/1] EmbeddedPkg: Fix multiple Virtual RTC issues Pete Batard
2019-02-25 23:52 ` [PATCH 1/1] " Pete Batard
2019-02-26  7:36   ` Ard Biesheuvel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox