93cf7ee2fd
Automatic submission by obs-autosubmit OBS-URL: https://build.opensuse.org/request/show/414973 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/u-boot?expand=0&rev=77
254 lines
8.4 KiB
Diff
254 lines
8.4 KiB
Diff
From 55b8f99ab597bdc6d67579d3b9cb66b2297b0e57 Mon Sep 17 00:00:00 2001
|
|
From: Alexander Graf <agraf@suse.de>
|
|
Date: Sun, 5 Jun 2016 13:05:08 +0200
|
|
Subject: [PATCH] efi_loader: Allow boards to implement get_time and
|
|
reset_system
|
|
|
|
EFI allows an OS to leverage firmware drivers while the OS is running. In the
|
|
generic code we so far had to stub those implementations out, because we would
|
|
need board specific knowledge about MMIO setups for it.
|
|
|
|
However, boards can easily implement those themselves. This patch provides the
|
|
framework so that a board can implement its own versions of get_time and
|
|
reset_system which would actually do something useful.
|
|
|
|
While at it we also introduce a simple way for code to reserve MMIO pointers
|
|
as runtime available.
|
|
|
|
Signed-off-by: Alexander Graf <agraf@suse.de>
|
|
---
|
|
cmd/bootefi.c | 4 ++
|
|
include/efi_loader.h | 18 ++++++++
|
|
lib/efi_loader/efi_runtime.c | 101 ++++++++++++++++++++++++++++++++++++++-----
|
|
3 files changed, 112 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
|
|
index 011f62c..a80ed48 100644
|
|
--- a/cmd/bootefi.c
|
|
+++ b/cmd/bootefi.c
|
|
@@ -205,6 +205,10 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
|
|
loaded_image_info.device_handle = nethandle;
|
|
#endif
|
|
|
|
+ /* Initialize EFI runtime services */
|
|
+ efi_reset_system_init();
|
|
+ efi_get_time_init();
|
|
+
|
|
/* Call our payload! */
|
|
debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
|
|
|
|
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
|
index 9738835..91d6a84 100644
|
|
--- a/include/efi_loader.h
|
|
+++ b/include/efi_loader.h
|
|
@@ -150,11 +150,29 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii)
|
|
#define EFI_RUNTIME_DATA __attribute__ ((section ("efi_runtime_data")))
|
|
#define EFI_RUNTIME_TEXT __attribute__ ((section ("efi_runtime_text")))
|
|
|
|
+/* Call this with mmio_ptr as the _pointer_ to a pointer to an MMIO region
|
|
+ * to make it available at runtime */
|
|
+void efi_add_runtime_mmio(void *mmio_ptr, u64 len);
|
|
+
|
|
+/* Boards may provide the functions below to implement RTS functionality */
|
|
+
|
|
+void EFI_RUNTIME_TEXT EFIAPI efi_reset_system(
|
|
+ enum efi_reset_type reset_type,
|
|
+ efi_status_t reset_status,
|
|
+ unsigned long data_size, void *reset_data);
|
|
+void efi_reset_system_init(void);
|
|
+
|
|
+efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_get_time(
|
|
+ struct efi_time *time,
|
|
+ struct efi_time_cap *capabilities);
|
|
+void efi_get_time_init(void);
|
|
+
|
|
#else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
|
|
|
|
/* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
|
|
#define EFI_RUNTIME_DATA
|
|
#define EFI_RUNTIME_TEXT
|
|
+static inline void efi_add_runtime_mmio(void **mmio_ptr, u64 len) { }
|
|
|
|
/* No loader configured, stub out EFI_ENTRY */
|
|
static inline void efi_restore_gd(void) { }
|
|
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
|
|
index 99b5ef1..5301d68 100644
|
|
--- a/lib/efi_loader/efi_runtime.c
|
|
+++ b/lib/efi_loader/efi_runtime.c
|
|
@@ -16,6 +16,16 @@
|
|
/* For manual relocation support */
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
+struct efi_runtime_mmio_list {
|
|
+ struct list_head link;
|
|
+ void **ptr;
|
|
+ u64 paddr;
|
|
+ u64 len;
|
|
+};
|
|
+
|
|
+/* This list contains all runtime available mmio regions */
|
|
+LIST_HEAD(efi_runtime_mmio);
|
|
+
|
|
static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void);
|
|
static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void);
|
|
static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void);
|
|
@@ -55,9 +65,10 @@ struct elf_rela {
|
|
* handle a good number of runtime callbacks
|
|
*/
|
|
|
|
-static void EFIAPI efi_reset_system(enum efi_reset_type reset_type,
|
|
- efi_status_t reset_status,
|
|
- unsigned long data_size, void *reset_data)
|
|
+static void EFIAPI efi_reset_system_boottime(
|
|
+ enum efi_reset_type reset_type,
|
|
+ efi_status_t reset_status,
|
|
+ unsigned long data_size, void *reset_data)
|
|
{
|
|
EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
|
|
reset_data);
|
|
@@ -72,11 +83,12 @@ static void EFIAPI efi_reset_system(enum efi_reset_type reset_type,
|
|
break;
|
|
}
|
|
|
|
- EFI_EXIT(EFI_SUCCESS);
|
|
+ while (1) { }
|
|
}
|
|
|
|
-static efi_status_t EFIAPI efi_get_time(struct efi_time *time,
|
|
- struct efi_time_cap *capabilities)
|
|
+static efi_status_t EFIAPI efi_get_time_boottime(
|
|
+ struct efi_time *time,
|
|
+ struct efi_time_cap *capabilities)
|
|
{
|
|
#if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
|
|
struct rtc_time tm;
|
|
@@ -107,6 +119,33 @@ static efi_status_t EFIAPI efi_get_time(struct efi_time *time,
|
|
#endif
|
|
}
|
|
|
|
+/* Boards may override the helpers below to implement RTS functionality */
|
|
+
|
|
+void __weak EFI_RUNTIME_TEXT EFIAPI efi_reset_system(
|
|
+ enum efi_reset_type reset_type,
|
|
+ efi_status_t reset_status,
|
|
+ unsigned long data_size, void *reset_data)
|
|
+{
|
|
+ /* Nothing we can do */
|
|
+ while (1) { }
|
|
+}
|
|
+
|
|
+void __weak efi_reset_system_init(void)
|
|
+{
|
|
+}
|
|
+
|
|
+efi_status_t __weak EFI_RUNTIME_TEXT EFIAPI efi_get_time(
|
|
+ struct efi_time *time,
|
|
+ struct efi_time_cap *capabilities)
|
|
+{
|
|
+ /* Nothing we can do */
|
|
+ return EFI_DEVICE_ERROR;
|
|
+}
|
|
+
|
|
+void __weak efi_get_time_init(void)
|
|
+{
|
|
+}
|
|
+
|
|
struct efi_runtime_detach_list_struct {
|
|
void *ptr;
|
|
void *patchto;
|
|
@@ -116,7 +155,7 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
|
|
{
|
|
/* do_reset is gone */
|
|
.ptr = &efi_runtime_services.reset_system,
|
|
- .patchto = NULL,
|
|
+ .patchto = efi_reset_system,
|
|
}, {
|
|
/* invalidate_*cache_all are gone */
|
|
.ptr = &efi_runtime_services.set_virtual_address_map,
|
|
@@ -124,7 +163,7 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
|
|
}, {
|
|
/* RTC accessors are gone */
|
|
.ptr = &efi_runtime_services.get_time,
|
|
- .patchto = &efi_device_error,
|
|
+ .patchto = &efi_get_time,
|
|
}, {
|
|
/* Clean up system table */
|
|
.ptr = &systab.con_in,
|
|
@@ -233,12 +272,38 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
|
|
EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
|
|
descriptor_version, virtmap);
|
|
|
|
+ /* Rebind mmio pointers */
|
|
+ for (i = 0; i < n; i++) {
|
|
+ struct efi_mem_desc *map = (void*)virtmap +
|
|
+ (descriptor_size * i);
|
|
+ struct list_head *lhandle;
|
|
+ efi_physical_addr_t map_start = map->physical_start;
|
|
+ efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT;
|
|
+ efi_physical_addr_t map_end = map_start + map_len;
|
|
+
|
|
+ /* Adjust all mmio pointers in this region */
|
|
+ list_for_each(lhandle, &efi_runtime_mmio) {
|
|
+ struct efi_runtime_mmio_list *lmmio;
|
|
+
|
|
+ lmmio = list_entry(lhandle,
|
|
+ struct efi_runtime_mmio_list,
|
|
+ link);
|
|
+ if ((map_start <= lmmio->paddr) &&
|
|
+ (map_end >= lmmio->paddr)) {
|
|
+ u64 off = map->virtual_start - map_start;
|
|
+ *lmmio->ptr = (void*)(lmmio->paddr + off);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Move the actual runtime code over */
|
|
for (i = 0; i < n; i++) {
|
|
struct efi_mem_desc *map;
|
|
|
|
map = (void*)virtmap + (descriptor_size * i);
|
|
if (map->type == EFI_RUNTIME_SERVICES_CODE) {
|
|
- ulong new_offset = map->virtual_start - (runtime_start - gd->relocaddr);
|
|
+ ulong new_offset = map->virtual_start -
|
|
+ (runtime_start - gd->relocaddr);
|
|
|
|
efi_runtime_relocate(new_offset, map);
|
|
/* Once we're virtual, we can no longer handle
|
|
@@ -251,6 +316,20 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
|
|
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
|
}
|
|
|
|
+void efi_add_runtime_mmio(void *mmio_ptr, u64 len)
|
|
+{
|
|
+ struct efi_runtime_mmio_list *newmmio;
|
|
+
|
|
+ u64 pages = (len + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT;
|
|
+ efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, false);
|
|
+
|
|
+ newmmio = calloc(1, sizeof(*newmmio));
|
|
+ newmmio->ptr = mmio_ptr;
|
|
+ newmmio->paddr = *(uintptr_t *)mmio_ptr;
|
|
+ newmmio->len = len;
|
|
+ list_add_tail(&newmmio->link, &efi_runtime_mmio);
|
|
+}
|
|
+
|
|
/*
|
|
* In the second stage, U-Boot has disappeared. To isolate our runtime code
|
|
* that at this point still exists from the rest, we put it into a special
|
|
@@ -292,7 +371,7 @@ struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = {
|
|
.revision = EFI_RUNTIME_SERVICES_REVISION,
|
|
.headersize = sizeof(struct efi_table_hdr),
|
|
},
|
|
- .get_time = &efi_get_time,
|
|
+ .get_time = &efi_get_time_boottime,
|
|
.set_time = (void *)&efi_device_error,
|
|
.get_wakeup_time = (void *)&efi_unimplemented,
|
|
.set_wakeup_time = (void *)&efi_unimplemented,
|
|
@@ -302,5 +381,5 @@ struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = {
|
|
.get_next_variable = (void *)&efi_device_error,
|
|
.set_variable = (void *)&efi_device_error,
|
|
.get_next_high_mono_count = (void *)&efi_device_error,
|
|
- .reset_system = &efi_reset_system,
|
|
+ .reset_system = &efi_reset_system_boottime,
|
|
};
|