Merge tag 'efi-2019-10-rc1' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
authorTom Rini <trini@konsulko.com>
Mon, 8 Jul 2019 20:02:51 +0000 (16:02 -0400)
committerTom Rini <trini@konsulko.com>
Mon, 8 Jul 2019 20:02:51 +0000 (16:02 -0400)
Pull request for UEFI sub-system for v2019.10-rc1

Fix a possible overflow for GUID partition tables.

For some runtime services we only have implementations valid at boottime.
So we replace them when leaving boottime. Move this from
SetVirtualAddressMap() to ExitBootServices() as SetVirtualAddressMap() is
not called by all operating systems. Adjust the Python tests accordingly.

Bump the supported UEFI specification version to 2.8.

12 files changed:
disk/part_efi.c
include/efi_api.h
include/efi_loader.h
lib/efi_loader/Kconfig
lib/efi_loader/efi_boottime.c
lib/efi_loader/efi_runtime.c
lib/efi_loader/efi_setup.c
lib/efi_loader/efi_variable.c
lib/efi_selftest/Kconfig
lib/efi_selftest/Makefile
lib/efi_selftest/efi_selftest_variables_runtime.c [new file with mode: 0644]
test/py/tests/test_efi_selftest.py

index c0fa753339c80216e45fd8f9d3e33093db0cb19c..3e026697dbe9911002db37635fa610dc75338ba5 100644 (file)
@@ -313,8 +313,8 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part,
                     - info->start;
        info->blksz = dev_desc->blksz;
 
-       sprintf((char *)info->name, "%s",
-                       print_efiname(&gpt_pte[part - 1]));
+       snprintf((char *)info->name, sizeof(info->name), "%s",
+                print_efiname(&gpt_pte[part - 1]));
        strcpy((char *)info->type, "U-Boot");
        info->bootable = is_bootable(&gpt_pte[part - 1]);
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
index a36ececc81e441bfb8cd84f5e93ae817f3f29e97..d4f32dbdc818f03f0b27447cdb1ee18da4a13e40 100644 (file)
@@ -23,8 +23,8 @@
 #include <asm/setjmp.h>
 #endif
 
-/* UEFI spec version 2.7 */
-#define EFI_SPECIFICATION_VERSION (2 << 16 | 70)
+/* UEFI spec version 2.8 */
+#define EFI_SPECIFICATION_VERSION (2 << 16 | 80)
 
 /* Types and defines for EFI CreateEvent */
 enum efi_timer_delay {
index b07155cecb7cab8ed91d276cc7381fd55a15cf5c..db4763fc9b768924d53c90bafd5d1ae4f72ab2d7 100644 (file)
@@ -325,10 +325,16 @@ extern struct list_head efi_register_notify_events;
 
 /* Initialize efi execution environment */
 efi_status_t efi_init_obj_list(void);
+/* Initialize variable services */
+efi_status_t efi_init_variables(void);
+/* Notify ExitBootServices() is called */
+void efi_variables_boot_exit_notify(void);
 /* Called by bootefi to initialize root node */
 efi_status_t efi_root_node_register(void);
 /* Called by bootefi to initialize runtime */
 efi_status_t efi_initialize_system_table(void);
+/* efi_runtime_detach() - detach unimplemented runtime functions */
+void efi_runtime_detach(void);
 /* Called by bootefi to make console interface available */
 efi_status_t efi_console_register(void);
 /* Called by bootefi to make all disk storage accessible as EFI objects */
@@ -618,6 +624,11 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
                                     const efi_guid_t *vendor, u32 attributes,
                                     efi_uintn_t data_size, const void *data);
 
+efi_status_t EFIAPI efi_query_variable_info(
+                       u32 attributes, u64 *maximum_variable_storage_size,
+                       u64 *remaining_variable_storage_size,
+                       u64 *maximum_variable_size);
+
 /*
  * See section 3.1.3 in the v2.7 UEFI spec for more details on
  * the layout of EFI_LOAD_OPTION.  In short it is:
index cd5436c576b1bcbe62aff6607df0fa864c5783ae..a7f2c68fa91a6d36d7307456a49f1234777d2bfb 100644 (file)
@@ -101,4 +101,10 @@ config EFI_PLATFORM_LANG_CODES
          RFC 4646 format, e.g. "en-US;de-DE". The first language code is used
          to initialize the PlatformLang variable.
 
+config EFI_HAVE_RUNTIME_RESET
+       # bool "Reset runtime service is available"
+       bool
+       default y
+       depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || SYSRESET_X86
+
 endif
index d104cc6b316155ea64fad9926c9e9935da7e7809..c2f89805c76776fe4a2bff2f9d6aea1a9b882469 100644 (file)
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- *  EFI application boot time services
+ * EFI application boot time services
  *
- *  Copyright (c) 2016 Alexander Graf
+ * Copyright (c) 2016 Alexander Graf
  */
 
 #include <common.h>
