aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2015-06-09 05:15:35 -0400
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2015-06-24 19:13:44 -0400
commitb2bd2370a25b78a7090ac701836d414cdb731bea (patch)
treec8add915914b5d963912ba61d065624d3f5ebcfa
parentc86a6c28957a9e8e9a71582a32e96971ad411ffe (diff)
rtc: efi: use correct EFI 'epoch'
The rtc-efi driver declares that the EFI 'epoch' is 1/1/1998, but the UEFI spec does not define it at all. It does define a range of [1900, 9999] for the 'Year' member of the EFI_TIME struct, so let's use 1900 as the minimum year and not 1998. Also, move the validation of the year to the convert_from_efi_time() routine where all other EFI_TIME fields are validated as well. This prevents rtc_read_time() failures when the RTC that backs the EFI time services is set to a date before 1998, e.g., when it has lost power. This also optimizes the compute_wday() routine, by replacing the for loop with a simple arithmetic expression, and by reusing the yearday value that we need to compute anyway when populating the rtc_time::tm_yday field. Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com> Cc: rtc-linux@googlegroups.com Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-rw-r--r--drivers/rtc/rtc-efi.c39
1 files changed, 14 insertions, 25 deletions
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index c5fbabb1e0fc..3806961b4348 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -24,10 +24,6 @@
24#include <linux/efi.h> 24#include <linux/efi.h>
25 25
26#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) 26#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
27/*
28 * EFI Epoch is 1/1/1998
29 */
30#define EFI_RTC_EPOCH 1998
31 27
32/* 28/*
33 * returns day of the year [0-365] 29 * returns day of the year [0-365]
@@ -38,31 +34,24 @@ compute_yday(efi_time_t *eft)
38 /* efi_time_t.month is in the [1-12] so, we need -1 */ 34 /* efi_time_t.month is in the [1-12] so, we need -1 */
39 return rtc_year_days(eft->day, eft->month - 1, eft->year); 35 return rtc_year_days(eft->day, eft->month - 1, eft->year);
40} 36}
37
41/* 38/*
42 * returns day of the week [0-6] 0=Sunday 39 * returns day of the week [0-6] 0=Sunday
43 *
44 * Don't try to provide a year that's before 1998, please !
45 */ 40 */
46static int 41static int
47compute_wday(efi_time_t *eft) 42compute_wday(efi_time_t *eft, int yday)
48{ 43{
49 int y; 44 int ndays = eft->year * (365 % 7)
50 int ndays = 0; 45 + (eft->year - 1) / 4
51 46 - (eft->year - 1) / 100
52 if (eft->year < EFI_RTC_EPOCH) { 47 + (eft->year - 1) / 400
53 pr_err("EFI year < " __stringify(EFI_RTC_EPOCH) ", invalid date\n"); 48 + yday;
54 return -1;
55 }
56
57 for (y = EFI_RTC_EPOCH; y < eft->year; y++)
58 ndays += 365 + (is_leap_year(y) ? 1 : 0);
59
60 ndays += compute_yday(eft);
61 49
62 /* 50 /*
63 * 4=1/1/1998 was a Thursday 51 * 1/1/0000 may or may not have been a Sunday (if it ever existed at
52 * all) but assuming it was makes this calculation work correctly.
64 */ 53 */
65 return (ndays + 4) % 7; 54 return ndays % 7;
66} 55}
67 56
68static void 57static void
@@ -103,16 +92,16 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
103 if (!eft->month || eft->month > 12) 92 if (!eft->month || eft->month > 12)
104 return false; 93 return false;
105 wtime->tm_mon = eft->month - 1; 94 wtime->tm_mon = eft->month - 1;
106 wtime->tm_year = eft->year - 1900;
107 95
108 /* day of the week [0-6], Sunday=0 */ 96 if (eft->year < 1900 || eft->year > 9999)
109 wtime->tm_wday = compute_wday(eft);
110 if (wtime->tm_wday < 0)
111 return false; 97 return false;
98 wtime->tm_year = eft->year - 1900;
112 99
113 /* day in the year [1-365]*/ 100 /* day in the year [1-365]*/
114 wtime->tm_yday = compute_yday(eft); 101 wtime->tm_yday = compute_yday(eft);
115 102
103 /* day of the week [0-6], Sunday=0 */
104 wtime->tm_wday = compute_wday(eft, wtime->tm_yday);
116 105
117 switch (eft->daylight & EFI_ISDST) { 106 switch (eft->daylight & EFI_ISDST) {
118 case EFI_ISDST: 107 case EFI_ISDST: