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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJZ4HqlAAoJECszeR4D/txgZ0YQAIwd158lVczf/cMnzf3UcIsH e4YUFvQJaGxJw5hccaewaEQJqtPhEEJuHnzc683XDoYISTgvzCyhNEs8o0f7LcX3 41c50x2bQPz7oFO5N60m58RknHqKiGd5VAC6+r4vBM8C0zFHeNTULo4fzn1qRgb3 YUHDiRMlToVZXCOkbCeFm+dEJvjkXWmDDDdJpFIgDs6Oj+jOuV+H1GRMF2d56V6r Dd4/QPAFl4sRprBAMlvsmuI7obwnGV7/aA4CHIlUqKOVcbddBq2KigX8ZpIYEpaf FhRfxRLuWqvDRKpn+ixKfgl4KiBE/CH7sg7F6Un0mIjQVvo8k22Jbetqi9m1j/+x YzIFnwzb9ZhQEFOmfHnH8M9+bMmHyW46wkS4gdO4OAd/W0SeyIZ0a0gB1prgb2LK RfYQ37WsZM5TRARlcvmJt4H5+EtRYLT8lLf+yPSuyX8/8ubVnYHWtVE1IMLCiCAG eVmTwfjLzo3c703RJd9rwDtE13lTQmIHczM4cWybQzooXA6ePLJpSZSWx7EJxdQq GC7jNIKyKpu2NjhM9fUssbU+SiYLaIvtUBSOlGrcP1TCVR/j8OQ0Y1eIc9xOprIi +VEZVB/Z59D8j2TMTn1Xr+hB9i5h9ZxcO88gdEwfs65uihfvJGVhV1AxTyiaxvNv novPhik2UyHG5buRHb2Y =PiNi -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
f855a7bc12
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
Load Diff
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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++;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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) = {
|
||||
|
@ -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 *)¬ification_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
lib/efi_selftest/efi_selftest_snp.c
Normal file
431
lib/efi_selftest/efi_selftest_snp.c
Normal file
@ -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,
|
||||
};
|
@ -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 *)¬ification_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
lib/efi_selftest/efi_selftest_util.c
Normal file
25
lib/efi_selftest/efi_selftest_util.c
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user