Browse Source

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

Patch queue for efi - 2017-10-13

This is the second batch of amazing improvements for efi_loader in 2017.11:

  - New self tests to verify our own code
  - A few bug fixes
  - colored text support
  - event and SNP improvements, should get us close to iPXE working
Tom Rini 6 years ago
parent
commit
f855a7bc12

+ 23 - 0
cmd/bootefi.c

@@ -127,6 +127,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
 {
 	struct efi_loaded_image loaded_image_info = {};
 	struct efi_object loaded_image_info_obj = {};
+	struct efi_device_path *memdp = NULL;
 	ulong ret;
 
 	ulong (*entry)(void *image_handle, struct efi_system_table *st)
@@ -135,6 +136,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
 	const efi_guid_t fdt_guid = EFI_FDT_GUID;
 	bootm_headers_t img = { 0 };
 
+	/*
+	 * Special case for efi payload not loaded from disk, such as
+	 * 'bootefi hello' or for example payload loaded directly into
+	 * memory via jtag/etc:
+	 */
+	if (!device_path && !image_path) {
+		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
+		/* actual addresses filled in after efi_load_pe() */
+		memdp = efi_dp_from_mem(0, 0, 0);
+		device_path = image_path = memdp;
+	} else {
+		assert(device_path && image_path);
+	}
+
 	/* Initialize and populate EFI object list */
 	if (!efi_obj_list_initalized)
 		efi_init_obj_list();
@@ -181,6 +196,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
 		goto exit;
 	}
 
+	if (memdp) {
+		struct efi_device_path_memory *mdp = (void *)memdp;
+		mdp->memory_type = loaded_image_info.image_code_type;
+		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
+		mdp->end_address = mdp->start_address +
+				loaded_image_info.image_size;
+	}
+
 	/* we don't support much: */
 	env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
 		"{ro,boot}(blob)0000000000000000");

+ 1 - 0
configs/qemu-x86_64_defconfig

@@ -63,3 +63,4 @@ CONFIG_USB_KEYBOARD=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
 CONFIG_FRAMEBUFFER_VESA_MODE_111=y
 CONFIG_CONSOLE_SCROLL_LINES=5
+CONFIG_CMD_BOOTEFI_SELFTEST=y

+ 1 - 0
configs/qemu-x86_defconfig

@@ -43,3 +43,4 @@ CONFIG_USB_KEYBOARD=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
 CONFIG_FRAMEBUFFER_VESA_MODE_111=y
 CONFIG_CONSOLE_SCROLL_LINES=5
+CONFIG_CMD_BOOTEFI_SELFTEST=y

+ 2 - 2
include/charset.h

@@ -9,7 +9,7 @@
 #ifndef __CHARSET_H_
 #define __CHARSET_H_
 