@@ -1968,10 +1968,14 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
        /* Make sure that notification functions are not called anymore */
        efi_tpl = TPL_HIGH_LEVEL;
 
-       /* TODO: Should persist EFI variables here */
+       /* Notify variable services */
+       efi_variables_boot_exit_notify();
 
        board_quiesce_devices();
 
+       /* Patch out unsupported runtime function */
+       efi_runtime_detach();
+
        /* Fix up caches for EFI payloads if necessary */
        efi_exit_caches();
 
@@ -3234,7 +3238,7 @@ static efi_status_t efi_connect_single_controller(
        if (r != EFI_SUCCESS)
                return r;
 
-       /*  Context Override */
+       /* Context Override */
        if (driver_image_handle) {
                for (; *driver_image_handle; ++driver_image_handle) {
                        for (i = 0; i < count; ++i) {
@@ -3341,7 +3345,7 @@ static efi_status_t EFIAPI efi_connect_controller(
                        }
                }
        }
-       /*  Check for child controller specified by end node */
+       /* Check for child controller specified by end node */
        if (ret != EFI_SUCCESS && remain_device_path &&
            remain_device_path->type == DEVICE_PATH_TYPE_END)
                ret = EFI_SUCCESS;
@@ -3620,11 +3624,7 @@ struct efi_system_table __efi_runtime_data systab = {
        },
        .fw_vendor = firmware_vendor,
        .fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8,
-       .con_in = &efi_con_in,
-       .con_out = &efi_con_out,
-       .std_err = &efi_con_out,
        .runtime = &efi_runtime_services,
-       .boottime = &efi_boot_services,
        .nr_tables = 0,
        .tables = NULL,
 };
@@ -3644,6 +3644,15 @@ efi_status_t efi_initialize_system_table(void)
                                sizeof(struct efi_configuration_table),
                                (void **)&systab.tables);
 
+       /*
+        * These entries will be set to NULL in ExitBootServices(). To avoid
+        * relocation in SetVirtualAddressMap(), set them dynamically.
+        */
+       systab.con_in = &efi_con_in;
+       systab.con_out = &efi_con_out;
+       systab.std_err = &efi_con_out;
+       systab.boottime = &efi_boot_services;
+
        /* Set CRC32 field in table headers */
        efi_update_table_header_crc32(&systab.hdr);
        efi_update_table_header_crc32(&efi_runtime_services.hdr);
index 40fdc0ea9286945a292d38080dd97a80671bf59d..7a64dd42ca7f3f698b3f96dc3cf8006e67aa79d0 100644 (file)
@@ -26,8 +26,6 @@ struct efi_runtime_mmio_list {
 LIST_HEAD(efi_runtime_mmio);
 
 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);
 
 /*
  * TODO(sjg@chromium.org): These defines and structures should come from the ELF
@@ -97,10 +95,7 @@ efi_status_t efi_init_runtime_supported(void)
         * This value must be synced with efi_runtime_detach_list
         * as well as efi_runtime_services.
         */
-#if CONFIG_IS_ENABLED(ARCH_BCM283X) || \
-    CONFIG_IS_ENABLED(FSL_LAYERSCAPE) || \
-    CONFIG_IS_ENABLED(SYSRESET_X86) || \
-    CONFIG_IS_ENABLED(PSCI_RESET)
+#ifdef CONFIG_EFI_HAVE_RUNTIME_RESET
        efi_runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM;
 #endif
        efi_runtime_services_supported |=
