[syslinux] [PATCH] efi: Call ExitBootServices at least twice

Paulo Alcantara pcacjr at zytor.com
Wed Sep 16 06:24:39 PDT 2015


On Wed, 26 Aug 2015 05:54:04 +0200
celelibi--- via Syslinux <syslinux at zytor.com> wrote:

> From: Sylvain Gault <sylvain.gault at gmail.com>
> 
> Some firmware implementations may need ExitBootServices to be called
> twice. The second time with an updated memory map key.
> 
> Signed-off-by: Sylvain Gault <sylvain.gault at gmail.com>
> ---
>  efi/main.c | 75
> +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file
> changed, 64 insertions(+), 11 deletions(-)
> 
> diff --git a/efi/main.c b/efi/main.c
> index 6dbc259..a39ab43 100644
> --- a/efi/main.c
> +++ b/efi/main.c
> @@ -1001,19 +1001,79 @@ static int handle_ramdisks(struct
> linux_header *hdr, return 0;
>  }
>  
> +/*
> + * Like get_memory_map but try to use the given buffer first,
> reallocate it if
> + * it's too small and always set the allocated size.
> + */
> +static EFI_MEMORY_DESCRIPTOR *
> +get_memory_map_realloc(EFI_MEMORY_DESCRIPTOR *map, UINTN *allocsize,
> +		       UINTN *nr_entries, UINTN *key, UINTN *desc_sz,
> +		       UINT32 *desc_ver)
> +{
> +	EFI_STATUS status;
> +	UINTN size, allocsizeadd;
> +
> +	allocsizeadd = sizeof(*map) * 2;
> +
> +	do {
> +		size = *allocsize;
> +		status = uefi_call_wrapper(BS->GetMemoryMap, 5,
> &size, map, key,
> +		                           desc_sz, desc_ver);
> +
> +		if (status == EFI_BUFFER_TOO_SMALL) {
> +			if (map)
> +				FreePool(map);
> +			allocsizeadd *= 2;
> +			*allocsize = size + allocsizeadd;
> +			map = AllocatePool(*allocsize);

Why don't you use ReallocatePool()?

Besides, you could just return inside loop when GetMemoryMap() returns
EFI_SUCCESS and thus avoiding to check twice for EFI_BUFFER_TOO_SMALL
prior to "status == EFI_SUCCESS" outside loop.

Thanks,

Paulo

> +		}
> +	} while (status == EFI_BUFFER_TOO_SMALL);
> +
> +	if (status == EFI_SUCCESS) {
> +		*nr_entries = size / *desc_sz;
> +		return map;
> +	}
> +
> +	if (map)
> +		FreePool(map);
> +	return NULL;
> +}
> +
>  static int exit_boot(struct boot_params *bp)
>  {
>  	struct e820_entry *e820buf, *e;
>  	EFI_MEMORY_DESCRIPTOR *map;
>  	EFI_STATUS status;
>  	uint32_t e820_type;
> -	UINTN i, nr_entries, key, desc_sz;
> +	UINTN i, nr_entries, key, desc_sz, allocsize;
>  	UINT32 desc_ver;
> +	int retry;
>  
> -	/* Build efi memory map */
> -	map = get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
> -	if (!map)
> +	/*
> +	 * Build efi memory map and call ExitBootServices as soon
> after as
> +	 * possible. Some implementations need two calls to
> ExitBootServices.
> +	 */
> +
> +	map = NULL;
> +	allocsize = 0;
> +	retry = 0;
> +	do {
> +		map = get_memory_map_realloc(map, &allocsize,
> &nr_entries, &key,
> +		                             &desc_sz, &desc_ver);
> +		if (!map)
> +			return -1;
> +
> +		status = uefi_call_wrapper(BS->ExitBootServices, 2,
> +		                           image_handle, key);
> +		retry++;
> +	} while (status != EFI_SUCCESS && retry < 3);
> +
> +	if (status != EFI_SUCCESS) {
> +		printf("Failed to exit boot services: 0x%016lx\n",
> status);
> +		FreePool(map);
>  		return -1;
> +	}
> +
>  
>  	bp->efi.memmap = (uint32_t)(unsigned long)map;
>  	bp->efi.memmap_size = nr_entries * desc_sz;
> @@ -1088,13 +1148,6 @@ static int exit_boot(struct boot_params *bp)
>  
>  	bp->e820_entries = e - e820buf;
>  
> -	status = uefi_call_wrapper(BS->ExitBootServices, 2,
> image_handle, key);
> -	if (status != EFI_SUCCESS) {
> -		printf("Failed to exit boot services: 0x%016lx\n",
> status);
> -		FreePool(map);
> -		return -1;
> -	}
> -
>  	return 0;
>  }
>  



-- 
Paulo Alcantara, C.E.S.A.R
Speaking for myself only.


More information about the Syslinux mailing list