-#define MAX_UTF8_PER_UTF16 4
+#define MAX_UTF8_PER_UTF16 3
 
 /**
  * utf16_strlen() - Get the length of an utf16 string
@@ -52,7 +52,7 @@ uint16_t *utf16_strdup(const uint16_t *s);
  * Converts 'size' characters of the utf16 string 'src' to utf8
  * written to the 'dest' buffer.
  *
- * NOTE that a single utf16 character can generate up to 4 utf8
+ * NOTE that a single utf16 character can generate up to 3 utf8
  * characters.  See MAX_UTF8_PER_UTF16.
  *
  * @dest   the destination buffer to write the utf8 characters

+ 77 - 26
include/efi_api.h

@@ -71,30 +71,31 @@ struct efi_boot_services {
 					 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, unsigned long *index);
+			struct efi_event **event, size_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);
 #define EFI_NATIVE_INTERFACE	0x00000000
 	efi_status_t (EFIAPI *install_protocol_interface)(
-			void **handle, efi_guid_t *protocol,
+			void **handle, const efi_guid_t *protocol,
 			int protocol_interface_type, void *protocol_interface);
 	efi_status_t (EFIAPI *reinstall_protocol_interface)(
-			void *handle, efi_guid_t *protocol,
+			void *handle, const efi_guid_t *protocol,
 			void *old_interface, void *new_interface);
 	efi_status_t (EFIAPI *uninstall_protocol_interface)(void *handle,
-			efi_guid_t *protocol, void *protocol_interface);
-	efi_status_t (EFIAPI *handle_protocol)(efi_handle_t, efi_guid_t *,
-					       void **);
+			const efi_guid_t *protocol, void *protocol_interface);
+	efi_status_t (EFIAPI *handle_protocol)(efi_handle_t,
+					       const efi_guid_t *protocol,
+					       void **protocol_interface);
 	void *reserved;
 	efi_status_t (EFIAPI *register_protocol_notify)(
-			efi_guid_t *protocol, struct efi_event *event,
+			const efi_guid_t *protocol, struct efi_event *event,
 			void **registration);
 	efi_status_t (EFIAPI *locate_handle)(
 			enum efi_locate_search_type search_type,
-			efi_guid_t *protocol, void *search_key,
+			const efi_guid_t *protocol, void *search_key,
 			unsigned long *buffer_size, efi_handle_t *buffer);
-	efi_status_t (EFIAPI *locate_device_path)(efi_guid_t *protocol,
+	efi_status_t (EFIAPI *locate_device_path)(const efi_guid_t *protocol,
 			struct efi_device_path **device_path,
 			efi_handle_t *device);
 	efi_status_t (EFIAPI *install_configuration_table)(
@@ -131,14 +132,14 @@ struct efi_boot_services {
 #define EFI_OPEN_PROTOCOL_BY_DRIVER           0x00000010
 #define EFI_OPEN_PROTOCOL_EXCLUSIVE           0x00000020
 	efi_status_t (EFIAPI *open_protocol)(efi_handle_t handle,
-			efi_guid_t *protocol, void **interface,
+			const efi_guid_t *protocol, void **interface,
 			efi_handle_t agent_handle,
 			efi_handle_t controller_handle, u32 attributes);
 	efi_status_t (EFIAPI *close_protocol)(void *handle,
-			efi_guid_t *protocol, void *agent_handle,
+			const efi_guid_t *protocol, void *agent_handle,
 			void *controller_handle);
 	efi_status_t(EFIAPI *open_protocol_information)(efi_handle_t handle,
-			efi_guid_t *protocol,
+			const efi_guid_t *protocol,
 			struct efi_open_protocol_info_entry **entry_buffer,
 			unsigned long *entry_count);
 	efi_status_t (EFIAPI *protocols_per_handle)(efi_handle_t handle,
@@ -146,9 +147,9 @@ struct efi_boot_services {
 			unsigned long *protocols_buffer_count);
 	efi_status_t (EFIAPI *locate_handle_buffer) (
 			enum efi_locate_search_type search_type,
-			efi_guid_t *protocol, void *search_key,
+			const efi_guid_t *protocol, void *search_key,
 			unsigned long *no_handles, efi_handle_t **buffer);
-	efi_status_t (EFIAPI *locate_protocol)(efi_guid_t *protocol,
+	efi_status_t (EFIAPI *locate_protocol)(const efi_guid_t *protocol,
 			void *registration, void **protocol_interface);
 	efi_status_t (EFIAPI *install_multiple_protocol_interfaces)(
 			void **handle, ...);
@@ -156,10 +157,9 @@ struct efi_boot_services {
 			void *handle, ...);
 	efi_status_t (EFIAPI *calculate_crc32)(void *data,
 			unsigned long data_size, uint32_t *crc32);
-	void (EFIAPI *copy_mem)(void *destination, void *source,
-			unsigned long length);
-	void (EFIAPI *set_mem)(void *buffer, unsigned long size,
-			uint8_t value);
+	void (EFIAPI *copy_mem)(void *destination, const void *source,
+			size_t length);
+	void (EFIAPI *set_mem)(void *buffer, size_t size, uint8_t value);
 	void *create_event_ex;
 };
 
@@ -297,8 +297,16 @@ struct efi_mac_addr {
 } __packed;
 
 #define DEVICE_PATH_TYPE_HARDWARE_DEVICE	0x01
+#  define DEVICE_PATH_SUB_TYPE_MEMORY		0x03
 #  define DEVICE_PATH_SUB_TYPE_VENDOR		0x04
 
+struct efi_device_path_memory {
+	struct efi_device_path dp;
+	u32 memory_type;
+	u64 start_address;
+	u64 end_address;
+} __packed;
+
 struct efi_device_path_vendor {
 	struct efi_device_path dp;
 	efi_guid_t guid;
@@ -425,6 +433,39 @@ struct simple_text_output_mode {
 	EFI_GUID(0x387477c2, 0x69c7, 0x11d2, \
 		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
+#define EFI_BLACK                0x00
+#define EFI_BLUE                 0x01
+#define EFI_GREEN                0x02
+#define EFI_CYAN                 0x03
+#define EFI_RED                  0x04
+#define EFI_MAGENTA              0x05
+#define EFI_BROWN                0x06
+#define EFI_LIGHTGRAY            0x07
+#define EFI_BRIGHT               0x08
+#define EFI_DARKGRAY             0x08
+#define EFI_LIGHTBLUE            0x09
+#define EFI_LIGHTGREEN           0x0a
+#define EFI_LIGHTCYAN            0x0b
+#define EFI_LIGHTRED             0x0c
+#define EFI_LIGHTMAGENTA         0x0d
+#define EFI_YELLOW               0x0e
+#define EFI_WHITE                0x0f
+#define EFI_BACKGROUND_BLACK     0x00
+#define EFI_BACKGROUND_BLUE      0x10
+#define EFI_BACKGROUND_GREEN     0x20
+#define EFI_BACKGROUND_CYAN      0x30
+#define EFI_BACKGROUND_RED       0x40
+#define EFI_BACKGROUND_MAGENTA   0x50
+#define EFI_BACKGROUND_BROWN     0x60
+#define EFI_BACKGROUND_LIGHTGRAY 0x70
+
+/* extract foreground color from EFI attribute */
+#define EFI_ATTR_FG(attr)        ((attr) & 0x07)
+/* treat high bit of FG as bright/bold (similar to edk2) */
+#define EFI_ATTR_BOLD(attr)      (((attr) >> 3) & 0x01)
+/* extract background color from EFI attribute */
+#define EFI_ATTR_BG(attr)        (((attr) >> 4) & 0x7)
+
 struct efi_simple_text_output_protocol {
 	void *reset;
 	efi_status_t (EFIAPI *output_string)(
@@ -593,11 +634,21 @@ struct efi_simple_network_mode {
 	u8 media_present;
 };
 
-#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST               0x01,
-#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST             0x02,
-#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST             0x04,
-#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS           0x08,
-#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10,
+/* receive_filters bit mask */
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST               0x01
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST             0x02
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST             0x04
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS           0x08
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10
+
+/* interrupt status bit mask */
+#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT	0x01
+#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT	0x02
+#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT	0x04
+#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT	0x08
+
+/* revision of the simple network protocol */
+#define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION	0x00010000
 
 struct efi_simple_network
 {
@@ -626,14 +677,14 @@ struct efi_simple_network
 	efi_status_t (EFIAPI *get_status)(struct efi_simple_network *this,
 			u32 *int_status, void **txbuf);
 	efi_status_t (EFIAPI *transmit)(struct efi_simple_network *this,
-			ulong header_size, ulong buffer_size, void *buffer,
+			size_t header_size, size_t buffer_size, void *buffer,
 			struct efi_mac_address *src_addr,
 			struct efi_mac_address *dest_addr, u16 *protocol);
 	efi_status_t (EFIAPI *receive)(struct efi_simple_network *this,
-			ulong *header_size, ulong *buffer_size, void *buffer,
+			size_t *header_size, size_t *buffer_size, void *buffer,
 			struct efi_mac_address *src_addr,
 			struct efi_mac_address *dest_addr, u16 *protocol);
-	void (EFIAPI *waitforpacket)(void);
+	struct efi_event *wait_for_packet;
 	struct efi_simple_network_mode *mode;
 };
 

+ 9 - 6
include/efi_loader.h

@@ -112,8 +112,8 @@ struct efi_handler {
 struct efi_object {
 	/* Every UEFI object is part of a global object list */
 	struct list_head link;
-	/* We support up to 8 "protocols" an object can be accessed through */
-	struct efi_handler protocols[8];
+	/* We support up to 16 "protocols" an object can be accessed through */
+	struct efi_handler protocols[16];
 	/* The object spawner can either use this for data or as identifier */
 	void *handle;
 };
@@ -136,8 +136,8 @@ struct efi_object {
  * @nofify_function:	Function to call when the event is triggered
  * @notify_context:	Data to be passed to the notify function
  * @trigger_type:	Type of timer, see efi_set_timer
- * @queued:		The notification functionis queued
- * @signaled:		The event occured
+ * @queued:		The notification function is queued
+ * @signaled:		The event occurred. The event is in the signaled state.
  */
 struct efi_event {
 	uint32_t type;
@@ -147,8 +147,8 @@ struct efi_event {
 	u64 trigger_next;
 	u64 trigger_time;
 	enum efi_timer_delay trigger_type;
-	int queued;
-	int signaled;
+	bool is_queued;
+	bool is_signaled;
 };
 
 
@@ -259,6 +259,9 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);
 struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
 					 const char *path);
 struct efi_device_path *efi_dp_from_eth(void);
+struct efi_device_path *efi_dp_from_mem(uint32_t mem_type,
+					uint64_t start_address,
+					uint64_t end_address);
 void efi_dp_split_file_path(struct efi_device_path *full_path,
 			    struct efi_device_path **device_path,
 			    struct efi_device_path **file_path);

+ 16 - 2
include/efi_selftest.h

@@ -14,14 +14,17 @@
 #include <efi_api.h>
 #include <linker_lists.h>
 
+#define EFI_ST_SUCCESS 0
+#define EFI_ST_FAILURE 1
+
 /*
  * Prints an error message.
  *
  * @...	format string followed by fields to print
  */
 #define efi_st_error(...) \
-	efi_st_printf("%s(%u):\nERROR: ", __FILE__, __LINE__); \
-	efi_st_printf(__VA_ARGS__) \
+	(efi_st_printf("%s(%u):\nERROR: ", __FILE__, __LINE__), \
+	efi_st_printf(__VA_ARGS__)) \
 
 /*
  * A test may be setup and executed at boottime,
@@ -57,6 +60,17 @@ void efi_st_exit_boot_services(void);
 void efi_st_printf(const char *fmt, ...)
 		 __attribute__ ((format (__printf__, 1, 2)));
 
+/*
+ * Compare memory.
+ * We cannot use lib/string.c due to different CFLAGS values.
+ *
+ * @buf1:	first buffer
+ * @buf2:	second buffer
+ * @length:	number of bytes to compare
+ * @return:	0 if both buffers contain the same bytes
+ */
+int efi_st_memcmp(const void *buf1, const void *buf2, size_t length);
+
 /*
  * Reads an Unicode character from the input device.
  *

File diff suppressed because it is too large
+ 536 - 65
lib/efi_loader/efi_boottime.c


+ 26 - 3
lib/efi_loader/efi_console.c

@@ -307,14 +307,37 @@ static efi_status_t EFIAPI efi_cout_set_mode(
 	return EFI_EXIT(EFI_SUCCESS);
 }
 
+static const struct {
+	unsigned int fg;
+	unsigned int bg;
+} color[] = {
+	{ 30, 40 },     /* 0: black */
+	{ 34, 44 },     /* 1: blue */
+	{ 32, 42 },     /* 2: green */
+	{ 36, 46 },     /* 3: cyan */
+	{ 31, 41 },     /* 4: red */
+	{ 35, 45 },     /* 5: magenta */
+	{ 33, 43 },     /* 6: brown, map to yellow as edk2 does*/
+	{ 37, 47 },     /* 7: light grey, map to white */
+};
+
+/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
 static efi_status_t EFIAPI efi_cout_set_attribute(
 			struct efi_simple_text_output_protocol *this,
 			unsigned long attribute)
 {
+	unsigned int bold = EFI_ATTR_BOLD(attribute);
+	unsigned int fg = EFI_ATTR_FG(attribute);
+	unsigned int bg = EFI_ATTR_BG(attribute);
+
 	EFI_ENTRY("%p, %lx", this, attribute);
 
-	/* Just ignore attributes (colors) for now */
-	return EFI_EXIT(EFI_UNSUPPORTED);
+	if (attribute)
+		printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
+	else
+		printf(ESC"[0;37;40m");
+
+	return EFI_EXIT(EFI_SUCCESS);
 }
 
 static efi_status_t EFIAPI efi_cout_clear_screen(
@@ -460,7 +483,7 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
 {
 	EFI_ENTRY("%p, %p", event, context);
 	if (tstc()) {
-		efi_con_in.wait_for_key->signaled = 1;
+		efi_con_in.wait_for_key->is_signaled = true;
 		efi_signal_event(efi_con_in.wait_for_key);
 		}
 	EFI_EXIT(EFI_SUCCESS);

+ 24 - 0
lib/efi_loader/efi_device_path.c

@@ -538,6 +538,30 @@ struct efi_device_path *efi_dp_from_eth(void)
 }
 #endif
 
+/* Construct a device-path for memory-mapped image */
+struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
+					uint64_t start_address,
+					uint64_t end_address)
+{
+	struct efi_device_path_memory *mdp;
+	void *buf, *start;
+
+	start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
+
+	mdp = buf;
+	mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+	mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
+	mdp->dp.length = sizeof(*mdp);
+	mdp->memory_type = memory_type;
+	mdp->start_address = start_address;
+	mdp->end_address = end_address;
+	buf = &mdp[1];
+
+	*((struct efi_device_path *)buf) = END;
+
+	return start;
+}
+
 /*
  * Helper to split a full device path (containing both device and file
  * parts) into it's constituent parts.

+ 9 - 0
lib/efi_loader/efi_device_path_to_text.c

@@ -24,6 +24,15 @@ static char *dp_unknown(char *s, struct efi_device_path *dp)
 static char *dp_hardware(char *s, struct efi_device_path *dp)
 {
 	switch (dp->sub_type) {
+	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)",
+			     mdp->memory_type,
+			     mdp->start_address,
+			     mdp->end_address);
+		break;
+	}
 	case DEVICE_PATH_SUB_TYPE_VENDOR: {
 		struct efi_device_path_vendor *vdp =
 			(struct efi_device_path_vendor *)dp;

+ 20 - 6
lib/efi_loader/efi_disk.c

@@ -254,18 +254,19 @@ static int efi_disk_create_eltorito(struct blk_desc *desc,
 #if CONFIG_IS_ENABLED(ISO_PARTITION)
 	char devname[32] = { 0 }; /* dp->str is u16[32] long */
 	disk_partition_t info;
-	int part = 1;
+	int part;
 
 	if (desc->part_type != PART_TYPE_ISO)
 		return 0;
 
 	/* and devices for each partition: */
-	while (!part_get_info(desc, part, &info)) {
+	for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+		if (part_get_info(desc, part, &info))
+			continue;
 		snprintf(devname, sizeof(devname), "%s:%d", pdevname,
 			 part);
 		efi_disk_add_dev(devname, if_typename, desc, diskid,
 				 info.start, part);
-		part++;
 		disks++;
 	}
 
@@ -299,15 +300,16 @@ int efi_disk_register(void)
 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
 		const char *if_typename = dev->driver->name;
 		disk_partition_t info;
-		int part = 1;
+		int part;
 
 		printf("Scanning disk %s...\n", dev->name);
 
 		/* add devices for each partition: */
-		while (!part_get_info(desc, part, &info)) {
+		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);
-			part++;
 		}
 
 		/* ... and add block device: */
@@ -340,6 +342,8 @@ 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)
@@ -349,6 +353,16 @@ 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: */
 			efi_disk_add_dev(devname, if_typename, desc, i, 0, 0);
 			disks++;
 