@@ -387,80 +382,102 @@ 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;
-};
-
-static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
-       {
-               /* do_reset is gone */
-               .ptr = &efi_runtime_services.reset_system,
-               .patchto = efi_reset_system,
-       }, {
-               /* invalidate_*cache_all are gone */
-               .ptr = &efi_runtime_services.set_virtual_address_map,
-               .patchto = &efi_unimplemented,
-       }, {
-               /* 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,
-               .patchto = NULL,
-       }, {
-               /* Clean up system table */
-               .ptr = &systab.con_out,
-               .patchto = NULL,
-       }, {
-               /* Clean up system table */
-               .ptr = &systab.std_err,
-               .patchto = NULL,
-       }, {
-               /* Clean up system table */
-               .ptr = &systab.boottime,
-               .patchto = NULL,
-       }, {
-               .ptr = &efi_runtime_services.get_variable,
-               .patchto = &efi_device_error,
-       }, {
-               .ptr = &efi_runtime_services.get_next_variable_name,
-               .patchto = &efi_device_error,
-       }, {
-               .ptr = &efi_runtime_services.set_variable,
-               .patchto = &efi_device_error,
-       }
-};
-
-static bool efi_runtime_tobedetached(void *p)
+/**
+ * efi_is_runtime_service_pointer() - check if pointer points to runtime table
+ *
+ * @p:         pointer to check
+ * Return:     true if the pointer points to a service function pointer in the
+ *             runtime table
+ */
+static bool efi_is_runtime_service_pointer(void *p)
 {
-       int i;
+       return p >= (void *)&efi_runtime_services.get_time &&
+              p <= (void *)&efi_runtime_services.query_variable_info;
+}
 
-       for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++)
-               if (efi_runtime_detach_list[i].ptr == p)
-                       return true;
+/**
+ * efi_runtime_detach() - detach unimplemented runtime functions
+ */
+void efi_runtime_detach(void)
+{
+       efi_runtime_services.reset_system = efi_reset_system;
+       efi_runtime_services.get_time = efi_get_time;
+       efi_runtime_services.set_time = efi_set_time;
 
-       return false;
+       /* Update CRC32 */
+       efi_update_table_header_crc32(&efi_runtime_services.hdr);
 }
 
-static void efi_runtime_detach(ulong offset)
+/**
+ * efi_set_virtual_address_map_runtime() - change from physical to virtual
+ *                                        mapping
+ *
+ * This function implements the SetVirtualAddressMap() runtime service after
+ * it is first called.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @memory_map_size:   size of the virtual map
+ * @descriptor_size:   size of an entry in the map
+ * @descriptor_version:        version of the map entries
+ * @virtmap:           virtual address mapping information
+ * Return:             status code EFI_UNSUPPORTED
+ */
+static efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
+                       unsigned long memory_map_size,
+                       unsigned long descriptor_size,
+                       uint32_t descriptor_version,
+                       struct efi_mem_desc *virtmap)
 {
-       int i;
-       ulong patchoff = offset - (ulong)gd->relocaddr;
+       return EFI_UNSUPPORTED;
+}
 
-       for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) {
-               ulong patchto = (ulong)efi_runtime_detach_list[i].patchto;
-               ulong *p = efi_runtime_detach_list[i].ptr;
-               ulong newaddr = patchto ? (patchto + patchoff) : 0;
+/**
+ * efi_convert_pointer_runtime() - convert from physical to virtual pointer
+ *
+ * This function implements the ConvertPointer() runtime service after
+ * 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_runtime(
+                       efi_uintn_t debug_disposition, void **address)
+{
+       return EFI_UNSUPPORTED;
+}
 
-               debug("%s: Setting %p to %lx\n", __func__, p, newaddr);
-               *p = newaddr;
+static __efi_runtime void efi_relocate_runtime_table(ulong offset)
+{
+       ulong patchoff;
+       void **pos;
+
+       /* Relocate the runtime services pointers */
+       patchoff = offset - gd->relocaddr;
+       for (pos = (void **)&efi_runtime_services.get_time;
+            pos <= (void **)&efi_runtime_services.query_variable_info; ++pos) {
+               if (*pos)
+                       *pos += patchoff;
        }
 
+       /*
+        * The entry for SetVirtualAddress() must point to a physical address.
+        * After the first execution the service must return EFI_UNSUPPORTED.
+        */
+       efi_runtime_services.set_virtual_address_map =
+                       &efi_set_virtual_address_map_runtime;
+
+       /*
+        * The entry for ConvertPointer() must point to a physical address.
+        * The service is not usable after SetVirtualAddress().
+        */
+       efi_runtime_services.convert_pointer = &efi_convert_pointer_runtime;
+
        /* Update CRC32 */
        efi_update_table_header_crc32(&efi_runtime_services.hdr);
 }
