diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/efi_loader/Makefile | 12 | ||||
| -rw-r--r-- | lib/efi_loader/dtbdump.c (renamed from lib/efi_selftest/dtbdump.c) | 0 | ||||
| -rw-r--r-- | lib/efi_loader/efi_boottime.c | 22 | ||||
| -rw-r--r-- | lib/efi_loader/efi_capsule.c | 13 | ||||
| -rw-r--r-- | lib/efi_loader/efi_device_path.c | 138 | ||||
| -rw-r--r-- | lib/efi_loader/efi_disk.c | 31 | ||||
| -rw-r--r-- | lib/efi_loader/efi_variable_tee.c | 31 | ||||
| -rw-r--r-- | lib/efi_loader/initrddump.c (renamed from lib/efi_selftest/initrddump.c) | 93 | ||||
| -rw-r--r-- | lib/efi_selftest/Makefile | 12 | 
9 files changed, 215 insertions, 137 deletions
| diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index b2c664d108b..befed7144e7 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -14,12 +14,24 @@ CFLAGS_efi_boottime.o += \    -DFW_PATCHLEVEL="0x$(PATCHLEVEL)"  CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding  CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI) +CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI) +CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI)  ifneq ($(CONFIG_CMD_BOOTEFI_HELLO_COMPILE),)  always += helloworld.efi  targets += helloworld.o  endif +ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) +always += dtbdump.efi +endif + +ifdef CONFIG_EFI_LOAD_FILE2_INITRD +always += initrddump.efi +endif +  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o  obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o  obj-y += efi_boottime.o diff --git a/lib/efi_selftest/dtbdump.c b/lib/efi_loader/dtbdump.c index 3ce2a07f9eb..3ce2a07f9eb 100644 --- a/lib/efi_selftest/dtbdump.c +++ b/lib/efi_loader/dtbdump.c diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index d0f3e05e708..5bcb8253edb 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1750,7 +1750,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,  	info->system_table = &systab;  	if (device_path) { -		info->device_handle = efi_dp_find_obj(device_path, NULL); +		info->device_handle = efi_dp_find_obj(device_path, NULL, NULL);  		dp = efi_dp_append(device_path, file_path);  		if (!dp) { @@ -1940,7 +1940,7 @@ efi_status_t efi_load_image_from_path(bool boot_policy,  {  	efi_handle_t device;  	efi_status_t ret; -	struct efi_device_path *dp; +	struct efi_device_path *dp, *rem;  	struct efi_load_file_protocol *load_file_protocol = NULL;  	efi_uintn_t buffer_size;  	uint64_t addr, pages; @@ -1951,18 +1951,18 @@ efi_status_t efi_load_image_from_path(bool boot_policy,  	*size = 0;  	dp = file_path; -	ret = EFI_CALL(efi_locate_device_path( -		       &efi_simple_file_system_protocol_guid, &dp, &device)); +	device = efi_dp_find_obj(dp, NULL, &rem); +	ret = efi_search_protocol(device, &efi_simple_file_system_protocol_guid, +				  NULL);  	if (ret == EFI_SUCCESS)  		return efi_load_image_from_file(file_path, buffer, size); -	ret = EFI_CALL(efi_locate_device_path( -		       &efi_guid_load_file_protocol, &dp, &device)); +	ret = efi_search_protocol(device, &efi_guid_load_file_protocol, NULL);  	if (ret == EFI_SUCCESS) {  		guid = &efi_guid_load_file_protocol;  	} else if (!boot_policy) {  		guid = &efi_guid_load_file2_protocol; -		ret = EFI_CALL(efi_locate_device_path(guid, &dp, &device)); +		ret = efi_search_protocol(device, guid, NULL);  	}  	if (ret != EFI_SUCCESS)  		return EFI_NOT_FOUND; @@ -1971,9 +1971,9 @@ efi_status_t efi_load_image_from_path(bool boot_policy,  	if (ret != EFI_SUCCESS)  		return EFI_NOT_FOUND;  	buffer_size = 0; -	ret = load_file_protocol->load_file(load_file_protocol, dp, -					    boot_policy, &buffer_size, -					    NULL); +	ret = EFI_CALL(load_file_protocol->load_file( +					load_file_protocol, rem, boot_policy, +					&buffer_size, NULL));  	if (ret != EFI_BUFFER_TOO_SMALL)  		goto out;  	pages = efi_size_in_pages(buffer_size); @@ -1984,7 +1984,7 @@ efi_status_t efi_load_image_from_path(bool boot_policy,  		goto out;  	}  	ret = EFI_CALL(load_file_protocol->load_file( -					load_file_protocol, dp, boot_policy, +					load_file_protocol, rem, boot_policy,  					&buffer_size, (void *)(uintptr_t)addr));  	if (ret != EFI_SUCCESS)  		efi_free_pages(addr, pages); diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index 613b531b825..f00440163d4 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -669,22 +669,29 @@ static efi_status_t get_dp_device(u16 *boot_var,  /**   * device_is_present_and_system_part - check if a device exists - * @dp		Device path   *   * Check if a device pointed to by the device path, @dp, exists and is   * located in UEFI system partition.   * + * @dp		device path   * Return:	true - yes, false - no   */  static bool device_is_present_and_system_part(struct efi_device_path *dp)  {  	efi_handle_t handle; +	struct efi_device_path *rem; -	handle = efi_dp_find_obj(dp, NULL); +	/* Check device exists */ +	handle = efi_dp_find_obj(dp, NULL, NULL);  	if (!handle)  		return false; -	return efi_disk_is_system_part(handle); +	/* Check device is on system partition */ +	handle = efi_dp_find_obj(dp, &efi_system_partition_guid, &rem); +	if (!handle) +		return false; + +	return true;  }  /** diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index dc787b4d3dd..0542aaae16c 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -122,20 +122,25 @@ int efi_dp_match(const struct efi_device_path *a,  	}  } -/* +/** + * efi_dp_shorten() - shorten device-path + *   * We can have device paths that start with a USB WWID or a USB Class node,   * and a few other cases which don't encode the full device path with bus   * hierarchy:   * - *   - MESSAGING:USB_WWID - *   - MESSAGING:USB_CLASS - *   - MEDIA:FILE_PATH - *   - MEDIA:HARD_DRIVE - *   - MESSAGING:URI + * * MESSAGING:USB_WWID + * * MESSAGING:USB_CLASS + * * MEDIA:FILE_PATH + * * MEDIA:HARD_DRIVE + * * MESSAGING:URI   *   * See UEFI spec (section 3.1.2, about short-form device-paths) + * + * @dp:		original device-path + * @Return:	shortened device-path or NULL   */ -static struct efi_device_path *shorten_path(struct efi_device_path *dp) +struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)  {  	while (dp) {  		/* @@ -154,69 +159,90 @@ static struct efi_device_path *shorten_path(struct efi_device_path *dp)  	return dp;  } -static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path, -				   struct efi_device_path **rem) +/** + * find_handle() - find handle by device path and installed protocol + * + * If @rem is provided, the handle with the longest partial match is returned. + * + * @dp:		device path to search + * @guid:	GUID of protocol that must be installed on path or NULL + * @short_path:	use short form device path for matching + * @rem:	pointer to receive remaining device path + * Return:	matching handle + */ +static efi_handle_t find_handle(struct efi_device_path *dp, +				const efi_guid_t *guid, bool short_path, +				struct efi_device_path **rem)  { -	struct efi_object *efiobj; -	efi_uintn_t dp_size = efi_dp_instance_size(dp); +	efi_handle_t handle, best_handle = NULL; +	efi_uintn_t len, best_len = 0; + +	len = efi_dp_instance_size(dp); -	list_for_each_entry(efiobj, &efi_obj_list, link) { +	list_for_each_entry(handle, &efi_obj_list, link) {  		struct efi_handler *handler; -		struct efi_device_path *obj_dp; +		struct efi_device_path *dp_current; +		efi_uintn_t len_current;  		efi_status_t ret; -		ret = efi_search_protocol(efiobj, -					  &efi_guid_device_path, &handler); +		if (guid) { +			ret = efi_search_protocol(handle, guid, &handler); +			if (ret != EFI_SUCCESS) +				continue; +		} +		ret = efi_search_protocol(handle, &efi_guid_device_path, +					  &handler);  		if (ret != EFI_SUCCESS)  			continue; -		obj_dp = handler->protocol_interface; - -		do { -			if (efi_dp_match(dp, obj_dp) == 0) { -				if (rem) { -					/* -					 * Allow partial matches, but inform -					 * the caller. -					 */ -					*rem = ((void *)dp) + -						efi_dp_instance_size(obj_dp); -					return efiobj; -				} else { -					/* Only return on exact matches */ -					if (efi_dp_instance_size(obj_dp) == -					    dp_size) -						return efiobj; -				} -			} - -			obj_dp = shorten_path(efi_dp_next(obj_dp)); -		} while (short_path && obj_dp); +		dp_current = handler->protocol_interface; +		if (short_path) { +			dp_current = efi_dp_shorten(dp_current); +			if (!dp_current) +				continue; +		} +		len_current = efi_dp_instance_size(dp_current); +		if (rem) { +			if (len_current > len) +				continue; +		} else { +			if (len_current != len) +				continue; +		} +		if (memcmp(dp_current, dp, len_current)) +			continue; +		if (!rem) +			return handle; +		if (len_current > best_len) { +			best_len = len_current; +			best_handle = handle; +			*rem = (void*)((u8 *)dp + len_current); +		}  	} - -	return NULL; +	return best_handle;  } -/* - * Find an efiobj from device-path, if 'rem' is not NULL, returns the - * remaining part of the device path after the matched object. +/** + * efi_dp_find_obj() - find handle by device path + * + * If @rem is provided, the handle with the longest partial match is returned. + * + * @dp:		device path to search + * @guid:	GUID of protocol that must be installed on path or NULL + * @rem:	pointer to receive remaining device path + * Return:	matching handle   */ -struct efi_object *efi_dp_find_obj(struct efi_device_path *dp, -				   struct efi_device_path **rem) +efi_handle_t efi_dp_find_obj(struct efi_device_path *dp, +			     const efi_guid_t *guid, +			     struct efi_device_path **rem)  { -	struct efi_object *efiobj; - -	/* Search for an exact match first */ -	efiobj = find_obj(dp, false, NULL); - -	/* Then for a fuzzy match */ -	if (!efiobj) -		efiobj = find_obj(dp, false, rem); +	efi_handle_t handle; -	/* And now for a fuzzy short match */ -	if (!efiobj) -		efiobj = find_obj(dp, true, rem); +	handle = find_handle(dp, guid, false, rem); +	if (!handle) +		/* Match short form device path */ +		handle = find_handle(dp, guid, true, rem); -	return efiobj; +	return handle;  }  /* diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 45127d17686..c905c12abc2 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -302,7 +302,7 @@ efi_fs_from_path(struct efi_device_path *full_path)  	efi_free_pool(file_path);  	/* Get the EFI object for the partition */ -	efiobj = efi_dp_find_obj(device_path, NULL); +	efiobj = efi_dp_find_obj(device_path, NULL, NULL);  	efi_free_pool(device_path);  	if (!efiobj)  		return NULL; @@ -587,32 +587,3 @@ efi_status_t efi_disk_register(void)  	return EFI_SUCCESS;  } - -/** - * efi_disk_is_system_part() - check if handle refers to an EFI system partition - * - * @handle:	handle of partition - * - * Return:	true if handle refers to an EFI system partition - */ -bool efi_disk_is_system_part(efi_handle_t handle) -{ -	struct efi_handler *handler; -	struct efi_disk_obj *diskobj; -	struct disk_partition info; -	efi_status_t ret; -	int r; - -	/* check if this is a block device */ -	ret = efi_search_protocol(handle, &efi_block_io_guid, &handler); -	if (ret != EFI_SUCCESS) -		return false; - -	diskobj = container_of(handle, struct efi_disk_obj, header); - -	r = part_get_info(diskobj->desc, diskobj->part, &info); -	if (r) -		return false; - -	return !!(info.bootable & PART_EFI_SYSTEM_PARTITION); -} diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index 58931c4efd7..dfef18435df 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -368,7 +368,7 @@ efi_status_t efi_get_variable_int(const u16 *variable_name,  	efi_uintn_t name_size;  	efi_uintn_t tmp_dsize;  	u8 *comm_buf = NULL; -	efi_status_t ret; +	efi_status_t ret, tmp;  	if (!variable_name || !vendor || !data_size) {  		ret = EFI_INVALID_PARAMETER; @@ -407,23 +407,32 @@ efi_status_t efi_get_variable_int(const u16 *variable_name,  	/* Communicate */  	ret = mm_communicate(comm_buf, payload_size); -	if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { -		/* Update with reported data size for trimmed case */ -		*data_size = var_acc->data_size; -	} -	if (ret != EFI_SUCCESS) -		goto out; - -	ret = get_property_int(variable_name, name_size, vendor, &var_property); -	if (ret != EFI_SUCCESS) +	if (ret != EFI_SUCCESS && ret != EFI_BUFFER_TOO_SMALL)  		goto out; +	/* Update with reported data size for trimmed case */ +	*data_size = var_acc->data_size; +	/* +	 * UEFI > 2.7 needs the attributes set even if the buffer is +	 * smaller +	 */  	if (attributes) { +		tmp = get_property_int(variable_name, name_size, vendor, +				       &var_property); +		if (tmp != EFI_SUCCESS) { +			ret = tmp; +			goto out; +		}  		*attributes = var_acc->attr; -		if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) +		if (var_property.property & +		    VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)  			*attributes |= EFI_VARIABLE_READ_ONLY;  	} +	/* return if ret is EFI_BUFFER_TOO_SMALL */ +	if (ret != EFI_SUCCESS) +		goto out; +  	if (data)  		memcpy(data, (u8 *)var_acc->name + var_acc->name_size,  		       var_acc->data_size); diff --git a/lib/efi_selftest/initrddump.c b/lib/efi_loader/initrddump.c index 4648d54b136..98721069816 100644 --- a/lib/efi_selftest/initrddump.c +++ b/lib/efi_loader/initrddump.c @@ -4,6 +4,9 @@   *   * initrddump.efi saves the initial RAM disk provided via the   * EFI_LOAD_FILE2_PROTOCOL. + * + * Specifying 'nocolor' as load option data suppresses colored output and + * clearing of the screen.   */  #include <common.h> @@ -25,6 +28,7 @@ static const efi_guid_t guid_simple_file_system_protocol =  					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;  static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;  static efi_handle_t handle; +static bool nocolor;  /*   * Device path defined by Linux to identify the handle providing the @@ -47,6 +51,17 @@ static const struct efi_initrd_dp initrd_dp = {  };  /** + * color() - set foreground color + * + * @color:	foreground color + */ +static void color(u8 color) +{ +	if (!nocolor) +		cout->set_attribute(cout, color | EFI_BACKGROUND_BLACK); +} + +/**   * print() - print string   *   * @string:	text @@ -57,15 +72,26 @@ static void print(u16 *string)  }  /** + * cls() - clear screen + */ +static void cls(void) +{ +	if (nocolor) +		print(u"\r\n"); +	else +		cout->clear_screen(cout); +} + +/**   * error() - print error string   *   * @string:	error text   */  static void error(u16 *string)  { -	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK); +	color(EFI_LIGHTRED);  	print(string); -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); +	color(EFI_LIGHTBLUE);  }  /* @@ -95,6 +121,14 @@ static void printx(u64 val, u32 prec)  }  /** + * efi_drain_input() - drain console input + */ +static void efi_drain_input(void) +{ +	cin->reset(cin, true); +} + +/**   * efi_input_yn() - get answer to yes/no question   *   * Return: @@ -111,8 +145,6 @@ static efi_status_t efi_input_yn(void)  	efi_uintn_t index;  	efi_status_t ret; -	/* Drain the console input */ -	ret = cin->reset(cin, true);  	for (;;) {  		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);  		if (ret != EFI_SUCCESS) @@ -153,8 +185,6 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)  	u16 outbuf[2] = u" ";  	efi_status_t ret; -	/* Drain the console input */ -	ret = cin->reset(cin, true);  	*buffer = 0;  	for (;;) {  		ret = bs->wait_for_event(1, &cin->wait_for_key, &index); @@ -215,10 +245,13 @@ static u16 *skip_whitespace(u16 *pos)   *   * @string:	string to search for keyword   * @keyword:	keyword to be searched - * Return:	true fi @string starts with the keyword + * Return:	true if @string starts with the keyword   */  static bool starts_with(u16 *string, u16 *keyword)  { +	if (!string || !keyword) +		return false; +  	for (; *keyword; ++string, ++keyword) {  		if (*string != *keyword)  			return false; @@ -364,6 +397,7 @@ static efi_status_t do_save(u16 *filename)  	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);  	if (ret == EFI_SUCCESS) {  		file->close(file); +		efi_drain_input();  		print(u"Overwrite existing file (y/n)? ");  		ret = efi_input_yn();  		print(u"\r\n"); @@ -401,6 +435,30 @@ out:  }  /** + * get_load_options() - get load options + * + * Return:	load options or NULL + */ +u16 *get_load_options(void) +{ +	efi_status_t ret; +	struct efi_loaded_image *loaded_image; + +	ret = bs->open_protocol(handle, &loaded_image_guid, +				(void **)&loaded_image, NULL, NULL, +				EFI_OPEN_PROTOCOL_GET_PROTOCOL); +	if (ret != EFI_SUCCESS) { +		error(u"Loaded image protocol not found\r\n"); +		return NULL; +	} + +	if (!loaded_image->load_options_size || !loaded_image->load_options) +		return NULL; + +	return loaded_image->load_options; +} + +/**   * efi_main() - entry point of the EFI application.   *   * @handle:	handle of the loaded image @@ -410,24 +468,30 @@ out:  efi_status_t EFIAPI efi_main(efi_handle_t image_handle,  			     struct efi_system_table *systab)  { +	u16 *load_options; +  	handle = image_handle;  	systable = systab;  	cerr = systable->std_err;  	cout = systable->con_out;  	cin = systable->con_in;  	bs = systable->boottime; +	load_options = get_load_options(); -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); -	cout->clear_screen(cout); -	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK); -	print(u"INITRD Dump\r\n========\r\n\r\n"); -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); +	if (starts_with(load_options, u"nocolor")) +		nocolor = true; + +	color(EFI_WHITE); +	cls(); +	print(u"INITRD Dump\r\n===========\r\n\r\n"); +	color(EFI_LIGHTBLUE);  	for (;;) {  		u16 command[BUFFER_SIZE];  		u16 *pos;  		efi_uintn_t ret; +		efi_drain_input();  		print(u"=> ");  		ret = efi_input(command, sizeof(command));  		if (ret == EFI_ABORTED) @@ -443,7 +507,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle,  			do_help();  	} -	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK); -	cout->clear_screen(cout); +	color(EFI_LIGHTGRAY); +	cls(); +  	return EFI_SUCCESS;  } diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 9ff6e1760c6..be8040d1c7e 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -8,16 +8,12 @@  asflags-y += -DHOST_ARCH="$(HOST_ARCH)"  ccflags-y += -DHOST_ARCH="$(HOST_ARCH)" -CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding -CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI)  CFLAGS_efi_selftest_miniapp_exception.o := $(CFLAGS_EFI) -Os -ffreestanding  CFLAGS_REMOVE_efi_selftest_miniapp_exception.o := $(CFLAGS_NON_EFI)  CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding  CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI)  CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding  CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding -CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI)  obj-y += \  efi_selftest.o \ @@ -83,14 +79,6 @@ efi_selftest_miniapp_exception.efi \  efi_selftest_miniapp_exit.efi \  efi_selftest_miniapp_return.efi -ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) -always += dtbdump.efi -endif - -ifdef CONFIG_EFI_LOAD_FILE2_INITRD -always += initrddump.efi -endif -  $(obj)/efi_miniapp_file_image_exception.h: $(obj)/efi_selftest_miniapp_exception.efi  	$(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exception.efi > \  	$(obj)/efi_miniapp_file_image_exception.h | 
