xref: /DragonStub/apps/helper.c (revision 2604d7835e66d1fccc0973634b0121c7925e25f6)
1*2604d783SLoGin #include "dragonstub/printk.h"
2f412fd2aSLoGin #include "efidef.h"
3f412fd2aSLoGin #include <efi.h>
4f412fd2aSLoGin #include <efilib.h>
5f412fd2aSLoGin #include <lib.h>
6f412fd2aSLoGin #include <dragonstub/dragonstub.h>
7f412fd2aSLoGin 
878b790faSLoGin bool efi_nochunk;
978b790faSLoGin bool efi_nokaslr = true;
1078b790faSLoGin // bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
11823f0493SLoGin bool efi_novamap = false;
1278b790faSLoGin 
1378b790faSLoGin static bool efi_noinitrd;
1478b790faSLoGin static bool efi_nosoftreserve;
1578b790faSLoGin static bool efi_disable_pci_dma = false;
1678b790faSLoGin // static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
1778b790faSLoGin 
18f412fd2aSLoGin enum efistub_event {
19f412fd2aSLoGin 	EFISTUB_EVT_INITRD,
20f412fd2aSLoGin 	EFISTUB_EVT_LOAD_OPTIONS,
21f412fd2aSLoGin 	EFISTUB_EVT_COUNT,
22f412fd2aSLoGin };
23f412fd2aSLoGin 
24f412fd2aSLoGin #define STR_WITH_SIZE(s) sizeof(s), s
25f412fd2aSLoGin 
26f412fd2aSLoGin static const struct {
27f412fd2aSLoGin 	u32 pcr_index;
28f412fd2aSLoGin 	u32 event_id;
29f412fd2aSLoGin 	u32 event_data_len;
30f412fd2aSLoGin 	u8 event_data[52];
31f412fd2aSLoGin } events[] = {
32f412fd2aSLoGin 	[EFISTUB_EVT_INITRD] = { 9, INITRD_EVENT_TAG_ID,
33f412fd2aSLoGin 				 STR_WITH_SIZE("Linux initrd") },
34f412fd2aSLoGin 	[EFISTUB_EVT_LOAD_OPTIONS] = { 9, LOAD_OPTIONS_EVENT_TAG_ID,
35f412fd2aSLoGin 				       STR_WITH_SIZE(
36f412fd2aSLoGin 					       "LOADED_IMAGE::LoadOptions") },
37f412fd2aSLoGin };
38f412fd2aSLoGin 
39f412fd2aSLoGin static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
40f412fd2aSLoGin 					     unsigned long load_size,
41f412fd2aSLoGin 					     enum efistub_event event)
42f412fd2aSLoGin {
43f412fd2aSLoGin 	efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
44f412fd2aSLoGin 	efi_tcg2_protocol_t *tcg2 = NULL;
45f412fd2aSLoGin 	efi_status_t status;
46f412fd2aSLoGin 
47f412fd2aSLoGin 	efi_bs_call(LocateProtocol, &tcg2_guid, NULL, (void **)&tcg2);
48f412fd2aSLoGin 	if (tcg2) {
49f412fd2aSLoGin 		struct efi_measured_event {
50f412fd2aSLoGin 			efi_tcg2_event_t event_data;
51f412fd2aSLoGin 			efi_tcg2_tagged_event_t tagged_event;
52f412fd2aSLoGin 			u8 tagged_event_data[];
53f412fd2aSLoGin 		} * evt;
54f412fd2aSLoGin 		int size = sizeof(*evt) + events[event].event_data_len;
55f412fd2aSLoGin 
56f412fd2aSLoGin 		status = efi_bs_call(AllocatePool, EfiLoaderData, size,
57f412fd2aSLoGin 				     (void **)&evt);
58f412fd2aSLoGin 		if (status != EFI_SUCCESS)
59f412fd2aSLoGin 			goto fail;
60f412fd2aSLoGin 
61f412fd2aSLoGin 		evt->event_data = (struct efi_tcg2_event){
62f412fd2aSLoGin 			.event_size = size,
63f412fd2aSLoGin 			.event_header.header_size =
64f412fd2aSLoGin 				sizeof(evt->event_data.event_header),
65f412fd2aSLoGin 			.event_header.header_version =
66f412fd2aSLoGin 				EFI_TCG2_EVENT_HEADER_VERSION,
67f412fd2aSLoGin 			.event_header.pcr_index = events[event].pcr_index,
68f412fd2aSLoGin 			.event_header.event_type = EV_EVENT_TAG,
69f412fd2aSLoGin 		};
70f412fd2aSLoGin 
71f412fd2aSLoGin 		evt->tagged_event = (struct efi_tcg2_tagged_event){
72f412fd2aSLoGin 			.tagged_event_id = events[event].event_id,
73f412fd2aSLoGin 			.tagged_event_data_size = events[event].event_data_len,
74f412fd2aSLoGin 		};
75f412fd2aSLoGin 
76f412fd2aSLoGin 		memcpy(evt->tagged_event_data, events[event].event_data,
77f412fd2aSLoGin 		       events[event].event_data_len);
78f412fd2aSLoGin 
79f412fd2aSLoGin 		status = efi_call_proto(tcg2, hash_log_extend_event, 0,
80f412fd2aSLoGin 					load_addr, load_size, &evt->event_data);
81f412fd2aSLoGin 		efi_bs_call(FreePool, evt);
82f412fd2aSLoGin 
83f412fd2aSLoGin 		if (status != EFI_SUCCESS)
84f412fd2aSLoGin 			goto fail;
85f412fd2aSLoGin 		return EFI_SUCCESS;
86f412fd2aSLoGin 	}
87f412fd2aSLoGin 
88f412fd2aSLoGin 	return EFI_UNSUPPORTED;
89f412fd2aSLoGin fail:
90f412fd2aSLoGin 	efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status);
91f412fd2aSLoGin 	return status;
92f412fd2aSLoGin }
93f412fd2aSLoGin 
94f412fd2aSLoGin /*
95f412fd2aSLoGin  * At least some versions of Dell firmware pass the entire contents of the
96f412fd2aSLoGin  * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the
97f412fd2aSLoGin  * OptionalData field.
98f412fd2aSLoGin  *
99f412fd2aSLoGin  * Detect this case and extract OptionalData.
100f412fd2aSLoGin  */
101f412fd2aSLoGin void efi_apply_loadoptions_quirk(const void **load_options,
102f412fd2aSLoGin 				 u32 *load_options_size)
103f412fd2aSLoGin {
104f412fd2aSLoGin #ifndef CONFIG_X86
105f412fd2aSLoGin 	return;
106f412fd2aSLoGin #else
107f412fd2aSLoGin 	const efi_load_option_t *load_option = *load_options;
108f412fd2aSLoGin 	efi_load_option_unpacked_t load_option_unpacked;
109f412fd2aSLoGin 	if (!load_option)
110f412fd2aSLoGin 		return;
111f412fd2aSLoGin 	if (*load_options_size < sizeof(*load_option))
112f412fd2aSLoGin 		return;
113f412fd2aSLoGin 	if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
114f412fd2aSLoGin 		return;
115f412fd2aSLoGin 
116f412fd2aSLoGin 	if (!efi_load_option_unpack(&load_option_unpacked, load_option,
117f412fd2aSLoGin 				    *load_options_size))
118f412fd2aSLoGin 		return;
119f412fd2aSLoGin 
120f412fd2aSLoGin 	efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n");
121f412fd2aSLoGin 	efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
122f412fd2aSLoGin 
123f412fd2aSLoGin 	*load_options = load_option_unpacked.optional_data;
124f412fd2aSLoGin 	*load_options_size = load_option_unpacked.optional_data_size;
125f412fd2aSLoGin #endif
126f412fd2aSLoGin }
127f412fd2aSLoGin 
128f412fd2aSLoGin /*
129f412fd2aSLoGin  * Convert the unicode UEFI command line to ASCII to pass to kernel.
130f412fd2aSLoGin  * Size of memory allocated return in *cmd_line_len.
131f412fd2aSLoGin  * Returns NULL on error.
132f412fd2aSLoGin  */
133f412fd2aSLoGin char *efi_convert_cmdline(EFI_LOADED_IMAGE *image, int *cmd_line_len)
134f412fd2aSLoGin {
135f412fd2aSLoGin 	const efi_char16_t *options = efi_table_attr(image, LoadOptions);
136f412fd2aSLoGin 	u32 options_size = efi_table_attr(image, LoadOptionsSize);
137f412fd2aSLoGin 	int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
138f412fd2aSLoGin 	unsigned long cmdline_addr = 0;
139f412fd2aSLoGin 	const efi_char16_t *s2;
140f412fd2aSLoGin 	bool in_quote = false;
141f412fd2aSLoGin 	efi_status_t status;
142f412fd2aSLoGin 	u32 options_chars;
143f412fd2aSLoGin 
144f412fd2aSLoGin 	if (options_size > 0)
145f412fd2aSLoGin 		efi_measure_tagged_event((unsigned long)options, options_size,
146f412fd2aSLoGin 					 EFISTUB_EVT_LOAD_OPTIONS);
147f412fd2aSLoGin 
148f412fd2aSLoGin 	efi_apply_loadoptions_quirk((const void **)&options, &options_size);
149f412fd2aSLoGin 	options_chars = options_size / sizeof(efi_char16_t);
150f412fd2aSLoGin 
151f412fd2aSLoGin 	if (options) {
152f412fd2aSLoGin 		s2 = options;
153f412fd2aSLoGin 		while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
154f412fd2aSLoGin 			efi_char16_t c = *s2++;
155f412fd2aSLoGin 
156f412fd2aSLoGin 			if (c < 0x80) {
157f412fd2aSLoGin 				if (c == L'\0' || c == L'\n')
158f412fd2aSLoGin 					break;
159f412fd2aSLoGin 				if (c == L'"')
160f412fd2aSLoGin 					in_quote = !in_quote;
161f412fd2aSLoGin 				else if (!in_quote && isspace((char)c))
162f412fd2aSLoGin 					safe_options_bytes = options_bytes;
163f412fd2aSLoGin 
164f412fd2aSLoGin 				options_bytes++;
165f412fd2aSLoGin 				continue;
166f412fd2aSLoGin 			}
167f412fd2aSLoGin 
168f412fd2aSLoGin 			/*
169f412fd2aSLoGin 			 * Get the number of UTF-8 bytes corresponding to a
170f412fd2aSLoGin 			 * UTF-16 character.
171f412fd2aSLoGin 			 * The first part handles everything in the BMP.
172f412fd2aSLoGin 			 */
173f412fd2aSLoGin 			options_bytes += 2 + (c >= 0x800);
174f412fd2aSLoGin 			/*
175f412fd2aSLoGin 			 * Add one more byte for valid surrogate pairs. Invalid
176f412fd2aSLoGin 			 * surrogates will be replaced with 0xfffd and take up
177f412fd2aSLoGin 			 * only 3 bytes.
178f412fd2aSLoGin 			 */
179f412fd2aSLoGin 			if ((c & 0xfc00) == 0xd800) {
180f412fd2aSLoGin 				/*
181f412fd2aSLoGin 				 * If the very last word is a high surrogate,
182f412fd2aSLoGin 				 * we must ignore it since we can't access the
183f412fd2aSLoGin 				 * low surrogate.
184f412fd2aSLoGin 				 */
185f412fd2aSLoGin 				if (!options_chars) {
186f412fd2aSLoGin 					options_bytes -= 3;
187f412fd2aSLoGin 				} else if ((*s2 & 0xfc00) == 0xdc00) {
188f412fd2aSLoGin 					options_bytes++;
189f412fd2aSLoGin 					options_chars--;
190f412fd2aSLoGin 					s2++;
191f412fd2aSLoGin 				}
192f412fd2aSLoGin 			}
193f412fd2aSLoGin 		}
194f412fd2aSLoGin 		if (options_bytes >= COMMAND_LINE_SIZE) {
195f412fd2aSLoGin 			options_bytes = safe_options_bytes;
196f412fd2aSLoGin 			efi_err("Command line is too long: truncated to %d bytes\n",
197f412fd2aSLoGin 				options_bytes);
198f412fd2aSLoGin 		}
199f412fd2aSLoGin 	}
200f412fd2aSLoGin 
201f412fd2aSLoGin 	options_bytes++; /* NUL termination */
202f412fd2aSLoGin 
203f412fd2aSLoGin 	status = efi_bs_call(AllocatePool, EfiLoaderData, options_bytes,
204f412fd2aSLoGin 			     (void **)&cmdline_addr);
205f412fd2aSLoGin 	if (status != EFI_SUCCESS)
206f412fd2aSLoGin 		return NULL;
207f412fd2aSLoGin 
208f412fd2aSLoGin 	snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
209f412fd2aSLoGin 		 options_bytes - 1, options);
210f412fd2aSLoGin 
211f412fd2aSLoGin 	*cmd_line_len = options_bytes;
212f412fd2aSLoGin 	return (char *)cmdline_addr;
213f412fd2aSLoGin }
21478b790faSLoGin 
21578b790faSLoGin /**
21678b790faSLoGin  *	parse_option_str - Parse a string and check an option is set or not
21778b790faSLoGin  *	@str: String to be parsed
21878b790faSLoGin  *	@option: option name
21978b790faSLoGin  *
22078b790faSLoGin  *	This function parses a string containing a comma-separated list of
22178b790faSLoGin  *	strings like a=b,c.
22278b790faSLoGin  *
22378b790faSLoGin  *	Return true if there's such option in the string, or return false.
22478b790faSLoGin  */
22578b790faSLoGin bool parse_option_str(const char *str, const char *option)
22678b790faSLoGin {
22778b790faSLoGin 	while (*str) {
22878b790faSLoGin 		if (!strncmp(str, option, strlen(option))) {
22978b790faSLoGin 			str += strlen(option);
23078b790faSLoGin 			if (!*str || *str == ',')
23178b790faSLoGin 				return true;
23278b790faSLoGin 		}
23378b790faSLoGin 
23478b790faSLoGin 		while (*str && *str != ',')
23578b790faSLoGin 			str++;
23678b790faSLoGin 
23778b790faSLoGin 		if (*str == ',')
23878b790faSLoGin 			str++;
23978b790faSLoGin 	}
24078b790faSLoGin 
24178b790faSLoGin 	return false;
24278b790faSLoGin }
24378b790faSLoGin 
24478b790faSLoGin /**
24578b790faSLoGin  * efi_parse_options() - Parse EFI command line options
24678b790faSLoGin  * @cmdline:	kernel command line
24778b790faSLoGin  *
24878b790faSLoGin  * Parse the ASCII string @cmdline for EFI options, denoted by the efi=
24978b790faSLoGin  * option, e.g. efi=nochunk.
25078b790faSLoGin  *
25178b790faSLoGin  * It should be noted that efi= is parsed in two very different
25278b790faSLoGin  * environments, first in the early boot environment of the EFI boot
25378b790faSLoGin  * stub, and subsequently during the kernel boot.
25478b790faSLoGin  *
25578b790faSLoGin  * Return:	status code
25678b790faSLoGin  */
25778b790faSLoGin efi_status_t efi_parse_options(char const *cmdline)
25878b790faSLoGin {
25978b790faSLoGin 	size_t len;
26078b790faSLoGin 	efi_status_t status;
26178b790faSLoGin 	char *str, *buf;
26278b790faSLoGin 
26378b790faSLoGin 	if (!cmdline)
26478b790faSLoGin 		return EFI_SUCCESS;
26578b790faSLoGin 
26678b790faSLoGin 	len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1;
26778b790faSLoGin 	status = efi_bs_call(AllocatePool, EfiLoaderData, len, (void **)&buf);
26878b790faSLoGin 	if (status != EFI_SUCCESS)
26978b790faSLoGin 		return status;
27078b790faSLoGin 
27178b790faSLoGin 	memcpy(buf, cmdline, len - 1);
27278b790faSLoGin 	buf[len - 1] = '\0';
27378b790faSLoGin 	str = skip_spaces(buf);
27478b790faSLoGin 
27578b790faSLoGin 	while (*str) {
27678b790faSLoGin 		char *param, *val;
27778b790faSLoGin 
27878b790faSLoGin 		str = next_arg(str, &param, &val);
27978b790faSLoGin 		if (!val && !strcmp(param, "--"))
28078b790faSLoGin 			break;
28178b790faSLoGin 
28278b790faSLoGin 		if (!strcmp(param, "nokaslr")) {
28378b790faSLoGin 			efi_nokaslr = true;
28478b790faSLoGin 		} else if (!strcmp(param, "quiet")) {
28578b790faSLoGin 			// efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
28678b790faSLoGin 		} else if (!strcmp(param, "noinitrd")) {
28778b790faSLoGin 			efi_noinitrd = true;
28878b790faSLoGin 		}
28978b790faSLoGin #ifdef CONFIG_X86_64
29078b790faSLoGin 		else if (IS_ENABLED(CONFIG_X86_64) &&
29178b790faSLoGin 			 !strcmp(param, "no5lvl")) {
29278b790faSLoGin 			efi_no5lvl = true;
29378b790faSLoGin 		}
29478b790faSLoGin #endif
29578b790faSLoGin 		else if (!strcmp(param, "efi") && val) {
29678b790faSLoGin 			efi_nochunk = parse_option_str(val, "nochunk");
29778b790faSLoGin 			efi_novamap |= parse_option_str(val, "novamap");
29878b790faSLoGin 
29978b790faSLoGin 			// efi_nosoftreserve =
30078b790faSLoGin 			// 	IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
30178b790faSLoGin 			// 	parse_option_str(val, "nosoftreserve");
30278b790faSLoGin 			efi_nosoftreserve = false;
30378b790faSLoGin 
30478b790faSLoGin 			if (parse_option_str(val, "disable_early_pci_dma"))
30578b790faSLoGin 				efi_disable_pci_dma = true;
30678b790faSLoGin 			if (parse_option_str(val, "no_disable_early_pci_dma"))
30778b790faSLoGin 				efi_disable_pci_dma = false;
30878b790faSLoGin 			if (parse_option_str(val, "debug")) {
30978b790faSLoGin 				// efi_loglevel = CONSOLE_LOGLEVEL_DEBUG;
31078b790faSLoGin 			}
31178b790faSLoGin 		} else if (!strcmp(param, "video") && val &&
31278b790faSLoGin 			   strstarts(val, "efifb:")) {
31378b790faSLoGin 			// efi_parse_option_graphics(val + strlen("efifb:"));
31478b790faSLoGin 		}
31578b790faSLoGin 	}
31678b790faSLoGin 	efi_bs_call(FreePool, buf);
31778b790faSLoGin 	return EFI_SUCCESS;
31878b790faSLoGin }
3193e6106c4SLoGin 
3203e6106c4SLoGin /**
3213e6106c4SLoGin  * get_efi_config_table() - retrieve UEFI configuration table
3223e6106c4SLoGin  * @guid:	GUID of the configuration table to be retrieved
3233e6106c4SLoGin  * Return:	pointer to the configuration table or NULL
3243e6106c4SLoGin  */
3253e6106c4SLoGin void *get_efi_config_table(efi_guid_t guid)
3263e6106c4SLoGin {
3273e6106c4SLoGin 	efi_config_table_t *tables = efi_table_attr(ST, ConfigurationTable);
3283e6106c4SLoGin 	int nr_tables = efi_table_attr(ST, NumberOfTableEntries);
3293e6106c4SLoGin 	int i;
3303e6106c4SLoGin 
3313e6106c4SLoGin 	for (i = 0; i < nr_tables; i++) {
3323e6106c4SLoGin 		efi_config_table_t *t = (void *)tables;
3333e6106c4SLoGin 		// print_efi_guid(&t->VendorGuid);
3343e6106c4SLoGin 		if (efi_guidcmp(t->VendorGuid, guid) == 0)
3353e6106c4SLoGin 			return efi_table_attr(t, VendorTable);
3363e6106c4SLoGin 
3373e6106c4SLoGin 		tables++;
3383e6106c4SLoGin 	}
3393e6106c4SLoGin 	return NULL;
3403e6106c4SLoGin }
341823f0493SLoGin 
342823f0493SLoGin /**
343823f0493SLoGin  * efi_exit_boot_services() - Exit boot services
344823f0493SLoGin  * @handle:	handle of the exiting image
345823f0493SLoGin  * @priv:	argument to be passed to @priv_func
346823f0493SLoGin  * @priv_func:	function to process the memory map before exiting boot services
347823f0493SLoGin  *
348823f0493SLoGin  * Handle calling ExitBootServices according to the requirements set out by the
349823f0493SLoGin  * spec.  Obtains the current memory map, and returns that info after calling
350823f0493SLoGin  * ExitBootServices.  The client must specify a function to perform any
351823f0493SLoGin  * processing of the memory map data prior to ExitBootServices.  A client
352823f0493SLoGin  * specific structure may be passed to the function via priv.  The client
353823f0493SLoGin  * function may be called multiple times.
354823f0493SLoGin  *
355823f0493SLoGin  * Return:	status code
356823f0493SLoGin  */
357823f0493SLoGin efi_status_t efi_exit_boot_services(void *handle, void *priv,
358823f0493SLoGin 				    efi_exit_boot_map_processing priv_func)
359823f0493SLoGin {
360823f0493SLoGin 	struct efi_boot_memmap *map;
361823f0493SLoGin 	efi_status_t status;
362823f0493SLoGin 
363823f0493SLoGin 	if (efi_disable_pci_dma) {
364823f0493SLoGin 		efi_todo("efi_exit_boot_services:: efi_disable_pci_dma: efi_pci_disable_bridge_busmaster");
365823f0493SLoGin 		// efi_pci_disable_bridge_busmaster();
366823f0493SLoGin 	}
367823f0493SLoGin 
368823f0493SLoGin 	status = efi_get_memory_map(&map, true);
369823f0493SLoGin 	if (status != EFI_SUCCESS)
370823f0493SLoGin 		return status;
371823f0493SLoGin 	efi_debug("before priv_func\n");
372823f0493SLoGin 	status = priv_func(map, priv);
373823f0493SLoGin 	if (status != EFI_SUCCESS) {
374823f0493SLoGin 
375823f0493SLoGin 		efi_bs_call(FreePool, map);
376823f0493SLoGin 		return status;
377823f0493SLoGin 	}
378823f0493SLoGin 
379823f0493SLoGin 	efi_debug("before ExitBootServices, handle=%p, map_key=%p\n", handle, map->map_key);
380*2604d783SLoGin 	efi_debug("BS->ExitBootServices=%p\n", BS->ExitBootServices);
381*2604d783SLoGin 	efi_debug("ST->BS->ExitBootServices=%p\n", ST->BootServices->ExitBootServices);
382823f0493SLoGin 	status = efi_bs_call(ExitBootServices, handle, map->map_key);
383*2604d783SLoGin 	// exit之后不能再使用打印函数,否则会出现错误
384823f0493SLoGin 
385823f0493SLoGin 	if (status == EFI_INVALID_PARAMETER) {
386823f0493SLoGin 		/*
387823f0493SLoGin 		 * The memory map changed between efi_get_memory_map() and
388823f0493SLoGin 		 * exit_boot_services().  Per the UEFI Spec v2.6, Section 6.4:
389823f0493SLoGin 		 * EFI_BOOT_SERVICES.ExitBootServices we need to get the
390823f0493SLoGin 		 * updated map, and try again.  The spec implies one retry
391823f0493SLoGin 		 * should be sufficent, which is confirmed against the EDK2
392823f0493SLoGin 		 * implementation.  Per the spec, we can only invoke
393823f0493SLoGin 		 * get_memory_map() and exit_boot_services() - we cannot alloc
394823f0493SLoGin 		 * so efi_get_memory_map() cannot be used, and we must reuse
395823f0493SLoGin 		 * the buffer.  For all practical purposes, the headroom in the
396823f0493SLoGin 		 * buffer should account for any changes in the map so the call
397823f0493SLoGin 		 * to get_memory_map() is expected to succeed here.
398823f0493SLoGin 		 */
399823f0493SLoGin 		map->map_size = map->buff_size;
400823f0493SLoGin 		status = efi_bs_call(GetMemoryMap, &map->map_size, &map->map,
401823f0493SLoGin 				     &map->map_key, &map->desc_size,
402823f0493SLoGin 				     &map->desc_ver);
403823f0493SLoGin 
404823f0493SLoGin 		/* exit_boot_services() was called, thus cannot free */
405823f0493SLoGin 		if (status != EFI_SUCCESS)
406823f0493SLoGin 			return status;
407823f0493SLoGin 
408823f0493SLoGin 		status = priv_func(map, priv);
409823f0493SLoGin 		/* exit_boot_services() was called, thus cannot free */
410823f0493SLoGin 		if (status != EFI_SUCCESS)
411823f0493SLoGin 			return status;
412823f0493SLoGin 
413823f0493SLoGin 		status = efi_bs_call(ExitBootServices, handle, map->map_key);
414823f0493SLoGin 	}
415823f0493SLoGin 
416823f0493SLoGin 	return status;
417823f0493SLoGin }