diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 05e128a..f3d47cd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,6 +59,7 @@ jobs: run: | mkdir -p build cp ntloader build/ + cp ntloader.i386 build/ cp ntloader.arm64 build/ cp initrd.cpio build/ cp fsuuid.exe build/ diff --git a/Makefile b/Makefile index 218f53c..ca712e7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ # Versioning information # -VERSION := v3.0.4 +VERSION := v3.0.5 +WIMBOOT_VERSION := v2.8.0 +SBAT_GENERATION := 1 # Abstract target-independent objects # @@ -95,6 +97,8 @@ OBJCOPY_arm64 ?= $(CROSS_arm64)$(OBJCOPY) CFLAGS += -Os -ffreestanding -Wall -W -Werror CFLAGS += -nostdinc -Iinclude/ -fshort-wchar CFLAGS += -DVERSION="\"$(VERSION)\"" +CFLAGS += -DWIMBOOT_VERSION="\"$(WIMBOOT_VERSION)\"" +CFLAGS += -DSBAT_GENERATION="\"$(SBAT_GENERATION)\"" CFLAGS += -include compiler.h ifneq ($(DEBUG),) CFLAGS += -DDEBUG=$(DEBUG) @@ -175,7 +179,7 @@ CFLAGS_arm64 += $(call CFLAGS_COND,arm64) # # Final targets -all : ntloader ntloader.x86_64 ntloader.arm64 +all : ntloader ntloader.i386 ntloader.x86_64 ntloader.arm64 ntloader : ntloader.x86_64 Makefile $(CP) $< $@ @@ -184,6 +188,10 @@ ntloader.%.elf : lib.%.a script.lds Makefile $(LD_$*) $(LDFLAGS) $(LDFLAGS_$*) -T script.lds -o $@ -q \ -Map ntloader.$*.map prefix.$*.o lib.$*.a +ntloader.i386.efi : \ +ntloader.%.efi : ntloader.%.elf elf2efi32 Makefile + ./elf2efi32 $< $@ + ntloader.x86_64.efi ntloader.arm64.efi : \ ntloader.%.efi : ntloader.%.elf elf2efi64 Makefile ./elf2efi64 --hybrid $< $@ @@ -204,6 +212,13 @@ include utils/build.mk %.i386.s : %.c $(HEADERS) Makefile $(CC_i386) $(CFLAGS) $(CFLAGS_i386) -S $< -o $@ +%.i386.o : %.i386.s i386.i Makefile + $(AS_i386) $(ASFLAGS) $(ASFLAGS_i386) i386.i $< -o $@ + +lib.i386.a : $(OBJECTS_i386) Makefile + $(RM) -f $@ + $(AR_i386) -r -s $@ $(OBJECTS_i386) + ############################################################################### # # i386 objects to be linked into an x86_64 binary @@ -255,6 +270,7 @@ lib.arm64.a : $(OBJECTS_arm64) Makefile clean : $(RM) -f $(RM_FILES) $(RM) -f *.s *.o *.a *.elf *.map + $(RM) -f ntloader.i386 ntloader.i386.* $(RM) -f ntloader.x86_64 ntloader.x86_64.* $(RM) -f ntloader.arm64 ntloader.arm64.* $(RM) -f ntloader diff --git a/README.md b/README.md index 217c483..4a32542 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## Compatibility -**Ntloader** supports BIOS (i386) and UEFI (x86_64, arm64) environments. +**Ntloader** supports BIOS (i386) and UEFI (i386, x86_64, arm64) environments. It is recommended to use GRUB2 (>=2.12) or GRUB4DOS to boot NTloader. ## Download diff --git a/docs/header.md b/docs/header.md index 9126a47..de84fcc 100644 --- a/docs/header.md +++ b/docs/header.md @@ -8,9 +8,16 @@ ## Compatibility -**Ntloader** supports BIOS (i386) and UEFI (x86_64, arm64) environments. +**Ntloader** supports BIOS (i386) and UEFI (i386, x86_64, arm64) environments. It is recommended to use GRUB2 (>=2.12) or GRUB4DOS to boot NTloader. +| Platform | ntloader | ntloader.i386 | ntloader.arm64 | +| :------------ | :-: | :-: | :-: | +| BIOS (i386) | yes | no | no | +| UEFI (i386) | no | yes | no | +| UEFI (x86_64) | yes | no | no | +| UEFI (arm64) | no | no | yes | + ## Download The source code is maintained in a git repository at https://github.com/grub4dos/ntloader. diff --git a/kern/die.c b/kern/die.c index 2c2aa38..a7e80ca 100644 --- a/kern/die.c +++ b/kern/die.c @@ -37,6 +37,7 @@ */ void die (const char *fmt, ...) { + EFI_RUNTIME_SERVICES *rs; va_list args; /* Print message */ @@ -50,13 +51,17 @@ void die (const char *fmt, ...) printf ("\n"); /* Reboot system */ -#ifdef __i386__ - reboot (); -#else - EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; - rs->ResetSystem (EfiResetWarm, 0, 0, NULL); - printf ("Failed to reboot\n"); -#endif + if (efi_systab) + { + rs = efi_systab->RuntimeServices; + rs->ResetSystem (EfiResetWarm, 0, 0, NULL); + printf ("Failed to reboot\n"); + + } + else + { + reboot(); + } /* Should be impossible to reach this */ __builtin_unreachable(); diff --git a/kern/efimain.c b/kern/efimain.c index cfa8a6b..14e9702 100644 --- a/kern/efimain.c +++ b/kern/efimain.c @@ -27,6 +27,27 @@ #include "efidisk.h" #include "efi/Protocol/LoadedImage.h" +/** SBAT section attributes */ +#define __sbat __attribute__ ((section (".sbat"), aligned (512))) + +/** SBAT metadata */ +#define SBAT_CSV \ + /* SBAT version */ \ + "sbat,1,SBAT Version,sbat,1," \ + "https://github.com/rhboot/shim/blob/main/SBAT.md" \ + "\n" \ + /* wimboot version */ \ + "wimboot," SBAT_GENERATION ",iPXE,wimboot," WIMBOOT_VERSION "," \ + "https://ipxe.org/wimboot" \ + "\n" \ + /* ntloader version */ \ + "ntloader," SBAT_GENERATION ",a1ive,ntloader," VERSION "," \ + "https://github.com/grub4dos/ntloader" \ + "\n" + +/** SBAT metadata (with no terminating NUL) */ +const char sbat[ sizeof (SBAT_CSV) - 1 ] __sbat = SBAT_CSV; + /** * Process command line * diff --git a/kern/payload.c b/kern/payload.c index 4f31036..fa81aa0 100644 --- a/kern/payload.c +++ b/kern/payload.c @@ -56,7 +56,6 @@ static void read_mem_file (struct vdisk_file *file, void *data, memcpy (data, (file->opaque + offset), len); } -#ifndef __i386__ /** * Get architecture-specific boot filename * @@ -75,7 +74,6 @@ static const CHAR16 *efi_bootarch (void) } return bootarch; } -#endif /** * File handler @@ -87,17 +85,15 @@ static const CHAR16 *efi_bootarch (void) */ static int add_file (const char *name, void *data, size_t len) { -#ifdef __i386__ - const char *bootarch = "bootmgr.exe"; -#else char bootarch[32]; + snprintf (bootarch, sizeof (bootarch), "%ls", efi_bootarch()); -#endif vdisk_add_file (name, data, len, read_mem_file); /* Check for special-case files */ - if (strcasecmp (name, bootarch) == 0) + if ((efi_systab && strcasecmp (name, bootarch) == 0) || + (!efi_systab && strcasecmp (name, "bootmgr.exe") == 0)) { DBG ("...found bootmgr file %s\n", name); nt_cmdline->bootmgr_length = len; diff --git a/libnt/bcd.c b/libnt/bcd.c index f6495b6..b258b5b 100644 --- a/libnt/bcd.c +++ b/libnt/bcd.c @@ -28,6 +28,7 @@ #include "bcd.h" #include "cmdline.h" #include "charset.h" +#include "efi.h" static void bcd_replace_suffix (const wchar_t *src, const wchar_t *dst) @@ -351,9 +352,8 @@ bcd_patch_data (void) bcd_patch_sz (&hive, objects, entry_guid, BCDOPT_SYSROOT, nt_cmdline->sysroot); -#ifdef __i386__ - bcd_replace_suffix (L".efi", L".exe"); -#else - bcd_replace_suffix (L".exe", L".efi"); -#endif + if (efi_systab) + bcd_replace_suffix (L".exe", L".efi"); + else + bcd_replace_suffix (L".efi", L".exe"); } diff --git a/posix/stdio.c b/posix/stdio.c index 9b4bffc..06e18e1 100644 --- a/posix/stdio.c +++ b/posix/stdio.c @@ -37,26 +37,37 @@ */ int putchar (int character) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout; + struct bootapp_callback_params params; + wchar_t wbuf[2]; + /* Convert LF to CR,LF */ if (character == '\n') putchar ('\r'); - /* Print character to EFI/BIOS console as applicable */ -#ifdef __i386__ - struct bootapp_callback_params params; - memset (¶ms, 0, sizeof (params)); - params.vector.interrupt = 0x10; - params.eax = (0x0e00 | character); - params.ebx = 0x0007; - call_interrupt (¶ms); -#else - wchar_t wbuf[2]; - EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; - wbuf[0] = character; - wbuf[1] = 0; - conout->OutputString (conout, wbuf); + /* Print character to bochs debug port */ +#if defined(__i386__) || defined(__x86_64__) + __asm__ __volatile__ ("outb %b0, $0xe9" + : : "a" (character)); #endif + /* Print character to EFI/BIOS console as applicable */ + if (efi_systab) + { + conout = efi_systab->ConOut; + wbuf[0] = character; + wbuf[1] = 0; + conout->OutputString (conout, wbuf); + } + else + { + memset (¶ms, 0, sizeof (params)); + params.vector.interrupt = 0x10; + params.eax = (0x0e00 | character); + params.ebx = 0x0007; + call_interrupt (¶ms); + } + return 0; } @@ -67,23 +78,29 @@ int putchar (int character) */ int getchar (void) { - int character; - -#ifdef __i386__ - struct bootapp_callback_params params; - memset (¶ms, 0, sizeof (params)); - params.vector.interrupt = 0x16; - call_interrupt (¶ms); - character = params.al; -#else + EFI_BOOT_SERVICES *bs; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin; EFI_INPUT_KEY key; UINTN index; - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; - bs->WaitForEvent (1, &conin->WaitForKey, &index); - conin->ReadKeyStroke (conin, &key); - character = key.UnicodeChar; -#endif + struct bootapp_callback_params params; + int character; + + /* Get character */ + if (efi_systab) + { + bs = efi_systab->BootServices; + conin = efi_systab->ConIn; + bs->WaitForEvent (1, &conin->WaitForKey, &index); + conin->ReadKeyStroke (conin, &key); + character = key.UnicodeChar; + } + else + { + memset (¶ms, 0, sizeof (params)); + params.vector.interrupt = 0x16; + call_interrupt (¶ms); + character = params.al; + } return character; } diff --git a/script.lds b/script.lds index 514c3d4..1fc7528 100644 --- a/script.lds +++ b/script.lds @@ -134,6 +134,18 @@ SECTIONS { } _bcd_len = ABSOLUTE ( _ebcd ) - ABSOLUTE ( _bcd ); + /* Secure Boot Advanced Targeting (SBAT) section */ + _sbat_pos = ( _bcd_pos + _bcd_len ); + .sbat : AT ( _sbat_pos ) { + _sbat = .; + *(.sbat) + *(.sbat.*) + _esbat = .; + ASSERT ( ABSOLUTE ( . ) <= ABSOLUTE ( _ebda_start ), + "Binary is too large (overlap the EBDA)" ); + } + _sbat_len = ABSOLUTE ( _esbat ) - ABSOLUTE ( _sbat ); + _end = .; /* Symbols required by i386.x86_64 objects */ diff --git a/utils/build.mk b/utils/build.mk index a22fe57..4d6cc3c 100644 --- a/utils/build.mk +++ b/utils/build.mk @@ -9,6 +9,9 @@ HOST_CFLAGS += -Wall -W -Werror -fshort-wchar -DNTLOADER_UTIL # EFI relocator # +elf2efi32 : utils/elf2efi.c + $(HOST_CC) $(HOST_CFLAGS) -idirafter include/ -DEFI_TARGET32 $< -o $@ + elf2efi64 : utils/elf2efi.c $(HOST_CC) $(HOST_CFLAGS) -idirafter include/ -DEFI_TARGET64 $< -o $@ diff --git a/utils/rootfs/bootia32.efi b/utils/rootfs/bootia32.efi new file mode 100644 index 0000000..f4026aa Binary files /dev/null and b/utils/rootfs/bootia32.efi differ