Patch queue for efi - 2017-12-05

Highlights for this release:
 
   - Dynamic EFI object creation (lists instead of static arrays)
   - EFI selftest improvements
   - Minor fixes
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABAgAGBQJaJxZhAAoJECszeR4D/txgtX4P/iTp602iM+2m4WP0P2K/L72b
 EsPAL4W/QXMBZBnq9MowQl7Ia3JU6bS1g2EDlbAvoQgbhmbTBfA6VxJmQj/AuOn0
 waxjyfBw/YL4010YAfmExdVy8Qj0k/SEXcxOiHYZJzmW1o3PXvLuLnetUNJ0Uip9
 GJQPcGjSaXY1VM7oAwpOVMWkbpaIIfgw9yrAc2Cw6KN8iHmaf6rPFBdWARGB7w9m
 znFtq0FpNQSLEEoyJVYAlqyRRsj+1wS3ExGnsL2no74njAgzKSWmdN7qFjkO7WC1
 w+CnZLiUv5MaboYK2uORW2qBQzRylyEXWCkqIaZL+EWElVqPRz7/VSDLUJxnZLbl
 vhDTRUB/kVwdrmB8lP21Rruk1EjCIyYDcGQ+nwhlDes/NJztfNlyOEm47N8LNyt6
 obRxOVC8nIjf4YptHB4CRgccGQAE7VqS/DqstV1plC1Ms+puG6SQvuPwlCkKX9XP
 qkZnirgzrUfGjmFMM3owoelA40jXWV4vv90HjQvwmaOftjPY3IJ+X0rgqUGbuOmn
 /R8OCW6PV0FIOx1k5/waZlqDnfFkChm56Rhxqf9LqEro37YTUjapXEgBn7a+132x
 /icaOySkFx0hy+cvPNQ5aXyNLQPDPS++Af9e/hcMewh4Zn5FrJqkJrmtLDZzGJIG
 LC5DWr8o9vwT41UftPb0
 =uyBA
 -----END PGP SIGNATURE-----

Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot

Patch queue for efi - 2017-12-05

Highlights for this release:

  - Dynamic EFI object creation (lists instead of static arrays)
  - EFI selftest improvements
  - Minor fixes
master
Tom Rini 7 years ago
commit 9188c4315c
  1. 73
      cmd/bootefi.c
  2. 15
      include/charset.h
  3. 6
      include/efi.h
  4. 48
      include/efi_api.h
  5. 66
      include/efi_loader.h
  6. 21
      include/efi_selftest.h
  7. 57
      lib/charset.c
  8. 2
      lib/efi/efi_stub.c
  9. 6
      lib/efi_loader/Makefile
  10. 788
      lib/efi_loader/efi_boottime.c
  11. 48
      lib/efi_loader/efi_console.c
  12. 67
      lib/efi_loader/efi_device_path.c
  13. 193
      lib/efi_loader/efi_device_path_to_text.c
  14. 103
      lib/efi_loader/efi_disk.c
  15. 34
      lib/efi_loader/efi_gop.c
  16. 20
      lib/efi_loader/efi_memory.c
  17. 31
      lib/efi_loader/efi_net.c
  18. 89
      lib/efi_loader/efi_watchdog.c
  19. 38
      lib/efi_loader/helloworld.c
  20. 22
      lib/efi_selftest/Makefile
  21. 153
      lib/efi_selftest/efi_selftest.c
  22. 10
      lib/efi_selftest/efi_selftest_console.c
  23. 390
      lib/efi_selftest/efi_selftest_devicepath.c
  24. 2
      lib/efi_selftest/efi_selftest_events.c
  25. 95
      lib/efi_selftest/efi_selftest_gop.c
  26. 354
      lib/efi_selftest/efi_selftest_manageprotocols.c
  27. 2
      lib/efi_selftest/efi_selftest_snp.c
  28. 53
      lib/efi_selftest/efi_selftest_textoutput.c
  29. 4
      lib/efi_selftest/efi_selftest_tpl.c
  30. 11
      lib/efi_selftest/efi_selftest_util.c
  31. 231
      lib/efi_selftest/efi_selftest_watchdog.c
  32. 4
      test/py/tests/test_efi_loader.py
  33. 14
      test/py/tests/test_efi_selftest.py