+ 125 - 18
lib/efi_loader/efi_net.c

@@ -19,6 +19,15 @@ static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
 static struct efi_pxe_packet *dhcp_ack;
 static bool new_rx_packet;
 static void *new_tx_packet;
+/*
+ * The notification function of this event is called in every timer cycle
+ * to check if a new network packet has been received.
+ */
+static struct efi_event *network_timer_event;
+/*
+ * This event is signaled when a packet has been received.
+ */
+static struct efi_event *wait_for_packet;
 
 struct efi_net_obj {
 	/* Generic EFI object parent class data */
@@ -78,9 +87,7 @@ static efi_status_t EFIAPI efi_net_receive_filters(
 	EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
 		  reset_mcast_filter, mcast_filter_count, mcast_filter);
 
-	/* XXX Do we care? */
-
-	return EFI_EXIT(EFI_SUCCESS);
+	return EFI_EXIT(EFI_UNSUPPORTED);
 }
 
 static efi_status_t EFIAPI efi_net_station_address(
@@ -89,7 +96,7 @@ static efi_status_t EFIAPI efi_net_station_address(
 {
 	EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
 
-	return EFI_EXIT(EFI_INVALID_PARAMETER);
+	return EFI_EXIT(EFI_UNSUPPORTED);
 }
 
 static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
@@ -98,7 +105,7 @@ static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
 {
 	EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
 
-	return EFI_EXIT(EFI_INVALID_PARAMETER);
+	return EFI_EXIT(EFI_UNSUPPORTED);
 }
 
 static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
@@ -118,7 +125,7 @@ static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
 	EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
 		  buffer);
 
-	return EFI_EXIT(EFI_INVALID_PARAMETER);
+	return EFI_EXIT(EFI_UNSUPPORTED);
 }
 
 static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
@@ -126,9 +133,14 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
 {
 	EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
 
-	/* We send packets synchronously, so nothing is outstanding */
-	if (int_status)
-		*int_status = 0;
+	efi_timer_check();
+
+	if (int_status) {
+		/* We send packets synchronously, so nothing is outstanding */
+		*int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+		if (new_rx_packet)
+			*int_status |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+	}
 	if (txbuf)
 		*txbuf = new_tx_packet;
 
@@ -138,12 +150,15 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
 }
 
 static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
