diff --git a/stand/efi/loader/arch/amd64/elf64_freebsd.c b/stand/efi/loader/arch/amd64/elf64_freebsd.c index 35bd4d6c141..62716d7b136 100644 --- a/stand/efi/loader/arch/amd64/elf64_freebsd.c +++ b/stand/efi/loader/arch/amd64/elf64_freebsd.c @@ -89,7 +89,7 @@ elf64_exec(struct preloaded_file *fp) Elf_Ehdr *ehdr; vm_offset_t modulep, kernend, trampcode, trampstack; int err, i; - bool copy_auto; + bool copy_auto, needs_pt4; copy_auto = copy_staging == COPY_STAGING_AUTO; if (copy_auto) @@ -156,6 +156,7 @@ elf64_exec(struct preloaded_file *fp) PT2[i] = (pd_entry_t)i * M(2); PT2[i] |= PG_V | PG_RW | PG_PS; } + needs_pt4 = false; } else { PT4 = (pml4_entry_t *)G(4); err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 9, @@ -167,7 +168,35 @@ elf64_exec(struct preloaded_file *fp) copy_staging = COPY_STAGING_AUTO; return (ENOMEM); } + needs_pt4 = true; + } + printf("%scopying staging tramp %p PT4 %p\n", + copy_staging == COPY_STAGING_ENABLE ? "" : "not ", + trampoline, PT4); + printf("Start @ 0x%lx ...\n", ehdr->e_entry); + + /* + * we have to cleanup here because net_cleanup() doesn't work after + * we call ExitBootServices + */ + dev_cleanup(); + + efi_time_fini(); + err = bi_load(fp->f_args, &modulep, &kernend, true); + if (err != 0) { + efi_time_init(); + if (copy_auto) + copy_staging = COPY_STAGING_AUTO; + return (err); + } + + /* + * staging might move in bi_load because we automatiaclly move when we + * copy data in. At this point, staging can't move anymore, so create + * PT4 with the correct value. + */ + if (needs_pt4) { bzero(PT4, 9 * EFI_PAGE_SIZE); PT3_l = &PT4[NPML4EPG * 1]; @@ -204,26 +233,6 @@ elf64_exec(struct preloaded_file *fp) } } - printf("staging %#lx (%scopying) tramp %p PT4 %p\n", - staging, copy_staging == COPY_STAGING_ENABLE ? "" : "not ", - trampoline, PT4); - printf("Start @ 0x%lx ...\n", ehdr->e_entry); - - /* - * we have to cleanup here because net_cleanup() doesn't work after - * we call ExitBootServices - */ - dev_cleanup(); - - efi_time_fini(); - err = bi_load(fp->f_args, &modulep, &kernend, true); - if (err != 0) { - efi_time_init(); - if (copy_auto) - copy_staging = COPY_STAGING_AUTO; - return (err); - } - trampoline(trampstack, copy_staging == COPY_STAGING_ENABLE ? efi_copy_finish : efi_copy_finish_nop, kernend, modulep, PT4, ehdr->e_entry); diff --git a/stand/efi/loader/arch/i386/elf64_freebsd.c b/stand/efi/loader/arch/i386/elf64_freebsd.c index 22cdd685ea9..f3f8c91e027 100644 --- a/stand/efi/loader/arch/i386/elf64_freebsd.c +++ b/stand/efi/loader/arch/i386/elf64_freebsd.c @@ -99,6 +99,7 @@ elf64_exec(struct preloaded_file *fp) struct user_segment_descriptor *gdt; vm_offset_t modulep, kernend, trampstack; int i; + bool needs_pt4; switch (copy_staging) { case COPY_STAGING_ENABLE: @@ -199,10 +200,8 @@ elf64_exec(struct preloaded_file *fp) */ PT2[i] = (i * M(2)) | PG_V | PG_RW | PG_PS; } + needs_pt4 = false; } else { - pdpt_entry_t *PT3_l, *PT3_u; - pd_entry_t *PT2_l0, *PT2_l1, *PT2_l2, *PT2_l3, *PT2_u0, *PT2_u1; - err = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, EFI_SIZE_TO_PAGES(512 * 9 * sizeof(uint64_t)), &ptr); if (EFI_ERROR(err)) { @@ -213,6 +212,38 @@ elf64_exec(struct preloaded_file *fp) } PT4 = (pml4_entry_t *)(uintptr_t)ptr; + needs_pt4 = true; + } + + printf("%scopying staging tramp %p PT4 %p GDT %p\n" + "Start @ %#llx ...\n", + type == AllocateMaxAddress ? "" : "not ", trampoline, PT4, gdt, + ehdr->e_entry + ); + + + /* + * we have to cleanup here because net_cleanup() doesn't work after + * we call ExitBootServices + */ + dev_cleanup(); + + efi_time_fini(); + err = bi_load(fp->f_args, &modulep, &kernend, true); + if (err != 0) { + efi_time_init(); + return (err); + } + + /* + * staging might move in bi_load because we automatiaclly move when we + * copy data in. At this point, staging can't move anymore, so create + * PT4 with the correct value. + */ + if (needs_pt4) { + pdpt_entry_t *PT3_l, *PT3_u; + pd_entry_t *PT2_l0, *PT2_l1, *PT2_l2, *PT2_l3, *PT2_u0, *PT2_u1; + PT3_l = &PT4[512]; PT3_u = &PT3_l[512]; PT2_l0 = &PT3_u[512]; @@ -245,27 +276,6 @@ elf64_exec(struct preloaded_file *fp) } } - printf( - "staging %#llx (%scopying) tramp %p PT4 %p GDT %p\n" - "Start @ %#llx ...\n", staging, - type == AllocateMaxAddress ? "" : "not ", trampoline, PT4, gdt, - ehdr->e_entry - ); - - - /* - * we have to cleanup here because net_cleanup() doesn't work after - * we call ExitBootServices - */ - dev_cleanup(); - - efi_time_fini(); - err = bi_load(fp->f_args, &modulep, &kernend, true); - if (err != 0) { - efi_time_init(); - return (err); - } - trampoline(trampstack, type == AllocateMaxAddress ? efi_copy_finish : efi_copy_finish_nop, kernend, modulep, PT4, gdtr, ehdr->e_entry); diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c index fc87a0bf52f..14e16ed5df8 100644 --- a/stand/efi/loader/bootinfo.c +++ b/stand/efi/loader/bootinfo.c @@ -209,6 +209,16 @@ bi_load_efi_data(struct preloaded_file *kfp, bool exit_bs) } #endif +#if defined(__amd64__) || defined(__i386__) + /* + * Staging can't move after this point, so report the final value before + * we try to exit boot services below. The metadata added is added to + * the malloced arena that we setup when we started and doesn't interact + * with boot services. + */ + printf("staging %#jx\n", (uintmax_t)staging); +#endif + do_vmap = true; efi_novmap = getenv("efi_disable_vmap"); if (efi_novmap != NULL) @@ -298,14 +308,20 @@ bi_load_efi_data(struct preloaded_file *kfp, bool exit_bs) * loader.conf(5). By default we will setup the virtual * map entries. */ - if (do_vmap) efi_do_vmap(mm, sz, dsz, mmver); + + /* + * Add the memory map to the metadata. addmetadata copies the data into + * the malloc arena, so we can safely free the memory map pages after. + * Or could if boot services was still running. + */ efihdr->memory_size = sz; efihdr->descriptor_size = dsz; efihdr->descriptor_version = mmver; file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, efihdr); + /* BS->FreePages(addr, pages); */ return (0); }