@ -6,10 +6,12 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#include <charset.h>
#include <common.h>
#include <command.h>
#include <dm.h>
#include <efi_loader.h>
#include <efi_selftest.h>
#include <errno.h>
#include <libfdt.h>
#include <libfdt_env.h>
@ -43,12 +45,39 @@ static void efi_init_obj_list(void)
#ifdef CONFIG_GENERATE_SMBIOS_TABLE
efi_smbios_register();
#endif
efi_watchdog_register();
/* Initialize EFI runtime services */
efi_reset_system_init();
efi_get_time_init();
}
/*
* Set the load options of an image from an environment variable.
*
* @loaded_image_info: the image
* @env_var: name of the environment variable
*/
static void set_load_options(struct efi_loaded_image *loaded_image_info,
const char *env_var)
{
size_t size;
const char *env = env_get(env_var);
loaded_image_info->load_options = NULL;
loaded_image_info->load_options_size = 0;
if (!env)
return;
size = strlen(env) + 1;
loaded_image_info->load_options = calloc(size, sizeof(u16));
if (!loaded_image_info->load_options) {
printf("ERROR: Out of memory\n");
return;
}
utf8_to_utf16(loaded_image_info->load_options, (u8 *)env, size);
loaded_image_info->load_options_size = size * 2;
}
static void *copy_fdt(void *fdt)
{
u64 fdt_size = fdt_totalsize(fdt);
@ -92,10 +121,10 @@ static void *copy_fdt(void *fdt)
return new_fdt;
}
static ulong efi_do_enter(void *image_handle,
struct efi_system_table *st,
asmlinkage ulong (*entry)(void *image_handle,
struct efi_system_table *st))
static efi_status_t efi_do_enter(
void *image_handle, struct efi_system_table *st,
asmlinkage ulong (*entry)(void *image_handle,
struct efi_system_table *st))
{
efi_status_t ret = EFI_LOAD_ERROR;
@ -106,7 +135,7 @@ static ulong efi_do_enter(void *image_handle,
}
#ifdef CONFIG_ARM64
static unsigned long efi_run_in_el2(asmlinkage ulong (*entry)(
static efi_status_t efi_run_in_el2(asmlinkage ulong (*entry)(
void *image_handle, struct efi_system_table *st),
void *image_handle, struct efi_system_table *st)
{
@ -121,9 +150,9 @@ static unsigned long efi_run_in_el2(asmlinkage ulong (*entry)(
* Load an EFI payload into a newly allocated piece of memory, register all
* EFI objects it would want to access and jump to it.
*/
static unsigned long do_bootefi_exec(void *efi, void *fdt,
struct efi_device_path *device_path,
struct efi_device_path *image_path)
static efi_status_t do_bootefi_exec(void *efi, void *fdt,
struct efi_device_path *device_path,
struct efi_device_path *image_path)
{
struct efi_loaded_image loaded_image_info = {};
struct efi_object loaded_image_info_obj = {};
@ -189,6 +218,8 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
efi_install_configuration_table(&fdt_guid, NULL);
}
/* Transfer environment variable bootargs as load options */
set_load_options(&loaded_image_info, "bootargs");
/* Load the EFI payload */
entry = efi_load_pe(efi, &loaded_image_info);
if (!entry) {
@ -223,7 +254,8 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
dcache_disable(); /* flush cache before switch to EL2 */
/* Move into EL2 and keep running there */
armv8_switch_to_el2((ulong)entry, (ulong)&loaded_image_info,
armv8_switch_to_el2((ulong)entry,
(ulong)&loaded_image_info_obj.handle,
(ulong)&systab, 0, (ulong)efi_run_in_el2,
ES_TO_AARCH64);
@ -232,7 +264,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
}
#endif
ret = efi_do_enter(&loaded_image_info, &systab, entry);
ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry);
exit:
/* image has returned, loaded-image obj goes *poof*: */
@ -277,7 +309,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
char *saddr, *sfdt;
unsigned long addr, fdt_addr = 0;
unsigned long r;
efi_status_t r;
if (argc < 2)
return CMD_RET_USAGE;
@ -298,6 +330,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
struct efi_loaded_image loaded_image_info = {};
struct efi_object loaded_image_info_obj = {};
/* Construct a dummy device path. */
bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
(uintptr_t)&efi_selftest,
(uintptr_t)&efi_selftest);
bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest");
efi_setup_loaded_image(&loaded_image_info,
&loaded_image_info_obj,
bootefi_device_path, bootefi_image_path);
@ -310,7 +348,14 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/* Initialize and populate EFI object list */
if (!efi_obj_list_initalized)
efi_init_obj_list();
return efi_selftest(&loaded_image_info, &systab);
/* Transfer environment variable efi_selftest as load options */
set_load_options(&loaded_image_info, "efi_selftest");
/* Execute the test */
r = efi_selftest(loaded_image_info_obj.handle, &systab);
efi_restore_gd();
free(loaded_image_info.load_options);
list_del(&loaded_image_info_obj.link);
return r != EFI_SUCCESS;
} else
#endif
if (!strcmp(argv[1], "bootmgr")) {
@ -356,6 +401,8 @@ static char bootefi_help_text[] =
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
"bootefi selftest\n"
" - boot an EFI selftest application stored within U-Boot\n"
" Use environment variable efi_selftest to select a single test.\n"
" Use 'setenv efi_selftest list' to enumerate all tests.\n"
#endif
"bootmgr [fdt addr]\n"
" - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
@ -390,6 +437,8 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
int part;
desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10));
if (!desc)
return;
part = parse_partnum(devnr);
bootefi_device_path = efi_dp_from_part(desc, part);

@ -9,6 +9,8 @@
#ifndef __CHARSET_H_
#define __CHARSET_H_
#include <linux/types.h>
#define MAX_UTF8_PER_UTF16 3
/**
@ -62,4 +64,17 @@ uint16_t *utf16_strdup(const uint16_t *s);
*/
uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size);
/**
* utf8_to_utf16() - Convert an utf8 string to utf16
*
* Converts up to 'size' characters of the utf16 string 'src' to utf8
* written to the 'dest' buffer. Stops at 0x00.
*
* @dest the destination buffer to write the utf8 characters
* @src the source utf16 string
* @size maximum number of utf16 characters to convert
* @return the pointer to the first unwritten byte in 'dest'
*/
uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size);
#endif /* __CHARSET_H_ */

@ -227,9 +227,9 @@ struct efi_time_cap {
};
enum efi_locate_search_type {
all_handles,
by_register_notify,
by_protocol
ALL_HANDLES,
BY_REGISTER_NOTIFY,
BY_PROTOCOL
};
struct efi_open_protocol_info_entry {

@ -28,8 +28,7 @@ enum efi_timer_delay {
EFI_TIMER_RELATIVE = 2
};
#define UINTN size_t
typedef long INTN;
#define efi_uintn_t size_t
typedef uint16_t *efi_string_t;
#define EVT_TIMER 0x80000000
@ -49,20 +48,22 @@ struct efi_event;
/* EFI Boot Services table */
struct efi_boot_services {
struct efi_table_hdr hdr;
efi_status_t (EFIAPI *raise_tpl)(UINTN new_tpl);
void (EFIAPI *restore_tpl)(UINTN old_tpl);
efi_status_t (EFIAPI *raise_tpl)(efi_uintn_t new_tpl);
void (EFIAPI *restore_tpl)(efi_uintn_t old_tpl);
efi_status_t (EFIAPI *allocate_pages)(int, int, unsigned long,
efi_status_t (EFIAPI *allocate_pages)(int, int, efi_uintn_t,
efi_physical_addr_t *);
efi_status_t (EFIAPI *free_pages)(efi_physical_addr_t, unsigned long);
efi_status_t (EFIAPI *get_memory_map)(unsigned long *memory_map_size,
struct efi_mem_desc *desc, unsigned long *key,
unsigned long *desc_size, u32 *desc_version);
efi_status_t (EFIAPI *allocate_pool)(int, unsigned long, void **);
efi_status_t (EFIAPI *free_pages)(efi_physical_addr_t, efi_uintn_t);
efi_status_t (EFIAPI *get_memory_map)(efi_uintn_t *memory_map_size,
struct efi_mem_desc *desc,
efi_uintn_t *key,
efi_uintn_t *desc_size,
u32 *desc_version);
efi_status_t (EFIAPI *allocate_pool)(int, efi_uintn_t, void **);
efi_status_t (EFIAPI *free_pool)(void *);
efi_status_t (EFIAPI *create_event)(uint32_t type,
UINTN notify_tpl,
efi_uintn_t notify_tpl,
void (EFIAPI *notify_function) (
struct efi_event *event,
void *context),
@ -70,8 +71,9 @@ struct efi_boot_services {
efi_status_t (EFIAPI *set_timer)(struct efi_event *event,
enum efi_timer_delay type,
uint64_t trigger_time);
efi_status_t (EFIAPI *wait_for_event)(unsigned long number_of_events,
struct efi_event **event, size_t *index);
efi_status_t (EFIAPI *wait_for_event)(efi_uintn_t number_of_events,
struct efi_event **event,
efi_uintn_t *index);
efi_status_t (EFIAPI *signal_event)(struct efi_event *event);
efi_status_t (EFIAPI *close_event)(struct efi_event *event);
efi_status_t (EFIAPI *check_event)(struct efi_event *event);
@ -94,7 +96,7 @@ struct efi_boot_services {
efi_status_t (EFIAPI *locate_handle)(
enum efi_locate_search_type search_type,
const efi_guid_t *protocol, void *search_key,
unsigned long *buffer_size, efi_handle_t *buffer);
efi_uintn_t *buffer_size, efi_handle_t *buffer);
efi_status_t (EFIAPI *locate_device_path)(const efi_guid_t *protocol,
struct efi_device_path **device_path,
efi_handle_t *device);
@ -141,14 +143,14 @@ struct efi_boot_services {
efi_status_t(EFIAPI *open_protocol_information)(efi_handle_t handle,
const efi_guid_t *protocol,
struct efi_open_protocol_info_entry **entry_buffer,
unsigned long *entry_count);
efi_uintn_t *entry_count);
efi_status_t (EFIAPI *protocols_per_handle)(efi_handle_t handle,
efi_guid_t ***protocol_buffer,
unsigned long *protocols_buffer_count);
efi_uintn_t *protocols_buffer_count);
efi_status_t (EFIAPI *locate_handle_buffer) (
enum efi_locate_search_type search_type,
const efi_guid_t *protocol, void *search_key,
unsigned long *no_handles, efi_handle_t **buffer);
efi_uintn_t *no_handles, efi_handle_t **buffer);
efi_status_t (EFIAPI *locate_protocol)(const efi_guid_t *protocol,
void *registration, void **protocol_interface);
efi_status_t (EFIAPI *install_multiple_protocol_interfaces)(
@ -249,7 +251,7 @@ struct efi_system_table {
struct efi_simple_text_output_protocol *std_err;
struct efi_runtime_services *runtime;
struct efi_boot_services *boottime;
unsigned long nr_tables;
efi_uintn_t nr_tables;
struct efi_configuration_table *tables;
};
@ -583,14 +585,14 @@ struct efi_gop_mode
struct efi_gop
{
efi_status_t (EFIAPI *query_mode)(struct efi_gop *this, u32 mode_number,
unsigned long *size_of_info,
efi_uintn_t *size_of_info,
struct efi_gop_mode_info **info);
efi_status_t (EFIAPI *set_mode)(struct efi_gop *this, u32 mode_number);
efi_status_t (EFIAPI *blt)(struct efi_gop *this, void *buffer,
unsigned long operation, unsigned long sx,
unsigned long sy, unsigned long dx,
unsigned long dy, unsigned long width,
unsigned long height, unsigned long delta);
u32 operation, efi_uintn_t sx,
efi_uintn_t sy, efi_uintn_t dx,
efi_uintn_t dy, efi_uintn_t width,
efi_uintn_t height, efi_uintn_t delta);
struct efi_gop_mode *mode;
};

@ -6,6 +6,9 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _EFI_LOADER_H
#define _EFI_LOADER_H 1
#include <common.h>
#include <part_efi.h>
#include <efi_api.h>
@ -75,9 +78,9 @@ const char *__efi_nesting_dec(void);
extern struct efi_runtime_services efi_runtime_services;
extern struct efi_system_table systab;
extern const struct efi_simple_text_output_protocol efi_con_out;
extern struct efi_simple_text_output_protocol efi_con_out;
extern struct efi_simple_input_interface efi_con_in;
extern const struct efi_console_control_protocol efi_console_control;
extern struct efi_console_control_protocol efi_console_control;
extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
uint16_t *efi_dp_str(struct efi_device_path *dp);
@ -98,6 +101,8 @@ extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
* interface (usually a struct with callback functions), this struct maps the
* protocol GUID to the respective protocol interface */
struct efi_handler {
/* Link to the list of protocols of a handle */
struct list_head link;
const efi_guid_t *guid;
void *protocol_interface;
};
@ -112,20 +117,12 @@ struct efi_handler {
struct efi_object {
/* Every UEFI object is part of a global object list */
struct list_head link;
/* We support up to 16 "protocols" an object can be accessed through */
struct efi_handler protocols[16];
/* The list of protocols */
struct list_head protocols;
/* The object spawner can either use this for data or as identifier */
void *handle;
};
#define EFI_PROTOCOL_OBJECT(_guid, _protocol) (struct efi_object){ \
.protocols = {{ \
.guid = &(_guid), \
.protocol_interface = (void *)(_protocol), \
}}, \
.handle = (void *)(_protocol), \
}
/**
* struct efi_event
*
@ -141,7 +138,7 @@ struct efi_object {
*/
struct efi_event {
uint32_t type;
UINTN notify_tpl;
efi_uintn_t notify_tpl;
void (EFIAPI *notify_function)(struct efi_event *event, void *context);
void *notify_context;
u64 trigger_next;
@ -163,6 +160,8 @@ int efi_disk_register(void);
int efi_gop_register(void);
/* Called by bootefi to make the network interface available */
int efi_net_register(void);
/* Called by bootefi to make the watchdog available */
int efi_watchdog_register(void);
/* Called by bootefi to make SMBIOS tables available */
void efi_smbios_register(void);
@ -171,6 +170,8 @@ efi_fs_from_path(struct efi_device_path *fp);
/* Called by networking code to memorize the dhcp ack package */
void efi_net_set_dhcp_ack(void *pkt, int len);
/* Called by efi_set_watchdog_timer to reset the timer */
efi_status_t efi_set_watchdog(unsigned long timeout);
/* Called from places to check whether a timer expired */
void efi_timer_check(void);
@ -185,8 +186,26 @@ void efi_restore_gd(void);
void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
/* Call this to set the current device name */
void efi_set_bootdev(const char *dev, const char *devnr, const char *path);
/* Add a new object to the object list. */
void efi_add_handle(struct efi_object *obj);
/* Create handle */
efi_status_t efi_create_handle(void **handle);
/* Call this to validate a handle and find the EFI object for it */
struct efi_object *efi_search_obj(const void *handle);
/* Find a protocol on a handle */
efi_status_t efi_search_protocol(const void *handle,
const efi_guid_t *protocol_guid,
struct efi_handler **handler);
/* Install new protocol on a handle */
efi_status_t efi_add_protocol(const void *handle, const efi_guid_t *protocol,
void *protocol_interface);
/* Delete protocol from a handle */
efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol,
void *protocol_interface);
/* Delete all protocols from a handle */
efi_status_t efi_remove_all_protocols(const void *handle);
/* Call this to create an event */
efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
void (EFIAPI *notify_function) (
struct efi_event *event,
void *context),
@ -208,20 +227,20 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);
/* Generic EFI memory allocator, call this to get memory */
void *efi_alloc(uint64_t len, int memory_type);
/* More specific EFI memory allocator, called by EFI payloads */
efi_status_t efi_allocate_pages(int type, int memory_type, unsigned long pages,
efi_status_t efi_allocate_pages(int type, int memory_type, efi_uintn_t pages,
uint64_t *memory);
/* EFI memory free function. */
efi_status_t efi_free_pages(uint64_t memory, unsigned long pages);
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages);
/* EFI memory allocator for small allocations */
efi_status_t efi_allocate_pool(int pool_type, unsigned long size,
efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size,
void **buffer);
/* EFI pool memory free function. */
efi_status_t efi_free_pool(void *buffer);
/* Returns the EFI memory map */
efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
struct efi_mem_desc *memory_map,
unsigned long *map_key,
unsigned long *descriptor_size,
efi_uintn_t *map_key,
efi_uintn_t *descriptor_size,
uint32_t *descriptor_version);
/* Adds a range into the EFI memory map */
uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
@ -243,7 +262,8 @@ extern void *efi_bounce_buffer;
struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b);
int efi_dp_match(const struct efi_device_path *a,
const struct efi_device_path *b);
struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
struct efi_device_path **rem);
unsigned efi_dp_size(const struct efi_device_path *dp);
@ -341,4 +361,6 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
const char *path) { }
static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
#endif
#endif /* CONFIG_EFI_LOADER && !CONFIG_SPL_BUILD */
#endif /* _EFI_LOADER_H */

@ -12,6 +12,7 @@
#include <common.h>
#include <efi.h>
#include <efi_api.h>
#include <efi_loader.h>
#include <linker_lists.h>
#define EFI_ST_SUCCESS 0
@ -27,6 +28,15 @@
efi_st_printf(__VA_ARGS__)) \
/*
* Prints a TODO message.
*
* @... format string followed by fields to print
*/
#define efi_st_todo(...) \
(efi_st_printf("%s(%u):\nTODO: ", __FILE__, __LINE__), \
efi_st_printf(__VA_ARGS__)) \
/*
* A test may be setup and executed at boottime,
* it may be setup at boottime and executed at runtime,
* or it may be setup and executed at runtime.
@ -72,6 +82,15 @@ void efi_st_printf(const char *fmt, ...)
int efi_st_memcmp(const void *buf1, const void *buf2, size_t length);
/*
* Compare an u16 string to a char string.
*
* @buf1: u16 string
* @buf2: char string
* @return: 0 if both buffers contain the same bytes
*/
int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2);
/*
* Reads an Unicode character from the input device.
*
* @return: Unicode character
@ -88,6 +107,7 @@ u16 efi_st_get_key(void);
* @setup: set up the unit test
* @teardown: tear down the unit test
* @execute: execute the unit test
* @on_request: test is only executed on request
*/
struct efi_unit_test {
const char *name;
@ -96,6 +116,7 @@ struct efi_unit_test {
const struct efi_system_table *systable);
int (*execute)(void);
int (*teardown)(void);
bool on_request;
};
/* Declare a new EFI unit test */

