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
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
#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 |
*/
static bool efi_is_runtime_service_pointer(void *p)
{
- return p >= (void *)&efi_runtime_services.get_time &&
- p <= (void *)&efi_runtime_services.query_variable_info;
+ return (p >= (void *)&efi_runtime_services.get_time &&
+ p <= (void *)&efi_runtime_services.query_variable_info) ||
+ p == (void *)&efi_events.prev ||
+ p == (void *)&efi_events.next;
}
/**
* 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)
{
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;
*/
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);
}
p = (void*)((ulong)rel->offset - base) + gd->relocaddr;
- /* The runtime services are updated in efi_runtime_detach() */
+ /*
+ * The runtime services table is updated in
+ * efi_relocate_runtime_table()
+ */
if (map && efi_is_runtime_service_pointer(p))
continue;
* 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;
+ efi_status_t ret = EFI_INVALID_PARAMETER;
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);
+ if (descriptor_version != EFI_MEMORY_DESCRIPTOR_VERSION ||
+ descriptor_size < sizeof(struct efi_mem_desc))
+ goto out;
+
+ efi_virtmap = virtmap;
+ efi_descriptor_size = descriptor_size;
+ efi_descriptor_count = n;
+
/*
* TODO:
* Further down we are cheating. While really we should implement
* We expose exactly one single runtime code section, so
* something is definitely going wrong.
*/
- return EFI_EXIT(EFI_INVALID_PARAMETER);
+ goto out;
+ }
+
+ /* Notify EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
+ list_for_each_entry(event, &efi_events, link) {
+ if (event->notify_function)
+ EFI_CALL_VOID(event->notify_function(
+ event, event->notify_context));
}
/* Rebind mmio pointers */
}
}
- /*
- * Some runtime services are implemented in a way that we can only offer
- * them at boottime. Replace those function pointers.
- *
- * TODO: move this call to ExitBootServices().
- */
- efi_runtime_detach();
-
/* Relocate the runtime. See TODO above */
for (i = 0; i < n; i++) {
struct efi_mem_desc *map;
efi_relocate_runtime_table(new_offset);
efi_runtime_relocate(new_offset, map);
- return EFI_EXIT(EFI_SUCCESS);
+ ret = EFI_SUCCESS;
+ goto out;
}
}
- return EFI_EXIT(EFI_INVALID_PARAMETER);
+out:
+ return EFI_EXIT(ret);
}
/**
struct efi_runtime_mmio_list *newmmio;
u64 pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
uint64_t addr = *(uintptr_t *)mmio_ptr;
- uint64_t retaddr;
+ efi_status_t ret;
- retaddr = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false);
- if (retaddr != addr)
+ ret = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false);
+ if (ret != EFI_SUCCESS)
return EFI_OUT_OF_RESOURCES;
newmmio = calloc(1, sizeof(*newmmio));
.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,