Date: Fri, 20 Sep 2024 14:59:21 GMT From: Warner Losh <imp@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: f8ca5d45c3c1 - main - stand: Add support for 64-bit machines with 32-bit UEFI implementations Message-ID: <202409201459.48KExLwl046755@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=f8ca5d45c3c1829759ecd87cb95d53e5ab7d0811 commit f8ca5d45c3c1829759ecd87cb95d53e5ab7d0811 Author: Ahmad Khalifa <ahmadkhalifa570@gmail.com> AuthorDate: 2024-05-14 19:40:06 +0000 Commit: Warner Losh <imp@FreeBSD.org> CommitDate: 2024-09-20 14:45:08 +0000 stand: Add support for 64-bit machines with 32-bit UEFI implementations Some machines have 64-bit capable cpus but are stuck on 32-bit uefi firmware. Add support for them by building a new "loader_ia32" with LOADER_DEFAULT_INTERP along with the 64-bit one. The loader can be disabled using MK_LOADER_IA32. Reviewed by: imp Pull Request: https://github.com/freebsd/freebsd-src/pull/1098 --- stand/common/bootstrap.h | 2 +- stand/common/load_elf.c | 4 +- stand/efi/Makefile | 1 + stand/efi/Makefile.inc | 4 + stand/efi/loader/Makefile | 24 ++- stand/efi/loader/arch/i386/Makefile.inc | 9 + stand/efi/loader/arch/i386/amd64_tramp.S | 100 +++++++++++ stand/efi/loader/arch/i386/elf64_freebsd.c | 274 +++++++++++++++++++++++++++++ stand/efi/loader/arch/i386/i386.ldscript | 55 ++++++ stand/efi/loader/arch/i386/setup.c | 51 ++++++ stand/efi/loader/arch/i386/start.S | 75 ++++++++ stand/efi/loader/bootinfo.c | 13 +- stand/efi/loader/conf.c | 4 +- stand/efi/loader/copy.c | 18 +- stand/efi/loader/loader_efi.h | 2 +- stand/efi/loader/main.c | 2 +- stand/efi/loader_ia32/Makefile | 6 + 17 files changed, 621 insertions(+), 23 deletions(-) diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h index 09c4832f5855..ab1e5249fc2a 100644 --- a/stand/common/bootstrap.h +++ b/stand/common/bootstrap.h @@ -239,7 +239,7 @@ struct preloaded_file size_t f_size; /* file size */ struct kernel_module *f_modules; /* list of modules if any */ struct preloaded_file *f_next; /* next file */ -#ifdef __amd64__ +#if defined(__amd64__) || defined(__i386__) bool f_kernphys_relocatable; #endif #if defined(__i386__) diff --git a/stand/common/load_elf.c b/stand/common/load_elf.c index 8877e5f8b7e0..eaa6bef6ee86 100644 --- a/stand/common/load_elf.c +++ b/stand/common/load_elf.c @@ -217,7 +217,7 @@ static int elf_section_header_convert(const Elf_Ehdr *ehdr, Elf_Shdr *shdr) } #endif -#ifdef __amd64__ +#if defined(__amd64__) || defined(__i386__) static bool is_kernphys_relocatable(elf_file_t ef) { @@ -491,7 +491,7 @@ __elfN(loadfile_raw)(char *filename, uint64_t dest, /* Load OK, return module pointer */ *result = (struct preloaded_file *)fp; err = 0; -#ifdef __amd64__ +#if defined(__amd64__) || defined(__i386__) fp->f_kernphys_relocatable = multiboot || is_kernphys_relocatable(&ef); #endif #ifdef __i386__ diff --git a/stand/efi/Makefile b/stand/efi/Makefile index 1a9cf68749a1..1887b9536a5b 100644 --- a/stand/efi/Makefile +++ b/stand/efi/Makefile @@ -11,6 +11,7 @@ SUBDIR.yes+= boot1 gptboot SUBDIR.${MK_FORTH}+= loader_4th SUBDIR.${MK_LOADER_LUA}+= loader_lua +SUBDIR.${MK_LOADER_IA32}+= loader_ia32 SUBDIR.yes+= loader_simp .include <bsd.subdir.mk> diff --git a/stand/efi/Makefile.inc b/stand/efi/Makefile.inc index 18751f0e4ecc..b5bd341d1b78 100644 --- a/stand/efi/Makefile.inc +++ b/stand/efi/Makefile.inc @@ -18,7 +18,11 @@ CFLAGS+= -fPIC .endif .if ${MACHINE_CPUARCH} == "amd64" +.if ${DO32:U0} == 1 +EFI_TARGET= efi-app-ia32 +.else EFI_TARGET= efi-app-x86_64 +.endif .else EFI_TARGET= binary .endif diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile index 8f6802831824..ae25910da2c5 100644 --- a/stand/efi/loader/Makefile +++ b/stand/efi/loader/Makefile @@ -6,7 +6,13 @@ LOADER_EXT2FS_SUPPORT?= no .include <bsd.init.mk> +.if ${MACHINE} == "amd64" && ${DO32:U0} == 1 +__arch= i386 +LOADER?= loader_ia32 +.else +__arch= ${MACHINE} LOADER?= loader_${LOADER_INTERP} +.endif PROG= ${LOADER}.sym INTERNALPROG= WARNS?= 3 @@ -52,13 +58,13 @@ CFLAGS.gfx_fb.c += -DHAVE_MEMCPY -I${SRCTOP}/sys/contrib/zlib CWARNFLAGS.main.c+= -Wno-format .PATH: ${.CURDIR}/../loader -.PATH: ${.CURDIR}/../loader/arch/${MACHINE} -.include "${.CURDIR}/../loader/arch/${MACHINE}/Makefile.inc" +.PATH: ${.CURDIR}/../loader/arch/${__arch} +.include "${.CURDIR}/../loader/arch/${__arch}/Makefile.inc" CFLAGS+= -I${.CURDIR} -CFLAGS+= -I${.CURDIR}/arch/${MACHINE} +CFLAGS+= -I${.CURDIR}/arch/${__arch} CFLAGS+= -I${EFISRC}/include -CFLAGS+= -I${EFISRC}/include/${MACHINE} +CFLAGS+= -I${EFISRC}/include/${__arch} CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include CFLAGS+= -I${BOOTSRC}/i386/libi386 CFLAGS+= -DEFI @@ -95,11 +101,11 @@ CLEANFILES+= 8x16.c FILES+= ${LOADER}.efi FILESMODE_${LOADER}.efi= ${BINMODE} -.if ${LOADER_INTERP} == ${LOADER_DEFAULT_INTERP} +.if ${LOADER_INTERP} == ${LOADER_DEFAULT_INTERP} && ${__arch} != "i386" LINKS+= ${BINDIR}/${LOADER}.efi ${BINDIR}/loader.efi .endif -LDSCRIPT= ${.CURDIR}/../loader/arch/${MACHINE}/${MACHINE}.ldscript +LDSCRIPT= ${.CURDIR}/../loader/arch/${__arch}/${__arch}.ldscript LDFLAGS+= -Wl,-T${LDSCRIPT},-Bsymbolic,-znotext -pie .if ${LINKER_TYPE} == "bfd" && ${LINKER_VERSION} >= 23400 LDFLAGS+= -Wl,--no-dynamic-linker @@ -125,8 +131,14 @@ ${LOADER}.efi: ${PROG} --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} LIBEFI= ${BOOTOBJ}/efi/libefi/libefi.a +LIBEFI32= ${BOOTOBJ}/efi/libefi32/libefi.a +.if ${__arch} == "i386" +DPADD= ${LDR_INTERP32} ${LIBEFI32} ${LIBSA32} ${LDSCRIPT} +LDADD= ${LDR_INTERP32} ${LIBEFI32} ${LIBSA32} +.else DPADD= ${LDR_INTERP} ${LIBEFI} ${LIBSAFDT} ${LIBEFI_FDT} ${LIBSA} ${LDSCRIPT} LDADD= ${LDR_INTERP} ${LIBEFI} ${LIBSAFDT} ${LIBEFI_FDT} ${LIBSA} +.endif .include <bsd.prog.mk> diff --git a/stand/efi/loader/arch/i386/Makefile.inc b/stand/efi/loader/arch/i386/Makefile.inc new file mode 100644 index 000000000000..e27b553c6bab --- /dev/null +++ b/stand/efi/loader/arch/i386/Makefile.inc @@ -0,0 +1,9 @@ +SRCS+= amd64_tramp.S \ + start.S \ + setup.c \ + elf64_freebsd.c + +.PATH: ${BOOTSRC}/i386/libi386 +SRCS+= nullconsole.c \ + comconsole.c \ + spinconsole.c diff --git a/stand/efi/loader/arch/i386/amd64_tramp.S b/stand/efi/loader/arch/i386/amd64_tramp.S new file mode 100644 index 000000000000..06f9262014b3 --- /dev/null +++ b/stand/efi/loader/arch/i386/amd64_tramp.S @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * Copyright (c) 2023 Ahmad Khalifa <ahmadkhalifa570@gmail.com> + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <machine/asmacros.h> + + .text + .globl amd64_tramp + +/* + * void amd64_tramp(uint32_t stack, void *copy_finish, uint32_t kernend, + * uint32_t modulep, uint32_t pagetable, uint32_t gdtr, uint64_t entry) + */ +amd64_tramp: + cli /* Make sure we don't get interrupted. */ + + calll *8(%esp) /* Call copy_finish so we're all ready to go. */ + + movl %cr0, %eax /* Paging may be enabled, disable it. */ + andl $0x7FFFFFFF, %eax + movl %eax, %cr0 + + movl %cr4, %eax /* PAE may be disabled, enable it. */ + orl $0x20, %eax + movl %eax, %cr4 + + movl 20(%esp), %eax /* Swap page tables. */ + movl %eax, %cr3 + + movl $0xC0000080, %ecx /* Enable long mode. */ + rdmsr + orl $0x100, %eax + wrmsr + + movl 12(%esp), %edi /* Stash the kernel and GDT values for later. */ + movl 16(%esp), %esi + movl 24(%esp), %ebx + movl 28(%esp), %edx + movl 32(%esp), %ebp + + movl 4(%esp), %esp /* Switch to our temporary stack. */ + + movl %cr0, %eax /* Enable paging and enter compatibility mode. */ + orl $0x80000000, %eax + movl %eax, %cr0 + + lgdtl (%ebx) /* Load GDT. */ + + pushl %edi /* Push kernend. */ + pushl %esi /* Push modulep. */ + pushl $0x0 + pushl %ebp /* Push 64-bit entry address. */ + pushl %edx + + calll 0f /* Find the address of ".longmode". */ +0: popl %eax + addl $(.longmode-0b), %eax + + pushl $0x8 /* Push CS. */ + pushl %eax /* Push the address. */ + lretl /* "Return" to 64-bit code. */ + + .code64 + +.longmode: + retq /* "Return" to kernel entry. */ + + .code32 + + ALIGN_TEXT +amd64_tramp_end: + + .data + .globl amd64_tramp_size +amd64_tramp_size: + .long amd64_tramp_end-amd64_tramp diff --git a/stand/efi/loader/arch/i386/elf64_freebsd.c b/stand/efi/loader/arch/i386/elf64_freebsd.c new file mode 100644 index 000000000000..ba5117b37016 --- /dev/null +++ b/stand/efi/loader/arch/i386/elf64_freebsd.c @@ -0,0 +1,274 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define __ELF_WORD_SIZE 64 +#include <sys/param.h> +#include <sys/linker.h> +#include <machine/elf.h> + +#include <efi.h> +#include <efilib.h> + +#include "bootstrap.h" + +#include "loader_efi.h" + +extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, + bool exit_bs); + +static int elf64_exec(struct preloaded_file *amp); +static int elf64_obj_exec(struct preloaded_file *amp); + +static struct file_format amd64_elf = { + .l_load = elf64_loadfile, + .l_exec = elf64_exec +}; + +static struct file_format amd64_elf_obj = { + .l_load = elf64_obj_loadfile, + .l_exec = elf64_obj_exec +}; + +struct file_format *file_formats[] = { + &amd64_elf, + &amd64_elf_obj, + 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 + +#define M(x) ((x) * 1024 * 1024) +#define G(x) (1ULL * (x) * 1024 * 1024 * 1024) + +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; + +extern EFI_PHYSICAL_ADDRESS staging; + +static void (*trampoline)(uint32_t stack, void *copy_finish, uint32_t kernend, + uint32_t modulep, uint64_t *pagetable, struct gdtr *gdtr, uint64_t entry); + +extern void *amd64_tramp; +extern uint32_t amd64_tramp_size; + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf64_exec(struct preloaded_file *fp) +{ + EFI_PHYSICAL_ADDRESS ptr; + EFI_ALLOCATE_TYPE type; + EFI_STATUS err; + struct file_metadata *md; + struct gdtr *gdtr; + Elf_Ehdr *ehdr; + vm_offset_t modulep, kernend, trampstack; + int i; + + switch (copy_staging) { + case COPY_STAGING_ENABLE: + type = AllocateMaxAddress; + break; + case COPY_STAGING_DISABLE: + type = AllocateAnyPages; + break; + case COPY_STAGING_AUTO: + type = fp->f_kernphys_relocatable ? + AllocateAnyPages : AllocateMaxAddress; + break; + } + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + 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); + 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); + + ptr = G(1); + err = BS->AllocatePages(type, EfiLoaderData, + EFI_SIZE_TO_PAGES(sizeof(struct gdtr) + sizeof(uint64_t) * 2), &ptr); + if (EFI_ERROR(err)) { + printf("Unable to allocate GDT\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; + + if (type == AllocateMaxAddress) { + /* Copy staging enabled */ + + ptr = G(1); + err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, + EFI_SIZE_TO_PAGES(512 * 3 * 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); + return (ENOMEM); + } + PT4 = (p4_entry_t *)(uintptr_t)ptr; + + PT3 = &PT4[512]; + PT2 = &PT3[512]; + + /* + * This is kinda brutal, but every single 1GB VM + * memory segment points to the same first 1GB of + * physical memory. But it is more than adequate. + */ + for (i = 0; i < 512; i++) { + /* + * Each slot of the L4 pages points to the + * same L3 page. + */ + PT4[i] = (uintptr_t)PT3 | PG_V | PG_RW; + + /* + * Each slot of the L3 pages points to the + * same L2 page. + */ + PT3[i] = (uintptr_t)PT2 | PG_V | PG_RW; + + /* + * The L2 page slots are mapped with 2MB pages for 1GB. + */ + PT2[i] = (i * M(2)) | PG_V | PG_RW | PG_PS; + } + } else { + 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); + return (ENOMEM); + } + PT4 = (p4_entry_t *)(uintptr_t)ptr; + + PT3_l = &PT4[512]; + PT3_u = &PT3_l[512]; + PT2_l0 = &PT3_u[512]; + PT2_l1 = &PT2_l0[512]; + PT2_l2 = &PT2_l1[512]; + PT2_l3 = &PT2_l2[512]; + PT2_u0 = &PT2_l3[512]; + PT2_u1 = &PT2_u0[512]; + + /* 1:1 mapping of lower 4G */ + PT4[0] = (uintptr_t)PT3_l | PG_V | PG_RW; + PT3_l[0] = (uintptr_t)PT2_l0 | PG_V | PG_RW; + PT3_l[1] = (uintptr_t)PT2_l1 | PG_V | PG_RW; + 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; + } + + /* mapping of kernel 2G below top */ + PT4[511] = (uintptr_t)PT3_u | PG_V | PG_RW; + PT3_u[511] = (uintptr_t)PT2_u1 | PG_V | PG_RW; + PT3_u[510] = (uintptr_t)PT2_u0 | PG_V | PG_RW; + /* compat mapping of phys @0 */ + PT2_u0[0] = PG_PS | PG_V | PG_RW; + /* this maps past staging area */ + for (i = 1; i < 1024; i++) { + PT2_u0[i] = (staging + (i - 1) * M(2)) + | PG_V | PG_RW | PG_PS; + } + } + + printf( + "staging %#llx (%scopying) tramp %p PT4 %p GDT %p\n" + "Start @ %#llx ...\n", staging, + type == AllocateMaxAddress ? "" : "not ", trampoline, PT4, GDT, + ehdr->e_entry + ); + + efi_time_fini(); + err = bi_load(fp->f_args, &modulep, &kernend, true); + if (err != 0) { + efi_time_init(); + return (err); + } + + dev_cleanup(); + + trampoline(trampstack, type == AllocateMaxAddress ? efi_copy_finish : + efi_copy_finish_nop, kernend, modulep, PT4, gdtr, ehdr->e_entry); + + panic("exec returned"); +} + +static int +elf64_obj_exec(struct preloaded_file *fp) +{ + return (EFTYPE); +} diff --git a/stand/efi/loader/arch/i386/i386.ldscript b/stand/efi/loader/arch/i386/i386.ldscript new file mode 100644 index 000000000000..dcbbf1b6d609 --- /dev/null +++ b/stand/efi/loader/arch/i386/i386.ldscript @@ -0,0 +1,55 @@ +OUTPUT_FORMAT("elf32-i386-freebsd", "elf32-i386-freebsd", "elf32-i386-freebsd") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + . = SIZEOF_HEADERS; + . = ALIGN(4096); + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.plt) + } =0xCCCCCCCC + . = ALIGN(4096); + .data : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + *(.opd) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.plabel) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + } + . = ALIGN(4096); + __gp = .; + .sdata : { + *(.got.plt .got) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rel.dyn : { + *(.rel.*) + *(.relset_*) + } + . = ALIGN(4096); + .reloc : { *(.reloc) } + . = ALIGN(4096); + .hash : { *(.hash) } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } +} diff --git a/stand/efi/loader/arch/i386/setup.c b/stand/efi/loader/arch/i386/setup.c new file mode 100644 index 000000000000..5d15e499ddb3 --- /dev/null +++ b/stand/efi/loader/arch/i386/setup.c @@ -0,0 +1,51 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Ahmad Khalifa <ahmadkhalifa570@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> + +#include <efi.h> +#include <efilib.h> + +#include <machine/specialreg.h> + +/* + * Check for long mode then call efi_main + */ +EFI_STATUS +setup(EFI_HANDLE IH, EFI_SYSTEM_TABLE *ST) { + u_int edx; + + asm("cpuid" : "=d"(edx) : "a"(0x80000001) : "ebx", "ecx"); + if ((edx & AMDID_LM) == 0) { + ST->ConOut->OutputString(ST->ConOut, (CHAR16 *) + L"This CPU doesn't support long mode.\r\n" + L"Unable to proceed.\r\n"); + ST->BootServices->Exit(IH, EFI_UNSUPPORTED, 0, NULL); + } + + return (efi_main(IH, ST)); +} diff --git a/stand/efi/loader/arch/i386/start.S b/stand/efi/loader/arch/i386/start.S new file mode 100644 index 000000000000..2754c81e509c --- /dev/null +++ b/stand/efi/loader/arch/i386/start.S @@ -0,0 +1,75 @@ +/*- + * Copyright (C) 1999 Hewlett-Packard Co. + * Contributed by David Mosberger <davidm@hpl.hp.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hewlett-Packard Co. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * crt0-efi-ia32.S - x86 EFI startup code. + */ + + .text + .align 4 + + .globl _start +_start: + pushl %ebp + movl %esp, %ebp + + pushl 12(%ebp) + pushl 8(%ebp) + + call 0f +0: popl %eax + movl %eax, %ebx + + addl $ImageBase-0b, %eax + addl $_DYNAMIC-0b, %ebx + + pushl %ebx + pushl %eax + call self_reloc + popl %ebx + popl %ebx + + call setup + +.exit: + leave + ret + + /* + * hand-craft a dummy .reloc section so EFI knows it's a relocatable + * executable: + */ + + .data + .section .reloc, "a" + .long 0 + .long 10 + .word 0 diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c index 0a53422142e2..5afb4c78353e 100644 --- a/stand/efi/loader/bootinfo.c +++ b/stand/efi/loader/bootinfo.c @@ -185,7 +185,7 @@ bi_load_efi_data(struct preloaded_file *kfp, bool exit_bs) struct efi_map_header *efihdr; bool do_vmap; -#if defined(__amd64__) || defined(__aarch64__) +#if defined(__amd64__) || defined(__aarch64__) || defined(__i386__) struct efi_fb efifb; efifb.fb_addr = gfx_state.tg_fb.fb_addr; @@ -339,7 +339,16 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs) vm_offset_t size; char *rootdevname; int howto; +#ifdef __i386__ + /* + * The 32-bit UEFI loader is used to + * boot the 64-bit kernel on machines + * that support it. + */ + bool is64 = true; +#else bool is64 = sizeof(long) == 8; +#endif #if defined(LOADER_FDT_SUPPORT) vm_offset_t dtbp; int dtb_size; @@ -438,7 +447,7 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs) module = *modulep; file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof(module), &module); #endif -#ifdef EFI +#if defined(EFI) && !defined(__i386__) file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(ST), &ST); #endif #ifdef LOADER_GELI_SUPPORT diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c index 3bc74ea6354c..0a0476873fe1 100644 --- a/stand/efi/loader/conf.c +++ b/stand/efi/loader/conf.c @@ -82,7 +82,7 @@ extern struct console eficom; /* Hack for backward compatibility -- but only for a while */ extern struct console comconsole; #endif -#if defined(__amd64__) +#if defined(__amd64__) || defined(__i386__) extern struct console comconsole; extern struct console nullconsole; extern struct console spinconsole; @@ -94,7 +94,7 @@ struct console *consoles[] = { #if defined(__aarch64__) && __FreeBSD_version < 1500000 &comconsole, #endif -#if defined(__amd64__) +#if defined(__amd64__) || defined(__i386__) &comconsole, &nullconsole, &spinconsole, diff --git a/stand/efi/loader/copy.c b/stand/efi/loader/copy.c index a0aea9823632..d34acea4e876 100644 --- a/stand/efi/loader/copy.c +++ b/stand/efi/loader/copy.c @@ -182,13 +182,13 @@ out: #endif #if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ - defined(__riscv) + defined(__riscv) || defined(__i386__) #define EFI_STAGING_2M_ALIGN 1 #else #define EFI_STAGING_2M_ALIGN 0 #endif -#if defined(__amd64__) +#if defined(__amd64__) || defined(__i386__) #define EFI_STAGING_SLOP M(8) #else #define EFI_STAGING_SLOP 0 @@ -209,7 +209,7 @@ efi_copy_free(void) stage_offset = 0; } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__i386__) int copy_staging = COPY_STAGING_AUTO; static int @@ -281,7 +281,7 @@ command_staging_slop(int argc, char *argv[]) COMMAND_SET(staging_slop, "staging_slop", "set staging slop", command_staging_slop); -#if defined(__amd64__) +#if defined(__amd64__) || defined(__i386__) /* * The staging area must reside in the first 1GB or 4GB physical * memory: see elf64_exec() in @@ -320,7 +320,8 @@ efi_copy_init(void) */ if (running_on_hyperv()) efi_verify_staging_size(&nr_pages); - +#endif +#if defined(__amd64__) || defined(__i386__) staging = get_staging_max(); #endif status = BS->AllocatePages(EFI_ALLOC_METHOD, EfiLoaderCode, @@ -380,9 +381,10 @@ efi_check_space(vm_offset_t end) end += staging_slop; nr_pages = EFI_SIZE_TO_PAGES(end - staging_end); -#if defined(__amd64__) +#if defined(__amd64__) || defined(__i386__) /* - * amd64 needs all memory to be allocated under the 1G or 4G boundary. + * The amd64 kernel needs all memory to be allocated under the 1G or + * 4G boundary. */ if (end > get_staging_max()) goto before_staging; @@ -427,7 +429,7 @@ expand: #if EFI_STAGING_2M_ALIGN nr_pages += M(2) / EFI_PAGE_SIZE; #endif -#if defined(__amd64__) +#if defined(__amd64__) || defined(__i386__) new_base = get_staging_max(); #endif status = BS->AllocatePages(EFI_ALLOC_METHOD, EfiLoaderCode, diff --git a/stand/efi/loader/loader_efi.h b/stand/efi/loader/loader_efi.h index 249860aa5e91..c9dfefcd4c74 100644 --- a/stand/efi/loader/loader_efi.h +++ b/stand/efi/loader/loader_efi.h @@ -32,7 +32,7 @@ #include <readin.h> #include <efi.h> -#ifdef __amd64__ +#if defined(__amd64__) || defined(__i386__) enum { COPY_STAGING_ENABLE, COPY_STAGING_DISABLE, diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 69fee3128569..790d5c0ce1ad 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -964,7 +964,7 @@ main(int argc, CHAR16 *argv[]) archsw.arch_getdev = efi_getdev; archsw.arch_copyin = efi_copyin; archsw.arch_copyout = efi_copyout; -#ifdef __amd64__ +#if defined(__amd64__) || defined(__i386__) archsw.arch_hypervisor = x86_hypervisor; #endif archsw.arch_readin = efi_readin; diff --git a/stand/efi/loader_ia32/Makefile b/stand/efi/loader_ia32/Makefile new file mode 100644 index 000000000000..003c75f43948 --- /dev/null +++ b/stand/efi/loader_ia32/Makefile @@ -0,0 +1,6 @@ +DO32=1 +INSTALL_LOADER_HELP_FILE=no + +NEWVERSWHAT?= "EFI loader" amd64-ia32 + +.include "../loader/Makefile"
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202409201459.48KExLwl046755>