@ -6,7 +6,6 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <charset.h>
#include <malloc.h>
@ -99,3 +98,59 @@ uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
return dest;
}
uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size)
{
while (size--) {
int extension_bytes;
uint32_t code;
extension_bytes = 0;
if (*src <= 0x7f) {
code = *src++;
/* Exit on zero byte */
if (!code)
size = 0;
} else if (*src <= 0xbf) {
/* Illegal code */
code = '?';
} else if (*src <= 0xdf) {
code = *src++ & 0x1f;
extension_bytes = 1;
} else if (*src <= 0xef) {
code = *src++ & 0x0f;
extension_bytes = 2;
} else if (*src <= 0xf7) {
code = *src++ & 0x07;
extension_bytes = 3;
} else {
/* Illegal code */
code = '?';
}
for (; extension_bytes && size; --size, --extension_bytes) {
if ((*src & 0xc0) == 0x80) {
code <<= 6;
code |= *src++ & 0x3f;
} else {
/* Illegal code */
code = '?';
++src;
--size;
break;
}
}
if (code < 0x10000) {
*dest++ = code;
} else {
/*
* Simplified expression for
* (((code - 0x10000) >> 10) & 0x3ff) | 0xd800
*/
*dest++ = (code >> 10) + 0xd7c0;
*dest++ = (code & 0x3ff) | 0xdc00;
}
}
return dest;
}

@ -277,7 +277,7 @@ efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table)
struct efi_boot_services *boot = sys_table->boottime;
struct efi_mem_desc *desc;
struct efi_entry_memmap map;
ulong key, desc_size, size;
efi_uintn_t key, desc_size, size;
efi_status_t ret;
u32 version;
int cs32;

@ -7,8 +7,8 @@
# This file only gets included with CONFIG_EFI_LOADER set, so all
# object inclusion implicitly depends on it
CFLAGS_helloworld.o := $(CFLAGS_EFI)
CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI)
CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding
CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI) -Os
ifneq ($(CONFIG_CMD_BOOTEFI_HELLO_COMPILE),)
always += helloworld.efi
@ -17,7 +17,7 @@ endif
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
obj-y += efi_file.o efi_variable.o efi_bootmgr.o
obj-y += efi_file.o efi_variable.o efi_bootmgr.o efi_watchdog.o
obj-$(CONFIG_LCD) += efi_gop.o
obj-$(CONFIG_DM_VIDEO) += efi_gop.o
obj-$(CONFIG_PARTITIONS) += efi_disk.o

File diff suppressed because it is too large Load Diff

