[U-Boot] [PATCH v2 1/1] efi_loader: implement SetTime

Heinrich Schuchardt xypron.glpk at gmx.de
Tue May 21 15:40:38 UTC 2019


Implement the SetTime() runtime service.

Extend the real time clock selftest to check setting the clock.

Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
---
v2
	fix reference to unknown parameter for CONFIG_DM_RTC=n
---
 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..5f40659ee7 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 <efi_selftest.h>

 #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.20.1



More information about the U-Boot mailing list