On 32bits platforms "struct timeval" or "time_t" are using u32 to code the date, this cause tools like "date" or "hwclock" failed even before setting the RTC device if the date is superior to year 2038 (or 2106).
To avoid this problem I add one RTC test file which directly use RTC ioctl to set and read RTC time and alarm values. rtctest_setdate allow to set any date/time given in the command line.
On this version 2 I add check of problematics years in rtctest like suggest by Alexandre.
Finally that had allowed me to test and fix rtc-st-lpc driver.
Benjamin Gaignard (3): tools: timer: add rtctest_setdate tool: timer: rtctest add check for problematic dates rtc: st-lpc: make it robust against y2038/2106 bug
drivers/rtc/rtc-st-lpc.c | 19 ++-- tools/testing/selftests/timers/Makefile | 2 +- tools/testing/selftests/timers/rtctest.c | 121 ++++++++++++++++++++++- tools/testing/selftests/timers/rtctest_setdate.c | 86 ++++++++++++++++ 4 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 tools/testing/selftests/timers/rtctest_setdate.c
This tool allow to set directly the time and date to a RTC device.
Unlike other tools isn't doens't use "struct timeval" or "time_t" so it is safe for 32bits platforms when testing for y2038/2106 bug.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- tools/testing/selftests/timers/Makefile | 2 +- tools/testing/selftests/timers/rtctest_setdate.c | 86 ++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/timers/rtctest_setdate.c
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile index 5fa1d7e9..54481f1 100644 --- a/tools/testing/selftests/timers/Makefile +++ b/tools/testing/selftests/timers/Makefile @@ -9,7 +9,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \
TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ skew_consistency clocksource-switch leap-a-day \ - leapcrash set-tai set-2038 set-tz + leapcrash set-tai set-2038 set-tz rtctest_setdate
include ../lib.mk diff --git a/tools/testing/selftests/timers/rtctest_setdate.c b/tools/testing/selftests/timers/rtctest_setdate.c new file mode 100644 index 0000000..2cb7848 --- /dev/null +++ b/tools/testing/selftests/timers/rtctest_setdate.c @@ -0,0 +1,86 @@ +/* Real Time Clock Driver Test + * by: Benjamin Gaignard (benjamin.gaignard@linaro.org) + * + * To build + * gcc rtctest_setdate.c -o rtctest_setdate + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdio.h> +#include <linux/rtc.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> + +static const char default_time[] = "00:00:00"; + +int main(int argc, char **argv) +{ + int fd, retval; + struct rtc_time new, current; + const char *rtc, *date; + const char *time = default_time; + + switch (argc) { + case 4: + time = argv[3]; + /* FALLTHROUGH */ + case 3: + date = argv[2]; + rtc = argv[1]; + break; + default: + fprintf(stderr, "usage: rtctest_setdate <rtcdev> <DD-MM-YYYY> [HH:MM:SS]\n"); + return 1; + } + + fd = open(rtc, O_RDONLY); + if (fd == -1) { + perror(rtc); + exit(errno); + } + + sscanf(date, "%d-%d-%d", &new.tm_mday, &new.tm_mon, &new.tm_year); + new.tm_mon -= 1; + new.tm_year -= 1900; + sscanf(time, "%d:%d:%d", &new.tm_hour, &new.tm_min, &new.tm_sec); + + fprintf(stderr, "Test will set RTC date/time to %d-%d-%d, %02d:%02d:%02d.\n", + new.tm_mday, new.tm_mon + 1, new.tm_year + 1900, + new.tm_hour, new.tm_min, new.tm_sec); + + /* Write the new date in RTC */ + retval = ioctl(fd, RTC_SET_TIME, &new); + if (retval == -1) { + perror("RTC_SET_TIME ioctl"); + close(fd); + exit(errno); + } + + /* Read back */ + retval = ioctl(fd, RTC_RD_TIME, ¤t); + if (retval == -1) { + perror("RTC_RD_TIME ioctl"); + exit(errno); + } + + fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", + current.tm_mday, current.tm_mon + 1, current.tm_year + 1900, + current.tm_hour, current.tm_min, current.tm_sec); + + close(fd); + return 0; +}
Some dates could be problematic because they reach the limits of RTC hardware capabilities. This patch add various of them but since it will change RTC date it will be activated only when 'd' args is set.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- tools/testing/selftests/timers/rtctest.c | 121 ++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/timers/rtctest.c b/tools/testing/selftests/timers/rtctest.c index 4230d30..715a016 100644 --- a/tools/testing/selftests/timers/rtctest.c +++ b/tools/testing/selftests/timers/rtctest.c @@ -21,6 +21,9 @@ #include <stdlib.h> #include <errno.h>
+#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif
/* * This expects the new RTC class driver framework, working with @@ -29,23 +32,77 @@ */ static const char default_rtc[] = "/dev/rtc0";
+static struct rtc_time cutoff_dates[] = { + { + .tm_year = 70, /* 1970 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 137, /* 2037 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 138, /* 2038 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 199, /* 2099 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 200, /* 2100 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 205, /* 2105 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 206, /* 2106 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 361, /* 2261 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 362, /* 2262 -1900 */ + .tm_mday = 1, + }, +}; + +static int compare_dates(struct rtc_time *a, struct rtc_time *b) +{ + if (a->tm_year != b->tm_year || + a->tm_mon != b->tm_mon || + a->tm_mday != b->tm_mday || + a->tm_hour != b->tm_hour || + a->tm_min != b->tm_min || + ((b->tm_sec - a->tm_sec) > 1)) + return 1; + + return 0; +}
int main(int argc, char **argv) { - int i, fd, retval, irqcount = 0; + int i, fd, retval, irqcount = 0, dangerous = 0; unsigned long tmp, data; struct rtc_time rtc_tm; const char *rtc = default_rtc; struct timeval start, end, diff;
switch (argc) { + case 3: + if (*argv[2] == 'd') + dangerous = 1; case 2: rtc = argv[1]; /* FALLTHROUGH */ case 1: break; default: - fprintf(stderr, "usage: rtctest [rtcdev]\n"); + fprintf(stderr, "usage: rtctest [rtcdev] [d]\n"); return 1; }
@@ -202,7 +259,7 @@ int main(int argc, char **argv) /* not all RTCs support periodic IRQs */ if (errno == EINVAL) { fprintf(stderr, "\nNo periodic IRQ support\n"); - goto done; + goto test_DATE; } perror("RTC_IRQP_READ ioctl"); exit(errno); @@ -221,7 +278,7 @@ int main(int argc, char **argv) if (errno == EINVAL) { fprintf(stderr, "\n...Periodic IRQ rate is fixed\n"); - goto done; + goto test_DATE; } perror("RTC_IRQP_SET ioctl"); exit(errno); @@ -269,6 +326,62 @@ int main(int argc, char **argv) } }
+test_DATE: + if (!dangerous) + goto done; + + fprintf(stderr, "\nTesting problematic dates\n"); + + for (i = 0; i < ARRAY_SIZE(cutoff_dates); i++) { + struct rtc_time current; + + /* Write the new date in RTC */ + retval = ioctl(fd, RTC_SET_TIME, &cutoff_dates[i]); + if (retval == -1) { + perror("RTC_SET_TIME ioctl"); + close(fd); + exit(errno); + } + + /* Read back */ + retval = ioctl(fd, RTC_RD_TIME, ¤t); + if (retval == -1) { + perror("RTC_RD_TIME ioctl"); + exit(errno); + } + + if(compare_dates(&cutoff_dates[i], ¤t)) { + fprintf(stderr,"Setting date %d failed\n", + cutoff_dates[i].tm_year + 1900); + goto done; + } + + cutoff_dates[i].tm_sec += 5; + + /* Write the new alarm in RTC */ + retval = ioctl(fd, RTC_ALM_SET, &cutoff_dates[i]); + if (retval == -1) { + perror("RTC_ALM_SET ioctl"); + close(fd); + exit(errno); + } + + /* Read back */ + retval = ioctl(fd, RTC_ALM_READ, ¤t); + if (retval == -1) { + perror("RTC_ALM_READ ioctl"); + exit(errno); + } + + if(compare_dates(&cutoff_dates[i], ¤t)) { + fprintf(stderr,"Setting alarm %d failed\n", + cutoff_dates[i].tm_year + 1900); + goto done; + } + + fprintf(stderr, "Setting year %d is OK \n", + cutoff_dates[i].tm_year + 1900); + } done: fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
Make driver use u64 variables and functions to be sure that it will support dates after year 2038.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org Acked-by: Patrice Chotard patrice.chotard@st.com --- drivers/rtc/rtc-st-lpc.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c index 74c0a33..82b0af1 100644 --- a/drivers/rtc/rtc-st-lpc.c +++ b/drivers/rtc/rtc-st-lpc.c @@ -99,7 +99,7 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm)
lpt = ((unsigned long long)lpt_msb << 32) | lpt_lsb; do_div(lpt, rtc->clkrate); - rtc_time_to_tm(lpt, tm); + rtc_time64_to_tm(lpt, tm);
return 0; } @@ -107,13 +107,10 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm) static int st_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct st_rtc *rtc = dev_get_drvdata(dev); - unsigned long long lpt; - unsigned long secs, flags; - int ret; + unsigned long long lpt, secs; + unsigned long flags;
- ret = rtc_tm_to_time(tm, &secs); - if (ret) - return ret; + secs = rtc_tm_to_time64(tm);
lpt = (unsigned long long)secs * rtc->clkrate;
@@ -161,13 +158,13 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct st_rtc *rtc = dev_get_drvdata(dev); struct rtc_time now; - unsigned long now_secs; - unsigned long alarm_secs; + unsigned long long now_secs; + unsigned long long alarm_secs; unsigned long long lpa;
st_rtc_read_time(dev, &now); - rtc_tm_to_time(&now, &now_secs); - rtc_tm_to_time(&t->time, &alarm_secs); + now_secs = rtc_tm_to_time64(&now); + alarm_secs = rtc_tm_to_time64(&t->time);
/* Invalid alarm time */ if (now_secs > alarm_secs)
On 06/19/2017 03:36 AM, Benjamin Gaignard wrote:
On 32bits platforms "struct timeval" or "time_t" are using u32 to code the date, this cause tools like "date" or "hwclock" failed even before setting the RTC device if the date is superior to year 2038 (or 2106).
To avoid this problem I add one RTC test file which directly use RTC ioctl to set and read RTC time and alarm values. rtctest_setdate allow to set any date/time given in the command line.
On this version 2 I add check of problematics years in rtctest like suggest by Alexandre.
Finally that had allowed me to test and fix rtc-st-lpc driver.
Benjamin Gaignard (3): tools: timer: add rtctest_setdate tool: timer: rtctest add check for problematic dates rtc: st-lpc: make it robust against y2038/2106 bug
drivers/rtc/rtc-st-lpc.c | 19 ++-- tools/testing/selftests/timers/Makefile | 2 +- tools/testing/selftests/timers/rtctest.c | 121 ++++++++++++++++++++++- tools/testing/selftests/timers/rtctest_setdate.c | 86 ++++++++++++++++ 4 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 tools/testing/selftests/timers/rtctest_setdate.c
Hi Thomas/John,
I can take the first two patches in this series through linux-kselftest with your or John's Ack. Please review and let me know one way or the other.
The third one is a rtc driver patch. Please let me know how do you want to handle this series soon we can get this into 4.13-rc1.
thanks, -- Shah
On 23/06/2017 at 13:40:41 -0600, Shuah Khan wrote:
On 06/19/2017 03:36 AM, Benjamin Gaignard wrote:
On 32bits platforms "struct timeval" or "time_t" are using u32 to code the date, this cause tools like "date" or "hwclock" failed even before setting the RTC device if the date is superior to year 2038 (or 2106).
To avoid this problem I add one RTC test file which directly use RTC ioctl to set and read RTC time and alarm values. rtctest_setdate allow to set any date/time given in the command line.
On this version 2 I add check of problematics years in rtctest like suggest by Alexandre.
Finally that had allowed me to test and fix rtc-st-lpc driver.
Benjamin Gaignard (3): tools: timer: add rtctest_setdate tool: timer: rtctest add check for problematic dates rtc: st-lpc: make it robust against y2038/2106 bug
drivers/rtc/rtc-st-lpc.c | 19 ++-- tools/testing/selftests/timers/Makefile | 2 +- tools/testing/selftests/timers/rtctest.c | 121 ++++++++++++++++++++++- tools/testing/selftests/timers/rtctest_setdate.c | 86 ++++++++++++++++ 4 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 tools/testing/selftests/timers/rtctest_setdate.c
Hi Thomas/John,
I can take the first two patches in this series through linux-kselftest with your or John's Ack. Please review and let me know one way or the other.
Well, I'm the maintainer for rtctest.c and I'll make sure to also be the one for rtctest_setdate.c.
The third one is a rtc driver patch. Please let me know how do you want to handle this series soon we can get this into 4.13-rc1.
I'll take the three patches but I still have comment I didn't have time to give yet.
Hi Alexandre,
On 06/23/2017 04:09 PM, Alexandre Belloni wrote:
On 23/06/2017 at 13:40:41 -0600, Shuah Khan wrote:
On 06/19/2017 03:36 AM, Benjamin Gaignard wrote:
On 32bits platforms "struct timeval" or "time_t" are using u32 to code the date, this cause tools like "date" or "hwclock" failed even before setting the RTC device if the date is superior to year 2038 (or 2106).
To avoid this problem I add one RTC test file which directly use RTC ioctl to set and read RTC time and alarm values. rtctest_setdate allow to set any date/time given in the command line.
On this version 2 I add check of problematics years in rtctest like suggest by Alexandre.
Finally that had allowed me to test and fix rtc-st-lpc driver.
Benjamin Gaignard (3): tools: timer: add rtctest_setdate tool: timer: rtctest add check for problematic dates rtc: st-lpc: make it robust against y2038/2106 bug
drivers/rtc/rtc-st-lpc.c | 19 ++-- tools/testing/selftests/timers/Makefile | 2 +- tools/testing/selftests/timers/rtctest.c | 121 ++++++++++++++++++++++- tools/testing/selftests/timers/rtctest_setdate.c | 86 ++++++++++++++++ 4 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 tools/testing/selftests/timers/rtctest_setdate.c
Hi Thomas/John,
I can take the first two patches in this series through linux-kselftest with your or John's Ack. Please review and let me know one way or the other.
Well, I'm the maintainer for rtctest.c and I'll make sure to also be the one for rtctest_setdate.c>
The third one is a rtc driver patch. Please let me know how do you want to handle this series soon we can get this into 4.13-rc1.
I'll take the three patches but I still have comment I didn't have time to give yet.
Okay. I will drop this off my radar then :)
thanks, -- Shuah
2017-06-24 0:34 GMT+02:00 Shuah Khan shuah@kernel.org:
Hi Alexandre,
On 06/23/2017 04:09 PM, Alexandre Belloni wrote:
On 23/06/2017 at 13:40:41 -0600, Shuah Khan wrote:
On 06/19/2017 03:36 AM, Benjamin Gaignard wrote:
On 32bits platforms "struct timeval" or "time_t" are using u32 to code the date, this cause tools like "date" or "hwclock" failed even before setting the RTC device if the date is superior to year 2038 (or 2106).
To avoid this problem I add one RTC test file which directly use RTC ioctl to set and read RTC time and alarm values. rtctest_setdate allow to set any date/time given in the command line.
On this version 2 I add check of problematics years in rtctest like suggest by Alexandre.
Finally that had allowed me to test and fix rtc-st-lpc driver.
Benjamin Gaignard (3): tools: timer: add rtctest_setdate tool: timer: rtctest add check for problematic dates rtc: st-lpc: make it robust against y2038/2106 bug
drivers/rtc/rtc-st-lpc.c | 19 ++-- tools/testing/selftests/timers/Makefile | 2 +- tools/testing/selftests/timers/rtctest.c | 121 ++++++++++++++++++++++- tools/testing/selftests/timers/rtctest_setdate.c | 86 ++++++++++++++++ 4 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 tools/testing/selftests/timers/rtctest_setdate.c
Hi Thomas/John,
I can take the first two patches in this series through linux-kselftest with your or John's Ack. Please review and let me know one way or the other.
Well, I'm the maintainer for rtctest.c and I'll make sure to also be the one for rtctest_setdate.c>
The third one is a rtc driver patch. Please let me know how do you want to handle this series soon we can get this into 4.13-rc1.
I'll take the three patches but I still have comment I didn't have time to give yet.
Alexandre, may you had time to give me feedback on this ?
Regards, Benjamin
Okay. I will drop this off my radar then :)
thanks, -- Shuah
On 19/06/2017 at 11:36:19 +0200, Benjamin Gaignard wrote:
On 32bits platforms "struct timeval" or "time_t" are using u32 to code the date, this cause tools like "date" or "hwclock" failed even before setting the RTC device if the date is superior to year 2038 (or 2106).
To avoid this problem I add one RTC test file which directly use RTC ioctl to set and read RTC time and alarm values. rtctest_setdate allow to set any date/time given in the command line.
On this version 2 I add check of problematics years in rtctest like suggest by Alexandre.
Finally that had allowed me to test and fix rtc-st-lpc driver.
Benjamin Gaignard (3): tools: timer: add rtctest_setdate tool: timer: rtctest add check for problematic dates rtc: st-lpc: make it robust against y2038/2106 bug
drivers/rtc/rtc-st-lpc.c | 19 ++-- tools/testing/selftests/timers/Makefile | 2 +- tools/testing/selftests/timers/rtctest.c | 121 ++++++++++++++++++++++- tools/testing/selftests/timers/rtctest_setdate.c | 86 ++++++++++++++++ 4 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 tools/testing/selftests/timers/rtctest_setdate.c
Applied, thanks.
I've fixed up the date to meaningful ones in patch 2.
linaro-kernel@lists.linaro.org