diff --git a/stand/efi/loader/arch/i386/elf64_freebsd.c b/stand/efi/loader/arch/i386/elf64_freebsd.c index 0dc16437d90..b02cda2269b 100644 --- a/stand/efi/loader/arch/i386/elf64_freebsd.c +++ b/stand/efi/loader/arch/i386/elf64_freebsd.c @@ -28,7 +28,11 @@ #define __ELF_WORD_SIZE 64 #include #include +#include +#include #include +#include +#include #include #include @@ -56,35 +60,14 @@ struct file_format *file_formats[] = { NULL }; -struct gdtr { - uint16_t size; - uint64_t ptr; -} __packed; - -#define PG_V 0x001 -#define PG_RW 0x002 -#define PG_PS 0x080 - -#define GDT_P 0x00800000000000 -#define GDT_E 0x00080000000000 -#define GDT_S 0x00100000000000 -#define GDT_RW 0x00020000000000 -#define GDT_L 0x20000000000000 - -typedef uint64_t p4_entry_t; -typedef uint64_t p3_entry_t; -typedef uint64_t p2_entry_t; -typedef uint64_t gdt_t; - -static p4_entry_t *PT4; -static p3_entry_t *PT3; -static p3_entry_t *PT3_l, *PT3_u; -static p2_entry_t *PT2; -static p2_entry_t *PT2_l0, *PT2_l1, *PT2_l2, *PT2_l3, *PT2_u0, *PT2_u1; -static gdt_t *GDT; +/* + * i386's pmap_pae.h doesn't provide this, so + * just typedef our own. + */ +typedef pdpt_entry_t pml4_entry_t; static void (*trampoline)(uint32_t stack, void *copy_finish, uint32_t kernend, - uint32_t modulep, uint64_t *pagetable, struct gdtr *gdtr, uint64_t entry); + uint32_t modulep, uint64_t *pagetable, void *gdtr, uint64_t entry); extern void *amd64_tramp; extern uint32_t amd64_tramp_size; @@ -97,12 +80,23 @@ extern uint32_t amd64_tramp_size; static int elf64_exec(struct preloaded_file *fp) { + /* + * segments.h gives us a 32-bit gdtr, but + * we want a 64-bit one, so define our own. + */ + struct { + uint16_t rd_limit; + uint64_t rd_base; + } __packed *gdtr; EFI_PHYSICAL_ADDRESS ptr; EFI_ALLOCATE_TYPE type; EFI_STATUS err; struct file_metadata *md; - struct gdtr *gdtr; Elf_Ehdr *ehdr; + pml4_entry_t *PT4; + pdpt_entry_t *PT3; + pd_entry_t *PT2; + struct user_segment_descriptor *gdt; vm_offset_t modulep, kernend, trampstack; int i; @@ -123,36 +117,47 @@ elf64_exec(struct preloaded_file *fp) return (EFTYPE); ehdr = (Elf_Ehdr *)&(md->md_data); - /* - * Make our temporary stack 32 bytes big, which is - * a little more than we need. - */ ptr = G(1); err = BS->AllocatePages(type, EfiLoaderCode, - EFI_SIZE_TO_PAGES(amd64_tramp_size + 32), &ptr); + EFI_SIZE_TO_PAGES(amd64_tramp_size), &ptr); if (EFI_ERROR(err)) { printf("Unable to allocate trampoline\n"); return (ENOMEM); } trampoline = (void *)(uintptr_t)ptr; - trampstack = ptr + amd64_tramp_size + 32; bcopy(&amd64_tramp, trampoline, amd64_tramp_size); + /* + * Allocate enough space for the GDTR + two GDT segments + + * our temporary stack (28 bytes). + */ +#define DATASZ (sizeof(*gdtr) + \ + sizeof(struct user_segment_descriptor) * 2 + 28) + ptr = G(1); err = BS->AllocatePages(type, EfiLoaderData, - EFI_SIZE_TO_PAGES(sizeof(struct gdtr) + sizeof(uint64_t) * 2), &ptr); + EFI_SIZE_TO_PAGES(DATASZ), &ptr); if (EFI_ERROR(err)) { - printf("Unable to allocate GDT\n"); + printf("Unable to allocate GDT and stack\n"); BS->FreePages((uintptr_t)trampoline, 1); return (ENOMEM); } - GDT = (gdt_t *)(uintptr_t)ptr; - GDT[1] = GDT_P | GDT_E | GDT_S | GDT_RW | GDT_L; /* CS */ - GDT[0] = 0; - gdtr = (struct gdtr *)&GDT[2]; - gdtr->size = sizeof(uint64_t) * 2 - 1; - gdtr->ptr = (uintptr_t)GDT; + + trampstack = ptr + DATASZ; + +#undef DATASZ + + gdt = (void *)(uintptr_t)ptr; + gdt[0] = (struct user_segment_descriptor) { 0 }; + gdt[1] = (struct user_segment_descriptor) { + .sd_p = 1, .sd_long = 1, .sd_type = SDT_MEMERC + }; + + gdtr = (void *)(uintptr_t)(ptr + + sizeof(struct user_segment_descriptor) * 2); + gdtr->rd_limit = sizeof(struct user_segment_descriptor) * 2 - 1; + gdtr->rd_base = (uintptr_t)gdt; if (type == AllocateMaxAddress) { /* Copy staging enabled */ @@ -163,10 +168,10 @@ elf64_exec(struct preloaded_file *fp) if (EFI_ERROR(err)) { printf("Unable to allocate trampoline page table\n"); BS->FreePages((uintptr_t)trampoline, 1); - BS->FreePages((uintptr_t)GDT, 1); + BS->FreePages((uintptr_t)gdt, 1); return (ENOMEM); } - PT4 = (p4_entry_t *)(uintptr_t)ptr; + PT4 = (pml4_entry_t *)(uintptr_t)ptr; PT3 = &PT4[512]; PT2 = &PT3[512]; @@ -195,15 +200,18 @@ elf64_exec(struct preloaded_file *fp) PT2[i] = (i * M(2)) | PG_V | PG_RW | PG_PS; } } 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)) { printf("Unable to allocate trampoline page table\n"); BS->FreePages((uintptr_t)trampoline, 1); - BS->FreePages((uintptr_t)GDT, 1); + BS->FreePages((uintptr_t)gdt, 1); return (ENOMEM); } - PT4 = (p4_entry_t *)(uintptr_t)ptr; + PT4 = (pml4_entry_t *)(uintptr_t)ptr; PT3_l = &PT4[512]; PT3_u = &PT3_l[512]; @@ -221,7 +229,7 @@ elf64_exec(struct preloaded_file *fp) PT3_l[2] = (uintptr_t)PT2_l2 | PG_V | PG_RW; PT3_l[3] = (uintptr_t)PT2_l3 | PG_V | PG_RW; for (i = 0; i < 2048; i++) { - PT2_l0[i] = ((p2_entry_t)i * M(2)) | PG_V | PG_RW | PG_PS; + PT2_l0[i] = ((pd_entry_t)i * M(2)) | PG_V | PG_RW | PG_PS; } /* mapping of kernel 2G below top */ @@ -240,7 +248,7 @@ 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, + type == AllocateMaxAddress ? "" : "not ", trampoline, PT4, gdt, ehdr->e_entry ); diff --git a/stand/i386/libi386/elf64_freebsd.c b/stand/i386/libi386/elf64_freebsd.c index b1340fd1f2e..89cc249e9d9 100644 --- a/stand/i386/libi386/elf64_freebsd.c +++ b/stand/i386/libi386/elf64_freebsd.c @@ -28,8 +28,11 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -43,16 +46,15 @@ static int elf64_obj_exec(struct preloaded_file *amp); struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; -#define PG_V 0x001 -#define PG_RW 0x002 -#define PG_PS 0x080 +/* + * i386's pmap_pae.h doesn't provide this, so + * just typedef our own. + */ +typedef pdpt_entry_t pml4_entry_t; -typedef uint64_t p4_entry_t; -typedef uint64_t p3_entry_t; -typedef uint64_t p2_entry_t; -extern p4_entry_t PT4[]; -extern p3_entry_t PT3[]; -extern p2_entry_t PT2[]; +extern pml4_entry_t PT4[]; +extern pdpt_entry_t PT3[]; +extern pd_entry_t PT2[]; uint32_t entry_hi; uint32_t entry_lo; @@ -91,11 +93,11 @@ elf64_exec(struct preloaded_file *fp) */ for (i = 0; i < 512; i++) { /* Each slot of the level 4 pages points to the same level 3 page */ - PT4[i] = (p4_entry_t)VTOP((uintptr_t)&PT3[0]); + PT4[i] = (pml4_entry_t)VTOP((uintptr_t)&PT3[0]); PT4[i] |= PG_V | PG_RW; /* Each slot of the level 3 pages points to the same level 2 page */ - PT3[i] = (p3_entry_t)VTOP((uintptr_t)&PT2[0]); + PT3[i] = (pdpt_entry_t)VTOP((uintptr_t)&PT2[0]); PT3[i] |= PG_V | PG_RW; /* The level 2 page slots are mapped with 2MB pages for 1GB. */ diff --git a/stand/userboot/userboot/elf64_freebsd.c b/stand/userboot/userboot/elf64_freebsd.c index 7f817a44da8..5a63fdb4990 100644 --- a/stand/userboot/userboot/elf64_freebsd.c +++ b/stand/userboot/userboot/elf64_freebsd.c @@ -31,9 +31,10 @@ #ifdef DEBUG #include #endif -#include -#include +#include +#include #include +#include #include #include "bootstrap.h" @@ -45,35 +46,21 @@ static int elf64_obj_exec(struct preloaded_file *amp); struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; -#define MSR_EFER 0xc0000080 -#define EFER_LME 0x00000100 -#define EFER_LMA 0x00000400 /* Long mode active (R) */ -#define CR4_PAE 0x00000020 -#define CR4_VMXE (1UL << 13) -#define CR4_PSE 0x00000010 -#define CR0_PG 0x80000000 -#define CR0_PE 0x00000001 /* Protected mode Enable */ -#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ - -#define PG_V 0x001 -#define PG_RW 0x002 -#define PG_PS 0x080 - -typedef uint64_t p4_entry_t; -typedef uint64_t p3_entry_t; -typedef uint64_t p2_entry_t; - #define GUEST_NULL_SEL 0 #define GUEST_CODE_SEL 1 #define GUEST_DATA_SEL 2 #define GUEST_GDTR_LIMIT (3 * 8 - 1) static void -setup_freebsd_gdt(uint64_t *gdtr) +setup_freebsd_gdt(struct user_segment_descriptor *gdt) { - gdtr[GUEST_NULL_SEL] = 0; - gdtr[GUEST_CODE_SEL] = 0x0020980000000000; - gdtr[GUEST_DATA_SEL] = 0x0000900000000000; + gdt[GUEST_NULL_SEL] = (struct user_segment_descriptor) { 0 }; + gdt[GUEST_CODE_SEL] = (struct user_segment_descriptor) { + .sd_p = 1, .sd_long = 1, .sd_type = SDT_MEME + }; + gdt[GUEST_DATA_SEL] = (struct user_segment_descriptor) { + .sd_p = 1, .sd_type = SDT_MEMRO + }; } /* @@ -90,10 +77,10 @@ elf64_exec(struct preloaded_file *fp) int err; int i; uint32_t stack[1024]; - p4_entry_t PT4[512]; - p3_entry_t PT3[512]; - p2_entry_t PT2[512]; - uint64_t gdtr[3]; + pml4_entry_t PT4[512]; + pdp_entry_t PT3[512]; + pd_entry_t PT2[512]; + struct user_segment_descriptor gdt[3]; if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) return(EFTYPE); @@ -122,11 +109,11 @@ elf64_exec(struct preloaded_file *fp) */ for (i = 0; i < 512; i++) { /* Each slot of the level 4 pages points to the same level 3 page */ - PT4[i] = (p4_entry_t) 0x3000; + PT4[i] = (pml4_entry_t) 0x3000; PT4[i] |= PG_V | PG_RW; /* Each slot of the level 3 pages points to the same level 2 page */ - PT3[i] = (p3_entry_t) 0x4000; + PT3[i] = (pdp_entry_t) 0x4000; PT3[i] |= PG_V | PG_RW; /* The level 2 page slots are mapped with 2MB pages for 1GB. */ @@ -154,9 +141,9 @@ elf64_exec(struct preloaded_file *fp) CALLBACK(setcr, 3, 0x2000); CALLBACK(setcr, 0, CR0_PG | CR0_PE | CR0_NE); - setup_freebsd_gdt(gdtr); - CALLBACK(copyin, gdtr, 0x5000, sizeof(gdtr)); - CALLBACK(setgdt, 0x5000, sizeof(gdtr)); + setup_freebsd_gdt(gdt); + CALLBACK(copyin, gdt, 0x5000, sizeof(gdt)); + CALLBACK(setgdt, 0x5000, sizeof(gdt)); CALLBACK(exec, ehdr->e_entry);