-		ulong header_size, ulong buffer_size, void *buffer,
+		size_t header_size, size_t buffer_size, void *buffer,
 		struct efi_mac_address *src_addr,
 		struct efi_mac_address *dest_addr, u16 *protocol)
 {
-	EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
-		  buffer_size, buffer, src_addr, dest_addr, protocol);
+	EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this,
+		  (unsigned long)header_size, (unsigned long)buffer_size,
+		  buffer, src_addr, dest_addr, protocol);
+
+	efi_timer_check();
 
 	if (header_size) {
 		/* We would need to create the header if header_size != 0 */
@@ -166,29 +181,66 @@ static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
 static void efi_net_push(void *pkt, int len)
 {
 	new_rx_packet = true;
+	wait_for_packet->is_signaled = true;
 }
 
+/*
+ * Receive a packet from a network interface.
+ *
+ * This function implements the Receive service of the Simple Network Protocol.
+ * See the UEFI spec for details.
+ *
+ * @this	the instance of the Simple Network Protocol
+ * @header_size	size of the media header
+ * @buffer_size	size of the buffer to receive the packet
+ * @buffer	buffer to receive the packet
+ * @src_addr	source MAC address
+ * @dest_addr	destination MAC address
+ * @protocol	protocol
+ * @return	status code
+ */
 static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
-		ulong *header_size, ulong *buffer_size, void *buffer,
+		size_t *header_size, size_t *buffer_size, void *buffer,
 		struct efi_mac_address *src_addr,
 		struct efi_mac_address *dest_addr, u16 *protocol)
 {
+	struct ethernet_hdr *eth_hdr;
+	size_t hdr_size = sizeof(struct ethernet_hdr);
+	u16 protlen;
+
 	EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
 		  buffer_size, buffer, src_addr, dest_addr, protocol);
 
-	push_packet = efi_net_push;
-	eth_rx();
-	push_packet = NULL;
+	efi_timer_check();
 
 	if (!new_rx_packet)
 		return EFI_EXIT(EFI_NOT_READY);
-
+	/* Check that we at least received an Ethernet header */
+	if (net_rx_packet_len < sizeof(struct ethernet_hdr)) {
+		new_rx_packet = false;
+		return EFI_EXIT(EFI_NOT_READY);
+	}
+	/* Fill export parameters */
+	eth_hdr = (struct ethernet_hdr *)net_rx_packet;
+	protlen = ntohs(eth_hdr->et_protlen);
+	if (protlen == 0x8100) {
+		hdr_size += 4;
+		protlen = ntohs(*(u16 *)&net_rx_packet[hdr_size - 2]);
+	}
+	if (header_size)
+		*header_size = hdr_size;
+	if (dest_addr)
+		memcpy(dest_addr, eth_hdr->et_dest, ARP_HLEN);
+	if (src_addr)
+		memcpy(src_addr, eth_hdr->et_src, ARP_HLEN);
+	if (protocol)
+		*protocol = protlen;
 	if (*buffer_size < net_rx_packet_len) {
 		/* Packet doesn't fit, try again with bigger buf */
 		*buffer_size = net_rx_packet_len;
 		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
 	}
-
+	/* Copy packet */
 	memcpy(buffer, net_rx_packet, net_rx_packet_len);
 	*buffer_size = net_rx_packet_len;
 	new_rx_packet = false;
@@ -206,10 +258,32 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
 	memcpy(dhcp_ack, pkt, min(len, maxsize));
 }
 
+/*
+ * Check if a new network packet has been received.
+ *
+ * This notification function is called in every timer cycle.
+ *
+ * @event	the event for which this notification function is registered
+ * @context	event context - not used in this function
+ */
+static void EFIAPI efi_network_timer_notify(struct efi_event *event,
+					    void *context)
+{
+	EFI_ENTRY("%p, %p", event, context);
+
+	if (!new_rx_packet) {
+		push_packet = efi_net_push;
+		eth_rx();
+		push_packet = NULL;
+	}
+	EFI_EXIT(EFI_SUCCESS);
+}
+
 /* This gets called from do_bootefi_exec(). */
 int efi_net_register(void)
 {
 	struct efi_net_obj *netobj;
+	efi_status_t r;
 
 	if (!eth_get_dev()) {
 		/* No eth device active, don't expose any */
@@ -228,6 +302,7 @@ int efi_net_register(void)
 	netobj->parent.protocols[2].guid = &efi_pxe_guid;
 	netobj->parent.protocols[2].protocol_interface = &netobj->pxe;
 	netobj->parent.handle = &netobj->net;
+	netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
 	netobj->net.start = efi_net_start;
 	netobj->net.stop = efi_net_stop;
 	netobj->net.initialize = efi_net_initialize;
@@ -244,6 +319,7 @@ int efi_net_register(void)
 	netobj->net.mode = &netobj->net_mode;
 	netobj->net_mode.state = EFI_NETWORK_STARTED;
 	memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
+	netobj->net_mode.hwaddr_size = ARP_HLEN;
 	netobj->net_mode.max_packet_size = PKTSIZE;
 
 	netobj->pxe.mode = &netobj->pxe_mode;
@@ -253,5 +329,36 @@ int efi_net_register(void)
 	/* Hook net up to the device list */
 	list_add_tail(&netobj->parent.link, &efi_obj_list);
 
+	/*
+	 * Create WaitForPacket event.
+	 */
+	r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
+			     efi_network_timer_notify, NULL,
+			     &wait_for_packet);
+	if (r != EFI_SUCCESS) {
+		printf("ERROR: Failed to register network event\n");
+		return r;
+	}
+	netobj->net.wait_for_packet = wait_for_packet;
+	/*
+	 * Create a timer event.
+	 *
+	 * The notification function is used to check if a new network packet
+	 * has been received.
+	 */
+	r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+			     efi_network_timer_notify, NULL,
+			     &network_timer_event);
+	if (r != EFI_SUCCESS) {
+		printf("ERROR: Failed to register network event\n");
+		return r;
+	}
+	/* Network is time critical, create event in every timer cyle */
+	r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
+	if (r != EFI_SUCCESS) {
+		printf("ERROR: Failed to set network timer\n");
+		return r;
+	}
+
 	return 0;
 }

+ 7 - 1
lib/efi_selftest/Makefile

@@ -15,12 +15,18 @@ 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_events.o \
 efi_selftest_exitbootservices.o \
-efi_selftest_tpl.o
+efi_selftest_snp.o \
+efi_selftest_tpl.o \
+efi_selftest_util.o

+ 19 - 18
lib/efi_selftest/efi_selftest.c

@@ -35,8 +35,8 @@ void efi_st_exit_boot_services(void)
 	ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
 				       &desc_version);
 	if (ret != EFI_BUFFER_TOO_SMALL) {
-		efi_st_printf("ERROR: GetMemoryMap did not return "
-			      "EFI_BUFFER_TOO_SMALL\n");
+		efi_st_error(
+			"GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
 		return;
 	}
 	/* Allocate extra space for newly allocated memory */
@@ -44,21 +44,18 @@ void efi_st_exit_boot_services(void)
 	ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
 				      (void **)&memory_map);
 	if (ret != EFI_SUCCESS) {
-		efi_st_printf("ERROR: AllocatePool did not return "
-			      "EFI_SUCCESS\n");
+		efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
 		return;
 	}
 	ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
 				       &desc_size, &desc_version);
 	if (ret != EFI_SUCCESS) {
-		efi_st_printf("ERROR: GetMemoryMap did not return "
-			      "EFI_SUCCESS\n");
+		efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
 		return;
 	}
 	ret = boottime->exit_boot_services(handle, map_key);
 	if (ret != EFI_SUCCESS) {
-		efi_st_printf("ERROR: ExitBootServices did not return "
-			      "EFI_SUCCESS\n");
+		efi_st_error("ExitBootServices did not return EFI_SUCCESS\n");
 		return;
 	}
 	efi_st_printf("\nBoot services terminated\n");
@@ -69,17 +66,18 @@ void efi_st_exit_boot_services(void)
  *
  * @test	the test to be executed
  * @failures	counter that will be incremented if a failure occurs