@@ -483,6 +500,10 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
 
                p = (void*)((ulong)rel->offset - base) + gd->relocaddr;
 
+               /* The runtime services are updated in efi_runtime_detach() */
+               if (map && efi_is_runtime_service_pointer(p))
+                       continue;
+
                debug("%s: rel->info=%#lx *p=%#lx rel->offset=%p\n", __func__,
                      rel->info, *p, rel->offset);
 
@@ -506,9 +527,8 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
                }
 #endif
                default:
-                       if (!efi_runtime_tobedetached(p))
-                               printf("%s: Unknown relocation type %llx\n",
-                                      __func__, rel->info & R_MASK);
+                       printf("%s: Unknown relocation type %llx\n",
+                              __func__, rel->info & R_MASK);
                        continue;
                }
 
@@ -516,9 +536,8 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
                if (map && ((newaddr < map->virtual_start) ||
                    newaddr > (map->virtual_start +
                              (map->num_pages << EFI_PAGE_SHIFT)))) {
-                       if (!efi_runtime_tobedetached(p))
-                               printf("%s: Relocation at %p is out of "
-                                      "range (%lx)\n", __func__, p, newaddr);
+                       printf("%s: Relocation at %p is out of range (%lx)\n",
+                              __func__, p, newaddr);
                        continue;
                }
 
@@ -623,7 +642,15 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
                }
        }
 
-       /* Move the actual runtime code over */
+       /*
+        * 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;
 
@@ -632,10 +659,8 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
                        ulong new_offset = map->virtual_start -
                                           map->physical_start + gd->relocaddr;
 
+                       efi_relocate_runtime_table(new_offset);
                        efi_runtime_relocate(new_offset, map);
-                       /* Once we're virtual, we can no longer handle
-                          complex callbacks */
-                       efi_runtime_detach(new_offset);
                        return EFI_EXIT(EFI_SUCCESS);
                }
        }
@@ -710,34 +735,6 @@ static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void)
        return EFI_UNSUPPORTED;
 }
 
-/**
- * efi_device_error() - replacement function, returns EFI_DEVICE_ERROR
- *
- * This function is used after SetVirtualAddressMap() is called as replacement
- * for services that are not available anymore due to constraints of the U-Boot
- * implementation.
- *
- * Return:     EFI_DEVICE_ERROR
- */
-static efi_status_t __efi_runtime EFIAPI efi_device_error(void)
-{
-       return EFI_DEVICE_ERROR;
-}
-
-/**
- * efi_invalid_parameter() - replacement function, returns EFI_INVALID_PARAMETER
- *
- * This function is used after SetVirtualAddressMap() is called as replacement
- * for services that are not available anymore due to constraints of the U-Boot
- * implementation.
- *
- * Return:     EFI_INVALID_PARAMETER
- */
-static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void)
-{
-       return EFI_INVALID_PARAMETER;
-}
-
 /**
  * efi_update_capsule() - process information from operating system
  *
@@ -782,33 +779,6 @@ efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
        return EFI_UNSUPPORTED;
 }
 
-/**
- * efi_query_variable_info() - get information about EFI variables
- *
- * This function implements the QueryVariableInfo() runtime service.
- *
- * See the Unified Extensible Firmware Interface (UEFI) specification for
- * details.
- *
- * @attributes:                                bitmask to select variables to be
- *                                     queried
- * @maximum_variable_storage_size:     maximum size of storage area for the
- *                                     selected variable types
- * @remaining_variable_storage_size:   remaining size of storage are for the
- *                                     selected variable types
- * @maximum_variable_size:             maximum size of a variable of the
- *                                     selected type
- * Returns:                            status code
- */
-efi_status_t __efi_runtime EFIAPI efi_query_variable_info(
-                       u32 attributes,
-                       u64 *maximum_variable_storage_size,
-                       u64 *remaining_variable_storage_size,
-                       u64 *maximum_variable_size)
-{
-       return EFI_UNSUPPORTED;
-}
-
 struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
        .hdr = {
                .signature = EFI_RUNTIME_SERVICES_SIGNATURE,
@@ -820,11 +790,11 @@ 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_invalid_parameter,
+       .convert_pointer = (void *)&efi_unimplemented,
        .get_variable = efi_get_variable,
        .get_next_variable_name = efi_get_next_variable_name,
        .set_variable = efi_set_variable,
-       .get_next_high_mono_count = (void *)&efi_device_error,
+       .get_next_high_mono_count = (void *)&efi_unimplemented,
        .reset_system = &efi_reset_system_boottime,
        .update_capsule = efi_update_capsule,
        .query_capsule_caps = efi_query_capsule_caps,
index bfb57836fa9fa22f8183c5330570288abad239f7..de7b616c6daa75ae2d67b5026c19201e4fb42f08 100644 (file)
@@ -102,6 +102,11 @@ efi_status_t efi_init_obj_list(void)
        /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
        switch_to_non_secure_mode();
 
+       /* Initialize variable services */
+       ret = efi_init_variables();
+       if (ret != EFI_SUCCESS)
+               goto out;
+
        /* Define supported languages */
        ret = efi_init_platform_lang();
        if (ret != EFI_SUCCESS)
index d6b75ca02e456c81be79d32f648cad65bd24e398..bc8ed678c9f1d56bed84f74fbd41c234b9b832dc 100644 (file)
@@ -520,3 +520,84 @@ out:
 
        return EFI_EXIT(ret);
 }