@ -46,6 +46,10 @@ static struct cout_mode efi_cout_modes[] = {
};
const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
const efi_guid_t efi_guid_text_output_protocol =
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
const efi_guid_t efi_guid_text_input_protocol =
EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
#define cESC '\x1b'
#define ESC "\x1b"
@ -81,7 +85,7 @@ static efi_status_t EFIAPI efi_cin_lock_std_in(
return EFI_EXIT(EFI_UNSUPPORTED);
}
const struct efi_console_control_protocol efi_console_control = {
struct efi_console_control_protocol efi_console_control = {
.get_mode = efi_cin_get_mode,
.set_mode = efi_cin_set_mode,
.lock_std_in = efi_cin_lock_std_in,
@ -374,7 +378,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor(
return EFI_EXIT(EFI_SUCCESS);
}
const struct efi_simple_text_output_protocol efi_con_out = {
struct efi_simple_text_output_protocol efi_con_out = {
.reset = efi_cout_reset,
.output_string = efi_cout_output_string,
.test_string = efi_cout_test_string,
@ -490,23 +494,38 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
}
static struct efi_object efi_console_control_obj =
EFI_PROTOCOL_OBJECT(efi_guid_console_control, &efi_console_control);
static struct efi_object efi_console_output_obj =
EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, &efi_con_out);
static struct efi_object efi_console_input_obj =
EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, &efi_con_in);
/* This gets called from do_bootefi_exec(). */
int efi_console_register(void)
{
efi_status_t r;
struct efi_object *efi_console_control_obj;
struct efi_object *efi_console_output_obj;
struct efi_object *efi_console_input_obj;
/* Hook up to the device list */
list_add_tail(&efi_console_control_obj.link, &efi_obj_list);
list_add_tail(&efi_console_output_obj.link, &efi_obj_list);
list_add_tail(&efi_console_input_obj.link, &efi_obj_list);
/* Create handles */
r = efi_create_handle((void **)&efi_console_control_obj);
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_add_protocol(efi_console_control_obj->handle,
&efi_guid_console_control, &efi_console_control);
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_create_handle((void **)&efi_console_output_obj);
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_add_protocol(efi_console_output_obj->handle,
&efi_guid_text_output_protocol, &efi_con_out);
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_create_handle((void **)&efi_console_input_obj);
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_add_protocol(efi_console_input_obj->handle,
&efi_guid_text_input_protocol, &efi_con_in);
if (r != EFI_SUCCESS)
goto out_of_memory;
/* Create console events */
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
efi_key_notify, NULL, &efi_con_in.wait_for_key);
if (r != EFI_SUCCESS) {
@ -525,4 +544,7 @@ int efi_console_register(void)
if (r != EFI_SUCCESS)
printf("ERROR: Failed to set console timer\n");
return r;
out_of_memory:
printf("ERROR: Out of meemory\n");
return r;
}

@ -68,7 +68,8 @@ struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
* representing a device with one representing a file on the device, or
* a device with a parent device.
*/
int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b)
int efi_dp_match(const struct efi_device_path *a,
const struct efi_device_path *b)
{
while (1) {
int ret;
@ -127,32 +128,27 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
struct efi_object *efiobj;
list_for_each_entry(efiobj, &efi_obj_list, link) {
int i;
for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
struct efi_handler *handler = &efiobj->protocols[i];
struct efi_device_path *obj_dp;
if (!handler->guid)
break;
if (guidcmp(handler->guid, &efi_guid_device_path))
continue;
obj_dp = handler->protocol_interface;
do {
if (efi_dp_match(dp, obj_dp) == 0) {
if (rem) {
*rem = ((void *)dp) +
efi_dp_size(obj_dp);
}
return efiobj;
struct efi_handler *handler;
struct efi_device_path *obj_dp;
efi_status_t ret;
ret = efi_search_protocol(efiobj->handle,
&efi_guid_device_path, &handler);
if (ret != EFI_SUCCESS)
continue;
obj_dp = handler->protocol_interface;
do {
if (efi_dp_match(dp, obj_dp) == 0) {
if (rem) {
*rem = ((void *)dp) +
efi_dp_size(obj_dp);
}
return efiobj;
}
obj_dp = shorten_path(efi_dp_next(obj_dp));
} while (short_path && obj_dp);
}
obj_dp = shorten_path(efi_dp_next(obj_dp));
} while (short_path && obj_dp);
}
return NULL;
@ -427,10 +423,27 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
hddp->partmap_type = 2;
else
hddp->partmap_type = 1;
hddp->signature_type = desc->sig_type;
if (hddp->signature_type != 0)
switch (desc->sig_type) {
case SIG_TYPE_NONE:
default:
hddp->signature_type = 0;
memset(hddp->partition_signature, 0,
sizeof(hddp->partition_signature));
break;
case SIG_TYPE_MBR:
hddp->signature_type = 1;
memset(hddp->partition_signature, 0,
sizeof(hddp->partition_signature));
memcpy(hddp->partition_signature, &desc->mbr_sig,
sizeof(desc->mbr_sig));
break;
case SIG_TYPE_GUID:
hddp->signature_type = 2;
memcpy(hddp->partition_signature, &desc->guid_sig,
sizeof(hddp->partition_signature));
break;
}
buf = &hddp[1];
}

@ -12,12 +12,31 @@
#define MAC_OUTPUT_LEN 22
#define UNKNOWN_OUTPUT_LEN 23
#define MAX_NODE_LEN 512
#define MAX_PATH_LEN 1024
const efi_guid_t efi_guid_device_path_to_text_protocol =
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
static u16 *efi_str_to_u16(char *str)
{
efi_uintn_t len;
u16 *out;
efi_status_t ret;
len = strlen(str) + 1;
ret = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, len * sizeof(u16),
(void **)&out);
if (ret != EFI_SUCCESS)
return NULL;
ascii2unicode(out, str);
out[len - 1] = 0;
return out;
}
static char *dp_unknown(char *s, struct efi_device_path *dp)
{
s += sprintf(s, "/UNKNOWN(%04x,%04x)", dp->type, dp->sub_type);
s += sprintf(s, "UNKNOWN(%04x,%04x)", dp->type, dp->sub_type);
return s;
}
@ -27,7 +46,7 @@ static char *dp_hardware(char *s, struct efi_device_path *dp)
case DEVICE_PATH_SUB_TYPE_MEMORY: {
struct efi_device_path_memory *mdp =
(struct efi_device_path_memory *)dp;
s += sprintf(s, "/MemoryMapped(0x%x,0x%llx,0x%llx)",
s += sprintf(s, "MemoryMapped(0x%x,0x%llx,0x%llx)",
mdp->memory_type,
mdp->start_address,
mdp->end_address);
@ -36,7 +55,7 @@ static char *dp_hardware(char *s, struct efi_device_path *dp)
case DEVICE_PATH_SUB_TYPE_VENDOR: {
struct efi_device_path_vendor *vdp =
(struct efi_device_path_vendor *)dp;
s += sprintf(s, "/VenHw(%pUl)", &vdp->guid);
s += sprintf(s, "VenHw(%pUl)", &vdp->guid);
break;
}
default:
@ -52,7 +71,7 @@ static char *dp_acpi(char *s, struct efi_device_path *dp)
case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: {
struct efi_device_path_acpi_path *adp =
(struct efi_device_path_acpi_path *)dp;
s += sprintf(s, "/Acpi(PNP%04x", EISA_PNP_NUM(adp->hid));
s += sprintf(s, "Acpi(PNP%04x", EISA_PNP_NUM(adp->hid));
if (adp->uid)
s += sprintf(s, ",%d", adp->uid);
s += sprintf(s, ")");
@ -71,7 +90,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
case DEVICE_PATH_SUB_TYPE_MSG_USB: {
struct efi_device_path_usb *udp =
(struct efi_device_path_usb *)dp;
s += sprintf(s, "/Usb(0x%x,0x%x)", udp->parent_port_number,
s += sprintf(s, "Usb(0x%x,0x%x)", udp->parent_port_number,
udp->usb_interface);
break;
}
@ -82,7 +101,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
if (mdp->if_type != 0 && mdp->if_type != 1)
break;
s += sprintf(s, "/MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
s += sprintf(s, "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
mdp->mac.addr[0], mdp->mac.addr[1],
mdp->mac.addr[2], mdp->mac.addr[3],
mdp->mac.addr[4], mdp->mac.addr[5],
@ -94,7 +113,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
struct efi_device_path_usb_class *ucdp =
(struct efi_device_path_usb_class *)dp;
s += sprintf(s, "/USBClass(%x,%x,%x,%x,%x)",
s += sprintf(s, "USBClass(%x,%x,%x,%x,%x)",
ucdp->vendor_id, ucdp->product_id,
ucdp->device_class, ucdp->device_subclass,
ucdp->device_protocol);
@ -108,7 +127,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
"SDCard" : "MMC";
struct efi_device_path_sd_mmc_path *sddp =
(struct efi_device_path_sd_mmc_path *)dp;
s += sprintf(s, "/%s(Slot%u)", typename, sddp->slot_number);
s += sprintf(s, "%s(Slot%u)", typename, sddp->slot_number);
break;
}
default:
@ -128,17 +147,19 @@ static char *dp_media(char *s, struct efi_device_path *dp)
switch (hddp->signature_type) {
case SIG_TYPE_MBR:
s += sprintf(s, "/HD(Part%d,Sig%08x)",
s += sprintf(s, "HD(Part%d,Sig%08x)",
hddp->partition_number,
*(uint32_t *)sig);
break;
case SIG_TYPE_GUID:
s += sprintf(s, "/HD(Part%d,Sig%pUl)",
s += sprintf(s, "HD(Part%d,Sig%pUl)",
hddp->partition_number, sig);
break;
default:
s += sprintf(s, "/HD(Part%d,MBRType=%02x,SigType=%02x)",
s += sprintf(s, "HD(Part%d,MBRType=%02x,SigType=%02x)",
hddp->partition_number, hddp->partmap_type,
hddp->signature_type);
break;
}
break;
@ -146,14 +167,16 @@ static char *dp_media(char *s, struct efi_device_path *dp)
case DEVICE_PATH_SUB_TYPE_CDROM_PATH: {
struct efi_device_path_cdrom_path *cddp =
(struct efi_device_path_cdrom_path *)dp;
s += sprintf(s, "/CDROM(0x%x)", cddp->boot_entry);
s += sprintf(s, "CDROM(0x%x)", cddp->boot_entry);
break;
}
case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
struct efi_device_path_file_path *fp =
(struct efi_device_path_file_path *)dp;
int slen = (dp->length - sizeof(*dp)) / 2;
s += sprintf(s, "/%-*ls", slen, fp->str);
if (slen > MAX_NODE_LEN - 2)
slen = MAX_NODE_LEN - 2;
s += sprintf(s, "%-.*ls", slen, fp->str);
break;
}
default:
@ -163,95 +186,119 @@ static char *dp_media(char *s, struct efi_device_path *dp)
return s;
}
static uint16_t *efi_convert_device_node_to_text(
struct efi_device_path *dp,
bool display_only,
bool allow_shortcuts)
/*
* Converts a single node to a char string.
*
* @buffer output buffer
* @dp device path or node
* @return end of string
*/
static char *efi_convert_single_device_node_to_text(
char *buffer,
struct efi_device_path *dp)
{
unsigned long len;
efi_status_t r;
char buf[512]; /* this ought be be big enough for worst case */
char *str = buf;
uint16_t *out;
while (dp) {
switch (dp->type) {
case DEVICE_PATH_TYPE_HARDWARE_DEVICE:
str = dp_hardware(str, dp);
break;
case DEVICE_PATH_TYPE_ACPI_DEVICE:
str = dp_acpi(str, dp);
break;
case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
str = dp_msging(str, dp);
break;
case DEVICE_PATH_TYPE_MEDIA_DEVICE:
str = dp_media(str, dp);
break;
default:
str = dp_unknown(str, dp);
}
char *str = buffer;
dp = efi_dp_next(dp);
switch (dp->type) {
case DEVICE_PATH_TYPE_HARDWARE_DEVICE:
str = dp_hardware(str, dp);
break;
case DEVICE_PATH_TYPE_ACPI_DEVICE:
str = dp_acpi(str, dp);
break;
case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
str = dp_msging(str, dp);
break;
case DEVICE_PATH_TYPE_MEDIA_DEVICE:
str = dp_media(str, dp);
break;
default:
str = dp_unknown(str, dp);
}
*str++ = '\0';
len = str - buf;
r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, 2 * len, (void **)&out);
if (r != EFI_SUCCESS)
return NULL;
ascii2unicode(out, buf);
out[len - 1] = 0;
return out;
*str = '\0';
return str;
}
/* helper for debug prints.. efi_free_pool() the result. */
uint16_t *efi_dp_str(struct efi_device_path *dp)
{
return efi_convert_device_node_to_text(dp, true, true);
}
static uint16_t EFIAPI *efi_convert_device_node_to_text_ext(
/*
* This function implements the ConvertDeviceNodeToText service of the
* EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* device_node device node to be converted
* display_only true if the shorter text represenation shall be used
* allow_shortcuts true if shortcut forms may be used
* @return text represenation of the device path
* NULL if out of memory of device_path is NULL
*/
static uint16_t EFIAPI *efi_convert_device_node_to_text(
struct efi_device_path *device_node,
bool display_only,
bool allow_shortcuts)
{
uint16_t *buffer;
char str[MAX_NODE_LEN];
uint16_t *text = NULL;
EFI_ENTRY("%p, %d, %d", device_node, display_only, allow_shortcuts);
buffer = efi_convert_device_node_to_text(device_node, display_only,
allow_shortcuts);
if (!device_node)
goto out;
efi_convert_single_device_node_to_text(str, device_node);
text = efi_str_to_u16(str);
out:
EFI_EXIT(EFI_SUCCESS);
return buffer;
return text;
}
/*
* This function implements the ConvertDevicePathToText service of the
* EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* device_path device path to be converted
* display_only true if the shorter text represenation shall be used
* allow_shortcuts true if shortcut forms may be used
* @return text represenation of the device path
* NULL if out of memory of device_path is NULL
*/
static uint16_t EFIAPI *efi_convert_device_path_to_text(
struct efi_device_path *device_path,
bool display_only,
bool allow_shortcuts)
{
uint16_t *buffer;
uint16_t *text = NULL;
char buffer[MAX_PATH_LEN];
char *str = buffer;
EFI_ENTRY("%p, %d, %d", device_path, display_only, allow_shortcuts);
/*
* Our device paths are all of depth one. So its is sufficient to
* to convert the first node.
*/
buffer = efi_convert_device_node_to_text(device_path, display_only,
allow_shortcuts);
if (!device_path)
goto out;
while (device_path &&
str + MAX_NODE_LEN < buffer + MAX_PATH_LEN) {
*str++ = '/';
str = efi_convert_single_device_node_to_text(str, device_path);
device_path = efi_dp_next(device_path);
}
text = efi_str_to_u16(buffer);
out:
EFI_EXIT(EFI_SUCCESS);
return buffer;
return text;
}
/* helper for debug prints.. efi_free_pool() the result. */
uint16_t *efi_dp_str(struct efi_device_path *dp)
{
return EFI_CALL(efi_convert_device_path_to_text(dp, true, true));
}
const struct efi_device_path_to_text_protocol efi_device_path_to_text = {
.convert_device_node_to_text = efi_convert_device_node_to_text_ext,
.convert_device_node_to_text = efi_convert_device_node_to_text,
.convert_device_path_to_text = efi_convert_device_path_to_text,
};

@ -196,6 +196,15 @@ efi_fs_from_path(struct efi_device_path *fp)
return diskobj->volume;
}
/*
* Create a device for a disk
*
* @name not used
* @if_typename interface name for block device
* @desc internal block device
* @dev_index device index for block device
* @offset offset into disk for simple partitions
*/
static void efi_disk_add_dev(const char *name,
const char *if_typename,
struct blk_desc *desc,
@ -204,29 +213,39 @@ static void efi_disk_add_dev(const char *name,
unsigned int part)
{
struct efi_disk_obj *diskobj;
efi_status_t ret;
/* Don't add empty devices */
if (!desc->lba)
return;
diskobj = calloc(1, sizeof(*diskobj));
if (!diskobj)
goto out_of_memory;
/* Hook up to the device list */
efi_add_handle(&diskobj->parent);
/* Fill in object data */
diskobj->dp = efi_dp_from_part(desc, part);
diskobj->part = part;
diskobj->parent.protocols[0].guid = &efi_block_io_guid;
diskobj->parent.protocols[0].protocol_interface = &diskobj->ops;
diskobj->parent.protocols[1].guid = &efi_guid_device_path;
diskobj->parent.protocols[1].protocol_interface = diskobj->dp;
ret = efi_add_protocol(diskobj->parent.handle, &efi_block_io_guid,
&diskobj->ops);
if (ret != EFI_SUCCESS)
goto out_of_memory;
ret = efi_add_protocol(diskobj->parent.handle, &efi_guid_device_path,
diskobj->dp);
if (ret != EFI_SUCCESS)
goto out_of_memory;
if (part >= 1) {
diskobj->volume = efi_simple_file_system(desc, part,
diskobj->dp);
diskobj->parent.protocols[2].guid =
&efi_simple_file_system_protocol_guid;
diskobj->parent.protocols[2].protocol_interface =
diskobj->volume;
ret = efi_add_protocol(diskobj->parent.handle,
&efi_simple_file_system_protocol_guid,
&diskobj->volume);
if (ret != EFI_SUCCESS)
goto out_of_memory;
}
diskobj->parent.handle = diskobj;
diskobj->ops = block_io_disk_template;
diskobj->ifname = if_typename;
diskobj->dev_index = dev_index;
@ -240,26 +259,22 @@ static void efi_disk_add_dev(const char *name,
diskobj->media.io_align = desc->blksz;
diskobj->media.last_block = desc->lba - offset;
diskobj->ops.media = &diskobj->media;
/* Hook up to the device list */
list_add_tail(&diskobj->parent.link, &efi_obj_list);
return;
out_of_memory:
printf("ERROR: Out of memory\n");
}
static int efi_disk_create_eltorito(struct blk_desc *desc,
const char *if_typename,
int diskid,
const char *pdevname)
static int efi_disk_create_partitions(struct blk_desc *desc,
const char *if_typename,
int diskid,
const char *pdevname)
{
int disks = 0;
#if CONFIG_IS_ENABLED(ISO_PARTITION)
char devname[32] = { 0 }; /* dp->str is u16[32] long */
disk_partition_t info;
int part;
if (desc->part_type != PART_TYPE_ISO)
return 0;
/* and devices for each partition: */
/* Add devices for each partition */
for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
if (part_get_info(desc, part, &info))
continue;
@ -270,10 +285,6 @@ static int efi_disk_create_eltorito(struct blk_desc *desc,
disks++;
}
/* ... and add block device: */
efi_disk_add_dev(devname, if_typename, desc, diskid, 0, 0);
#endif
return disks;
}
@ -299,31 +310,18 @@ int efi_disk_register(void)
uclass_next_device_check(&dev)) {
struct blk_desc *desc = dev_get_uclass_platdata(dev);
const char *if_typename = dev->driver->name;
disk_partition_t info;
int part;
printf("Scanning disk %s...\n", dev->name);
/* add devices for each partition: */
for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
if (part_get_info(desc, part, &info))
continue;
efi_disk_add_dev(dev->name, if_typename, desc,
desc->devnum, 0, part);
}
/* ... and add block device: */
/* Add block device for the full device */
efi_disk_add_dev(dev->name, if_typename, desc,
desc->devnum, 0, 0);
disks++;
/*
* El Torito images show up as block devices in an EFI world,
* so let's create them here
*/
disks += efi_disk_create_eltorito(desc, if_typename,
desc->devnum, dev->name);
/* Partitions show up as block devices in EFI */
disks += efi_disk_create_partitions(desc, if_typename,
desc->devnum, dev->name);
}
#else
int i, if_type;
@ -342,8 +340,6 @@ int efi_disk_register(void)
for (i = 0; i < 4; i++) {
struct blk_desc *desc;
char devname[32] = { 0 }; /* dp->str is u16[32] long */
disk_partition_t info;
int part;
desc = blk_get_devnum_by_type(if_type, i);
if (!desc)
@ -354,24 +350,13 @@ int efi_disk_register(void)
snprintf(devname, sizeof(devname), "%s%d",
if_typename, i);
/* add devices for each partition: */
for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
if (part_get_info(desc, part, &info))
continue;
efi_disk_add_dev(devname, if_typename, desc,
i, 0, part);
}
/* ... and add block device: */
/* Add block device for the full device */
efi_disk_add_dev(devname, if_typename, desc, i, 0, 0);
disks++;
/*
* El Torito images show up as block devices
* in an EFI world, so let's create them here
*/
disks += efi_disk_create_eltorito(desc, if_typename,
i, devname);
/* Partitions show up as block devices in EFI */
disks += efi_disk_create_partitions(desc, if_typename,
i, devname);
}
}
#endif

@ -32,7 +32,7 @@ struct efi_gop_obj {
};
static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number,
unsigned long *size_of_info,
efi_uintn_t *size_of_info,
struct efi_gop_mode_info **info)
{
struct efi_gop_obj *gopobj;
@ -56,17 +56,17 @@ static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
return EFI_EXIT(EFI_SUCCESS);
}
static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer,
unsigned long operation, unsigned long sx,
unsigned long sy, unsigned long dx,
unsigned long dy, unsigned long width,
unsigned long height, unsigned long delta)
efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer,
u32 operation, efi_uintn_t sx,
efi_uintn_t sy, efi_uintn_t dx,
efi_uintn_t dy, efi_uintn_t width,
efi_uintn_t height, efi_uintn_t delta)
{
struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops);
int i, j, line_len16, line_len32;
void *fb;
EFI_ENTRY("%p, %p, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx", this,
EFI_ENTRY("%p, %p, %u, %zu, %zu, %zu, %zu, %zu, %zu, %zu", this,
buffer, operation, sx, sy, dx, dy, width, height, delta);
if (operation != EFI_BLT_BUFFER_TO_VIDEO)
@ -132,6 +132,7 @@ int efi_gop_register(void)
u32 bpix, col, row;
u64 fb_base, fb_size;
void *fb;
efi_status_t ret;
#ifdef CONFIG_DM_VIDEO
struct udevice *vdev;
@ -173,11 +174,21 @@ int efi_gop_register(void)
}
gopobj = calloc(1, sizeof(*gopobj));
if (!gopobj) {
printf("ERROR: Out of memory\n");
return 1;
}
/* Hook up to the device list */
efi_add_handle(&gopobj->parent);
/* Fill in object data */
gopobj->parent.protocols[0].guid = &efi_gop_guid;
gopobj->parent.protocols[0].protocol_interface = &gopobj->ops;
gopobj->parent.handle = &gopobj->ops;
ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid,
&gopobj->ops);
if (ret != EFI_SUCCESS) {
printf("ERROR: Out of memory\n");
return 1;
}
gopobj->ops.query_mode = gop_query_mode;
gopobj->ops.set_mode = gop_set_mode;
gopobj->ops.blt = gop_blt;
@ -206,8 +217,5 @@ int efi_gop_register(void)
gopobj->bpix = bpix;
gopobj->fb = fb;
/* Hook up to the device list */
list_add_tail(&gopobj->parent.link, &efi_obj_list);
return 0;
}