+ * @return	EFI_ST_SUCCESS for success
  */
 static int setup(struct efi_unit_test *test, unsigned int *failures)
 {
 	int ret;
 
 	if (!test->setup)
-		return 0;
+		return EFI_ST_SUCCESS;
 	efi_st_printf("\nSetting up '%s'\n", test->name);
 	ret = test->setup(handle, systable);
-	if (ret) {
-		efi_st_printf("ERROR: Setting up '%s' failed\n", test->name);
+	if (ret != EFI_ST_SUCCESS) {
+		efi_st_error("Setting up '%s' failed\n", test->name);
 		++*failures;
 	} else {
 		efi_st_printf("Setting up '%s' succeeded\n", test->name);
@@ -92,17 +90,18 @@ static int setup(struct efi_unit_test *test, unsigned int *failures)
  *
  * @test	the test to be executed
  * @failures	counter that will be incremented if a failure occurs
+ * @return	EFI_ST_SUCCESS for success
  */
 static int execute(struct efi_unit_test *test, unsigned int *failures)
 {
 	int ret;
 
 	if (!test->execute)
-		return 0;
+		return EFI_ST_SUCCESS;
 	efi_st_printf("\nExecuting '%s'\n", test->name);
 	ret = test->execute();
-	if (ret) {
-		efi_st_printf("ERROR: Executing '%s' failed\n", test->name);
+	if (ret != EFI_ST_SUCCESS) {
+		efi_st_error("Executing '%s' failed\n", test->name);
 		++*failures;
 	} else {
 		efi_st_printf("Executing '%s' succeeded\n", test->name);
@@ -115,17 +114,18 @@ static int execute(struct efi_unit_test *test, unsigned int *failures)
  *
  * @test	the test to be torn down
  * @failures	counter that will be incremented if a failure occurs
+ * @return	EFI_ST_SUCCESS for success
  */
 static int teardown(struct efi_unit_test *test, unsigned int *failures)
 {
 	int ret;
 
 	if (!test->teardown)
-		return 0;
+		return EFI_ST_SUCCESS;
 	efi_st_printf("\nTearing down '%s'\n", test->name);
 	ret = test->teardown();
-	if (ret) {
-		efi_st_printf("ERROR: Tearing down '%s' failed\n", test->name);
+	if (ret != EFI_ST_SUCCESS) {
+		efi_st_error("Tearing down '%s' failed\n", test->name);
 		++*failures;
 	} else {
 		efi_st_printf("Tearing down '%s' succeeded\n", test->name);
@@ -213,7 +213,8 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
 	efi_st_get_key();
 	runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY,
 			      sizeof(reset_message), reset_message);
-	efi_st_printf("\nERROR: reset failed.\n");
+	efi_st_printf("\n");
+	efi_st_error("Reset failed.\n");
 
 	return EFI_UNSUPPORTED;
 }

+ 40 - 1
lib/efi_selftest/efi_selftest_console.c

@@ -12,6 +12,37 @@
 struct efi_simple_text_output_protocol *con_out;
 struct efi_simple_input_interface *con_in;
 
+/*
+ * Print a MAC address to an u16 string
+ *
+ * @pointer: mac address
+ * @buf: pointer to buffer address
+ * on return position of terminating zero word
+ */
+static void mac(void *pointer, u16 **buf)
+{
+	int i, j;
+	u16 c;
+	u8 *p = (u8 *)pointer;
+	u8 byte;
+	u16 *pos = *buf;
+
+	for (i = 0; i < ARP_HLEN; ++i) {
+		if (i)
+			*pos++ = ':';
+		byte = p[i];
+		for (j = 4; j >= 0; j -= 4) {
+			c = (byte >> j) & 0x0f;
+			c += '0';
+			if (c > '9')
+				c += 'a' - '9' - 1;
+			*pos++ = c;
+		}
+	}
+	*pos = 0;
+	*buf = pos;
+}
+
 /*
  * Print a pointer to an u16 string
  *
@@ -146,7 +177,15 @@ void efi_st_printf(const char *fmt, ...)
 				int2dec(va_arg(args, s32), &pos);
 				break;
 			case 'p':
-				pointer(va_arg(args, void*), &pos);
+				++c;
+				switch (*c) {
+				case 'm':
+					mac(va_arg(args, void*), &pos);
+					break;
+				default:
+					--c;
+					pointer(va_arg(args, void*), &pos);
+				}
 				break;
 			case 's':
 				s = va_arg(args, const char *);

+ 46 - 38
lib/efi_selftest/efi_selftest_events.c

@@ -14,20 +14,22 @@
 
 static struct efi_event *event_notify;
 static struct efi_event *event_wait;
-static unsigned int counter;
+static unsigned int timer_ticks;
 static struct efi_boot_services *boottime;
 
 /*
- * Notification function, increments a counter.
+ * Notification function, increments the notfication count if parameter
+ * context is provided.
  *
  * @event	notified event
- * @context	pointer to the counter
+ * @context	pointer to the notification count
  */
 static void EFIAPI notify(struct efi_event *event, void *context)
 {
-	if (!context)
-		return;
-	++*(unsigned int *)context;
+	unsigned int *count = context;
+
+	if (count)
+		++*count;
 }
 
 /*
@@ -38,6 +40,7 @@ static void EFIAPI notify(struct efi_event *event, void *context)
  *
  * @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)
@@ -47,25 +50,27 @@ static int setup(const efi_handle_t handle,
 	boottime = systable->boottime;
 
 	ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL,
-				     TPL_CALLBACK, notify, (void *)&counter,
+				     TPL_CALLBACK, notify, (void *)&timer_ticks,
 				     &event_notify);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("could not create event\n");
-		return 1;
+		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 1;
+		return EFI_ST_FAILURE;
 	}
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 /*
  * Tear down unit test.
  *
  * Close the events created in setup.
+ *
+ * @return:	EFI_ST_SUCCESS for success
  */
 static int teardown(void)
 {
@@ -76,7 +81,7 @@ static int teardown(void)
 		event_notify = NULL;
 		if (ret != EFI_SUCCESS) {
 			efi_st_error("could not close event\n");
-			return 1;
+			return EFI_ST_FAILURE;
 		}
 	}
 	if (event_wait) {
@@ -84,10 +89,10 @@ static int teardown(void)
 		event_wait = NULL;
 		if (ret != EFI_SUCCESS) {
 			efi_st_error("could not close event\n");
-			return 1;
+			return EFI_ST_FAILURE;
 		}
 	}
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 /*
@@ -98,92 +103,95 @@ static int teardown(void)
  *
  * Run a 100 ms single shot timer and check that it is called once
  * while waiting for 100 ms periodic timer for two periods.
+ *
+ * @return:	EFI_ST_SUCCESS for success
  */
 static int execute(void)
 {
-	unsigned long index;
+	size_t index;
 	efi_status_t ret;
 
 	/* Set 10 ms timer */
-	counter = 0;
+	timer_ticks = 0;
 	ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Set 100 ms timer */
 	ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 
+	/* Set some arbitrary non-zero value to make change detectable. */
 	index = 5;
 	ret = boottime->wait_for_event(1, &event_wait, &index);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not wait for event\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	ret = boottime->check_event(event_wait);
 	if (ret != EFI_NOT_READY) {
 		efi_st_error("Signaled state was not cleared.\n");
 		efi_st_printf("ret = %u\n", (unsigned int)ret);
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	if (index != 0) {
 		efi_st_error("WaitForEvent returned wrong index\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
-	efi_st_printf("Counter periodic: %u\n", counter);
-	if (counter < 8 || counter > 12) {
+	efi_st_printf("Notification count periodic: %u\n", timer_ticks);
+	if (timer_ticks < 8 || timer_ticks > 12) {
 		efi_st_error("Incorrect timing of events\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0);
 	if (index != 0) {
 		efi_st_error("Could not cancel timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Set 10 ms timer */
-	counter = 0;
+	timer_ticks = 0;
 	ret = boottime->set_timer(event_notify, EFI_TIMER_RELATIVE, 100000);
 	if (index != 0) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Set 100 ms timer */
 	ret = boottime->set_timer(event_wait, EFI_TIMER_PERIODIC, 1000000);
 	if (index != 0) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		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 1;
+		return EFI_ST_FAILURE;
 	}
-	efi_st_printf("Counter single shot: %u\n", counter);
-	if (counter != 1) {
+	efi_st_printf("Notification count single shot: %u\n", timer_ticks);
+	if (timer_ticks != 1) {
 		efi_st_error("Single shot timer failed\n");
-		return 1;
+		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 1;
+		return EFI_ST_FAILURE;
 	}
-	efi_st_printf("Stopped counter: %u\n", counter);
-	if (counter != 1) {
+	efi_st_printf("Notification count stopped timer: %u\n", timer_ticks);
+	if (timer_ticks != 1) {
 		efi_st_error("Stopped timer fired\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0);
-	if (index != 0) {
+	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not cancel timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 EFI_UNIT_TEST(events) = {

+ 26 - 20
lib/efi_selftest/efi_selftest_exitbootservices.c

@@ -1,5 +1,5 @@
 /*
- * efi_selftest_events
+ * efi_selftest_exitbootservices
  *
  * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
  *
@@ -13,19 +13,19 @@
 
 static struct efi_boot_services *boottime;
 static struct efi_event *event_notify;
-static unsigned int counter;
+static unsigned int notification_count;
 
 /*
- * Notification function, increments a counter.
+ * Notification function, increments the notification count.
  *
  * @event	notified event
- * @context	pointer to the counter
+ * @context	pointer to the notification count
  */
 static void EFIAPI notify(struct efi_event *event, void *context)
 {
-	if (!context)
-		return;
-	++*(unsigned int *)context;
+	unsigned int *count = context;
+
+	++*count;
 }
 
 /*
@@ -35,6 +35,7 @@ static void EFIAPI notify(struct efi_event *event, void *context)
  *
  * @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)
@@ -43,21 +44,24 @@ static int setup(const efi_handle_t handle,
 
 	boottime = systable->boottime;
 
-	counter = 0;
+	notification_count = 0;
 	ret = boottime->create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES,
-				     TPL_CALLBACK, notify, (void *)&counter,
+				     TPL_CALLBACK, notify,
+				     (void *)&notification_count,
 				     &event_notify);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("could not create event\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 /*
  * Tear down unit test.
  *
  * Close the event created in setup.
+ *
+ * @return:	EFI_ST_SUCCESS for success
  */
 static int teardown(void)
 {
@@ -68,10 +72,10 @@ static int teardown(void)
 		event_notify = NULL;
 		if (ret != EFI_SUCCESS) {
 			efi_st_error("could not close event\n");
-			return 1;
+			return EFI_ST_FAILURE;
 		}
 	}
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 /*
@@ -82,19 +86,21 @@ static int teardown(void)
  *
  * Call ExitBootServices again and check that the notification function is
  * not called again.
+ *
+ * @return:	EFI_ST_SUCCESS for success
  */
 static int execute(void)
 {
-	if (counter != 1) {
-		efi_st_error("ExitBootServices was not notified");
-		return 1;
+	if (notification_count != 1) {
+		efi_st_error("ExitBootServices was not notified\n");
+		return EFI_ST_FAILURE;
 	}
 	efi_st_exit_boot_services();
-	if (counter != 1) {
-		efi_st_error("ExitBootServices was notified twice");
-		return 1;
+	if (notification_count != 1) {
+		efi_st_error("ExitBootServices was notified twice\n");
+		return EFI_ST_FAILURE;
 	}
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 EFI_UNIT_TEST(exitbootservices) = {

+ 431 - 0
lib/efi_selftest/efi_selftest_snp.c

@@ -0,0 +1,431 @@
+/*
+ * efi_selftest_snp
+ *
+ * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * This unit test covers the Simple Network Protocol as well as
+ * the CopyMem and SetMem boottime services.
+ *
+ * A DHCP discover message is sent. The test is successful if a
+ * DHCP reply is received.
+ *
+ * TODO: Once ConnectController and DisconnectController are implemented
+ *	 we should connect our code as controller.
+ */
+
+#include <efi_selftest.h>
+
+/*
+ * MAC address for broadcasts
+ */
+static const u8 BROADCAST_MAC[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+struct dhcp_hdr {
+	u8 op;
+#define BOOTREQUEST 1
+#define BOOTREPLY 2
+	u8 htype;
+# define HWT_ETHER 1
+	u8 hlen;
+# define HWL_ETHER 6
+	u8 hops;
+	u32 xid;
+	u16 secs;
+	u16 flags;
+#define DHCP_FLAGS_UNICAST	0x0000
+#define DHCP_FLAGS_BROADCAST	0x0080
+	u32 ciaddr;
+	u32 yiaddr;
+	u32 siaddr;
+	u32 giaddr;
+	u8 chaddr[16];
+	u8 sname[64];
+	u8 file[128];
+};
+
+/*
+ * Message type option.
+ */
+#define DHCP_MESSAGE_TYPE	0x35
+#define DHCPDISCOVER		1
+#define DHCPOFFER		2
+#define DHCPREQUEST		3
+#define DHCPDECLINE		4
+#define DHCPACK			5
+#define DHCPNAK			6
+#define DHCPRELEASE		7
+
+struct dhcp {
+	struct ethernet_hdr eth_hdr;
+	struct ip_udp_hdr ip_udp;
+	struct dhcp_hdr dhcp_hdr;
+	u8 opt[128];
+} __packed;
+
+static struct efi_boot_services *boottime;
+static struct efi_simple_network *net;
+static struct efi_event *timer;
+static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
+/* IP packet ID */
+static unsigned int net_ip_id;
+
+/*
+ * Compute the checksum of the IP header. We cover even values of length only.
+ * We cannot use net/checksum.c due to different CFLAGS values.
+ *
+ * @buf:	IP header
+ * @len:	length of header in bytes
+ * @return:	checksum
+ */
+static unsigned int efi_ip_checksum(const void *buf, size_t len)
+{
+	size_t i;
+	u32 sum = 0;
+	const u16 *pos = buf;
+
+	for (i = 0; i < len; i += 2)
+		sum += *pos++;
+
+	sum = (sum >> 16) + (sum & 0xffff);
+	sum += sum >> 16;
+	sum = ~sum & 0xffff;
+
+	return sum;
+}
+
+/*
+ * Transmit a DHCPDISCOVER message.
+ */
+static efi_status_t send_dhcp_discover(void)
+{
+	efi_status_t ret;
+	struct dhcp p = {};
+
+	/*
+	 * Fill ethernet header
+	 */
+	boottime->copy_mem(p.eth_hdr.et_dest, (void *)BROADCAST_MAC, ARP_HLEN);
+	boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address,
+			   ARP_HLEN);
+	p.eth_hdr.et_protlen = htons(PROT_IP);
+	/*
+	 * Fill IP header
+	 */
+	p.ip_udp.ip_hl_v	= 0x45;
+	p.ip_udp.ip_len		= htons(sizeof(struct dhcp) -
+					sizeof(struct ethernet_hdr));
+	p.ip_udp.ip_id		= htons(++net_ip_id);
+	p.ip_udp.ip_off		= htons(IP_FLAGS_DFRAG);
+	p.ip_udp.ip_ttl		= 0xff; /* time to live */
+	p.ip_udp.ip_p		= IPPROTO_UDP;
+	boottime->set_mem(&p.ip_udp.ip_dst, 4, 0xff);
+	p.ip_udp.ip_sum		= efi_ip_checksum(&p.ip_udp, IP_HDR_SIZE);
+
+	/*
+	 * Fill UDP header
+	 */
+	p.ip_udp.udp_src	= htons(68);
+	p.ip_udp.udp_dst	= htons(67);
+	p.ip_udp.udp_len	= htons(sizeof(struct dhcp) -
+					sizeof(struct ethernet_hdr) -
+					sizeof(struct ip_hdr));
+	/*
+	 * Fill DHCP header
+	 */
+	p.dhcp_hdr.op		= BOOTREQUEST;
+	p.dhcp_hdr.htype	= HWT_ETHER;
+	p.dhcp_hdr.hlen		= HWL_ETHER;
+	p.dhcp_hdr.flags	= htons(DHCP_FLAGS_UNICAST);
+	boottime->copy_mem(&p.dhcp_hdr.chaddr,
+			   &net->mode->current_address, ARP_HLEN);
+	/*
+	 * Fill options
+	 */
+	p.opt[0]	= 0x63; /* DHCP magic cookie */
+	p.opt[1]	= 0x82;
+	p.opt[2]	= 0x53;
+	p.opt[3]	= 0x63;
+	p.opt[4]	= DHCP_MESSAGE_TYPE;
+	p.opt[5]	= 0x01; /* length */
+	p.opt[6]	= DHCPDISCOVER;
+	p.opt[7]	= 0x39; /* maximum message size */
+	p.opt[8]	= 0x02; /* length */
+	p.opt[9]	= 0x02; /* 576 bytes */
+	p.opt[10]	= 0x40;
+	p.opt[11]	= 0xff; /* end of options */
+
+	/*
+	 * Transmit DHCPDISCOVER message.
+	 */
+	ret = net->transmit(net, 0, sizeof(struct dhcp), &p, NULL, NULL, 0);
+	if (ret != EFI_SUCCESS)
+		efi_st_error("Sending a DHCP request failed\n");
+	else
+		efi_st_printf("DHCP Discover\n");
+	return ret;
+}
+
+/*
+ * Setup unit test.
+ *
+ * Create a 1 s periodic timer.
+ * Start the network driver.
+ *
+ * @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;
+
+	/*
+	 * Create a timer event.
+	 */
+	ret = boottime->create_event(EVT_TIMER, TPL_CALLBACK, NULL, NULL,
+				     &timer);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("Failed to create event\n");
+		return EFI_ST_FAILURE;
+	}
+	/*
+	 * Set timer period to 1s.
+	 */
+	ret = boottime->set_timer(timer, EFI_TIMER_PERIODIC, 10000000);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("Failed to set timer\n");
+		return EFI_ST_FAILURE;
+	}
+	/*
+	 * Find an interface implementing the SNP protocol.
+	 */
+	ret = boottime->locate_protocol(&efi_net_guid, NULL, (void **)&net);
+	if (ret != EFI_SUCCESS) {
+		net = NULL;
+		efi_st_error("Failed to locate simple network protocol\n");
+		return EFI_ST_FAILURE;
+	}
+	/*
+	 * Check hardware address size.
+	 */
+	if (!net->mode) {
+		efi_st_error("Mode not provided\n");
+		return EFI_ST_FAILURE;
+	}
+	if (net->mode->hwaddr_size != ARP_HLEN) {
+		efi_st_error("HwAddressSize = %u, expected %u\n",
+			     net->mode->hwaddr_size, ARP_HLEN);
+		return EFI_ST_FAILURE;
+	}
+	/*
+	 * Check that WaitForPacket event exists.
+	 */
+	if (!net->wait_for_packet) {
+		efi_st_error("WaitForPacket event missing\n");
+		return EFI_ST_FAILURE;
+	}
+	/*
+	 * Initialize network adapter.
+	 */
+	ret = net->initialize(net, 0, 0);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("Failed to initialize network adapter\n");
+		return EFI_ST_FAILURE;
+	}
+	/*
+	 * Start network adapter.
+	 */
+	ret = net->start(net);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("Failed to start network adapter\n");
+		return EFI_ST_FAILURE;
+	}
+	return EFI_ST_SUCCESS;
+}
+
+/*
+ * Execute unit test.
+ *
+ * A DHCP discover message is sent. The test is successful if a
+ * DHCP reply is received within 10 seconds.
+ *
+ * @return:	EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+	efi_status_t ret;
+	struct efi_event *events[2];
+	size_t index;
+	union {
+		struct dhcp p;
+		u8 b[PKTSIZE];
+	} buffer;
+	struct efi_mac_address srcaddr;
+	struct efi_mac_address destaddr;
+	size_t buffer_size;
+	u8 *addr;
+	/*
+	 * The timeout is to occur after 10 s.
+	 */
+	unsigned int timeout = 10;
+
+	/* Setup may have failed */
+	if (!net || !timer) {
+		efi_st_error("Cannot execute test after setup failure\n");
+		return EFI_ST_FAILURE;
+	}
+
+	/*
+	 * Send DHCP discover message
+	 */
+	ret = send_dhcp_discover();
+	if (ret != EFI_SUCCESS)
+		return EFI_ST_FAILURE;
+
+	/*
+	 * If we would call WaitForEvent only with the WaitForPacket event,
+	 * our code would block until a packet is received which might never
+	 * occur. By calling WaitFor event with both a timer event and the
+	 * WaitForPacket event we can escape this blocking situation.
+	 *
+	 * If the timer event occurs before we have received a DHCP reply
+	 * a further DHCP discover message is sent.
+	 */
+	events[0] = timer;
+	events[1] = net->wait_for_packet;
+	for (;;) {
+		/*
+		 * Wait for packet to be received or timer event.
+		 */
+		boottime->wait_for_event(2, events, &index);
+		if (index == 0) {
+			/*
+			 * The timer event occurred. Check for timeout.
+			 */
+			--timeout;
+			if (!timeout) {
+				efi_st_error("Timeout occurred\n");
+				return EFI_ST_FAILURE;
+			}
+			/*
+			 * Send further DHCP discover message
+			 */
+			ret = send_dhcp_discover();
+			if (ret != EFI_SUCCESS)
+				return EFI_ST_FAILURE;
+			continue;
+		}
+		/*
+		 * Receive packet
+		 */
+		buffer_size = sizeof(buffer);
+		net->receive(net, NULL, &buffer_size, &buffer,
+			     &srcaddr, &destaddr, NULL);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to receive packet");
+			return EFI_ST_FAILURE;
+		}
+		/*
+		 * Check the packet is meant for this system.
+		 * Unfortunately QEMU ignores the broadcast flag.
+		 * So we have to check for broadcasts too.
+		 */
+		if (efi_st_memcmp(&destaddr, &net->mode->current_address,
+				  ARP_HLEN) &&
+		    efi_st_memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN))
+			continue;
+		/*
+		 * Check this is a DHCP reply
+		 */
+		if (buffer.p.eth_hdr.et_protlen != ntohs(PROT_IP) ||
+		    buffer.p.ip_udp.ip_hl_v != 0x45 ||
+		    buffer.p.ip_udp.ip_p != IPPROTO_UDP ||
+		    buffer.p.ip_udp.udp_src != ntohs(67) ||
+		    buffer.p.ip_udp.udp_dst != ntohs(68) ||
+		    buffer.p.dhcp_hdr.op != BOOTREPLY)
+			continue;
+		/*
+		 * We successfully received a DHCP reply.
+		 */
+		break;
+	}
+
+	/*
+	 * Write a log message.
+	 */
+	addr = (u8 *)&buffer.p.ip_udp.ip_src;
+	efi_st_printf("DHCP reply received from %u.%u.%u.%u (%pm) ",
+		      addr[0], addr[1], addr[2], addr[3], &srcaddr);
+	if (!efi_st_memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN))
+		efi_st_printf("as broadcast message.\n");
+	else
+		efi_st_printf("as unicast message.\n");
+
+	return EFI_ST_SUCCESS;
+}
+
+/*
+ * Tear down unit test.
+ *
+ * Close the timer event created in setup.
+ * Shut down the network adapter.
+ *
+ * @return:	EFI_ST_SUCCESS for success
+ */
+static int teardown(void)
+{
+	efi_status_t ret;
+	int exit_status = EFI_ST_SUCCESS;
+
+	if (timer) {
+		/*
+		 * Stop timer.
+		 */
+		ret = boottime->set_timer(timer, EFI_TIMER_STOP, 0);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to stop timer");
+			exit_status = EFI_ST_FAILURE;
+		}
+		/*
+		 * Close timer event.
+		 */
+		ret = boottime->close_event(timer);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to close event");
+			exit_status = EFI_ST_FAILURE;
+		}
+	}
+	if (net) {
+		/*
+		 * Stop network adapter.
+		 */
+		ret = net->stop(net);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to stop network adapter\n");
+			exit_status = EFI_ST_FAILURE;
+		}
+		/*
+		 * Shut down network adapter.
+		 */
+		ret = net->shutdown(net);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to shut down network adapter\n");
+			exit_status = EFI_ST_FAILURE;
+		}
+	}
+
+	return exit_status;
+}
+
+EFI_UNIT_TEST(snp) = {
+	.name = "simple network protocol",
+	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+	.setup = setup,
+	.execute = execute,
+	.teardown = teardown,
+};

+ 50 - 40
lib/efi_selftest/efi_selftest_tpl.c

@@ -13,20 +13,21 @@
 
 static struct efi_event *event_notify;
 static struct efi_event *event_wait;
-static unsigned int counter;
+static unsigned int notification_count;
 static struct efi_boot_services *boottime;
 
 /*
- * Notification function, increments a counter.
+ * Notification function, increments the notification count.
  *
  * @event	notified event
- * @context	pointer to the counter
+ * @context	pointer to the notification count
  */
 static void EFIAPI notify(struct efi_event *event, void *context)
 {
-	if (!context)
-		return;
-	++*(unsigned int *)context;
+	unsigned int *count = context;
+
+	if (count)
+		++*count;
 }
 
 /*
@@ -37,6 +38,7 @@ static void EFIAPI notify(struct efi_event *event, void *context)
  *
  * @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)
@@ -46,25 +48,28 @@ static int setup(const efi_handle_t handle,
 	boottime = systable->boottime;
 
 	ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL,
-				     TPL_CALLBACK, notify, (void *)&counter,
+				     TPL_CALLBACK, notify,
+				     (void *)&notification_count,
 				     &event_notify);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("could not create event\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT,
 				     TPL_HIGH_LEVEL, notify, NULL, &event_wait);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("could not create event\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 /*
  * Tear down unit test.
  *
  * Close the events created in setup.
+ *
+ * @return:	EFI_ST_SUCCESS for success
  */
 static int teardown(void)
 {
@@ -75,7 +80,7 @@ static int teardown(void)
 		event_notify = NULL;
 		if (ret != EFI_SUCCESS) {
 			efi_st_error("could not close event\n");
-			return 1;
+			return EFI_ST_FAILURE;
 		}
 	}
 	if (event_wait) {
@@ -83,11 +88,11 @@ static int teardown(void)
 		event_wait = NULL;
 		if (ret != EFI_SUCCESS) {
 			efi_st_error("could not close event\n");
-			return 1;
+			return EFI_ST_FAILURE;
 		}
 	}
 	boottime->restore_tpl(TPL_APPLICATION);
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 /*
@@ -101,108 +106,113 @@ static int teardown(void)
  *
  * Lower the TPL level and check that the queued notification
  * function is called.
+ *
+ * @return:	EFI_ST_SUCCESS for success
  */
 static int execute(void)
 {
-	unsigned long index;
+	size_t index;
 	efi_status_t ret;
 	UINTN old_tpl;
 
 	/* Set 10 ms timer */
-	counter = 0;
+	notification_count = 0;
 	ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Set 100 ms timer */
 	ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	index = 5;
 	ret = boottime->wait_for_event(1, &event_wait, &index);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not wait for event\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	ret = boottime->check_event(event_wait);
 	if (ret != EFI_NOT_READY) {
 		efi_st_error("Signaled state was not cleared.\n");
 		efi_st_printf("ret = %u\n", (unsigned int)ret);
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	if (index != 0) {
 		efi_st_error("WaitForEvent returned wrong index\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
-	efi_st_printf("Counter with TPL level TPL_APPLICATION: %u\n", counter);
-	if (counter < 8 || counter > 12) {
+	efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n",
+		      notification_count);
+	if (notification_count < 8 || notification_count > 12) {
 		efi_st_error("Incorrect timing of events\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0);
 	if (index != 0) {
 		efi_st_error("Could not cancel timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Raise TPL level */
 	old_tpl = boottime->raise_tpl(TPL_CALLBACK);
 	if (old_tpl != TPL_APPLICATION) {
 		efi_st_error("Initial TPL level was not TPL_APPLICATION");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Set 10 ms timer */
-	counter = 0;
+	notification_count = 0;
 	ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
 	if (index != 0) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Set 100 ms timer */
 	ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	do {
 		ret = boottime->check_event(event_wait);
 	} while (ret == EFI_NOT_READY);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not check event\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
-	efi_st_printf("Counter with TPL level TPL_CALLBACK: %u\n", counter);
-	if (counter != 0) {
+	efi_st_printf("Notification count with TPL level TPL_CALLBACK: %u\n",
+		      notification_count);
+	if (notification_count != 0) {
 		efi_st_error("Suppressed timer fired\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Set 1 ms timer */
 	ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not set timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	/* Restore the old TPL level */
 	boottime->restore_tpl(TPL_APPLICATION);
 	ret = boottime->wait_for_event(1, &event_wait, &index);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not wait for event\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
-	efi_st_printf("Counter with TPL level TPL_APPLICATION: %u\n", counter);
-	if (counter < 1) {
+	efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n",
+		      notification_count);
+	if (notification_count < 1) {
 		efi_st_error("Queued timer event did not fire\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 	ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0);
-	if (index != 0) {
+	if (ret != EFI_SUCCESS) {
 		efi_st_error("Could not cancel timer\n");
-		return 1;
+		return EFI_ST_FAILURE;
 	}
 
-	return 0;
+	return EFI_ST_SUCCESS;
 }
 
 EFI_UNIT_TEST(tpl) = {

+ 25 - 0
lib/efi_selftest/efi_selftest_util.c

@@ -0,0 +1,25 @@
+/*
+ * efi_selftest_util
+ *
+ * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Utility functions
+ */
+
+#include <efi_selftest.h>
+
+int efi_st_memcmp(const void *buf1, const void *buf2, size_t length)
+{
+	const u8 *pos1 = buf1;
+	const u8 *pos2 = buf2;
+
+	for (; length; --length) {
+		if (*pos1 != *pos2)
+			return *pos1 - *pos2;
+		++pos1;
+		++pos2;
+	}
+	return EFI_ST_SUCCESS;
+}

Some files were not shown because too many files changed in this diff