提交 1d63ec3f 编写于 作者: T Tom Rini

Merge tag 'efi-2019-07-rc1' of git://git.denx.de/u-boot-efi

Pull request for UEFI sub-system for v2019.07-rc1

The patch series adds support for the BootNext and BootCurrent variables.

The rest is mostly bug fixes. With the bug fixes in place it becomes
possible to use the EFI Shell `edit` command.

A new unit test is supplied to check the image base and size fields of the
loaded image protocol.

An inline check when freeing memory from the pool safeguards against double
frees.
......@@ -333,6 +333,10 @@ struct efi_system_table {
EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \
0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
#define LOADED_IMAGE_DEVICE_PATH_GUID \
EFI_GUID(0xbc62157e, 0x3e33, 0x4fec, \
0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf)
#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000
struct efi_loaded_image {
......
......@@ -135,6 +135,7 @@ extern const efi_guid_t efi_guid_event_group_reset_system;
/* GUID of the device tree table */
extern const efi_guid_t efi_guid_fdt;
extern const efi_guid_t efi_guid_loaded_image;
extern const efi_guid_t efi_guid_loaded_image_device_path;
extern const efi_guid_t efi_guid_device_path_to_text_protocol;
extern const efi_guid_t efi_simple_file_system_protocol_guid;
extern const efi_guid_t efi_file_info_guid;
......@@ -203,15 +204,11 @@ struct efi_object {
* struct efi_loaded_image_obj - handle of a loaded image
*
* @header: EFI object header
* @reloc_base: base address for the relocated image
* @reloc_size: size of the relocated image
* @exit_jmp: long jump buffer for returning form started image
* @entry: entry address of the relocated image
*/
struct efi_loaded_image_obj {
struct efi_object header;
void *reloc_base;
aligned_u64 reloc_size;
efi_status_t exit_status;
struct jmp_buf_data exit_jmp;
EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
......@@ -320,10 +317,19 @@ efi_status_t efi_create_handle(efi_handle_t *handle);
void efi_delete_handle(efi_handle_t obj);
/* Call this to validate a handle and find the EFI object for it */
struct efi_object *efi_search_obj(const efi_handle_t handle);
/* Load image */
efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_handle_t parent_image,
struct efi_device_path *file_path,
void *source_buffer,
efi_uintn_t source_size,
efi_handle_t *image_handle);
/* Start image */
efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
efi_uintn_t *exit_data_size,
u16 **exit_data);
/* Unload image */
efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle);
/* Find a protocol on a handle */
efi_status_t efi_search_protocol(const efi_handle_t handle,
const efi_guid_t *protocol_guid,
......
......@@ -141,6 +141,7 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
efi_deserialize_load_option(&lo, load_option);
if (lo.attributes & LOAD_OPTION_ACTIVE) {
u32 attributes;
efi_status_t ret;
debug("%s: trying to load \"%ls\" from %pD\n",
......@@ -151,6 +152,16 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
if (ret != EFI_SUCCESS)
goto error;
attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS;
size = sizeof(n);
ret = EFI_CALL(efi_set_variable(
L"BootCurrent",
(efi_guid_t *)&efi_global_variable_guid,
attributes, size, &n));
if (ret != EFI_SUCCESS)
goto error;
printf("Booting: %ls\n", lo.label);
efi_dp_split_file_path(lo.file_path, device_path, file_path);
}
......@@ -162,21 +173,53 @@ error:
}
/*
* Attempt to load, in the order specified by BootOrder EFI variable, the
* available load-options, finding and returning the first one that can
* be loaded successfully.
* Attempt to load from BootNext or in the order specified by BootOrder
* EFI variable, the available load-options, finding and returning
* the first one that can be loaded successfully.
*/
void *efi_bootmgr_load(struct efi_device_path **device_path,
struct efi_device_path **file_path)
{
uint16_t *bootorder;
u16 bootnext, *bootorder;
efi_uintn_t size;
void *image = NULL;
int i, num;
efi_status_t ret;
bs = systab.boottime;
rs = systab.runtime;
/* BootNext */
bootnext = 0;
size = sizeof(bootnext);
ret = EFI_CALL(efi_get_variable(L"BootNext",
(efi_guid_t *)&efi_global_variable_guid,
NULL, &size, &bootnext));
if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
/* BootNext does exist here */
if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16))
printf("BootNext must be 16-bit integer\n");
/* delete BootNext */
ret = EFI_CALL(efi_set_variable(
L"BootNext",
(efi_guid_t *)&efi_global_variable_guid,
0, 0, &bootnext));
/* load BootNext */
if (ret == EFI_SUCCESS) {
if (size == sizeof(u16)) {
image = try_load_entry(bootnext, device_path,
file_path);
if (image)
return image;
}
} else {
printf("Deleting BootNext failed\n");
}
}
/* BootOrder */
bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
if (!bootorder) {
printf("BootOrder not defined\n");
......
......@@ -26,6 +26,9 @@ LIST_HEAD(efi_obj_list);
/* List of all events */
LIST_HEAD(efi_events);
/* Handle of the currently executing image */
static efi_handle_t current_image;
/*
* If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
* we need to do trickery with caches. Since we don't want to break the EFI
......@@ -1519,6 +1522,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
efi_status_t ret;
struct efi_loaded_image *info = NULL;
struct efi_loaded_image_obj *obj = NULL;
struct efi_device_path *dp;
/* In case of EFI_OUT_OF_RESOURCES avoid illegal free by caller. */
*handle_ptr = NULL;
......@@ -1542,15 +1546,19 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
if (device_path) {
info->device_handle = efi_dp_find_obj(device_path, NULL);
/*
* When asking for the device path interface, return
* bootefi_device_path
*/
ret = efi_add_protocol(&obj->header,
&efi_guid_device_path, device_path);
if (ret != EFI_SUCCESS)
dp = efi_dp_append(device_path, file_path);
if (!dp) {
ret = EFI_OUT_OF_RESOURCES;
goto failure;
}
} else {
dp = NULL;
}
ret = efi_add_protocol(&obj->header,
&efi_guid_loaded_image_device_path, dp);
if (ret != EFI_SUCCESS)
goto failure;
/*
* When asking for the loaded_image interface, just
......@@ -1679,18 +1687,19 @@ error:
*
* Return: status code
*/
static efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_handle_t parent_image,
struct efi_device_path *file_path,
void *source_buffer,
efi_uintn_t source_size,
efi_handle_t *image_handle)
efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_handle_t parent_image,
struct efi_device_path *file_path,
void *source_buffer,
efi_uintn_t source_size,
efi_handle_t *image_handle)
{
struct efi_device_path *dp, *fp;
struct efi_loaded_image *info = NULL;
struct efi_loaded_image_obj **image_obj =
(struct efi_loaded_image_obj **)image_handle;
efi_status_t ret;
void *dest_buffer;
EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image,
file_path, source_buffer, source_size, image_handle);
......@@ -1706,7 +1715,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
}
if (!source_buffer) {
ret = efi_load_image_from_path(file_path, &source_buffer,
ret = efi_load_image_from_path(file_path, &dest_buffer,
&source_size);
if (ret != EFI_SUCCESS)
goto error;
......@@ -1719,154 +1728,30 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
/* In this case, file_path is the "device" path, i.e.
* something like a HARDWARE_DEVICE:MEMORY_MAPPED
*/
u64 addr;
void *dest_buffer;
ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
EFI_RUNTIME_SERVICES_CODE,
efi_size_in_pages(source_size), &addr);
if (ret != EFI_SUCCESS)
goto error;
dest_buffer = (void *)(uintptr_t)addr;
memcpy(dest_buffer, source_buffer, source_size);
source_buffer = dest_buffer;
dest_buffer = source_buffer;
dp = file_path;
fp = NULL;
}
ret = efi_setup_loaded_image(dp, fp, image_obj, &info);
if (ret != EFI_SUCCESS)
goto error_invalid_image;
ret = efi_load_pe(*image_obj, source_buffer, info);
if (ret != EFI_SUCCESS)
goto error_invalid_image;
/* Update the type of the allocated memory */
efi_add_memory_map((uintptr_t)source_buffer,
efi_size_in_pages(source_size),
info->image_code_type, false);
info->system_table = &systab;
info->parent_handle = parent_image;
return EFI_EXIT(EFI_SUCCESS);
error_invalid_image:
/* The image is invalid. Release all associated resources. */
efi_free_pages((uintptr_t)source_buffer,
efi_size_in_pages(source_size));
efi_delete_handle(*image_handle);
*image_handle = NULL;
free(info);
if (ret == EFI_SUCCESS)
ret = efi_load_pe(*image_obj, dest_buffer, info);
if (!source_buffer)
/* Release buffer to which file was loaded */
efi_free_pages((uintptr_t)dest_buffer,
efi_size_in_pages(source_size));
if (ret == EFI_SUCCESS) {
info->system_table = &systab;
info->parent_handle = parent_image;
} else {
/* The image is invalid. Release all associated resources. */
efi_delete_handle(*image_handle);
*image_handle = NULL;
free(info);
}
error:
return EFI_EXIT(ret);
}
/**
* efi_start_image() - call the entry point of an image
* @image_handle: handle of the image
* @exit_data_size: size of the buffer
* @exit_data: buffer to receive the exit data of the called image
*
* This function implements the StartImage service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
efi_uintn_t *exit_data_size,
u16 **exit_data)
{
struct efi_loaded_image_obj *image_obj =
(struct efi_loaded_image_obj *)image_handle;
efi_status_t ret;
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
efi_is_direct_boot = false;
/* call the image! */
if (setjmp(&image_obj->exit_jmp)) {
/*
* We called the entry point of the child image with EFI_CALL
* in the lines below. The child image called the Exit() boot
* service efi_exit() which executed the long jump that brought
* us to the current line. This implies that the second half
* of the EFI_CALL macro has not been executed.
*/
#ifdef CONFIG_ARM
/*
* efi_exit() called efi_restore_gd(). We have to undo this
* otherwise __efi_entry_check() will put the wrong value into
* app_gd.
*/
gd = app_gd;
#endif
/*
* To get ready to call EFI_EXIT below we have to execute the
* missed out steps of EFI_CALL.
*/
assert(__efi_entry_check());
debug("%sEFI: %lu returned by started image\n",
__efi_nesting_dec(),
(unsigned long)((uintptr_t)image_obj->exit_status &
~EFI_ERROR_MASK));
return EFI_EXIT(image_obj->exit_status);
}
ret = EFI_CALL(image_obj->entry(image_handle, &systab));
/*
* Usually UEFI applications call Exit() instead of returning.
* But because the world doesn't consist of ponies and unicorns,
* we're happy to emulate that behavior on behalf of a payload
* that forgot.
*/
return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL));
}
/**
* efi_exit() - leave an EFI application or driver
* @image_handle: handle of the application or driver that is exiting
* @exit_status: status code
* @exit_data_size: size of the buffer in bytes
* @exit_data: buffer with data describing an error
*
* This function implements the Exit service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
efi_status_t exit_status,
efi_uintn_t exit_data_size,
u16 *exit_data)
{
/*
* TODO: We should call the unload procedure of the loaded
* image protocol.
*/
struct efi_loaded_image_obj *image_obj =
(struct efi_loaded_image_obj *)image_handle;
EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status,
exit_data_size, exit_data);
/* Make sure entry/exit counts for EFI world cross-overs match */
EFI_EXIT(exit_status);
/*
* But longjmp out with the U-Boot gd, not the application's, as
* the other end is a setjmp call inside EFI context.
*/
efi_restore_gd();
image_obj->exit_status = exit_status;
longjmp(&image_obj->exit_jmp, 1);
panic("EFI application exited");
}
/**
* efi_unload_image() - unload an EFI image
* @image_handle: handle of the image to be unloaded
......@@ -1878,7 +1763,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
*
* Return: status code
*/
static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
{
struct efi_object *efiobj;
......@@ -2734,6 +2619,139 @@ out:
return EFI_EXIT(r);
}
/**
* efi_start_image() - call the entry point of an image
* @image_handle: handle of the image
* @exit_data_size: size of the buffer
* @exit_data: buffer to receive the exit data of the called image
*
* This function implements the StartImage service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
efi_uintn_t *exit_data_size,
u16 **exit_data)
{
struct efi_loaded_image_obj *image_obj =
(struct efi_loaded_image_obj *)image_handle;
efi_status_t ret;
void *info;
efi_handle_t parent_image = current_image;
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
/* Check parameters */
ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image,
&info, NULL, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL));
if (ret != EFI_SUCCESS)
return EFI_EXIT(EFI_INVALID_PARAMETER);
efi_is_direct_boot = false;
/* call the image! */
if (setjmp(&image_obj->exit_jmp)) {
/*
* We called the entry point of the child image with EFI_CALL
* in the lines below. The child image called the Exit() boot
* service efi_exit() which executed the long jump that brought
* us to the current line. This implies that the second half
* of the EFI_CALL macro has not been executed.
*/
#ifdef CONFIG_ARM
/*
* efi_exit() called efi_restore_gd(). We have to undo this
* otherwise __efi_entry_check() will put the wrong value into
* app_gd.
*/
gd = app_gd;
#endif
/*
* To get ready to call EFI_EXIT below we have to execute the
* missed out steps of EFI_CALL.
*/
assert(__efi_entry_check());
debug("%sEFI: %lu returned by started image\n",
__efi_nesting_dec(),
(unsigned long)((uintptr_t)image_obj->exit_status &
~EFI_ERROR_MASK));
current_image = parent_image;
return EFI_EXIT(image_obj->exit_status);
}
current_image = image_handle;
ret = EFI_CALL(image_obj->entry(image_handle, &systab));
/*
* Usually UEFI applications call Exit() instead of returning.
* But because the world doesn't consist of ponies and unicorns,
* we're happy to emulate that behavior on behalf of a payload
* that forgot.
*/
return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL));
}
/**
* efi_exit() - leave an EFI application or driver
* @image_handle: handle of the application or driver that is exiting
* @exit_status: status code
* @exit_data_size: size of the buffer in bytes
* @exit_data: buffer with data describing an error
*
* This function implements the Exit service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
efi_status_t exit_status,
efi_uintn_t exit_data_size,
u16 *exit_data)
{
/*
* TODO: We should call the unload procedure of the loaded
* image protocol.
*/
efi_status_t ret;
void *info;
struct efi_loaded_image_obj *image_obj =
(struct efi_loaded_image_obj *)image_handle;
EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status,
exit_data_size, exit_data);
/* Check parameters */
if (image_handle != current_image)
goto out;
ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image,
&info, NULL, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL));
if (ret != EFI_SUCCESS)
goto out;
/* Make sure entry/exit counts for EFI world cross-overs match */
EFI_EXIT(exit_status);
/*
* But longjmp out with the U-Boot gd, not the application's, as
* the other end is a setjmp call inside EFI context.
*/
efi_restore_gd();
image_obj->exit_status = exit_status;
longjmp(&image_obj->exit_jmp, 1);
panic("EFI application exited");
out:
return EFI_EXIT(EFI_INVALID_PARAMETER);
}
/**
* efi_handle_protocol() - get interface of a protocol on a handle
* @handle: handle on which the protocol shall be opened
......
......@@ -797,9 +797,26 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
ret = EFI_NOT_READY;
goto out;
}
/*
* CTRL+A - CTRL+Z have to be signaled as a - z.
* SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
*/
switch (next_key.key.unicode_char) {
case 0x01 ... 0x07:
case 0x0b ... 0x0c:
case 0x0e ... 0x1a:
if (!(next_key.key_state.key_toggle_state &
EFI_CAPS_LOCK_ACTIVE) ^
!(next_key.key_state.key_shift_state &
(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
next_key.key.unicode_char += 0x40;
else
next_key.key.unicode_char += 0x60;
}
*key_data = next_key;
key_available = false;
efi_con_in.wait_for_key->is_signaled = false;
out:
return EFI_EXIT(ret);
}
......
......@@ -134,6 +134,25 @@ static int sanitize_path(char *path)
return 0;
}
/**
* efi_create_file() - create file or directory
*
* @fh: file handle
* @attributes: attributes for newly created file
* Returns: 0 for success
*/
static int efi_create_file(struct file_handle *fh, u64 attributes)
{
loff_t actwrite;
void *buffer = &actwrite;
if (attributes & EFI_FILE_DIRECTORY)
return fs_mkdir(fh->path);
else
return fs_write(fh->path, map_to_sysmem(buffer), 0, 0,
&actwrite);
}
/**
* file_open() - open a file handle
*
......@@ -176,6 +195,7 @@ static struct efi_file_handle *file_open(struct file_system *fs,
if (parent) {
char *p = fh->path;
int exists;
if (plen > 0) {
strcpy(p, parent->path);
......@@ -192,18 +212,17 @@ static struct efi_file_handle *file_open(struct file_system *fs,
if (set_blk_dev(fh))
goto error;
if ((mode & EFI_FILE_MODE_CREATE) &&
(attributes & EFI_FILE_DIRECTORY)) {
if (fs_mkdir(fh->path))
goto error;
} else if (!((mode & EFI_FILE_MODE_CREATE) ||
fs_exists(fh->path)))
goto error;
exists = fs_exists(fh->path);
/* fs_exists() calls fs_close(), so open file system again */
if (set_blk_dev(fh))
goto error;
if (!exists) {
if (!(mode & EFI_FILE_MODE_CREATE) ||
efi_create_file(fh, attributes))
goto error;
}
/* figure out if file is a directory: */
fh->isdir = is_dir(fh);
} else {
......@@ -257,10 +276,12 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
/* Open file */
*new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes);
if (*new_handle)
if (*new_handle) {
EFI_PRINT("file handle %p\n", *new_handle);
ret = EFI_SUCCESS;
else
} else {
ret = EFI_NOT_FOUND;
}
out:
return EFI_EXIT(ret);
}
......@@ -616,9 +637,72 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
efi_uintn_t buffer_size,
void *buffer)
{
EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer);
struct file_handle *fh = to_fh(file);
efi_status_t ret = EFI_UNSUPPORTED;
EFI_ENTRY("%p, %pUl, %zu, %p", file, info_type, buffer_size, buffer);
if (!guidcmp(info_type, &efi_file_info_guid)) {
struct efi_file_info *info = (struct efi_file_info *)buffer;
char *filename = basename(fh);
char *new_file_name, *pos;
loff_t file_size;
return EFI_EXIT(EFI_UNSUPPORTED);
if (buffer_size < sizeof(struct efi_file_info)) {
ret = EFI_BAD_BUFFER_SIZE;
goto out;
}
/* We cannot change the directory attribute */
if (!fh->isdir != !(info->attribute & EFI_FILE_DIRECTORY)) {
ret = EFI_ACCESS_DENIED;
goto out;
}
/* Check for renaming */
new_file_name = malloc(utf16_utf8_strlen(info->file_name));
if (!new_file_name) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
pos = new_file_name;
utf16_utf8_strcpy(&pos, info->file_name);
if (strcmp(new_file_name, filename)) {
/* TODO: we do not support renaming */
EFI_PRINT("Renaming not supported\n");
free(new_file_name);
ret = EFI_ACCESS_DENIED;
goto out;
}
free(new_file_name);
/* Check for truncation */
if (set_blk_dev(fh)) {
ret = EFI_DEVICE_ERROR;
goto out;
}
if (fs_size(fh->path, &file_size)) {
ret = EFI_DEVICE_ERROR;
goto out;
}
if (file_size != info->file_size) {
/* TODO: we do not support truncation */
EFI_PRINT("Truncation not supported\n");
ret = EFI_ACCESS_DENIED;
goto out;
}
/*
* We do not care for the other attributes
* TODO: Support read only
*/
ret = EFI_SUCCESS;
} else if (!guidcmp(info_type, &efi_file_system_info_guid)) {
if (buffer_size < sizeof(struct efi_file_system_info)) {
ret = EFI_BAD_BUFFER_SIZE;
goto out;
}
} else {
ret = EFI_UNSUPPORTED;
}
out:
return EFI_EXIT(ret);
}
static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
......
......@@ -14,6 +14,8 @@
const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
const efi_guid_t efi_guid_loaded_image_device_path
= LOADED_IMAGE_DEVICE_PATH_GUID;
const efi_guid_t efi_simple_file_system_protocol_guid =
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
......@@ -59,10 +61,10 @@ static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj,
{
printf("UEFI image");
printf(" [0x%p:0x%p]",
obj->reloc_base, obj->reloc_base + obj->reloc_size - 1);
if (pc && pc >= obj->reloc_base &&
pc < obj->reloc_base + obj->reloc_size)
printf(" pc=0x%zx", pc - obj->reloc_base);
image->image_base, image->image_base + image->image_size - 1);
if (pc && pc >= image->image_base &&
pc < image->image_base + image->image_size)
printf(" pc=0x%zx", pc - image->image_base);
if (image->file_path)
printf(" '%pD'", image->file_path);
printf("\n");
......@@ -227,7 +229,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
unsigned long rel_size;
int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
uint64_t image_base;
uint64_t image_size;
unsigned long virt_size = 0;
int supported = 0;
......@@ -271,7 +272,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
IMAGE_NT_HEADERS64 *nt64 = (void *)nt;
IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader;
image_base = opt->ImageBase;
image_size = opt->SizeOfImage;
efi_set_code_and_data_type(loaded_image_info, opt->Subsystem);
efi_reloc = efi_alloc(virt_size,
loaded_image_info->image_code_type);
......@@ -287,7 +287,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
} else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader;
image_base = opt->ImageBase;
image_size = opt->SizeOfImage;
efi_set_code_and_data_type(loaded_image_info, opt->Subsystem);
efi_reloc = efi_alloc(virt_size,
loaded_image_info->image_code_type);
......@@ -306,6 +305,11 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
return EFI_LOAD_ERROR;
}
/* Copy PE headers */
memcpy(efi_reloc, efi, sizeof(*dos) + sizeof(*nt)
+ nt->FileHeader.SizeOfOptionalHeader
+ num_sections * sizeof(IMAGE_SECTION_HEADER));
/* Load sections into RAM */
for (i = num_sections - 1; i >= 0; i--) {
IMAGE_SECTION_HEADER *sec = &sections[i];
......@@ -330,10 +334,8 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
invalidate_icache_all();
/* Populate the loaded image interface bits */
loaded_image_info->image_base = efi;
loaded_image_info->image_size = image_size;
handle->reloc_base = efi_reloc;
handle->reloc_size = virt_size;
loaded_image_info->image_base = efi_reloc;
loaded_image_info->image_size = virt_size;
return EFI_SUCCESS;
}
......@@ -15,6 +15,9 @@
DECLARE_GLOBAL_DATA_PTR;
/* Magic number identifying memory allocated from pool */
#define EFI_ALLOC_POOL_MAGIC 0x1fe67ddf6491caa2
efi_uintn_t efi_memory_map_key;
struct efi_mem_list {
......@@ -33,7 +36,12 @@ LIST_HEAD(efi_mem);
void *efi_bounce_buffer;
#endif
/*
/**
* efi_pool_allocation - memory block allocated from pool
*
* @num_pages: number of pages allocated
* @checksum: checksum
*
* U-Boot services each EFI AllocatePool request as a separate
* (multiple) page allocation. We have to track the number of pages
* to be able to free the correct amount later.
......@@ -43,9 +51,26 @@ void *efi_bounce_buffer;
*/
struct efi_pool_allocation {
u64 num_pages;
u64 checksum;
char data[] __aligned(ARCH_DMA_MINALIGN);
};
/**
* checksum() - calculate checksum for memory allocated from pool
*
* @alloc: allocation header
* Return: checksum, always non-zero
*/
static u64 checksum(struct efi_pool_allocation *alloc)
{
u64 addr = (uintptr_t)alloc;
u64 ret = (addr >> 32) ^ (addr << 32) ^ alloc->num_pages ^
EFI_ALLOC_POOL_MAGIC;
if (!ret)
++ret;
return ret;
}
/*
* Sorts the memory list from highest address to lowest address
*
......@@ -204,8 +229,8 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
bool carve_again;
uint64_t carved_pages = 0;
debug("%s: 0x%llx 0x%llx %d %s\n", __func__,
start, pages, memory_type, overlap_only_ram ? "yes" : "no");
EFI_PRINT("%s: 0x%llx 0x%llx %d %s\n", __func__,
start, pages, memory_type, overlap_only_ram ? "yes" : "no");
if (memory_type >= EFI_MAX_MEMORY_TYPE)
return EFI_INVALID_PARAMETER;
......@@ -409,17 +434,24 @@ void *efi_alloc(uint64_t len, int memory_type)
return NULL;
}
/*
* Free memory pages.
/**
* efi_free_pages() - free memory pages
*
* @memory start of the memory area to be freed
* @pages number of pages to be freed
* @return status code
* @memory: start of the memory area to be freed
* @pages: number of pages to be freed
* Return: status code
*/
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
{
uint64_t r = 0;
/* Sanity check */
if (!memory || (memory & EFI_PAGE_MASK)) {
printf("%s: illegal free 0x%llx, 0x%zx\n", __func__,
memory, pages);
return EFI_INVALID_PARAMETER;
}
r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
/* Merging of adjacent free regions is missing */
......@@ -429,13 +461,13 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
return EFI_NOT_FOUND;
}
/*
* Allocate memory from pool.
/**
* efi_allocate_pool - allocate memory from pool
*
* @pool_type type of the pool from which memory is to be allocated
* @size number of bytes to be allocated
* @buffer allocated memory
* @return status code
* @pool_type: type of the pool from which memory is to be allocated
* @size: number of bytes to be allocated
* @buffer: allocated memory
* Return: status code
*/
efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer)
{
......@@ -458,17 +490,18 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer)
if (r == EFI_SUCCESS) {
alloc = (struct efi_pool_allocation *)(uintptr_t)addr;
alloc->num_pages = num_pages;
alloc->checksum = checksum(alloc);
*buffer = alloc->data;
}
return r;
}
/*
* Free memory from pool.
/**
* efi_free_pool() - free memory from pool
*
* @buffer start of memory to be freed
* @return status code
* @buffer: start of memory to be freed
* Return: status code
*/
efi_status_t efi_free_pool(void *buffer)
{
......@@ -479,8 +512,15 @@ efi_status_t efi_free_pool(void *buffer)
return EFI_INVALID_PARAMETER;
alloc = container_of(buffer, struct efi_pool_allocation, data);
/* Sanity check, was the supplied address returned by allocate_pool */
assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0);
/* Check that this memory was allocated by efi_allocate_pool() */
if (((uintptr_t)alloc & EFI_PAGE_MASK) ||
alloc->checksum != checksum(alloc)) {
printf("%s: illegal free 0x%p\n", __func__, buffer);
return EFI_INVALID_PARAMETER;
}
/* Avoid double free */
alloc->checksum = 0;
r = efi_free_pages((uintptr_t)alloc, alloc->num_pages);
......
......@@ -10,6 +10,9 @@
#define OBJ_LIST_NOT_INITIALIZED 1
/* Language code for American English according to RFC 4646 */
#define EN_US L"en-US"
static efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED;
/* Initialize and populate EFI object list */
......@@ -24,6 +27,30 @@ efi_status_t efi_init_obj_list(void)
*/
efi_save_gd();
/*
* Variable PlatformLang defines the language that the machine has been
* configured for.
*/
ret = EFI_CALL(efi_set_variable(L"PlatformLang",
&efi_global_variable_guid,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(EN_US), EN_US));
if (ret != EFI_SUCCESS)
goto out;
/*
* Variable PlatformLangCodes defines the language codes that the
* machine can support.
*/
ret = EFI_CALL(efi_set_variable(L"PlatformLangCodes",
&efi_global_variable_guid,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(EN_US), EN_US));
if (ret != EFI_SUCCESS)
goto out;
/* Initialize once only */
if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
return efi_obj_list_initialized;
......
......@@ -180,7 +180,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
if (ret)
return EFI_EXIT(ret);
debug("%s: get '%s'\n", __func__, native_name);
EFI_PRINT("get '%s'\n", native_name);
val = env_get(native_name);
free(native_name);
......@@ -211,7 +211,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
if (hex2bin(data, s, len))
return EFI_EXIT(EFI_DEVICE_ERROR);
debug("%s: got value: \"%s\"\n", __func__, s);
EFI_PRINT("got value: \"%s\"\n", s);
} else if ((s = prefix(val, "(utf8)"))) {
unsigned len = strlen(s) + 1;
......@@ -226,9 +226,9 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
memcpy(data, s, len);
((char *)data)[len] = '\0';
debug("%s: got value: \"%s\"\n", __func__, (char *)data);
EFI_PRINT("got value: \"%s\"\n", (char *)data);
} else {
debug("%s: invalid value: '%s'\n", __func__, val);
EFI_PRINT("invalid value: '%s'\n", val);
return EFI_EXIT(EFI_DEVICE_ERROR);
}
......@@ -485,7 +485,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
s = bin2hex(s, data, data_size);
*s = '\0';
debug("%s: setting: %s=%s\n", __func__, native_name, val);
EFI_PRINT("setting: %s=%s\n", native_name, val);
if (env_set(native_name, val))
ret = EFI_DEVICE_ERROR;
......
......@@ -11,22 +11,70 @@
#include <common.h>
#include <efi_api.h>
/*
static efi_guid_t loaded_image_protocol_guid = LOADED_IMAGE_GUID;
/**
* check_loaded_image_protocol() - check image_base/image_size
*
* Try to open the loaded image protocol. Check that this function is located
* between image_base and image_base + image_size.
*
* @image_handle: handle of the loaded image
* @systable: system table
* @return: status code
*/
static efi_status_t EFIAPI check_loaded_image_protocol
(efi_handle_t image_handle, struct efi_system_table *systable)
{
struct efi_simple_text_output_protocol *cout = systable->con_out;
struct efi_boot_services *boottime = systable->boottime;
struct efi_loaded_image *loaded_image_protocol;
efi_status_t ret;
/*
* Open the loaded image protocol.
*/
ret = boottime->open_protocol
(image_handle, &loaded_image_protocol_guid,
(void **)&loaded_image_protocol, NULL,
NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret != EFI_SUCCESS) {
cout->output_string(cout,
L"Could not open loaded image protocol");
return ret;
}
if ((void *)check_loaded_image_protocol <
loaded_image_protocol->image_base ||
(void *)check_loaded_image_protocol >=
loaded_image_protocol->image_base +
loaded_image_protocol->image_size) {
cout->output_string(cout,
L"Incorrect image_base or image_size\n");
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
* Entry point of the EFI application.
*
* @handle handle of the loaded image
* @systable system table
* @return status code
* @handle: handle of the loaded image
* @systable: system table
* @return: status code
*/
efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
{
struct efi_simple_text_output_protocol *con_out = systable->con_out;
efi_status_t ret = EFI_UNSUPPORTED;
con_out->output_string(con_out, L"EFI application calling Exit\n");
if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS)
ret = EFI_NOT_FOUND;
/* The return value is checked by the calling test */
systable->boottime->exit(handle, EFI_UNSUPPORTED, 0, NULL);
systable->boottime->exit(handle, ret, 0, NULL);
/*
* This statement should not be reached.
......
......@@ -141,7 +141,7 @@ def test_efi_selftest_text_input_ex(u_boot_console):
u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
['Unicode char 4 \(unknown\), scan code 0 \(CTRL\+Null\)'])
['Unicode char 100 \\(\'d\'\\), scan code 0 \\(CTRL\\+Null\\)'])
if m != 0:
raise Exception('EOT failed in \'text input\' test')
u_boot_console.drain_console()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册