@ -276,7 +276,7 @@ static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr)
}
efi_status_t efi_allocate_pages(int type, int memory_type,
unsigned long pages, uint64_t *memory)
efi_uintn_t pages, uint64_t *memory)
{
u64 len = pages << EFI_PAGE_SHIFT;
efi_status_t r = EFI_SUCCESS;
@ -338,7 +338,7 @@ void *efi_alloc(uint64_t len, int memory_type)
return NULL;
}
efi_status_t efi_free_pages(uint64_t memory, unsigned long pages)
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
{
uint64_t r = 0;
@ -351,7 +351,7 @@ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages)
return EFI_NOT_FOUND;
}
efi_status_t efi_allocate_pool(int pool_type, unsigned long size,
efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size,
void **buffer)
{
efi_status_t r;
@ -392,16 +392,16 @@ efi_status_t efi_free_pool(void *buffer)
return r;
}
efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
struct efi_mem_desc *memory_map,
unsigned long *map_key,
unsigned long *descriptor_size,
uint32_t *descriptor_version)
efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
struct efi_mem_desc *memory_map,
efi_uintn_t *map_key,
efi_uintn_t *descriptor_size,
uint32_t *descriptor_version)
{
ulong map_size = 0;
efi_uintn_t map_size = 0;
int map_entries = 0;
struct list_head *lhandle;
unsigned long provided_map_size = *memory_map_size;
efi_uintn_t provided_map_size = *memory_map_size;
list_for_each(lhandle, &efi_mem)
map_entries++;

@ -292,16 +292,25 @@ int efi_net_register(void)
/* We only expose the "active" eth device, so one is enough */
netobj = calloc(1, sizeof(*netobj));
if (!netobj)
goto out_of_memory;
/* Hook net up to the device list */
efi_add_handle(&netobj->parent);
/* Fill in object data */
netobj->parent.protocols[0].guid = &efi_net_guid;
netobj->parent.protocols[0].protocol_interface = &netobj->net;
netobj->parent.protocols[1].guid = &efi_guid_device_path;
netobj->parent.protocols[1].protocol_interface =
efi_dp_from_eth();
netobj->parent.protocols[2].guid = &efi_pxe_guid;
netobj->parent.protocols[2].protocol_interface = &netobj->pxe;
netobj->parent.handle = &netobj->net;
r = efi_add_protocol(netobj->parent.handle, &efi_net_guid,
&netobj->net);
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_add_protocol(netobj->parent.handle, &efi_guid_device_path,
efi_dp_from_eth());
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_add_protocol(netobj->parent.handle, &efi_pxe_guid,
&netobj->pxe);
if (r != EFI_SUCCESS)
goto out_of_memory;
netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
netobj->net.start = efi_net_start;
netobj->net.stop = efi_net_stop;
@ -326,9 +335,6 @@ int efi_net_register(void)
if (dhcp_ack)
netobj->pxe_mode.dhcp_ack = *dhcp_ack;
/* Hook net up to the device list */
list_add_tail(&netobj->parent.link, &efi_obj_list);
/*
* Create WaitForPacket event.
*/
@ -361,4 +367,7 @@ int efi_net_register(void)
}
return 0;
out_of_memory:
printf("ERROR: Out of memory\n");
return 1;
}

@ -0,0 +1,89 @@
/*
* EFI watchdog
*
* Copyright (c) 2017 Heinrich Schuchardt
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <efi_loader.h>
/* Conversion factor from seconds to multiples of 100ns */
#define EFI_SECONDS_TO_100NS 10000000ULL
static struct efi_event *watchdog_timer_event;
/*
* Reset the system when the watchdog event is notified.
*
* @event: the watchdog event
* @context: not used
*/
static void EFIAPI efi_watchdog_timer_notify(struct efi_event *event,
void *context)
{
EFI_ENTRY("%p, %p", event, context);
printf("\nEFI: Watchdog timeout\n");
EFI_CALL_VOID(efi_runtime_services.reset_system(EFI_RESET_COLD,
EFI_SUCCESS, 0, NULL));
EFI_EXIT(EFI_UNSUPPORTED);
}
/*
* Reset the watchdog timer.
*
* This function is used by the SetWatchdogTimer service.
*
* @timeout: seconds before reset by watchdog
* @return: status code
*/
efi_status_t efi_set_watchdog(unsigned long timeout)
{
efi_status_t r;
if (timeout)
/* Reset watchdog */
r = efi_set_timer(watchdog_timer_event, EFI_TIMER_RELATIVE,
EFI_SECONDS_TO_100NS * timeout);
else
/* Deactivate watchdog */
r = efi_set_timer(watchdog_timer_event, EFI_TIMER_STOP, 0);
return r;
}
/*
* Initialize the EFI watchdog.
*
* This function is called by efi_init_obj_list()
*/
int efi_watchdog_register(void)
{
efi_status_t r;
/*
* Create a timer event.
*/
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
efi_watchdog_timer_notify, NULL,
&watchdog_timer_event);
if (r != EFI_SUCCESS) {
printf("ERROR: Failed to register watchdog event\n");
return r;
}
/*
* The UEFI standard requires that the watchdog timer is set to five
* minutes when invoking an EFI boot option.
*
* Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
* 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
*/
r = efi_set_watchdog(300);
if (r != EFI_SUCCESS) {
printf("ERROR: Failed to set watchdog timer\n");
return r;
}
return 0;
}

@ -5,20 +5,52 @@
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*
* This program demonstrates calling a boottime service.
* It writes a greeting and the load options to the console.
*/
#include <common.h>
#include <part_efi.h>
#include <efi_api.h>
/*
* Entry point of the EFI application.
*
* @handle handle of the loaded image
* @systable system table
* @return status code
*/
efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
{
struct efi_simple_text_output_protocol *con_out = systable->con_out;
struct efi_boot_services *boottime = systable->boottime;
struct efi_loaded_image *loaded_image;
const efi_guid_t loaded_image_guid = LOADED_IMAGE_GUID;
efi_status_t ret;
con_out->output_string(con_out, L"Hello, world!\n");
boottime->exit(handle, 0, 0, NULL);
return EFI_SUCCESS;
/* Get the loaded image protocol */
ret = boottime->handle_protocol(handle, &loaded_image_guid,
(void **)&loaded_image);
if (ret != EFI_SUCCESS) {
con_out->output_string(con_out,
L"Cannot open loaded image protocol\n");
goto out;
}
/* Output the load options */
con_out->output_string(con_out, L"Load options: ");
if (loaded_image->load_options_size && loaded_image->load_options)
con_out->output_string(con_out,
(u16 *)loaded_image->load_options);
else
con_out->output_string(con_out, L"<none>");
con_out->output_string(con_out, L"\n");
out:
boottime->exit(handle, ret, 0, NULL);
/* We should never arrive here */
return ret;
}

@ -7,26 +7,16 @@
# This file only gets included with CONFIG_EFI_LOADER set, so all
# object inclusion implicitly depends on it
CFLAGS_efi_selftest.o := $(CFLAGS_EFI)
CFLAGS_REMOVE_efi_selftest.o := $(CFLAGS_NON_EFI)
CFLAGS_efi_selftest_console.o := $(CFLAGS_EFI)
CFLAGS_REMOVE_efi_selftest_console.o := $(CFLAGS_NON_EFI)
CFLAGS_efi_selftest_events.o := $(CFLAGS_EFI)
CFLAGS_REMOVE_efi_selftest_events.o := $(CFLAGS_NON_EFI)
CFLAGS_efi_selftest_exitbootservices.o := $(CFLAGS_EFI)
CFLAGS_REMOVE_efi_selftest_exitbootservices.o := $(CFLAGS_NON_EFI)
CFLAGS_efi_selftest_snp.o := $(CFLAGS_EFI)
CFLAGS_REMOVE_efi_selftest_snp.o := $(CFLAGS_NON_EFI)
CFLAGS_efi_selftest_tpl.o := $(CFLAGS_EFI)
CFLAGS_REMOVE_efi_selftest_tpl.o := $(CFLAGS_NON_EFI)
CFLAGS_efi_selftest_util.o := $(CFLAGS_EFI)
CFLAGS_REMOVE_efi_selftest_util.o := $(CFLAGS_NON_EFI)
obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \
efi_selftest.o \
efi_selftest_console.o \
efi_selftest_devicepath.o \
efi_selftest_events.o \
efi_selftest_exitbootservices.o \
efi_selftest_gop.o \
efi_selftest_manageprotocols.o \
efi_selftest_snp.o \
efi_selftest_textoutput.o \
efi_selftest_tpl.o \
efi_selftest_util.o
efi_selftest_util.o \
efi_selftest_watchdog.o