+
+/**
+ * efi_query_variable_info() - get information about EFI variables
+ *
+ * This function implements the QueryVariableInfo() runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @attributes:                                bitmask to select variables to be
+ *                                     queried
+ * @maximum_variable_storage_size:     maximum size of storage area for the
+ *                                     selected variable types
+ * @remaining_variable_storage_size:   remaining size of storage are for the
+ *                                     selected variable types
+ * @maximum_variable_size:             maximum size of a variable of the
+ *                                     selected type
+ * Returns:                            status code
+ */
+efi_status_t __efi_runtime EFIAPI efi_query_variable_info(
+                       u32 attributes,
+                       u64 *maximum_variable_storage_size,
+                       u64 *remaining_variable_storage_size,
+                       u64 *maximum_variable_size)
+{
+       return EFI_UNSUPPORTED;
+}
+
+/**
+ * efi_get_variable_runtime() - runtime implementation of GetVariable()
+ */
+static efi_status_t __efi_runtime EFIAPI
+efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
+                        u32 *attributes, efi_uintn_t *data_size, void *data)
+{
+       return EFI_UNSUPPORTED;
+}
+
+/**
+ * efi_get_next_variable_name_runtime() - runtime implementation of
+ *                                       GetNextVariable()
+ */
+static efi_status_t __efi_runtime EFIAPI
+efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
+                                  u16 *variable_name, const efi_guid_t *vendor)
+{
+       return EFI_UNSUPPORTED;
+}
+
+/**
+ * efi_set_variable_runtime() - runtime implementation of SetVariable()
+ */
+static efi_status_t __efi_runtime EFIAPI
+efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
+                        u32 attributes, efi_uintn_t data_size,
+                        const void *data)
+{
+       return EFI_UNSUPPORTED;
+}
+
+/**
+ * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
+ */
+void efi_variables_boot_exit_notify(void)
+{
+       efi_runtime_services.get_variable = efi_get_variable_runtime;
+       efi_runtime_services.get_next_variable_name =
+                               efi_get_next_variable_name_runtime;
+       efi_runtime_services.set_variable = efi_set_variable_runtime;
+       efi_update_table_header_crc32(&efi_runtime_services.hdr);
+}
+
+/**
+ * efi_init_variables() - initialize variable services
+ *
+ * Return:     status code
+ */
+efi_status_t efi_init_variables(void)
+{
+       return EFI_SUCCESS;
+}
index 59f9f36801c54b0bf6862a1a8345a4c021479857..d20f5899afa02c44409d80bafffc04a7798fd0b9 100644 (file)
@@ -1,9 +1,9 @@
 config CMD_BOOTEFI_SELFTEST
-       bool "Allow booting an EFI efi_selftest"
+       bool "UEFI unit tests"
        depends on CMD_BOOTEFI
        imply FAT
        imply FAT_WRITE
        help
-         This adds aEFI test application to U-Boot that can be executed
-         with the 'bootefi selftest' command. It provides extended tests of
-         the EFI API implementation.
+         This adds a UEFI test application to U-Boot that can be executed
+         via the 'bootefi selftest' command. It provides extended tests of
+         the UEFI API implementation.
index 3bebd0f5737bd090bda0101f2d4b0e2bfb98c2d5..88678755ccada8b1f2ac2ea53bb78201c7c183fc 100644 (file)
@@ -35,6 +35,7 @@ efi_selftest_textoutput.o \
 efi_selftest_tpl.o \
 efi_selftest_util.o \
 efi_selftest_variables.o \
