219 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- stand/efi/loader/bootinfo.c.orig
 | |
| +++ stand/efi/loader/bootinfo.c
 | |
| @@ -287,12 +287,12 @@
 | |
|  bi_load_efi_data(struct preloaded_file *kfp)
 | |
|  {
 | |
|  	EFI_MEMORY_DESCRIPTOR *mm;
 | |
| -	EFI_PHYSICAL_ADDRESS addr;
 | |
| +	EFI_PHYSICAL_ADDRESS addr = 0;
 | |
|  	EFI_STATUS status;
 | |
|  	const char *efi_novmap;
 | |
|  	size_t efisz;
 | |
|  	UINTN efi_mapkey;
 | |
| -	UINTN mmsz, pages, retry, sz;
 | |
| +	UINTN dsz, pages, retry, sz;
 | |
|  	UINT32 mmver;
 | |
|  	struct efi_map_header *efihdr;
 | |
|  	bool do_vmap;
 | |
| @@ -323,76 +323,94 @@
 | |
|  	efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
 | |
|  
 | |
|  	/*
 | |
| -	 * Assgin size of EFI_MEMORY_DESCRIPTOR to keep compatible with
 | |
| +	 * Assign size of EFI_MEMORY_DESCRIPTOR to keep compatible with
 | |
|  	 * u-boot which doesn't fill this value when buffer for memory
 | |
|  	 * descriptors is too small (eg. 0 to obtain memory map size)
 | |
|  	 */
 | |
| -	mmsz = sizeof(EFI_MEMORY_DESCRIPTOR);
 | |
| +	dsz = sizeof(EFI_MEMORY_DESCRIPTOR);
 | |
|  
 | |
|  	/*
 | |
| -	 * It is possible that the first call to ExitBootServices may change
 | |
| -	 * the map key. Fetch a new map key and retry ExitBootServices in that
 | |
| -	 * case.
 | |
| +	 * Allocate enough pages to hold the bootinfo block and the
 | |
| +	 * memory map EFI will return to us. The memory map has an
 | |
| +	 * unknown size, so we have to determine that first. Note that
 | |
| +	 * the AllocatePages call can itself modify the memory map, so
 | |
| +	 * we have to take that into account as well. The changes to
 | |
| +	 * the memory map are caused by splitting a range of free
 | |
| +	 * memory into two, so that one is marked as being loader
 | |
| +	 * data.
 | |
| +	 */
 | |
| +
 | |
| +	sz = 0;
 | |
| +
 | |
| +	/*
 | |
| +	 * Matthew Garrett has observed at least one system changing the
 | |
| +	 * memory map when calling ExitBootServices, causing it to return an
 | |
| +	 * error, probably because callbacks are allocating memory.
 | |
| +	 * So we need to retry calling it at least once.
 | |
|  	 */
 | |
|  	for (retry = 2; retry > 0; retry--) {
 | |
| -		/*
 | |
| -		 * Allocate enough pages to hold the bootinfo block and the
 | |
| -		 * memory map EFI will return to us. The memory map has an
 | |
| -		 * unknown size, so we have to determine that first. Note that
 | |
| -		 * the AllocatePages call can itself modify the memory map, so
 | |
| -		 * we have to take that into account as well. The changes to
 | |
| -		 * the memory map are caused by splitting a range of free
 | |
| -		 * memory into two (AFAICT), so that one is marked as being
 | |
| -		 * loader data.
 | |
| -		 */
 | |
| -		sz = 0;
 | |
| -		BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver);
 | |
| -		sz += mmsz;
 | |
| -		sz = (sz + 0xf) & ~0xf;
 | |
| -		pages = EFI_SIZE_TO_PAGES(sz + efisz);
 | |
| -		status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
 | |
| -		     pages, &addr);
 | |
| -		if (EFI_ERROR(status)) {
 | |
| -			printf("%s: AllocatePages error %lu\n", __func__,
 | |
| -			    EFI_ERROR_CODE(status));
 | |
| -			return (ENOMEM);
 | |
| -		}
 | |
| +		for (;;) {
 | |
| +			status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &dsz, &mmver);
 | |
| +			if (!EFI_ERROR(status))
 | |
| +				break;
 | |
| +
 | |
| +			if (status != EFI_BUFFER_TOO_SMALL) {
 | |
| +				printf("%s: GetMemoryMap error %lu\n", __func__,
 | |
| +	                           EFI_ERROR_CODE(status));
 | |
| +				return (EINVAL);
 | |
| +			}
 | |
| +
 | |
| +			if (addr != 0)
 | |
| +				BS->FreePages(addr, pages);
 | |
| +
 | |
| +			/* Add 10 descriptors to the size to allow for
 | |
| +			 * fragmentation caused by calling AllocatePages */
 | |
| +			sz += (10 * dsz);
 | |
| +			pages = EFI_SIZE_TO_PAGES(sz + efisz);
 | |
| +			status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
 | |
| +					pages, &addr);
 | |
| +			if (EFI_ERROR(status)) {
 | |
| +				printf("%s: AllocatePages error %lu\n", __func__,
 | |
| +				    EFI_ERROR_CODE(status));
 | |
| +				return (ENOMEM);
 | |
| +			}
 | |
|  
 | |