@ -9,6 +9,13 @@
#include <efi_selftest.h>
#include <vsprintf.h>
/*
* Constants for test step bitmap
*/
#define EFI_ST_SETUP 1
#define EFI_ST_EXECUTE 2
#define EFI_ST_TEARDOWN 4
static const struct efi_system_table *systable;
static const struct efi_boot_services *boottime;
static const struct efi_runtime_services *runtime;
@ -25,9 +32,9 @@ static u16 reset_message[] = L"Selftest completed";
*/
void efi_st_exit_boot_services(void)
{
unsigned long map_size = 0;
unsigned long map_key;
unsigned long desc_size;
efi_uintn_t map_size = 0;
efi_uintn_t map_key;
efi_uintn_t desc_size;
u32 desc_version;
efi_status_t ret;
struct efi_mem_desc *memory_map;
@ -134,6 +141,70 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures)
}
/*
* Check that a test exists.
*
* @testname: name of the test
* @return: test
*/
static struct efi_unit_test *find_test(const u16 *testname)
{
struct efi_unit_test *test;
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
if (!efi_st_strcmp_16_8(testname, test->name))
return test;
}
efi_st_printf("\nTest '%ps' not found\n", testname);
return NULL;
}
/*
* List all available tests.
*/
static void list_all_tests(void)
{
struct efi_unit_test *test;
/* List all tests */
efi_st_printf("\nAvailable tests:\n");
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
efi_st_printf("'%s'%s\n", test->name,
test->on_request ? " - on request" : "");
}
}
/*
* Execute test steps of one phase.
*
* @testname name of a single selected test or NULL
* @phase test phase
* @steps steps to execute
* failures returns EFI_ST_SUCCESS if all test steps succeeded
*/
void efi_st_do_tests(const u16 *testname, unsigned int phase,
unsigned int steps, unsigned int *failures)
{
struct efi_unit_test *test;
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
if (testname ?
efi_st_strcmp_16_8(testname, test->name) : test->on_request)
continue;
if (test->phase != phase)
continue;
if (steps & EFI_ST_SETUP)
setup(test, failures);
if (steps & EFI_ST_EXECUTE)
execute(test, failures);
if (steps & EFI_ST_TEARDOWN)
teardown(test, failures);
}
}
/*
* Execute selftest of the EFI API
*
* This is the main entry point of the EFI selftest application.
@ -153,8 +224,10 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures)
efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
struct efi_system_table *systab)
{
struct efi_unit_test *test;
unsigned int failures = 0;
const u16 *testname = NULL;
struct efi_loaded_image *loaded_image;
efi_status_t ret;
systable = systab;
boottime = systable->boottime;
@ -163,47 +236,59 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
con_out = systable->con_out;
con_in = systable->con_in;
efi_st_printf("\nTesting EFI API implementation\n");
ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image,
(void **)&loaded_image);
if (ret != EFI_SUCCESS) {
efi_st_error("Cannot open loaded image protocol\n");
return ret;
}
efi_st_printf("\nNumber of tests to execute: %u\n",
ll_entry_count(struct efi_unit_test, efi_unit_test));
if (loaded_image->load_options)
testname = (u16 *)loaded_image->load_options;
/* Execute boottime tests */
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
if (test->phase == EFI_EXECUTE_BEFORE_BOOTTIME_EXIT) {
setup(test, &failures);
execute(test, &failures);
teardown(test, &failures);
if (testname) {
if (!efi_st_strcmp_16_8(testname, "list") ||
!find_test(testname)) {
list_all_tests();
/*
* TODO:
* Once the Exit boottime service is correctly
* implemented we should call
* boottime->exit(image_handle, EFI_SUCCESS, 0, NULL);
* here, cf.
* https://lists.denx.de/pipermail/u-boot/2017-October/308720.html
*/
return EFI_SUCCESS;
}
}
efi_st_printf("\nTesting EFI API implementation\n");
if (testname)
efi_st_printf("\nSelected test: '%ps'\n", testname);
else
efi_st_printf("\nNumber of tests to execute: %u\n",
ll_entry_count(struct efi_unit_test,
efi_unit_test));
/* Execute boottime tests */
efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
&failures);
/* Execute mixed tests */
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT)
setup(test, &failures);
}
efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
EFI_ST_SETUP, &failures);
efi_st_exit_boot_services();
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT) {
execute(test, &failures);
teardown(test, &failures);
}
}
efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures);
/* Execute runtime tests */
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
if (test->phase == EFI_SETUP_AFTER_BOOTTIME_EXIT) {
setup(test, &failures);
execute(test, &failures);
teardown(test, &failures);
}
}
efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT,
EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
&failures);
/* Give feedback */
efi_st_printf("\nSummary: %u failures\n\n", failures);

