From 433bfe7b122eab59ef54e435154f31407668f5b2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 19 May 2019 20:07:39 +0200 Subject: [PATCH] efi_loader: implement SetTime Implement the SetTime() runtime service. Extend the real time clock selftest to check setting the clock. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_runtime.c | 73 ++++++++++++++++++++++++++++- lib/efi_selftest/efi_selftest_rtc.c | 56 ++++++++++++++++++---- 2 files changed, 120 insertions(+), 9 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 636dfdab39..8d1370b4dd 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -214,7 +214,57 @@ out: #endif } +/** + * efi_set_time_boottime() - set current time + * + * This function implements the SetTime() runtime service before + * SetVirtualAddressMap() is called. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @time: pointer to structure to with current time + * Returns: status code + */ +static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time) +{ +#ifdef CONFIG_DM_RTC + efi_status_t ret = EFI_SUCCESS; + struct rtc_time tm; + struct udevice *dev; + + EFI_ENTRY("%p", time); + + if (!time) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + if (uclass_get_device(UCLASS_RTC, 0, &dev)) { + ret = EFI_UNSUPPORTED; + goto out; + } + memset(&tm, 0, sizeof(tm)); + tm.tm_year = time->year; + tm.tm_mon = time->month; + tm.tm_mday = time->day; + tm.tm_hour = time->hour; + tm.tm_min = time->minute; + tm.tm_sec = time->second; + tm.tm_isdst = time->daylight == EFI_TIME_IN_DAYLIGHT; + /* Calculate day of week */ + rtc_calc_weekday(&tm); + + if (dm_rtc_set(dev, &tm)) + ret = EFI_DEVICE_ERROR; +out: + return EFI_EXIT(ret); +#else + EFI_ENTRY("%p", time); + return EFI_EXIT(EFI_UNSUPPORTED); +#endif +} /** * efi_reset_system() - reset system * @@ -271,6 +321,24 @@ efi_status_t __weak __efi_runtime EFIAPI efi_get_time( return EFI_DEVICE_ERROR; } +/** + * efi_set_time() - set current time + * + * This function implements the SetTime runtime service after + * SetVirtualAddressMap() is called. As the U-Boot driver are not available + * anymore only an error code is returned. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @time: pointer to structure to with current time + * Returns: status code + */ +efi_status_t __weak __efi_runtime EFIAPI efi_set_time(struct efi_time *time) +{ + return EFI_UNSUPPORTED; +} + struct efi_runtime_detach_list_struct { void *ptr; void *patchto; @@ -289,6 +357,9 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { /* RTC accessors are gone */ .ptr = &efi_runtime_services.get_time, .patchto = &efi_get_time, + }, { + .ptr = &efi_runtime_services.set_time, + .patchto = &efi_set_time, }, { /* Clean up system table */ .ptr = &systab.con_in, @@ -697,7 +768,7 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .headersize = sizeof(struct efi_runtime_services), }, .get_time = &efi_get_time_boottime, - .set_time = (void *)&efi_device_error, + .set_time = &efi_set_time_boottime, .get_wakeup_time = (void *)&efi_unimplemented, .set_wakeup_time = (void *)&efi_unimplemented, .set_virtual_address_map = &efi_set_virtual_address_map, diff --git a/lib/efi_selftest/efi_selftest_rtc.c b/lib/efi_selftest/efi_selftest_rtc.c index 8d440dc0b3..9eb29add3b 100644 --- a/lib/efi_selftest/efi_selftest_rtc.c +++ b/lib/efi_selftest/efi_selftest_rtc.c @@ -10,6 +10,7 @@ #include #define EFI_ST_NO_RTC "Could not read real time clock\n" +#define EFI_ST_NO_RTC_SET "Could not set real time clock\n" static struct efi_runtime_services *runtime; @@ -30,17 +31,26 @@ static int setup(const efi_handle_t handle, /* * Execute unit test. * - * Display current time. + * Read and display current time. + * Set a new value and read it back. + * Set the real time clock back the current time. * * @return: EFI_ST_SUCCESS for success */ static int execute(void) { efi_status_t ret; - struct efi_time tm; + struct efi_time tm, tm_old, tm_new = { + .year = 2017, + .month = 5, + .day = 19, + .hour = 13, + .minute = 47, + .second = 53, + }; /* Display current time */ - ret = runtime->get_time(&tm, NULL); + ret = runtime->get_time(&tm_old, NULL); if (ret != EFI_SUCCESS) { #ifdef CONFIG_CMD_DATE efi_st_error(EFI_ST_NO_RTC); @@ -49,11 +59,41 @@ static int execute(void) efi_st_todo(EFI_ST_NO_RTC); return EFI_ST_SUCCESS; #endif - } else { - efi_st_printf("Time according to real time clock: " - "%.4u-%.2u-%.2u %.2u:%.2u:%.2u\n", - tm.year, tm.month, tm.day, - tm.hour, tm.minute, tm.second); + } + 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); + 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) { + efi_st_error(EFI_ST_NO_RTC); + return EFI_ST_FAILURE; + } + if (tm.year != tm_new.year || + tm.month != tm_new.month || + tm.day != tm_new.day || + tm.hour != tm_new.hour || + tm.minute != tm_new.minute || + tm.second < tm_new.second || + tm.second > tm_new.second + 2) { + efi_st_error(EFI_ST_NO_RTC_SET); + return EFI_ST_FAILURE; + } + /* Set time back to old value */ + ret = runtime->set_time(&tm_old); + if (ret != EFI_SUCCESS) { + efi_st_error(EFI_ST_NO_RTC_SET); + return EFI_ST_FAILURE; } return EFI_ST_SUCCESS; -- 2.39.5