| -		/*
 | |
| -		 * Read the memory map and stash it after bootinfo. Align the
 | |
| -		 * memory map on a 16-byte boundary (the bootinfo block is page
 | |
| -		 * aligned).
 | |
| -		 */
 | |
| -		efihdr = (struct efi_map_header *)(uintptr_t)addr;
 | |
| -		mm = (void *)((uint8_t *)efihdr + efisz);
 | |
| -		sz = (EFI_PAGE_SIZE * pages) - efisz;
 | |
| -
 | |
| -		status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver);
 | |
| -		if (EFI_ERROR(status)) {
 | |
| -			printf("%s: GetMemoryMap error %lu\n", __func__,
 | |
| -			    EFI_ERROR_CODE(status));
 | |
| -			return (EINVAL);
 | |
| -		}
 | |
| -		status = BS->ExitBootServices(IH, efi_mapkey);
 | |
| -		if (EFI_ERROR(status) == 0) {
 | |
|  			/*
 | |
| -			 * This may be disabled by setting efi_disable_vmap in
 | |
| -			 * loader.conf(5). By default we will setup the virtual
 | |
| -			 * map entries.
 | |
| +			 * Read the memory map and stash it after bootinfo. Align the
 | |
| +			 * memory map on a 16-byte boundary (the bootinfo block is page
 | |
| +			 * aligned).
 | |
|  			 */
 | |
| -			if (do_vmap)
 | |
| -				efi_do_vmap(mm, sz, mmsz, mmver);
 | |
| -			efihdr->memory_size = sz;
 | |
| -			efihdr->descriptor_size = mmsz;
 | |
| -			efihdr->descriptor_version = mmver;
 | |
| -			file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz,
 | |
| -			    efihdr);
 | |
| -			return (0);
 | |
| +			efihdr = (struct efi_map_header *)(uintptr_t)addr;
 | |
| +			mm = (void *)((uint8_t *)efihdr + efisz);
 | |
| +			sz = (EFI_PAGE_SIZE * pages) - efisz;
 | |
|  		}
 | |
| +
 | |
| +		status = BS->ExitBootServices(IH, efi_mapkey);
 | |
| +		if (!EFI_ERROR(status))
 | |
| +			break;
 | |
| +	}
 | |
| +
 | |
| +	if (retry == 0) {
 | |
|  		BS->FreePages(addr, pages);
 | |
| +		printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status));
 | |
| +		return (EINVAL);
 | |
|  	}
 | |
| -	printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status));
 | |
| -	return (EINVAL);
 | |
| +
 | |
| +	/*
 | |
| +	 * This may be disabled by setting efi_disable_vmap in
 | |
| +	 * loader.conf(5). By default we will setup the virtual
 | |
| +	 * map entries.
 | |
| +	 */
 | |
| +
 | |
| +	if (do_vmap)
 | |
| +		efi_do_vmap(mm, sz, dsz, mmver);
 | |
| +	efihdr->memory_size = sz;
 | |
| +	efihdr->descriptor_size = dsz;
 | |
| +	efihdr->descriptor_version = mmver;
 | |
| +	file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz,
 | |
| +	    efihdr);
 | |
| +
 | |
| +	return (0);
 | |
|  }
 | |
|  
 | |
|  /*
 | |
| --- stand/efi/loader/copy.c.orig
 | |
| +++ stand/efi/loader/copy.c
 | |
| @@ -95,7 +95,7 @@
 | |
|  efi_verify_staging_size(unsigned long *nr_pages)
 | |
|  {
 | |
|  	UINTN sz;
 | |
| -	EFI_MEMORY_DESCRIPTOR *map, *p;
 | |
| +	EFI_MEMORY_DESCRIPTOR *map = NULL, *p;
 | |
|  	EFI_PHYSICAL_ADDRESS start, end;
 | |
|  	UINTN key, dsz;
 | |
|  	UINT32 dver;
 | |
| @@ -104,17 +104,28 @@
 | |
|  	unsigned long available_pages = 0;
 | |
|  
 | |
|  	sz = 0;
 | |
| -	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
 | |
| -	if (status != EFI_BUFFER_TOO_SMALL) {
 | |
| -		printf("Can't determine memory map size\n");
 | |
| -		return;
 | |
| -	}
 | |
|  
 | |
| -	map = malloc(sz);
 | |
| -	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
 | |
| -	if (EFI_ERROR(status)) {
 | |
| -		printf("Can't read memory map\n");
 | |
| -		goto out;
 | |
| +	for (;;) {
 | |
| +		status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
 | |
| +		if (!EFI_ERROR(status))
 | |
| +			break;
 | |
| +
 | |
| +		if (status != EFI_BUFFER_TOO_SMALL) {
 | |
| +			printf("Can't read memory map: %lu\n",
 | |
| +			    EFI_ERROR_CODE(status));
 | |
| +			goto out;
 | |
| +		}
 | |
| +
 | |
| +		free(map);
 | |
| +
 | |
| +		/* Allocate 10 descriptors more than the size reported,
 | |
| +		 * to allow for any fragmentation caused by calling
 | |
| +		 * malloc */
 | |
| +		map = malloc(sz + (10 * dsz));
 | |
| +		if (map == NULL) {
 | |
| +			printf("Unable to allocate memory\n");
 | |
| +			goto out;
 | |
| +		}
 | |
|  	}
 | |
|  
 | |
|  	ndesc = sz / dsz;
 |