@ -142,6 +142,7 @@ void efi_st_printf(const char *fmt, ...)
const char *c;
u16 *pos = buf;
const char *s;
const u16 *u;
va_start(args, fmt);
@ -179,9 +180,18 @@ void efi_st_printf(const char *fmt, ...)
case 'p':
++c;
switch (*c) {
/* MAC address */
case 'm':
mac(va_arg(args, void*), &pos);
break;
/* u16 string */
case 's':
u = va_arg(args, u16*);
/* Ensure string fits into buffer */
for (; *u && pos < buf + 120; ++u)
*pos++ = *u;
break;
default:
--c;
pointer(va_arg(args, void*), &pos);

@ -0,0 +1,390 @@
/*
* efi_selftest_devicepath
*
* Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* This unit test checks the following protocol services:
* DevicePathToText
*/
#include <efi_selftest.h>
static struct efi_boot_services *boottime;
static efi_handle_t handle1;
static efi_handle_t handle2;
static efi_handle_t handle3;
struct interface {
void (EFIAPI * inc)(void);
} interface;
static efi_guid_t guid_device_path = DEVICE_PATH_GUID;
static efi_guid_t guid_device_path_to_text_protocol =
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
static efi_guid_t guid_protocol =
EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0x7d);
static efi_guid_t guid_vendor1 =
EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xb1);
static efi_guid_t guid_vendor2 =
EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xa2);
static efi_guid_t guid_vendor3 =
EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xc3);
static u8 *dp1;
static u8 *dp2;
static u8 *dp3;
struct efi_device_path_to_text_protocol *device_path_to_text;
/*
* Setup unit test.
*
* Create three handles. Install a new protocol on two of them and
* provice device paths.
*
* handle1
* guid interface
* handle2
* guid interface
* handle3
*
* @handle: handle of the loaded image
* @systable: system table
*/
static int setup(const efi_handle_t img_handle,
const struct efi_system_table *systable)
{
struct efi_device_path_vendor vendor_node;
struct efi_device_path end_node;
efi_status_t ret;
boottime = systable->boottime;
ret = boottime->locate_protocol(&guid_device_path_to_text_protocol,
NULL, (void **)&device_path_to_text);
if (ret != EFI_SUCCESS) {
device_path_to_text = NULL;
efi_st_error(
"Device path to text protocol is not available.\n");
return EFI_ST_FAILURE;
}
ret = boottime->allocate_pool(EFI_LOADER_DATA,
sizeof(struct efi_device_path_vendor) +
sizeof(struct efi_device_path),
(void **)&dp1);
if (ret != EFI_SUCCESS)
goto out_of_memory;
ret = boottime->allocate_pool(EFI_LOADER_DATA, 2 *
sizeof(struct efi_device_path_vendor) +
sizeof(struct efi_device_path),
(void **)&dp2);
if (ret != EFI_SUCCESS)
goto out_of_memory;
ret = boottime->allocate_pool(EFI_LOADER_DATA, 3 *
sizeof(struct efi_device_path_vendor) +
sizeof(struct efi_device_path),
(void **)&dp3);
if (ret != EFI_SUCCESS)
goto out_of_memory;
vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
vendor_node.dp.length = sizeof(struct efi_device_path_vendor);
boottime->copy_mem(&vendor_node.guid, &guid_vendor1,
sizeof(efi_guid_t));
boottime->copy_mem(dp1, &vendor_node,
sizeof(struct efi_device_path_vendor));
boottime->copy_mem(dp2, &vendor_node,
sizeof(struct efi_device_path_vendor));
boottime->copy_mem(dp3, &vendor_node,
sizeof(struct efi_device_path_vendor));
boottime->copy_mem(&vendor_node.guid, &guid_vendor2,
sizeof(efi_guid_t));
boottime->copy_mem(dp2 + sizeof(struct efi_device_path_vendor),
&vendor_node, sizeof(struct efi_device_path_vendor));
boottime->copy_mem(dp3 + sizeof(struct efi_device_path_vendor),
&vendor_node, sizeof(struct efi_device_path_vendor));
boottime->copy_mem(&vendor_node.guid, &guid_vendor3,
sizeof(efi_guid_t));
boottime->copy_mem(dp3 + 2 * sizeof(struct efi_device_path_vendor),
&vendor_node, sizeof(struct efi_device_path_vendor));
end_node.type = DEVICE_PATH_TYPE_END;
end_node.sub_type = DEVICE_PATH_SUB_TYPE_END;
end_node.length = sizeof(struct efi_device_path);
boottime->copy_mem(dp1 + sizeof(struct efi_device_path_vendor),
&end_node, sizeof(struct efi_device_path));
boottime->copy_mem(dp2 + 2 * sizeof(struct efi_device_path_vendor),
&end_node, sizeof(struct efi_device_path));
boottime->copy_mem(dp3 + 3 * sizeof(struct efi_device_path_vendor),
&end_node, sizeof(struct efi_device_path));
ret = boottime->install_protocol_interface(&handle1,
&guid_device_path,
EFI_NATIVE_INTERFACE,
dp1);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallProtocolInterface failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->install_protocol_interface(&handle1,
&guid_protocol,
EFI_NATIVE_INTERFACE,
&interface);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallProtocolInterface failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->install_protocol_interface(&handle2,
&guid_device_path,
EFI_NATIVE_INTERFACE,
dp2);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallProtocolInterface failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->install_protocol_interface(&handle2,
&guid_protocol,
EFI_NATIVE_INTERFACE,
&interface);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallProtocolInterface failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->install_protocol_interface(&handle3,
&guid_device_path,
EFI_NATIVE_INTERFACE,
dp3);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallProtocolInterface failed\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
out_of_memory:
efi_st_error("Out of memory\n");
return EFI_ST_FAILURE;
}
/*
* Tear down unit test.
*
*/
static int teardown(void)
{
efi_status_t ret;
ret = boottime->uninstall_protocol_interface(&handle1,
&guid_device_path,
dp1);
if (ret != EFI_SUCCESS)
efi_st_todo("UninstallProtocolInterface failed\n");
ret = boottime->uninstall_protocol_interface(&handle1,
&guid_protocol,
&interface);
if (ret != EFI_SUCCESS)
efi_st_todo("UninstallProtocolInterface failed\n");
ret = boottime->uninstall_protocol_interface(&handle2,
&guid_device_path,
dp2);
if (ret != EFI_SUCCESS)
efi_st_todo("UninstallProtocolInterface failed\n");
ret = boottime->uninstall_protocol_interface(&handle2,
&guid_protocol,
&interface);
if (ret != EFI_SUCCESS)
efi_st_todo("UninstallProtocolInterface failed\n");
ret = boottime->uninstall_protocol_interface(&handle3,
&guid_device_path,
dp3);
if (ret != EFI_SUCCESS)
efi_st_todo("UninstallProtocolInterface failed\n");
if (dp1) {
ret = boottime->free_pool(dp1);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
return EFI_ST_FAILURE;
}
}
if (dp2) {
ret = boottime->free_pool(dp2);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
return EFI_ST_FAILURE;
}
}
if (dp3) {
ret = boottime->free_pool(dp3);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
return EFI_ST_FAILURE;
}
}
return EFI_ST_SUCCESS;
}
/*
* Execute unit test.
*
*/
static int execute(void)
{
struct efi_device_path *remaining_dp;
void *handle;
/*
* This device path node ends with the letter 't' of 'u-boot'.
* The following '.bin' does not belong to the node but is
* helps to test the correct truncation.
*/
struct {
struct efi_device_path dp;
u16 text[12];
} __packed dp_node = {
{ DEVICE_PATH_TYPE_MEDIA_DEVICE,
DEVICE_PATH_SUB_TYPE_FILE_PATH,
sizeof(struct efi_device_path) + 12},
L"u-boot.bin",
};
u16 *string;
efi_status_t ret;
efi_uintn_t i, no_handles;
efi_handle_t *handles;
struct efi_device_path *dp;
/* Display all available device paths */
ret = boottime->locate_handle_buffer(BY_PROTOCOL,
&guid_device_path,
NULL, &no_handles, &handles);
if (ret != EFI_SUCCESS) {
efi_st_error("Cannot retrieve device path protocols.\n");
return EFI_ST_FAILURE;
}
efi_st_printf("Installed device path protocols:\n");
for (i = 0; i < no_handles; ++i) {
ret = boottime->open_protocol(handles[i], &guid_device_path,
(void **)&dp, NULL, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret != EFI_SUCCESS) {
efi_st_error("Cannot open device path protocol.\n");
return EFI_ST_FAILURE;
}
string = device_path_to_text->convert_device_path_to_text(
dp, true, false);
if (!string) {
efi_st_error("ConvertDevicePathToText failed\n");
return EFI_ST_FAILURE;
}
efi_st_printf("%ps\n", string);
ret = boottime->free_pool(string);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->close_protocol(handles[i], &guid_device_path,
NULL, NULL);
if (ret != EFI_SUCCESS)
efi_st_todo("Cannot close device path protocol.\n");
}
ret = boottime->free_pool(handles);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
return EFI_ST_FAILURE;
}
efi_st_printf("\n");
/* Test ConvertDevicePathToText */
string = device_path_to_text->convert_device_path_to_text(
(struct efi_device_path *)dp2, true, false);
if (!string) {
efi_st_error("ConvertDevicePathToText failed\n");
return EFI_ST_FAILURE;
}
efi_st_printf("dp2: %ps\n", string);
if (efi_st_strcmp_16_8(
string,
"/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)")
) {
efi_st_error("Incorrect text from ConvertDevicePathToText\n");
return EFI_ST_FAILURE;
}
ret = boottime->free_pool(string);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
return EFI_ST_FAILURE;
}
/* Test ConvertDeviceNodeToText */
string = device_path_to_text->convert_device_node_to_text(
(struct efi_device_path *)&dp_node, true, false);
if (!string) {
efi_st_error("ConvertDeviceNodeToText failed\n");
return EFI_ST_FAILURE;
}
efi_st_printf("dp_node: %ps\n", string);
ret = boottime->free_pool(string);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
return EFI_ST_FAILURE;
}
if (efi_st_strcmp_16_8(string, "u-boot")) {
efi_st_error(
"Incorrect conversion by ConvertDeviceNodeToText\n");
return EFI_ST_FAILURE;
}
/* Test LocateDevicePath */
remaining_dp = (struct efi_device_path *)dp3;
ret = boottime->locate_device_path(&guid_protocol, &remaining_dp,
&handle);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateDevicePath failed\n");
return EFI_ST_FAILURE;
}
if (handle != handle2) {
efi_st_error("LocateDevicePath returned wrong handle\n");
return EFI_ST_FAILURE;
}
string = device_path_to_text->convert_device_path_to_text(remaining_dp,
true, false);
if (!string) {
efi_st_error("ConvertDevicePathToText failed\n");
return EFI_ST_FAILURE;
}
efi_st_printf("remaining device path: %ps\n", string);
if (efi_st_strcmp_16_8(string,
"/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)")
) {
efi_st_error("LocateDevicePath: wrong remaining device path\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(devicepath) = {
.name = "device path",
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
.teardown = teardown,
};

@ -108,7 +108,7 @@ static int teardown(void)
*/
static int execute(void)
{
size_t index;
efi_uintn_t index;
efi_status_t ret;
/* Set 10 ms timer */

@ -0,0 +1,95 @@
/*
* efi_selftest_gop
*
* Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* Test the graphical output protocol.
*/
#include <efi_selftest.h>
static struct efi_boot_services *boottime;
static efi_guid_t efi_gop_guid = EFI_GOP_GUID;
static struct efi_gop *gop;
/*
* Setup unit test.
*
* @handle: handle of the loaded image
* @systable: system table
* @return: EFI_ST_SUCCESS for success
*/
static int setup(const efi_handle_t handle,
const struct efi_system_table *systable)
{
efi_status_t ret;
boottime = systable->boottime;
ret = boottime->locate_protocol(&efi_gop_guid, NULL, (void **)&gop);
if (ret != EFI_SUCCESS) {
gop = NULL;
efi_st_printf("Graphical output protocol is not available.\n");
}
return EFI_ST_SUCCESS;
}
/*
* Tear down unit test.
*
* @return: EFI_ST_SUCCESS for success
*/
static int teardown(void)
{
return EFI_ST_SUCCESS;
}
/*
* Execute unit test.
*
* @return: EFI_ST_SUCCESS for success
*/
static int execute(void)
{
efi_status_t ret;
u32 i, max_mode;
efi_uintn_t size;
struct efi_gop_mode_info *info;
if (!gop)
return EFI_ST_SUCCESS;
if (!gop->mode) {
efi_st_error("EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE missing\n");
return EFI_ST_FAILURE;
}
max_mode = gop->mode->max_mode;
if (!max_mode) {
efi_st_error("No graphical mode available\n");
return EFI_ST_FAILURE;
}
efi_st_printf("Number of available modes: %u\n", max_mode);
for (i = 0; i < max_mode; ++i) {
ret = gop->query_mode(gop, i, &size, &info);
if (ret != EFI_SUCCESS) {
efi_st_printf("Could not query mode %u\n", i);
return EFI_ST_FAILURE;
}
efi_st_printf("Mode %u: %u x %u\n",
i, info->width, info->height);
}
return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(gop) = {
.name = "graphical output",
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
.teardown = teardown,
};

@ -0,0 +1,354 @@
/*
* efi_selftest_manageprotocols
*
* Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* This unit test checks the following protocol services:
* InstallProtocolInterface, UninstallProtocolInterface,
* InstallMultipleProtocolsInterfaces, UninstallMultipleProtocolsInterfaces,
* HandleProtocol, ProtocolsPerHandle,
* LocateHandle, LocateHandleBuffer.
*/
#include <efi_selftest.h>
/*
* The test currently does not actually call the interface function.
* So this is just a dummy structure.
*/
struct interface {
void (EFIAPI * inc)(void);
};
static struct efi_boot_services *boottime;
static efi_guid_t guid1 =
EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a,
0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf);
static efi_guid_t guid2 =
EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77,
0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f);
static efi_guid_t guid3 =
EFI_GUID(0x06d641a3, 0xf4e7, 0xe0c9,
0xe7, 0x8d, 0x41, 0x2d, 0x72, 0xa6, 0xb1, 0x24);
static efi_handle_t handle1;
static efi_handle_t handle2;
static struct interface interface1;
static struct interface interface2;
static struct interface interface3;
static struct interface interface4;
/*
* Find a handle in an array.
*
* @handle: handle to find
* @count: number of entries in the array
* @buffer: array to search
*/
efi_status_t find_in_buffer(efi_handle_t handle, size_t count,
efi_handle_t *buffer)
{
size_t i;
for (i = 0; i < count; ++i) {
if (buffer[i] == handle)
return EFI_SUCCESS;
}
return EFI_NOT_FOUND;
}
/*
* Setup unit test.
*
* Create two handles and install two out of three protocol interfaces on each
* of them:
*
* handle1
* guid1 interface1
* guid3 interface3
* handle2
* guid1 interface4
* guid2 interface2
*
* @handle: handle of the loaded image
* @systable: system table
*/
static int setup(const efi_handle_t img_handle,
const struct efi_system_table *systable)
{
efi_status_t ret;
efi_handle_t handle;
boottime = systable->boottime;
ret = boottime->install_protocol_interface(&handle1, &guid3,
EFI_NATIVE_INTERFACE,
&interface3);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallProtocolInterface failed\n");
return EFI_ST_FAILURE;
}
if (!handle1) {
efi_st_error("InstallProtocolInterface failed to create handle\n");
return EFI_ST_FAILURE;
}
handle = handle1;
ret = boottime->install_protocol_interface(&handle1, &guid1,
EFI_NATIVE_INTERFACE,
&interface1);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallProtocolInterface failed\n");
return EFI_ST_FAILURE;
}
if (handle != handle1) {
efi_st_error("InstallProtocolInterface failed to use handle\n");
return EFI_ST_FAILURE;
}
ret = boottime->install_multiple_protocol_interfaces(&handle2,
&guid1, &interface4, &guid2, &interface2, NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallMultipleProtocolInterfaces failed\n");
return EFI_ST_FAILURE;
}
if (!handle2 || handle1 == handle2) {
efi_st_error("InstallMultipleProtocolInterfaces failed to create handle\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
/*
* Tear down unit test.
*
*/
static int teardown(void)
{
return EFI_ST_SUCCESS;
}
/*
* Execute unit test.
*
*/
static int execute(void)
{
struct interface *interface;
efi_status_t ret;
efi_handle_t *buffer;
size_t buffer_size;
efi_uintn_t count = 0;
efi_guid_t **prot_buffer;
efi_uintn_t prot_count;
/*
* Test HandleProtocol
*/
ret = boottime->handle_protocol(handle1, &guid3, (void **)&interface);
if (ret != EFI_SUCCESS) {
efi_st_error("HandleProtocol failed to retrieve interface\n");
return EFI_ST_FAILURE;
}
if (interface != &interface3) {
efi_st_error("HandleProtocol returned wrong interface\n");
return EFI_ST_FAILURE;
}
ret = boottime->handle_protocol(handle1, &guid2, (void **)&interface);
if (ret == EFI_SUCCESS) {
efi_st_error("HandleProtocol returned not installed interface\n");
return EFI_ST_FAILURE;
}
/*
* Test LocateHandleBuffer with AllHandles
*/
ret = boottime->locate_handle_buffer(ALL_HANDLES, NULL, NULL,
&count, &buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandleBuffer with AllHandles failed\n");
return EFI_ST_FAILURE;
}
buffer_size = count;
ret = find_in_buffer(handle1, count, buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandleBuffer failed to locate new handle\n");
return EFI_ST_FAILURE;
}
ret = find_in_buffer(handle2, count, buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandleBuffer failed to locate new handle\n");
return EFI_ST_FAILURE;
}
boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
/*
* Test error handling in UninstallMultipleProtocols
*
* Try to uninstall more protocols than there are installed.
*/
ret = boottime->uninstall_multiple_protocol_interfaces(
handle2,
&guid1, &interface4,
&guid2, &interface2,
&guid3, &interface3,
NULL);
if (ret == EFI_SUCCESS) {
efi_st_todo("UninstallMultipleProtocolInterfaces did not catch error\n");
return EFI_ST_FAILURE;
}
/*
* Test LocateHandleBuffer with ByProtocol
*/
count = buffer_size;
ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL,
&count, &buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandleBuffer failed to locate new handles\n");
return EFI_ST_FAILURE;
}
if (count != 2) {
efi_st_error("LocateHandleBuffer failed to locate new handles\n");
return EFI_ST_FAILURE;
}
ret = find_in_buffer(handle1, count, buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandleBuffer failed to locate new handle\n");
return EFI_ST_FAILURE;
}
ret = find_in_buffer(handle2, count, buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandleBuffer failed to locate new handle\n");
return EFI_ST_FAILURE;
}
boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
/*
* Test LocateHandle with ByProtocol
*/
count = buffer_size * sizeof(efi_handle_t);
ret = boottime->locate_handle(BY_PROTOCOL, &guid1, NULL,
&count, buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandle with ByProtocol failed\n");
return EFI_ST_FAILURE;
}
if (count / sizeof(efi_handle_t) != 2) {
efi_st_error("LocateHandle failed to locate new handles\n");
return EFI_ST_FAILURE;
}
buffer_size = count;
ret = find_in_buffer(handle1, count, buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandle failed to locate new handles\n");
return EFI_ST_FAILURE;
}
ret = find_in_buffer(handle2, count, buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandle failed to locate new handles\n");
return EFI_ST_FAILURE;
}
boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
/*
* Test LocateProtocol
*/
ret = boottime->locate_protocol(&guid1, NULL, (void **)&interface);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateProtocol failed\n");
return EFI_ST_FAILURE;
}
if (interface != &interface1 && interface != &interface4) {
efi_st_error("LocateProtocol failed to locate protocol\n");
return EFI_ST_FAILURE;
}
/*
* Test UninstallMultipleProtocols
*/
ret = boottime->uninstall_multiple_protocol_interfaces(
handle2,
&guid1, &interface4,
&guid2, &interface2,
NULL);
if (ret != EFI_SUCCESS) {
efi_st_todo("UninstallMultipleProtocolInterfaces failed\n");
/* This test is known to fail due to missing implementation */
}
/*
* Check that the protocols are really uninstalled.
*/
count = buffer_size;
ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL,
&count, &buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("LocateHandleBuffer failed\n");
return EFI_ST_FAILURE;
}
if (count != 1) {
efi_st_todo("UninstallMultipleProtocolInterfaces failed to uninstall protocols\n");
/* This test is known to fail due to missing implementation */
}
ret = find_in_buffer(handle1, count, buffer);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to locate new handle\n");
return EFI_ST_FAILURE;
}
boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
/*
* Test ProtocolsPerHandle
*/
ret = boottime->protocols_per_handle(handle1,
&prot_buffer, &prot_count);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to get protocols per handle\n");
return EFI_ST_FAILURE;
}
if (prot_count != 2) {
efi_st_error("Failed to get protocols per handle\n");
return EFI_ST_FAILURE;
}
if (efi_st_memcmp(prot_buffer[0], &guid1, 16) &&
efi_st_memcmp(prot_buffer[1], &guid1, 16)) {
efi_st_error("Failed to get protocols per handle\n");
return EFI_ST_FAILURE;
}
if (efi_st_memcmp(prot_buffer[0], &guid3, 16) &&
efi_st_memcmp(prot_buffer[1], &guid3, 16)) {
efi_st_error("Failed to get protocols per handle\n");
return EFI_ST_FAILURE;
}
/*
* Uninstall remaining protocols
*/
ret = boottime->uninstall_protocol_interface(handle1, &guid1,
&interface1);
if (ret != EFI_SUCCESS) {
efi_st_todo("UninstallProtocolInterface failed\n");
/* This test is known to fail due to missing implementation */
}
ret = boottime->handle_protocol(handle1, &guid1, (void **)&interface);
if (ret == EFI_SUCCESS) {
efi_st_todo("UninstallProtocolInterface failed\n");
/* This test is known to fail due to missing implementation */
}
ret = boottime->uninstall_protocol_interface(handle1, &guid3,
&interface1);
if (ret != EFI_SUCCESS) {
efi_st_todo("UninstallProtocolInterface failed\n");
/* This test is known to fail due to missing implementation */
}
return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(protserv) = {
.name = "manage protocols",
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
.teardown = teardown,
};

