[U-Boot] [PATCH v2 0/5] efi_loader: parameter checks in SetTime()

The UEFI spec requires to check the validity of the time stamp passed to SetTime().
For the runtime version of SetTime() defined a weak implementation. Put the definition into include/efi_loader.h to make it available to implementors.
v2:
Make the handling of daylight saving times more consistent.
Add Kconfig options to select if the GetTime() and SetTime() runtime services shall be available.
Heinrich Schuchardt (5): rtc: export rtc_month_days() efi_loader: check time in SetTime() efi_loader: export efi_set_time() efi_loader: handling of daylight saving time efi_loader: Kconfig entries for GetTime(), SetTime()
drivers/rtc/rtc-lib.c | 2 +- include/efi_loader.h | 2 ++ include/rtc.h | 8 ++++++ lib/efi_loader/Kconfig | 16 ++++++++++++ lib/efi_loader/efi_runtime.c | 39 +++++++++++++++++++++++------ lib/efi_selftest/Makefile | 2 +- lib/efi_selftest/efi_selftest_rtc.c | 17 +++++-------- 7 files changed, 66 insertions(+), 20 deletions(-)
-- 2.20.1

Export function rtc_month_days() for reuse in the UEFI subsystem.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 no change --- drivers/rtc/rtc-lib.c | 2 +- include/rtc.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index 6528ddfebb..1f7bdade29 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -23,7 +23,7 @@ static const unsigned char rtc_days_in_month[] = { /* * The number of days in the month. */ -static int rtc_month_days(unsigned int month, unsigned int year) +int rtc_month_days(unsigned int month, unsigned int year) { return rtc_days_in_month[month] + (is_leap_year(year) && month == 1); } diff --git a/include/rtc.h b/include/rtc.h index 2c3a5743e3..b255bdc7a3 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -258,4 +258,12 @@ void rtc_to_tm(u64 time_t, struct rtc_time *time); */ unsigned long rtc_mktime(const struct rtc_time *time);
+/** + * rtc_month_days() - The number of days in the month + * + * @month: month (January = 0) + * @year: year (4 digits) + */ +int rtc_month_days(unsigned int month, unsigned int year); + #endif /* _RTC_H_ */ -- 2.20.1

The UEFI spec prescribes that we check that the timestamp passed to SetTime() is checked for validity.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 avoid unused function warning if CONFIG_DM_RTC is not set --- lib/efi_loader/efi_runtime.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 058b40a887..2082d1304f 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -214,6 +214,30 @@ out: #endif }
+#ifdef CONFIG_DM_RTC + +/** + * efi_validate_time() - checks if timestamp is valid + * + * @time: timestamp to validate + * Returns: 0 if timestamp is valid, 1 otherwise + */ +static int efi_validate_time(struct efi_time *time) +{ + return (!time || + time->year < 1900 || time->year > 9999 || + !time->month || time->month > 12 || !time->day || + time->day > rtc_month_days(time->month - 1, time->year) || + time->hour > 23 || time->minute > 59 || time->second > 59 || + time->nanosecond > 999999999 || + time->daylight & + ~(EFI_TIME_IN_DAYLIGHT | EFI_TIME_ADJUST_DAYLIGHT) || + ((time->timezone < -1440 || time->timezone > 1440) && + time->timezone != EFI_UNSPECIFIED_TIMEZONE)); +} + +#endif + /** * efi_set_time_boottime() - set current time * @@ -235,7 +259,7 @@ static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time)
EFI_ENTRY("%p", time);
- if (!time) { + if (efi_validate_time(time)) { ret = EFI_INVALID_PARAMETER; goto out; } -- 2.20.1

To let a board implement the runtime version of SetTime() we have to provide the definition of the weak function in an include.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 no change --- include/efi_loader.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/efi_loader.h b/include/efi_loader.h index 77b2f60bdc..23ce732267 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -594,6 +594,8 @@ efi_status_t __efi_runtime EFIAPI efi_get_time( struct efi_time *time, struct efi_time_cap *capabilities);
+efi_status_t __efi_runtime EFIAPI efi_set_time(struct efi_time *time); + #ifdef CONFIG_CMD_BOOTEFI_SELFTEST /* * Entry point for the tests of the EFI API. -- 2.20.1

If SetTime() is meant to set daylight saving time it will be called with Time.Daylight == EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT.
Return 0 from GetTime() if time is not in daylight because we cannot determine if we are in a time zone with daylight saving time.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 new patch --- lib/efi_loader/efi_runtime.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 2082d1304f..98ab4de03d 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -195,9 +195,9 @@ static efi_status_t EFIAPI efi_get_time_boottime( time->hour = tm.tm_hour; time->minute = tm.tm_min; time->second = tm.tm_sec; - time->daylight = EFI_TIME_ADJUST_DAYLIGHT; - if (tm.tm_isdst > 0) - time->daylight |= EFI_TIME_IN_DAYLIGHT; + if (tm.tm_isdst) + time->daylight = + EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT; time->timezone = EFI_UNSPECIFIED_TIMEZONE;
if (capabilities) { @@ -276,7 +276,8 @@ static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time) tm.tm_hour = time->hour; tm.tm_min = time->minute; tm.tm_sec = time->second; - tm.tm_isdst = time->daylight == EFI_TIME_IN_DAYLIGHT; + tm.tm_isdst = time->daylight == + (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT); /* Calculate day of week */ rtc_calc_weekday(&tm);
-- 2.20.1

The GetTime() and the SetTime() runtime services are not obligatory. So let's make them customizable.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 new patch --- lib/efi_loader/Kconfig | 16 ++++++++++++++++ lib/efi_loader/efi_runtime.c | 6 +++--- lib/efi_selftest/Makefile | 2 +- lib/efi_selftest/efi_selftest_rtc.c | 17 ++++++----------- 4 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index fc04ea39d0..cd5436c576 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -18,6 +18,22 @@ config EFI_LOADER
if EFI_LOADER
+config EFI_GET_TIME + bool "GetTime() runtime service" + depends on DM_RTC + default y + help + Provide the GetTime() runtime service at boottime. This service + can be used by an EFI application to read the real time clock. + +config EFI_SET_TIME + bool "SetTime() runtime service" + depends on EFI_GET_TIME + default n + help + Provide the SetTime() runtime service at boottime. This service + can be used by an EFI application to adjust the real time clock. + config EFI_DEVICE_PATH_TO_TEXT bool "Device path to text protocol" default y diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 98ab4de03d..9c50955c9b 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -167,7 +167,7 @@ static efi_status_t EFIAPI efi_get_time_boottime( struct efi_time *time, struct efi_time_cap *capabilities) { -#ifdef CONFIG_DM_RTC +#ifdef CONFIG_EFI_GET_TIME efi_status_t ret = EFI_SUCCESS; struct rtc_time tm; struct udevice *dev; @@ -214,7 +214,7 @@ out: #endif }
-#ifdef CONFIG_DM_RTC +#ifdef CONFIG_EFI_SET_TIME
/** * efi_validate_time() - checks if timestamp is valid @@ -252,7 +252,7 @@ static int efi_validate_time(struct efi_time *time) */ static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time) { -#ifdef CONFIG_DM_RTC +#ifdef CONFIG_EFI_SET_TIME efi_status_t ret = EFI_SUCCESS; struct rtc_time tm; struct udevice *dev; diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index cfbb40c891..b032154147 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -27,7 +27,6 @@ efi_selftest_loaded_image.o \ efi_selftest_manageprotocols.o \ efi_selftest_memory.o \ efi_selftest_register_notify.o \ -efi_selftest_rtc.o \ efi_selftest_snp.o \ efi_selftest_textinput.o \ efi_selftest_textinputex.o \ @@ -43,6 +42,7 @@ efi_selftest_unicode_collation.o
obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o +obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) obj-y += efi_selftest_fdt.o diff --git a/lib/efi_selftest/efi_selftest_rtc.c b/lib/efi_selftest/efi_selftest_rtc.c index 9eb29add3b..6f7035dee6 100644 --- a/lib/efi_selftest/efi_selftest_rtc.c +++ b/lib/efi_selftest/efi_selftest_rtc.c @@ -40,7 +40,9 @@ static int setup(const efi_handle_t handle, static int execute(void) { efi_status_t ret; - struct efi_time tm, tm_old, tm_new = { + struct efi_time tm_old; +#ifdef CONFIG_EFI_SET_TIME + struct efi_time tm, tm_new = { .year = 2017, .month = 5, .day = 19, @@ -48,31 +50,23 @@ static int execute(void) .minute = 47, .second = 53, }; +#endif
/* Display current time */ ret = runtime->get_time(&tm_old, NULL); if (ret != EFI_SUCCESS) { -#ifdef CONFIG_CMD_DATE efi_st_error(EFI_ST_NO_RTC); return EFI_ST_FAILURE; -#else - efi_st_todo(EFI_ST_NO_RTC); - return EFI_ST_SUCCESS; -#endif } efi_st_printf("Time according to real time clock: " "%.4u-%.2u-%.2u %.2u:%.2u:%.2u\n", tm_old.year, tm_old.month, tm_old.day, tm_old.hour, tm_old.minute, tm_old.second); +#ifdef CONFIG_EFI_SET_TIME ret = runtime->set_time(&tm_new); if (ret != EFI_SUCCESS) { -#ifdef CONFIG_CMD_DATE efi_st_error(EFI_ST_NO_RTC_SET); return EFI_ST_FAILURE; -#else - efi_st_todo(EFI_ST_NO_RTC_SET); - return EFI_ST_SUCCESS; -#endif } ret = runtime->get_time(&tm, NULL); if (ret != EFI_SUCCESS) { @@ -95,6 +89,7 @@ static int execute(void) efi_st_error(EFI_ST_NO_RTC_SET); return EFI_ST_FAILURE; } +#endif
return EFI_ST_SUCCESS; } -- 2.20.1
participants (1)
-
Heinrich Schuchardt