From 80a4800ee1526a4a46cd02b3ea2fd37eebb77504 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 16 Aug 2016 21:08:45 +0200 Subject: 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 --- lib/efi_loader/efi_runtime.c | 102 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 11 deletions(-) (limited to 'lib/efi_loader/efi_runtime.c') diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 99b5ef11c2e..f73e6d97cbc 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,39 @@ 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; + uintptr_t new_addr = lmmio->paddr + off; + *lmmio->ptr = (void *)new_addr; + } + } + } + + /* 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 +317,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 +372,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 +382,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, }; -- cgit v1.2.3 From 65e4c0b168651285adeab66f32f3a14668f3e4bd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Sep 2016 15:27:35 -0600 Subject: x86: efi: Add EFI loader support for x86 Add the required pieces to support the EFI loader on x86. Since U-Boot only builds for 32-bit on x86, only a 32-bit EFI application is supported. If a 64-bit kernel must be booted, U-Boot supports this directly using FIT (see doc/uImage.FIT/kernel.its). U-Boot can act as a payload for both 32-bit and 64-bit EFI. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Signed-off-by: Alexander Graf --- lib/efi_loader/efi_runtime.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/efi_loader/efi_runtime.c') diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index f73e6d97cbc..f007ca640a3 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -44,6 +44,10 @@ static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void); #elif defined(CONFIG_ARM) #define R_RELATIVE 23 #define R_MASK 0xffULL +#elif defined(CONFIG_X86) +#include +#define R_RELATIVE R_386_RELATIVE +#define R_MASK 0xffULL #else #error Need to add relocation awareness #endif -- cgit v1.2.3 From 3c63db9ca9765c85bbcf2a06f4183cfb0036ea33 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 14 Oct 2016 13:45:30 +0200 Subject: efi_loader: Rename EFI_RUNTIME_{TEXT, DATA} to __efi_runtime{, _data} Compiler attributes are more commonly __foo style tags rather than big upper case eye sores like EFI_RUNTIME_TEXT. Simon Glass felt quite strongly about this, so this patch converts our existing defines over to more eye friendly ones. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass --- lib/efi_loader/efi_runtime.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'lib/efi_loader/efi_runtime.c') diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index f007ca640a3..dd52755d1d7 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -26,9 +26,9 @@ struct efi_runtime_mmio_list { /* 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); +static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void); +static efi_status_t __efi_runtime EFIAPI efi_device_error(void); +static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void); #ifdef CONFIG_SYS_CACHELINE_SIZE #define EFI_CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE @@ -125,7 +125,7 @@ static efi_status_t EFIAPI efi_get_time_boottime( /* Boards may override the helpers below to implement RTS functionality */ -void __weak EFI_RUNTIME_TEXT EFIAPI efi_reset_system( +void __weak __efi_runtime EFIAPI efi_reset_system( enum efi_reset_type reset_type, efi_status_t reset_status, unsigned long data_size, void *reset_data) @@ -138,7 +138,7 @@ void __weak efi_reset_system_init(void) { } -efi_status_t __weak EFI_RUNTIME_TEXT EFIAPI efi_get_time( +efi_status_t __weak __efi_runtime EFIAPI efi_get_time( struct efi_time *time, struct efi_time_cap *capabilities) { @@ -346,7 +346,7 @@ void efi_add_runtime_mmio(void *mmio_ptr, u64 len) * function or variable below this line. * * Please keep everything fully self-contained and annotated with - * EFI_RUNTIME_TEXT and EFI_RUNTIME_DATA markers. + * __efi_runtime and __efi_runtime_data markers. */ /* @@ -355,22 +355,22 @@ void efi_add_runtime_mmio(void *mmio_ptr, u64 len) * address map calls. */ -static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void) +static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void) { return EFI_UNSUPPORTED; } -static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void) +static efi_status_t __efi_runtime EFIAPI efi_device_error(void) { return EFI_DEVICE_ERROR; } -static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void) +static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void) { return EFI_INVALID_PARAMETER; } -struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = { +struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .hdr = { .signature = EFI_RUNTIME_SERVICES_SIGNATURE, .revision = EFI_RUNTIME_SERVICES_REVISION, -- cgit v1.2.3