git: 5e8bd45ffb41 - main - stand/elf64_freebsd.c: use headers instead of doing things ourselves

From: Warner Losh <imp_at_FreeBSD.org>
Date: Thu, 05 Dec 2024 00:18:56 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=5e8bd45ffb416f6d4e041690e3e656fd907492bf

commit 5e8bd45ffb416f6d4e041690e3e656fd907492bf
Author:     Ahmad Khalifa <ahmadkhalifa570@gmail.com>
AuthorDate: 2024-09-27 16:08:11 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-12-05 00:19:17 +0000

    stand/elf64_freebsd.c: use headers instead of doing things ourselves
    
    Try our best to use headers instead of doing things ourselves. With
    i386's headers, there are some holes we need to fill manually.
    
    Reviewed by: imp
    Pull Request: https://github.com/freebsd/freebsd-src/pull/1446
---
 stand/efi/loader/arch/i386/elf64_freebsd.c | 104 ++++++++++++++++-------------
 stand/i386/libi386/elf64_freebsd.c         |  24 ++++---
 stand/userboot/userboot/elf64_freebsd.c    |  53 ++++++---------
 3 files changed, 89 insertions(+), 92 deletions(-)

diff --git a/stand/efi/loader/arch/i386/elf64_freebsd.c b/stand/efi/loader/arch/i386/elf64_freebsd.c
index 0dc16437d905..b02cda2269bc 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 <sys/param.h>
 #include <sys/linker.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
 #include <machine/elf.h>
+#include <machine/pmap_pae.h>
+#include <machine/segments.h>
 
 #include <efi.h>
 #include <efilib.h>
@@ -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 b1340fd1f2e2..89cc249e9d96 100644
--- a/stand/i386/libi386/elf64_freebsd.c
+++ b/stand/i386/libi386/elf64_freebsd.c
@@ -28,8 +28,11 @@
 #include <sys/param.h>
 #include <sys/exec.h>
 #include <sys/linker.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
 #include <string.h>
 #include <machine/bootinfo.h>
+#include <machine/pmap_pae.h>
 #include <machine/elf.h>
 #include <stand.h>
 
@@ -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 7f817a44da88..5a63fdb4990c 100644
--- a/stand/userboot/userboot/elf64_freebsd.c
+++ b/stand/userboot/userboot/elf64_freebsd.c
@@ -31,9 +31,10 @@
 #ifdef DEBUG
 #include <machine/_inttypes.h>
 #endif
-#include <string.h>
-#include <i386/include/bootinfo.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
 #include <machine/elf.h>
+#include <machine/segments.h>
 #include <stand.h>
 
 #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);