From owner-svn-src-stable-10@freebsd.org Thu Jan 7 04:02:39 2016 Return-Path: Delivered-To: svn-src-stable-10@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7E900A6584E; Thu, 7 Jan 2016 04:02:39 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 404F21E0D; Thu, 7 Jan 2016 04:02:39 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u0742cK7028267; Thu, 7 Jan 2016 04:02:38 GMT (envelope-from emaste@FreeBSD.org) Received: (from emaste@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u0742cNA028264; Thu, 7 Jan 2016 04:02:38 GMT (envelope-from emaste@FreeBSD.org) Message-Id: <201601070402.u0742cNA028264@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: emaste set sender to emaste@FreeBSD.org using -f From: Ed Maste Date: Thu, 7 Jan 2016 04:02:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r293304 - in stable/10/sys/boot/efi/loader: . arch/amd64 X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Jan 2016 04:02:39 -0000 Author: emaste Date: Thu Jan 7 04:02:37 2016 New Revision: 293304 URL: https://svnweb.freebsd.org/changeset/base/293304 Log: loader.efi: combine GetMemoryMap and ExitBootServices and retry on error MFC r292338: UEFI: combine GetMemoryMap and ExitBootServices and retry on error The EFI memory map may change before or during the first ExitBootServices call. In that case ExitBootServices returns an error, and GetMemoryMap and ExitBootServices must be retried. Glue together calls to GetMemoryMap(), ExitBootServices() and storage of (now up-to-date) MODINFOMD_EFI_MAP metadata within a single function. That new function - bi_add_efi_data_and_exit() - uses space previously allocated in bi_load_efi_data() to store the memory map (it will fail if that space is too short). It handles re-calling GetMemoryMap() once to update the map key if necessary. Finally, if ExitBootServices() is successful, it stores the memory map and its header as MODINFOMD_EFI_MAP metadata. ExitBootServices() calls are now done earlier, from within arch- independent bi_load() code. MFC r292442: loader.efi: show EFI error number, not full status value EFI return values set the high bit to indicate an error. The log messages changed here are printed only in the case of an error, so including the error bit is redundant. Also switch to decimal to match the error definitions (in sys/boot/efi/include/efierr.h). MFC r292515: loader.efi: refresh size in GetMemoryMap retry loop If ExitBootServices fails due to a changed efi_mapkey then GetMemoryMap must be called again. In this case it is also possible for the memory map to grow, so repeat the initial GetMemoryMap call to fetch the new size. Also roll bi_add_efi_data_and_exit into bi_load_efi_data as there's no need for it to be a separate function. PR: 202455 Relnotes: Yes Sponsored by: The FreeBSD Foundation Modified: stable/10/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c stable/10/sys/boot/efi/loader/bootinfo.c stable/10/sys/boot/efi/loader/loader_efi.h Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c ============================================================================== --- stable/10/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c Thu Jan 7 03:28:56 2016 (r293303) +++ stable/10/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c Thu Jan 7 04:02:37 2016 (r293304) @@ -174,13 +174,6 @@ elf64_exec(struct preloaded_file *fp) if (err != 0) return(err); - status = BS->ExitBootServices(IH, efi_mapkey); - if (EFI_ERROR(status)) { - printf("%s: ExitBootServices() returned 0x%lx\n", __func__, - (long)status); - return (EINVAL); - } - dev_cleanup(); trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4, Modified: stable/10/sys/boot/efi/loader/bootinfo.c ============================================================================== --- stable/10/sys/boot/efi/loader/bootinfo.c Thu Jan 7 03:28:56 2016 (r293303) +++ stable/10/sys/boot/efi/loader/bootinfo.c Thu Jan 7 04:02:37 2016 (r293304) @@ -48,8 +48,6 @@ __FBSDID("$FreeBSD$"); #include "framebuffer.h" #include "loader_efi.h" -UINTN efi_mapkey; - static const char howto_switches[] = "aCdrgDmphsv"; static int howto_masks[] = { RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, @@ -230,7 +228,8 @@ bi_load_efi_data(struct preloaded_file * EFI_PHYSICAL_ADDRESS addr; EFI_STATUS status; size_t efisz; - UINTN mmsz, pages, sz; + UINTN efi_mapkey; + UINTN mmsz, pages, retry, sz; UINT32 mmver; struct efi_map_header *efihdr; struct efi_fb efifb; @@ -252,49 +251,63 @@ bi_load_efi_data(struct preloaded_file * efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; /* - * 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. + * 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. */ - 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() returned 0x%lx\n", __func__, - (long)status); - return (ENOMEM); - } + 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__, + (unsigned long)(status & ~EFI_ERROR_MASK)); + 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 *)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() returned 0x%lx\n", __func__, - (long)status); - return (EINVAL); + /* + * 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 *)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__, + (unsigned long)(status & ~EFI_ERROR_MASK)); + return (EINVAL); + } + status = BS->ExitBootServices(IH, efi_mapkey); + if (EFI_ERROR(status) == 0) { + efihdr->memory_size = sz; + efihdr->descriptor_size = mmsz; + efihdr->descriptor_version = mmver; + file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, + efihdr); + return (0); + } + BS->FreePages(addr, pages); } - - efihdr->memory_size = sz; - efihdr->descriptor_size = mmsz; - efihdr->descriptor_version = mmver; - - file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, efihdr); - - return (0); + printf("ExitBootServices error %lu\n", + (unsigned long)(status & ~EFI_ERROR_MASK)); + return (EINVAL); } /* Modified: stable/10/sys/boot/efi/loader/loader_efi.h ============================================================================== --- stable/10/sys/boot/efi/loader/loader_efi.h Thu Jan 7 03:28:56 2016 (r293303) +++ stable/10/sys/boot/efi/loader/loader_efi.h Thu Jan 7 04:02:37 2016 (r293304) @@ -44,8 +44,6 @@ ssize_t efi_copyout(const vm_offset_t sr ssize_t efi_readin(const int fd, vm_offset_t dest, const size_t len); void * efi_translate(vm_offset_t ptr); -extern UINTN efi_mapkey; - void efi_copy_finish(void); #endif /* _LOADER_EFI_COPY_H_ */