summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/efi_loader/Kconfig8
-rw-r--r--lib/efi_loader/efi_boottime.c28
-rw-r--r--lib/efi_loader/efi_runtime.c89
-rw-r--r--lib/efi_selftest/efi_selftest_set_virtual_address_map.c31
4 files changed, 122 insertions, 34 deletions
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index a7f2c68fa9..c7027a9676 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -107,4 +107,12 @@ config EFI_HAVE_RUNTIME_RESET
default y
depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || SYSRESET_X86
+config EFI_GRUB_ARM32_WORKAROUND
+ bool "Workaround for GRUB on 32bit ARM"
+ default y
+ depends on ARM && !ARM64
+ help
+ GRUB prior to version 2.04 requires U-Boot to disable caches. This
+ workaround currently is also needed on systems with caches that
+ cannot be managed via CP15.
endif
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 4f6e8d1679..f75ca1a67c 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -39,14 +39,6 @@ LIST_HEAD(efi_register_notify_events);
/* Handle of the currently executing image */
static efi_handle_t current_image;
-/*
- * If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
- * we need to do trickery with caches. Since we don't want to break the EFI
- * aware boot path, only apply hacks when loading exiting directly (breaking
- * direct Linux EFI booting along the way - oh well).
- */
-static bool efi_is_direct_boot = true;
-
#ifdef CONFIG_ARM
/*
* The "gd" pointer lives in a register on ARM and AArch64 that we declare
@@ -1911,13 +1903,21 @@ error:
*/
static void efi_exit_caches(void)
{
-#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
+#if defined(CONFIG_EFI_GRUB_ARM32_WORKAROUND)
/*
- * Grub on 32bit ARM needs to have caches disabled before jumping into
- * a zImage, but does not know of all cache layers. Give it a hand.
+ * Boooting Linux via GRUB prior to version 2.04 fails on 32bit ARM if
+ * caches are enabled.
+ *
+ * TODO:
+ * According to the UEFI spec caches that can be managed via CP15
+ * operations should be enabled. Caches requiring platform information
+ * to manage should be disabled. This should not happen in
+ * ExitBootServices() but before invoking any UEFI binary is invoked.
+ *
+ * We want to keep the current workaround while GRUB prior to version
+ * 2.04 is still in use.
*/
- if (efi_is_direct_boot)
- cleanup_before_linux();
+ cleanup_before_linux();
#endif
}
@@ -2893,8 +2893,6 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
if (ret != EFI_SUCCESS)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- efi_is_direct_boot = false;
-
image_obj->exit_data_size = exit_data_size;
image_obj->exit_data = exit_data;
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 8b56ab0207..fb24131462 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -81,6 +81,10 @@ struct elf_rela {
long addend;
};
+static __efi_runtime_data struct efi_mem_desc *efi_virtmap;
+static __efi_runtime_data efi_uintn_t efi_descriptor_count;
+static __efi_runtime_data efi_uintn_t efi_descriptor_size;
+
/*
* EFI runtime code lives in two stages. In the first stage, U-Boot and an EFI
* payload are running concurrently at the same time. In this mode, we can
@@ -89,7 +93,9 @@ struct elf_rela {
efi_status_t efi_init_runtime_supported(void)
{
- u16 efi_runtime_services_supported = 0;
+ u16 efi_runtime_services_supported =
+ EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP |
+ EFI_RT_SUPPORTED_CONVERT_POINTER;
/*
* This value must be synced with efi_runtime_detach_list
@@ -98,8 +104,7 @@ efi_status_t efi_init_runtime_supported(void)
#ifdef CONFIG_EFI_HAVE_RUNTIME_RESET
efi_runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM;
#endif
- efi_runtime_services_supported |=
- EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP;
+
return EFI_CALL(efi_set_variable(L"RuntimeServicesSupported",
&efi_global_variable_guid,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
@@ -427,8 +432,8 @@ void efi_runtime_detach(void)
* Return: status code EFI_UNSUPPORTED
*/
static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
- unsigned long memory_map_size,
- unsigned long descriptor_size,
+ efi_uintn_t memory_map_size,
+ efi_uintn_t descriptor_size,
uint32_t descriptor_version,
struct efi_mem_desc *virtmap)
{
@@ -454,6 +459,58 @@ static __efi_runtime efi_status_t EFIAPI efi_convert_pointer_runtime(
return EFI_UNSUPPORTED;
}
+/**
+ * efi_convert_pointer_runtime() - convert from physical to virtual pointer
+ *
+ * This function implements the ConvertPointer() runtime service until
+ * the first call to SetVirtualAddressMap().
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @debug_disposition: indicates if pointer may be converted to NULL
+ * @address: pointer to be converted
+ * Return: status code EFI_UNSUPPORTED
+ */
+static __efi_runtime efi_status_t EFIAPI efi_convert_pointer(
+ efi_uintn_t debug_disposition, void **address)
+{
+ efi_physical_addr_t addr = (uintptr_t)*address;
+ efi_uintn_t i;
+ efi_status_t ret = EFI_NOT_FOUND;
+
+ EFI_ENTRY("%zu %p", debug_disposition, address);
+
+ if (!efi_virtmap) {
+ ret = EFI_UNSUPPORTED;
+ goto out;
+ }
+
+ if (!address) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ for (i = 0; i < efi_descriptor_count; i++) {
+ struct efi_mem_desc *map = (void *)efi_virtmap +
+ (efi_descriptor_size * i);
+
+ if (addr >= map->physical_start &&
+ (addr < map->physical_start
+ + (map->num_pages << EFI_PAGE_SHIFT))) {
+ *address = (void *)(uintptr_t)
+ (addr + map->virtual_start -
+ map->physical_start);
+
+ ret = EFI_SUCCESS;
+ break;
+ }
+ }
+
+out:
+ return EFI_EXIT(ret);
+}
+
static __efi_runtime void efi_relocate_runtime_table(ulong offset)
{
ulong patchoff;
@@ -480,6 +537,12 @@ static __efi_runtime void efi_relocate_runtime_table(ulong offset)
*/
efi_runtime_services.convert_pointer = &efi_convert_pointer_runtime;
+ /*
+ * TODO: Update UEFI variable RuntimeServicesSupported removing flags
+ * EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP and
+ * EFI_RT_SUPPORTED_CONVERT_POINTER as required by the UEFI spec 2.8.
+ */
+
/* Update CRC32 */
efi_update_table_header_crc32(&efi_runtime_services.hdr);
}
@@ -571,19 +634,23 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
* Return: status code
*/
static efi_status_t EFIAPI efi_set_virtual_address_map(
- unsigned long memory_map_size,
- unsigned long descriptor_size,
+ efi_uintn_t memory_map_size,
+ efi_uintn_t descriptor_size,
uint32_t descriptor_version,
struct efi_mem_desc *virtmap)
{
- int n = memory_map_size / descriptor_size;
- int i;
+ efi_uintn_t n = memory_map_size / descriptor_size;
+ efi_uintn_t i;
int rt_code_sections = 0;
struct efi_event *event;
- EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
+ EFI_ENTRY("%zx %zx %x %p", memory_map_size, descriptor_size,
descriptor_version, virtmap);
+ efi_virtmap = virtmap;
+ efi_descriptor_size = descriptor_size;
+ efi_descriptor_count = n;
+
/*
* TODO:
* Further down we are cheating. While really we should implement
@@ -800,7 +867,7 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
.get_wakeup_time = (void *)&efi_unimplemented,
.set_wakeup_time = (void *)&efi_unimplemented,
.set_virtual_address_map = &efi_set_virtual_address_map,
- .convert_pointer = (void *)&efi_unimplemented,
+ .convert_pointer = efi_convert_pointer,
.get_variable = efi_get_variable,
.get_next_variable_name = efi_get_next_variable_name,
.set_variable = efi_set_variable,
diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c
index 6ee7bbeb01..a4e5a50f63 100644
--- a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c
+++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c
@@ -20,6 +20,7 @@ static u32 desc_version;
static u64 page1;
static u64 page2;
static u32 notify_call_count;
+static bool convert_pointer_failed;
/**
* notify () - notification function
@@ -39,17 +40,28 @@ static void EFIAPI notify(struct efi_event *event, void *context)
addr = (void *)(uintptr_t)page1;
ret = runtime->convert_pointer(0, &addr);
- if (ret != EFI_SUCCESS)
- efi_st_todo("ConvertPointer failed\n");
- if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE)
- efi_st_todo("ConvertPointer wrong address\n");
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("ConvertPointer failed\n");
+ convert_pointer_failed = true;
+ return;
+ }
+ if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE) {
+ efi_st_error("ConvertPointer wrong address\n");
+ convert_pointer_failed = true;
+ return;
+ }
addr = (void *)(uintptr_t)page2;
ret = runtime->convert_pointer(0, &addr);
- if (ret != EFI_SUCCESS)
- efi_st_todo("ConvertPointer failed\n");
- if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE)
- efi_st_todo("ConvertPointer wrong address\n");
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("ConvertPointer failed\n");
+ convert_pointer_failed = true;
+ return;
+ }
+ if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE) {
+ efi_st_error("ConvertPointer wrong address\n");
+ convert_pointer_failed = true;
+ }
}
/**
@@ -123,6 +135,7 @@ static int setup(const efi_handle_t handle,
case EFI_LOADER_DATA:
case EFI_BOOT_SERVICES_CODE:
case EFI_BOOT_SERVICES_DATA:
+ case EFI_CONVENTIONAL_MEMORY:
continue;
}
memcpy(pos1, pos2, desc_size);
@@ -180,6 +193,8 @@ static int execute(void)
notify_call_count);
return EFI_ST_FAILURE;
}
+ if (convert_pointer_failed)
+ return EFI_ST_FAILURE;
return EFI_ST_SUCCESS;
}