@ -260,7 +260,7 @@ static int execute(void)
{
efi_status_t ret;
struct efi_event *events[2];
size_t index;
efi_uintn_t index;
union {
struct dhcp p;
u8 b[PKTSIZE];

@ -0,0 +1,53 @@
/*
* efi_selftest_textoutput
*
* Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* Test the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
*
* The following services are tested:
* OutputString, TestString, SetAttribute.
*/
#include <efi_selftest.h>
/*
* Execute unit test.
*
* @return: EFI_ST_SUCCESS for success
*/
static int execute(void)
{
size_t foreground;
size_t background;
size_t attrib;
efi_status_t ret;
/* SetAttribute */
efi_st_printf("\nColor palette\n");
for (foreground = 0; foreground < 0x10; ++foreground) {
for (background = 0; background < 0x80; background += 0x10) {
attrib = foreground | background;
con_out->set_attribute(con_out, attrib);
efi_st_printf("%p", (void *)attrib);
}
con_out->set_attribute(con_out, 0);
efi_st_printf("\n");
}
/* TestString */
ret = con_out->test_string(con_out,
L" !\"#$%&'()*+,-./0-9:;<=>?@A-Z[\\]^_`a-z{|}~\n");
if (ret != EFI_ST_SUCCESS) {
efi_st_error("TestString failed for ANSI characters\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(textoutput) = {
.name = "text output",
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
.execute = execute,
};

@ -111,9 +111,9 @@ static int teardown(void)
*/
static int execute(void)
{
size_t index;
efi_uintn_t index;
efi_status_t ret;
UINTN old_tpl;
efi_uintn_t old_tpl;
/* Set 10 ms timer */
notification_count = 0;

@ -21,5 +21,14 @@ int efi_st_memcmp(const void *buf1, const void *buf2, size_t length)
++pos1;
++pos2;
}
return EFI_ST_SUCCESS;
return 0;
}
int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2)
{
for (; *buf1 || *buf2; ++buf1, ++buf2) {
if (*buf1 != *buf2)
return *buf1 - *buf2;
}
return 0;
}

@ -0,0 +1,231 @@
/*
* efi_selftest_watchdog
*
* Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* The 'watchdog timer' unit test checks that the watchdog timer
* will not cause a system restart during the timeout period after
* a timer reset.
*
* The 'watchdog reboot' unit test checks that the watchdog timer
* actually reboots the system after a timeout. The test is only
* executed on explicit request. Use the following commands:
*
* setenv efi_selftest watchdog reboot
* bootefi selftest
*/
#include <efi_selftest.h>
/*
* This is the communication structure for the notification function.
*/
struct notify_context {
/* Status code returned when resetting watchdog */
efi_status_t status;
/* Number of invocations of the notification function */
unsigned int timer_ticks;
};
static struct efi_event *event_notify;
static struct efi_event *event_wait;
static struct efi_boot_services *boottime;
static struct notify_context notification_context;
static bool watchdog_reset;
/*
* Notification function, increments the notfication count if parameter
* context is provided.
*
* @event notified event
* @context pointer to the timeout
*/
static void EFIAPI notify(struct efi_event *event, void *context)
{
struct notify_context *notify_context = context;
efi_status_t ret = EFI_SUCCESS;
if (!notify_context)
return;
/* Reset watchdog timer to one second */
ret = boottime->set_watchdog_timer(1, 0, 0, NULL);
if (ret != EFI_SUCCESS)
notify_context->status = ret;
/* Count number of calls */
notify_context->timer_ticks++;
}
/*
* Setup unit test.
*
* Create two timer events.
* One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT.
*
* @handle: handle of the loaded image
* @systable: system table
* @return: EFI_ST_SUCCESS for success
*/
static int setup(const efi_handle_t handle,
const struct efi_system_table *systable)
{
efi_status_t ret;
boottime = systable->boottime;
notification_context.status = EFI_SUCCESS;
notification_context.timer_ticks = 0;
ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK, notify,
(void *)&notification_context,
&event_notify);
if (ret != EFI_SUCCESS) {
efi_st_error("could not create event\n");
return EFI_ST_FAILURE;
}
ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT,
TPL_CALLBACK, notify, NULL, &event_wait);
if (ret != EFI_SUCCESS) {
efi_st_error("could not create event\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
/*
* Execute the test resetting the watchdog in a timely manner. No reboot occurs.
*
* @handle: handle of the loaded image
* @systable: system table
* @return: EFI_ST_SUCCESS for success
*/
static int setup_timer(const efi_handle_t handle,
const struct efi_system_table *systable)
{
watchdog_reset = true;
return setup(handle, systable);
}
/*
* Execute the test without resetting the watchdog. A system reboot occurs.
*
* @handle: handle of the loaded image
* @systable: system table
* @return: EFI_ST_SUCCESS for success
*/
static int setup_reboot(const efi_handle_t handle,
const struct efi_system_table *systable)
{
watchdog_reset = false;
return setup(handle, systable);
}
/*
* Tear down unit test.
*
* Close the events created in setup.
*
* @return: EFI_ST_SUCCESS for success
*/
static int teardown(void)
{
efi_status_t ret;
/* Set the watchdog timer to the five minute default value */
ret = boottime->set_watchdog_timer(300, 0, 0, NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("Setting watchdog timer failed\n");
return EFI_ST_FAILURE;
}
if (event_notify) {
ret = boottime->close_event(event_notify);
event_notify = NULL;
if (ret != EFI_SUCCESS) {
efi_st_error("Could not close event\n");
return EFI_ST_FAILURE;
}
}
if (event_wait) {
ret = boottime->close_event(event_wait);
event_wait = NULL;
if (ret != EFI_SUCCESS) {
efi_st_error("Could not close event\n");
return EFI_ST_FAILURE;
}
}
return EFI_ST_SUCCESS;
}
/*
* Execute unit test.
*
* Run a 600 ms periodic timer that resets the watchdog to one second
* on every timer tick.
*
* Run a 1350 ms single shot timer and check that the 600ms timer has
* been called 2 times.
*
* @return: EFI_ST_SUCCESS for success
*/
static int execute(void)
{
size_t index;
efi_status_t ret;
/* Set the watchdog timeout to one second */
ret = boottime->set_watchdog_timer(1, 0, 0, NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("Setting watchdog timer failed\n");
return EFI_ST_FAILURE;
}
if (watchdog_reset) {
/* Set 600 ms timer */
ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC,
6000000);
if (ret != EFI_SUCCESS) {
efi_st_error("Could not set timer\n");
return EFI_ST_FAILURE;
}
}
/* Set 1350 ms timer */
ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 13500000);
if (ret != EFI_SUCCESS) {
efi_st_error("Could not set timer\n");
return EFI_ST_FAILURE;
}
ret = boottime->wait_for_event(1, &event_wait, &index);
if (ret != EFI_SUCCESS) {
efi_st_error("Could not wait for event\n");
return EFI_ST_FAILURE;
}
if (notification_context.status != EFI_SUCCESS) {
efi_st_error("Setting watchdog timer failed\n");
return EFI_ST_FAILURE;
}
if (notification_context.timer_ticks != 2) {
efi_st_error("The timer was called %u times, expected 2.\n",
notification_context.timer_ticks);
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(watchdog1) = {
.name = "watchdog timer",
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
.setup = setup_timer,
.execute = execute,
.teardown = teardown,
};
EFI_UNIT_TEST(watchdog2) = {
.name = "watchdog reboot",
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
.setup = setup_reboot,
.execute = execute,
.teardown = teardown,
.on_request = true,
};

@ -12,7 +12,7 @@ import u_boot_utils
"""
Note: This test relies on boardenv_* containing configuration values to define
which the network environment available for testing. Without this, the parts
which network environment is available for testing. Without this, the parts
that rely on network will be automatically skipped.
For example:
@ -154,6 +154,8 @@ def test_efi_helloworld_net(u_boot_console):
output = u_boot_console.run_command('bootefi %x' % addr)
expected_text = 'Hello, world'
assert expected_text in output
expected_text = '## Application terminated, r = 0'
assert expected_text in output
@pytest.mark.buildconfigspec('cmd_bootefi_hello')
def test_efi_helloworld_builtin(u_boot_console):

@ -1,4 +1,3 @@
# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2017, Heinrich Schuchardt <xypron.glpk@gmx.de>
#
# SPDX-License-Identifier: GPL-2.0
@ -14,6 +13,7 @@ def test_efi_selftest(u_boot_console):
Run bootefi selftest
"""
u_boot_console.run_command(cmd='setenv efi_selftest')
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0:
@ -23,3 +23,15 @@ def test_efi_selftest(u_boot_console):
if m != 0:
raise Exception('Reset failed during the EFI selftest')
u_boot_console.restart_uboot();
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
def test_efi_selftest_watchdog_reboot(u_boot_console):
u_boot_console.run_command(cmd='setenv efi_selftest list')
output = u_boot_console.run_command('bootefi selftest')
assert '\'watchdog reboot\'' in output
u_boot_console.run_command(cmd='setenv efi_selftest watchdog reboot')
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
m = u_boot_console.p.expect(['resetting', 'U-Boot'])
if m != 0:
raise Exception('Reset failed in \'watchdog reboot\' test')
u_boot_console.restart_uboot();

Loading…
Cancel
Save