From cbf0ffea14c812a19b2eede887e3db1ccc425cd4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 25 Oct 2020 07:25:05 +0100 Subject: [PATCH 1/6] Makefile: provide constant with seconds since epoch Provide a constant U_BOOT_EPOCH with the number of seconds since 1970-01-01. This constant can be used to initialize a software real time clock until it is updated via the 'sntp' command. Signed-off-by: Heinrich Schuchardt --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 5a0ef18668..c21729cf52 100644 --- a/Makefile +++ b/Makefile @@ -1870,6 +1870,7 @@ define filechk_timestamp.h LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TZ "%z"'; \ LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_DMI_DATE "%m/%d/%Y"'; \ LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_BUILD_DATE 0x%Y%m%d'; \ + LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_EPOCH %s'; \ else \ return 42; \ fi; \ @@ -1879,6 +1880,7 @@ define filechk_timestamp.h LC_ALL=C date +'#define U_BOOT_TZ "%z"'; \ LC_ALL=C date +'#define U_BOOT_DMI_DATE "%m/%d/%Y"'; \ LC_ALL=C date +'#define U_BOOT_BUILD_DATE 0x%Y%m%d'; \ + LC_ALL=C date +'#define U_BOOT_EPOCH %s'; \ fi) endef From 87e9963d5acaa41f3c54c1dee9159c775352f86a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 22 Oct 2020 23:52:14 +0200 Subject: [PATCH 2/6] rtc: provide an emulated RTC On a board without hardware clock this software real time clock can be used. The build time is used to initialize the RTC. So you will have to adjust the time either manually using the 'date' command or use the 'sntp' to update the RTC with the time from a network time server. See CONFIG_CMD_SNTP and CONFIG_BOOTP_NTPSERVER. The RTC time is advanced according to CPU ticks. Signed-off-by: Heinrich Schuchardt --- MAINTAINERS | 1 + drivers/rtc/Kconfig | 11 ++++++ drivers/rtc/Makefile | 1 + drivers/rtc/emul_rtc.c | 80 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 drivers/rtc/emul_rtc.c diff --git a/MAINTAINERS b/MAINTAINERS index 69a5bc3768..d9f80325f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -678,6 +678,7 @@ S: Maintained T: git https://gitlab.denx.de/u-boot/custodians/u-boot-efi.git F: doc/api/efi.rst F: doc/uefi/* +F: drivers/rtc/emul_rtc.c F: include/capitalization.h F: include/charset.h F: include/cp1250.h diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 63662001c2..d06d272e14 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -63,6 +63,17 @@ config RTC_DS3232 Support for Dallas Semiconductor (now Maxim) DS3232 compatible Real Time Clock devices. +config RTC_EMULATION + bool "Enable emulated RTC" + depends on DM_RTC + help + On a board without hardware clock this software real time clock can be + used. The build time is used to initialize the RTC. So you will have + to adjust the time either manually using the 'date' command or use + the 'sntp' to update the RTC with the time from a network time server. + See CONFIG_CMD_SNTP and CONFIG_BOOTP_NTPSERVER. The RTC time is + advanced according to CPU ticks. + config RTC_ISL1208 bool "Enable ISL1208 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 12eb449583..ef66dc4bf0 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_RTC_DS164x) += ds164x.o obj-$(CONFIG_RTC_DS174x) += ds174x.o obj-$(CONFIG_RTC_DS3231) += ds3231.o obj-$(CONFIG_RTC_DS3232) += ds3232.o +obj-$(CONFIG_RTC_EMULATION) += emul_rtc.o obj-$(CONFIG_RTC_FTRTC010) += ftrtc010.o obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o obj-$(CONFIG_RTC_IMXDI) += imxdi.o diff --git a/drivers/rtc/emul_rtc.c b/drivers/rtc/emul_rtc.c new file mode 100644 index 0000000000..c98c24bbb3 --- /dev/null +++ b/drivers/rtc/emul_rtc.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020, Heinrich Schuchardt + * + * This driver emulates a real time clock based on timer ticks. + */ + +#include +#include +#include +#include +#include + +/** + * struct emul_rtc - private data for emulated RTC driver + */ +struct emul_rtc { + /** + * @offset_us: microseconds from 1970-01-01 to timer_get_us() base + */ + u64 offset_us; + /** + * @isdst: daylight saving time + */ + int isdst; +}; + +static int emul_rtc_get(struct udevice *dev, struct rtc_time *time) +{ + struct emul_rtc *priv = dev_get_priv(dev); + u64 now; + + if (!priv->offset_us) { + /* Use the build date as initial time */ + priv->offset_us = U_BOOT_EPOCH * 1000000ULL - timer_get_us(); + priv->isdst = -1; + } + + now = timer_get_us() + priv->offset_us; + do_div(now, 1000000); + rtc_to_tm(now, time); + time->tm_isdst = priv->isdst; + + return 0; +} + +static int emul_rtc_set(struct udevice *dev, const struct rtc_time *time) +{ + struct emul_rtc *priv = dev_get_priv(dev); + + if (time->tm_year < 1970) + return -EINVAL; + + priv->offset_us = rtc_mktime(time) * 1000000ULL - timer_get_us(); + + if (time->tm_isdst > 0) + priv->isdst = 1; + else if (time->tm_isdst < 0) + priv->isdst = -1; + else + priv->isdst = 0; + + return 0; +} + +static const struct rtc_ops emul_rtc_ops = { + .get = emul_rtc_get, + .set = emul_rtc_set, +}; + +U_BOOT_DRIVER(rtc_emul) = { + .name = "rtc_emul", + .id = UCLASS_RTC, + .ops = &emul_rtc_ops, + .priv_auto_alloc_size = sizeof(struct emul_rtc), +}; + +U_BOOT_DEVICE(rtc_emul) = { + .name = "rtc_emul", +}; From d3d6afae3c56af4f7b68d777468d509b3d6bdb55 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 15 Oct 2020 12:30:09 +0200 Subject: [PATCH 3/6] trace: conserve gd register on RISC-V An UEFI application may change the value of the register that gd lives in. But some of our functions like get_ticks() access this register. So we have to set the gd register to the U-Boot value when entering a trace point and set it back to the application value when exiting the trace point. Signed-off-by: Heinrich Schuchardt --- lib/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/trace.c b/lib/trace.c index 831283c283..defc9716d8 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -57,7 +57,7 @@ static inline uintptr_t __attribute__((no_instrument_function)) return offset / FUNC_SITE_SIZE; } -#if defined(CONFIG_EFI_LOADER) && defined(CONFIG_ARM) +#if defined(CONFIG_EFI_LOADER) && (defined(CONFIG_ARM) || defined(CONFIG_RISCV)) /** * trace_gd - the value of the gd register From 19763ea0d235643ec33f8e3615a5c9943ecdc36b Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 22 Oct 2020 01:04:20 +0300 Subject: [PATCH 4/6] efi_loader: Sort header file ordering Order header files according to https://www.denx.de/wiki/U-Boot/CodingStyle Suggested-by: Heinrich Schuchardt Signed-off-by: Ilias Apalodimas Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index bf78176217..2896c3ea5a 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -6,18 +6,17 @@ */ #include +#include #include #include #include #include #include -#include -#include -#include -#include #include +#include #include #include +#include DECLARE_GLOBAL_DATA_PTR; From 529441ca89b155abcad2acea62b6f35c19b1c0ac Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 22 Oct 2020 01:04:21 +0300 Subject: [PATCH 5/6] efi_loader: Disable devices before handing over control U-Boot Driver Model is supposed to remove devices with either DM_REMOVE_ACTIVE_DMA or DM_REMOVE_OS_PREPARE flags set, before exiting. Our bootm command does that by explicitly calling calling "dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);" and we also disable any USB devices. The EFI equivalent is doing none of those at the moment. As a result probing an fTPM driver now renders it unusable in Linux. During our (*probe) callback we open a session with OP-TEE, which is supposed to close with our (*remove) callback. Since the (*remove) is never called, once we boot into Linux and try to probe the device again we are getting a busy error response. Moreover all uclass (*preremove) functions won't run. So let's fix this by mimicking what bootm does and disconnect devices when efi_exit_boot_services() is called. Signed-off-by: Ilias Apalodimas Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 2896c3ea5a..b26ac9fbfc 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -15,6 +17,7 @@ #include #include #include +#include #include #include @@ -1993,7 +1996,10 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, list_del(&evt->link); } + if IS_ENABLED(CONFIG_USB_DEVICE) + udc_disconnect(); board_quiesce_devices(); + dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); /* Patch out unsupported runtime function */ efi_runtime_detach(); From 0eae552d18690a19cc714046fb1665138f5701f6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 23 Oct 2020 05:30:29 +0200 Subject: [PATCH 6/6] efi_loader: daylight saving time Adjust the SetTime() and GetTime() runtime services to correctly convert the daylight saving time information when communicating with the RTC. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_runtime.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index dea2b4e5ee..1fa1595e40 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -266,9 +266,13 @@ static efi_status_t EFIAPI efi_get_time_boottime( time->hour = tm.tm_hour; time->minute = tm.tm_min; time->second = tm.tm_sec; - if (tm.tm_isdst) + if (tm.tm_isdst > 0) time->daylight = EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT; + else if (!tm.tm_isdst) + time->daylight = EFI_TIME_ADJUST_DAYLIGHT; + else + time->daylight = 0; time->timezone = EFI_UNSPECIFIED_TIMEZONE; if (capabilities) { @@ -347,8 +351,17 @@ 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_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT); + switch (time->daylight) { + case EFI_TIME_ADJUST_DAYLIGHT: + tm.tm_isdst = 0; + break; + case EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT: + tm.tm_isdst = 1; + break; + default: + tm.tm_isdst = -1; + break; + } /* Calculate day of week */ rtc_calc_weekday(&tm);