+efi_selftest_variables_runtime.o \
 efi_selftest_watchdog.o
 
 obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o
diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
new file mode 100644 (file)
index 0000000..b3b40ad
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_variables_runtime
+ *
+ * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This unit test checks the runtime services for variables after
+ * ExitBootServices():
+ * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
+ */
+
+#include <efi_selftest.h>
+
+#define EFI_ST_MAX_DATA_SIZE 16
+#define EFI_ST_MAX_VARNAME_SIZE 40
+
+static struct efi_boot_services *boottime;
+static struct efi_runtime_services *runtime;
+static const efi_guid_t guid_vendor0 =
+       EFI_GUID(0x67029eb5, 0x0af2, 0xf6b1,
+                0xda, 0x53, 0xfc, 0xb5, 0x66, 0xdd, 0x1c, 0xe6);
+
+/*
+ * Setup unit test.
+ *
+ * @handle     handle of the loaded image
+ * @systable   system table
+ */
+static int setup(const efi_handle_t img_handle,
+                const struct efi_system_table *systable)
+{
+       boottime = systable->boottime;
+       runtime = systable->runtime;
+
+       return EFI_ST_SUCCESS;
+}
+
+/**
+ * execute() - execute unit test
+ *
+ * As runtime support is not implmented expect EFI_UNSUPPORTED to be returned.
+ */
+static int execute(void)
+{
+       efi_status_t ret;
+       efi_uintn_t len;
+       u32 attr;
+       u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c,
+                   0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,};
+       u8 data[EFI_ST_MAX_DATA_SIZE];
+       u16 varname[EFI_ST_MAX_VARNAME_SIZE];
+       efi_guid_t guid;
+       u64 max_storage, rem_storage, max_size;
+
+       ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                                          &max_storage, &rem_storage,
+                                          &max_size);
+       if (ret != EFI_UNSUPPORTED) {
+               efi_st_error("QueryVariableInfo failed\n");
+               return EFI_ST_FAILURE;
+       }
+
+       ret = runtime->set_variable(L"efi_st_var0", &guid_vendor0,
+                                   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                   EFI_VARIABLE_RUNTIME_ACCESS,
+                                   3, v + 4);
+       if (ret != EFI_UNSUPPORTED) {
+               efi_st_error("SetVariable failed\n");
+               return EFI_ST_FAILURE;
+       }
+       len = 3;
+       ret = runtime->get_variable(L"efi_st_var0", &guid_vendor0,
+                                   &attr, &len, data);
+       if (ret != EFI_UNSUPPORTED) {
+               efi_st_error("GetVariable failed\n");
+               return EFI_ST_FAILURE;
+       }
+       memset(&guid, 0, 16);
+       *varname = 0;
+       ret = runtime->get_next_variable_name(&len, varname, &guid);
+       if (ret != EFI_UNSUPPORTED) {
+               efi_st_error("GetNextVariableName failed\n");
+               return EFI_ST_FAILURE;
+       }
+
+       return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(variables_run) = {
+       .name = "variables at runtime",
+       .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
+       .setup = setup,
+       .execute = execute,
+};
index 07e4db0452840cd736ac7ae5d2bb469e277d44ed..d5430f9c127525919c4ea3a2768ccc4cdee35f7e 100644 (file)
@@ -19,10 +19,6 @@ def test_efi_selftest(u_boot_console):
        m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
        if m != 0:
                raise Exception('Failures occurred during the EFI selftest')
-       u_boot_console.run_command(cmd='', wait_for_echo=False, wait_for_prompt=False);
-       m = u_boot_console.p.expect(['resetting', 'U-Boot'])
-       if m != 0:
-               raise Exception('Reset failed during the EFI selftest')
        u_boot_console.restart_uboot();
 
 @pytest.mark.buildconfigspec('cmd_bootefi_selftest')
@@ -37,7 +33,7 @@ def test_efi_selftest_device_tree(u_boot_console):
        u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False)
        m = u_boot_console.p.expect(['serial-number: Testing DT', 'U-Boot'])
        if m != 0:
-               raise Exception('Reset failed in \'device tree\' test')
+               raise Exception('serial-number missing in device tree')
        u_boot_console.restart_uboot();
 
 @pytest.mark.buildconfigspec('cmd_bootefi_selftest')