From 4f47a61ed2896d173474fca99d4d42589c0c10e6 Mon Sep 17 00:00:00 2001 From: Karina Date: Sun, 19 Apr 2026 20:12:59 +0400 Subject: [PATCH] initial --- .gitignore | 2 + Bootloader/CMakeLists.txt | 44 + Bootloader/Source/cmake/aarch64-uefi.cmake | 20 + Bootloader/Source/main.c | 6 + Bootloader/Source/uefi/Makefile | 135 ++ Bootloader/Source/uefi/crt_aarch64.c | 239 ++++ Bootloader/Source/uefi/crt_riscv64.c | 270 ++++ Bootloader/Source/uefi/crt_x86_64.c | 241 ++++ Bootloader/Source/uefi/dirent.c | 76 + Bootloader/Source/uefi/elf_aarch64_efi.lds | 63 + Bootloader/Source/uefi/elf_riscv64_efi.lds | 64 + Bootloader/Source/uefi/elf_x86_64_efi.lds | 76 + Bootloader/Source/uefi/qsort.c | 154 +++ Bootloader/Source/uefi/stat.c | 68 + Bootloader/Source/uefi/stdio.c | 817 +++++++++++ Bootloader/Source/uefi/stdlib.c | 365 +++++ Bootloader/Source/uefi/string.c | 262 ++++ Bootloader/Source/uefi/time.c | 146 ++ Bootloader/Source/uefi/uefi.h | 1446 ++++++++++++++++++++ Bootloader/Source/uefi/unistd.c | 65 + Bootloader/justfile | 14 + justfile | 58 + 22 files changed, 4631 insertions(+) create mode 100644 .gitignore create mode 100644 Bootloader/CMakeLists.txt create mode 100644 Bootloader/Source/cmake/aarch64-uefi.cmake create mode 100644 Bootloader/Source/main.c create mode 100644 Bootloader/Source/uefi/Makefile create mode 100644 Bootloader/Source/uefi/crt_aarch64.c create mode 100644 Bootloader/Source/uefi/crt_riscv64.c create mode 100644 Bootloader/Source/uefi/crt_x86_64.c create mode 100644 Bootloader/Source/uefi/dirent.c create mode 100644 Bootloader/Source/uefi/elf_aarch64_efi.lds create mode 100644 Bootloader/Source/uefi/elf_riscv64_efi.lds create mode 100644 Bootloader/Source/uefi/elf_x86_64_efi.lds create mode 100644 Bootloader/Source/uefi/qsort.c create mode 100644 Bootloader/Source/uefi/stat.c create mode 100644 Bootloader/Source/uefi/stdio.c create mode 100644 Bootloader/Source/uefi/stdlib.c create mode 100644 Bootloader/Source/uefi/string.c create mode 100644 Bootloader/Source/uefi/time.c create mode 100644 Bootloader/Source/uefi/uefi.h create mode 100644 Bootloader/Source/uefi/unistd.c create mode 100644 Bootloader/justfile create mode 100644 justfile diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13359a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.build +.vscode \ No newline at end of file diff --git a/Bootloader/CMakeLists.txt b/Bootloader/CMakeLists.txt new file mode 100644 index 0000000..03faca3 --- /dev/null +++ b/Bootloader/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.20) +project(ksOS_bootloader LANGUAGES C ASM) + +set(UEFI_COMPILE_OPTIONS + -std=c23 + -target aarch64-unknown-windows-msvc + -Wall -Wextra + -fno-builtin +) + +set(POSIX_UEFI_SOURCES + Source/uefi/crt_aarch64.c + Source/uefi/dirent.c + Source/uefi/qsort.c + Source/uefi/stat.c + Source/uefi/stdio.c + Source/uefi/stdlib.c + Source/uefi/string.c + Source/uefi/time.c + Source/uefi/unistd.c +) + +add_library(posix_uefi_lib STATIC ${POSIX_UEFI_SOURCES}) +target_compile_options(posix_uefi_lib PRIVATE ${UEFI_COMPILE_OPTIONS}) +target_include_directories(posix_uefi_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Source/uefi) + +add_executable(BOOTAA64 Source/main.c) +target_compile_options(BOOTAA64 PRIVATE ${UEFI_COMPILE_OPTIONS}) + +target_link_libraries(BOOTAA64 PRIVATE posix_uefi_lib) + +target_link_options(BOOTAA64 PRIVATE + -fuse-ld=lld + -target aarch64-unknown-windows-msvc + -nostdlib + -Wl,-subsystem:efi_application + -Wl,-entry:uefi_init +) + +set_target_properties(BOOTAA64 PROPERTIES + SUFFIX ".EFI" + OUTPUT_NAME "BOOTAA64" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/efi_bin" +) \ No newline at end of file diff --git a/Bootloader/Source/cmake/aarch64-uefi.cmake b/Bootloader/Source/cmake/aarch64-uefi.cmake new file mode 100644 index 0000000..d62a460 --- /dev/null +++ b/Bootloader/Source/cmake/aarch64-uefi.cmake @@ -0,0 +1,20 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_ASM_COMPILER clang) + +set(TARGET_TRIPLE "aarch64-unknown-windows-msvc") +set(CMAKE_C_COMPILER_TARGET ${TARGET_TRIPLE}) +set(CMAKE_ASM_COMPILER_TARGET ${TARGET_TRIPLE}) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +set(UEFI_PLATFORM_FLAGS + "-ffreestanding -fno-stack-protector -fshort-wchar" +) + +set(CMAKE_C_FLAGS_INIT "${UEFI_PLATFORM_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld") \ No newline at end of file diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c new file mode 100644 index 0000000..e9586c9 --- /dev/null +++ b/Bootloader/Source/main.c @@ -0,0 +1,6 @@ +#include "uefi/uefi.h" + +int main() { + printf("Meow!\n"); + return 0; +} \ No newline at end of file diff --git a/Bootloader/Source/uefi/Makefile b/Bootloader/Source/uefi/Makefile new file mode 100644 index 0000000..64952c1 --- /dev/null +++ b/Bootloader/Source/uefi/Makefile @@ -0,0 +1,135 @@ +# detect architecture +MYARCH = $(shell uname -m | sed s,i[3456789]86,ia32, | sed s,amd,x86_,) +ifeq ($(ARCH),) +ARCH = $(MYARCH) +endif + +# get source files, generate object names +ifeq ($(SRCS),) +SRCS = $(wildcard *.c) $(wildcard *.S) +endif +ifeq ($(OBJS),) +TMP = $(SRCS:.c=.o) +OBJS = $(TMP:.S=.o) +endif +ifneq ($(OUTDIR),) +# OUTDIR is not used with uefi/*.o deliberately +OUTDIR:=$(addsuffix /,$(OUTDIR)) +endif +CFLAGS += -fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -I. -I./uefi \ + -I/usr/include -I/usr/include/efi -I/usr/include/efi/protocol -I/usr/include/efi/$(ARCH) -D__$(ARCH)__ +ifeq ($(ARCH),x86_64) +CFLAGS += -DHAVE_USE_MS_ABI -mno-red-zone +endif + +# for libuefi.a +LIBSRCS = $(filter-out $(wildcard crt_*.c),$(wildcard *.c)) $(wildcard *.S) +TMP2 = $(LIBSRCS:.c=.o) +LIBOBJS = $(TMP2:.S=.o) +MAKE ?= make + +# detect toolchain +ifeq ($(wildcard /usr/bin/clang)$(wildcard /usr/local/bin/clang)$(wildcard /usr/lib/llvm/*/bin/clang)$(wildcard /gnu/store/*/bin/clang),) +USE_GCC = 1 +endif +ifneq ($(USE_GCC),) +ifeq ($(ARCH),x86_64) +CFLAGS += -maccumulate-outgoing-args +endif +CFLAGS += -Wno-builtin-declaration-mismatch -fpic -fPIC +LDFLAGS += -nostdlib -shared -Bsymbolic -Luefi uefi/crt_$(ARCH).o +LIBS += -o $(addprefix $(OUTDIR),$(TARGET).so) -luefi -T uefi/elf_$(ARCH)_efi.lds +# see if we're cross-compiling +ifneq ($(ARCH),$(MYARCH)) +CC = $(ARCH)-elf-gcc +LD = $(ARCH)-elf-ld +OBJCOPY ?= $(ARCH)-elf-objcopy +else +CC = gcc +LD = ld +OBJCOPY ?= objcopy +endif +ifeq ($(ARCH),aarch64) +EFIARCH = pei-aarch64-little +else +ifeq ($(ARCH),riscv64) +EFIARCH = pei-riscv64-little +else +EFIARCH = efi-app-$(ARCH) +endif +endif +AR ?= ar +else +CFLAGS += --target=$(ARCH)-pc-win32-coff -Wno-builtin-requires-header -Wno-incompatible-library-redeclaration -Wno-long-long +LDFLAGS += -subsystem:efi_application -nodefaultlib -dll -entry:uefi_init uefi/*.o +LIBS = -out:$(addprefix $(OUTDIR),$(TARGET)) +CC = clang +LD = lld -flavor link +OBJCOPY = true +endif + +# recipies +ifeq ($(wildcard uefi/Makefile),) +ALLTARGETS = crt_$(ARCH).o libuefi.a buildlib +else +ALLTARGETS = uefi/crt_$(ARCH).o uefi/libuefi.a $(OBJS) $(TARGET) +endif + +all: $(OUTDIR) $(EXTRA) $(ALLTARGETS) $(ALSO) + +ifneq ($(OUTDIR),) +$(OUTDIR): + @mkdir -p $(OUTDIR) +endif + +uefi/libuefi.a: + @$(MAKE) --no-print-directory -C uefi libuefi.a USE_GCC=$(USE_GCC) ARCH=$(ARCH) + +libuefi.lib: $(LIBOBJS) + +libuefi.a: $(LIBOBJS) + @rm $@ 2>/dev/null || true + $(AR) -rsv $@ $(LIBOBJS) >/dev/null + +$(TARGET): $(addprefix $(OUTDIR),$(TARGET).so) +ifneq ($(USE_GCC),) + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target $(EFIARCH) --subsystem=10 $^ $(addprefix $(OUTDIR),$@) || echo target: $(EFIARCH) + @rm $(addprefix $(OUTDIR),$(TARGET).so) +endif + +$(addprefix $(OUTDIR),$(TARGET).so): $(addprefix $(OUTDIR),$(OBJS)) $(EXTRA) + $(LD) $(LDFLAGS) $^ $(LIBS) + @rm $(addprefix $(OUTDIR),*.lib) 2>/dev/null || true + +uefi/%.o: uefi/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $(addprefix $(OUTDIR),$@) + +%.o: %.S + $(CC) $(CFLAGS) -c $< -o $(addprefix $(OUTDIR),$@) + +buildlib: + @mkdir ../build ../build/uefi 2>/dev/null || true + @cp crt_$(ARCH).o ../build/uefi/crt0.o + @cp elf_$(ARCH)_efi.lds ../build/uefi/link.ld +ifneq ($(USE_GCC),) + @cp libuefi.a uefi.h ../build/uefi +else + @cp uefi.h ../build/uefi + @cp libuefi.a ../build/uefi/libuefi.dll.a +endif + +clean: + @rm $(addprefix $(OUTDIR),$(TARGET)) *.o *.a *.lib *.elf $(LIBOBJS) 2>/dev/null || true +ifneq ($(OUTDIR),) + @rm -rf $(OUTDIR) +endif + +distclean: clean +ifeq ($(wildcard uefi/Makefile),) + @rm -rf ../build 2>/dev/null || true +else + @rm uefi/*.o uefi/libuefi.a 2>/dev/null || true +endif diff --git a/Bootloader/Source/uefi/crt_aarch64.c b/Bootloader/Source/uefi/crt_aarch64.c new file mode 100644 index 0000000..82324a5 --- /dev/null +++ b/Bootloader/Source/uefi/crt_aarch64.c @@ -0,0 +1,239 @@ +/* + * crt_aarch64.c + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief C runtime, bootstraps an EFI application to call standard main() + * + */ + +#include + +/* this is implemented by the application */ +extern int main(int argc, char_t **argv); + +/* definitions for elf relocations */ +#ifndef __clang__ +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint64_t Elf64_Addr; +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define R_AARCH64_RELATIVE 1027 /* Adjust by program base */ +#endif + +/* globals to store system table pointers */ +efi_handle_t IM = NULL; +efi_system_table_t *ST = NULL; +efi_boot_services_t *BS = NULL; +efi_runtime_services_t *RT = NULL; +efi_loaded_image_protocol_t *LIP = NULL; +#ifndef UEFI_NO_UTF8 +char *__argvutf8 = NULL; +#endif + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap(void) +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" +#ifndef __clang__ + " .globl _start\n" + "_start:\n" + " ldr x2, =ImageBase\n" + " adrp x3, _DYNAMIC\n" + " add x3, x3, #:lo12:_DYNAMIC\n" + " bl uefi_init\n" + " ret\n" + + /* fake a relocation record, so that EFI won't complain */ + " .data\n" + "dummy: .long 0\n" + " .section .reloc, \"a\"\n" + "label1:\n" + " .long dummy-label1\n" + " .long 10\n" + " .word 0\n" + ".text\n" +#else + " .globl __chkstk\n" + "__chkstk:\n" + " ret\n" +#endif + ); + + /* setjmp and longjmp */ + __asm__ __volatile__ ( + " .p2align 3\n" + " .globl setjmp\n" + "setjmp:\n" + " mov x16, sp\n" + " stp x19, x20, [x0, #0]\n" + " stp x21, x22, [x0, #16]\n" + " stp x23, x24, [x0, #32]\n" + " stp x25, x26, [x0, #48]\n" + " stp x27, x28, [x0, #64]\n" + " stp x29, x30, [x0, #80]\n" + " str x16, [x0, #96]\n" + " stp d8, d9, [x0, #112]\n" + " stp d10, d11, [x0, #128]\n" + " stp d12, d13, [x0, #144]\n" + " stp d14, d15, [x0, #160]\n" + " mov w0, #0\n" + " ret\n" + ); + __asm__ __volatile__ ( + " .globl longjmp\n" + "longjmp:\n" + " ldp x19, x20, [x0, #0]\n" + " ldp x21, x22, [x0, #16]\n" + " ldp x23, x24, [x0, #32]\n" + " ldp x25, x26, [x0, #48]\n" + " ldp x27, x28, [x0, #64]\n" + " ldp x29, x30, [x0, #80]\n" + " ldr x16, [x0, #96]\n" + " ldp d8, d9, [x0, #112]\n" + " ldp d10, d11, [x0, #128]\n" + " ldp d12, d13, [x0, #144]\n" + " ldp d14, d15, [x0, #160]\n" + " mov sp, x16\n" + " cmp w1, #0\n" + " mov w0, #1\n" + " csel w0, w1, w0, ne\n" + " br x30\n" + ); +} + +/** + * Initialize POSIX-UEFI and call the application's main() function + */ +efi_status_t uefi_init ( + efi_handle_t image, efi_system_table_t *systab +#ifndef __clang__ + , uintptr_t ldbase, Elf64_Dyn *dyn +#endif +) { + efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; + efi_shell_parameters_protocol_t *shp = NULL; + efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID; + efi_shell_interface_protocol_t *shi = NULL; + efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + efi_status_t status; + int argc = 0, i, ret; + wchar_t **argv = NULL; +#ifndef UEFI_NO_UTF8 + int j; + char *s; +#endif +#ifndef __clang__ + long relsz = 0, relent = 0; + Elf64_Rel *rel = 0; + uintptr_t *addr; + /* handle relocations */ + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break; + case DT_RELASZ: relsz = dyn[i].d_un.d_val; break; + case DT_RELAENT: relent = dyn[i].d_un.d_val; break; + default: break; + } + } + if (rel && relent) { + while (relsz > 0) { + if(ELF64_R_TYPE (rel->r_info) == R_AARCH64_RELATIVE) + { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + } +#else + (void)i; +#endif + /* failsafes, should never happen */ + if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || + !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) + return EFI_UNSUPPORTED; + /* save EFI pointers and loaded image into globals */ + IM = image; + ST = systab; + BS = systab->BootServices; + RT = systab->RuntimeServices; + BS->HandleProtocol(image, &lipGuid, (void **)&LIP); + /* get command line arguments */ + status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; } + else { + /* if shell 2.0 failed, fallback to shell 1.0 interface */ + status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; } + } + /* call main */ +#ifndef UEFI_NO_UTF8 + if(argc && argv) { + ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); + for(i = 0; i < argc; i++) + for(j = 0; argv[i] && argv[i][j]; j++) + ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); + if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } + else { + s = __argvutf8 + argc * (int)sizeof(uintptr_t); + *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); + for(i = 0; i < argc; i++) { + *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; + for(j = 0; argv[i] && argv[i][j]; j++) { + if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else + if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else + { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } + } + *s++ = 0; + } + } + } + ret = main(argc, (char**)__argvutf8); + if(__argvutf8) BS->FreePool(__argvutf8); + return ret; +#else + ret = main(argc, argv); +#endif + return ret ? EFIERR(ret) : EFI_SUCCESS; +} diff --git a/Bootloader/Source/uefi/crt_riscv64.c b/Bootloader/Source/uefi/crt_riscv64.c new file mode 100644 index 0000000..77b52ae --- /dev/null +++ b/Bootloader/Source/uefi/crt_riscv64.c @@ -0,0 +1,270 @@ +/* + * crt_riscv64.c + * + * Copyright (C) 2023 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief C runtime, bootstraps an EFI application to call standard main() + * + */ + +#include + +/* this is implemented by the application */ +extern int main(int argc, char_t **argv); + +/* definitions for elf relocations */ +#ifndef __clang__ +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint64_t Elf64_Addr; +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define R_RISCV_RELATIVE 3 /* Adjust by program base */ +#endif + +/* globals to store system table pointers */ +efi_handle_t IM = NULL; +efi_system_table_t *ST = NULL; +efi_boot_services_t *BS = NULL; +efi_runtime_services_t *RT = NULL; +efi_loaded_image_protocol_t *LIP = NULL; +#ifndef UEFI_NO_UTF8 +char *__argvutf8 = NULL; +#endif + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap(void) +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" +#ifndef __clang__ + " .globl _start\n" + "_start:\n" + " lla a2, ImageBase\n" + " lui a3, %hi(_DYNAMIC)\n" + " addi a3, a3, %lo(_DYNAMIC)\n" + " call uefi_init\n" + " ret\n" + + /* fake a relocation record, so that EFI won't complain */ + " .data\n" + "dummy: .long 0\n" + " .section .reloc, \"a\"\n" + "label1:\n" + " .long dummy-label1\n" + " .long 10\n" + " .word 0\n" + ".text\n" +#else + " .globl __chkstk\n" + "__chkstk:\n" + " ret\n" +#endif + ); + + /* setjmp and longjmp */ + __asm__ __volatile__ ( + " .p2align 3\n" + " .globl setjmp\n" + "setjmp:\n" + " sd ra, 0(a0)\n" + " sd sp, 8(a0)\n" + " sd s0, 16(a0)\n" + " sd s1, 24(a0)\n" + " sd s2, 32(a0)\n" + " sd s3, 40(a0)\n" + " sd s4, 48(a0)\n" + " sd s5, 56(a0)\n" + " sd s6, 64(a0)\n" + " sd s7, 72(a0)\n" + " sd s8, 80(a0)\n" + " sd s9, 88(a0)\n" + " sd s10, 96(a0)\n" + " sd s11, 104(a0)\n" +#ifndef __riscv_float_abi_soft + " fsd fs0, 112(a0)\n" + " fsd fs1, 120(a0)\n" + " fsd fs2, 128(a0)\n" + " fsd fs3, 136(a0)\n" + " fsd fs4, 144(a0)\n" + " fsd fs5, 152(a0)\n" + " fsd fs6, 160(a0)\n" + " fsd fs7, 168(a0)\n" + " fsd fs8, 176(a0)\n" + " fsd fs9, 184(a0)\n" + " fsd fs10,192(a0)\n" + " fsd fs11,200(a0)\n" +#endif + " li a0, 0\n" + " ret\n" + ); + __asm__ __volatile__ ( + " .globl longjmp\n" + "longjmp:\n" + " ld ra, 0(a0)\n" + " ld sp, 8(a0)\n" + " ld s0, 16(a0)\n" + " ld s1, 24(a0)\n" + " ld s2, 32(a0)\n" + " ld s3, 40(a0)\n" + " ld s4, 48(a0)\n" + " ld s5, 56(a0)\n" + " ld s6, 64(a0)\n" + " ld s7, 72(a0)\n" + " ld s8, 80(a0)\n" + " ld s9, 88(a0)\n" + " ld s10, 96(a0)\n" + " ld s11, 104(a0)\n" +#ifndef __riscv_float_abi_soft + " fld fs0, 112(a0)\n" + " fld fs1, 120(a0)\n" + " fld fs2, 128(a0)\n" + " fld fs3, 136(a0)\n" + " fld fs4, 144(a0)\n" + " fld fs5, 152(a0)\n" + " fld fs6, 160(a0)\n" + " fld fs7, 168(a0)\n" + " fld fs8, 176(a0)\n" + " fld fs9, 184(a0)\n" + " fld fs10,192(a0)\n" + " fld fs11,200(a0)\n" +#endif + " seqz a0, a1\n" + " add a0, a0, a1\n" + " ret\n" + ); +} + +/** + * Initialize POSIX-UEFI and call the application's main() function + */ +efi_status_t uefi_init ( + efi_handle_t image, efi_system_table_t *systab +#ifndef __clang__ + , uintptr_t ldbase, Elf64_Dyn *dyn +#endif +) { + efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; + efi_shell_parameters_protocol_t *shp = NULL; + efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID; + efi_shell_interface_protocol_t *shi = NULL; + efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + efi_status_t status; + int argc = 0, i, ret; + wchar_t **argv = NULL; +#ifndef UEFI_NO_UTF8 + int j; + char *s; +#endif +#ifndef __clang__ + long relsz = 0, relent = 0; + Elf64_Rel *rel = 0; + uintptr_t *addr; + /* handle relocations */ + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break; + case DT_RELASZ: relsz = dyn[i].d_un.d_val; break; + case DT_RELAENT: relent = dyn[i].d_un.d_val; break; + default: break; + } + } + if (rel && relent) { + while (relsz > 0) { + if(ELF64_R_TYPE (rel->r_info) == R_RISCV_RELATIVE) + { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + } +#else + (void)i; +#endif + /* failsafes, should never happen */ + if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || + !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) + return EFI_UNSUPPORTED; + /* save EFI pointers and loaded image into globals */ + IM = image; + ST = systab; + BS = systab->BootServices; + RT = systab->RuntimeServices; + BS->HandleProtocol(image, &lipGuid, (void **)&LIP); + /* get command line arguments */ + status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; } + else { + /* if shell 2.0 failed, fallback to shell 1.0 interface */ + status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; } + } + /* call main */ +#ifndef UEFI_NO_UTF8 + if(argc && argv) { + ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); + for(i = 0; i < argc; i++) + for(j = 0; argv[i] && argv[i][j]; j++) + ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); + if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } + else { + s = __argvutf8 + argc * (int)sizeof(uintptr_t); + *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); + for(i = 0; i < argc; i++) { + *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; + for(j = 0; argv[i] && argv[i][j]; j++) { + if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else + if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else + { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } + } + *s++ = 0; + } + } + } + ret = main(argc, (char**)__argvutf8); + if(__argvutf8) BS->FreePool(__argvutf8); + return ret; +#else + ret = main(argc, argv); +#endif + return ret ? EFIERR(ret) : EFI_SUCCESS; +} diff --git a/Bootloader/Source/uefi/crt_x86_64.c b/Bootloader/Source/uefi/crt_x86_64.c new file mode 100644 index 0000000..b146bb3 --- /dev/null +++ b/Bootloader/Source/uefi/crt_x86_64.c @@ -0,0 +1,241 @@ +/* + * crt_x86_64.c + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief C runtime, bootstraps an EFI application to call standard main() + * + */ + +#include + +/* this is implemented by the application */ +extern int main(int argc, char_t **argv); + +/* definitions for elf relocations */ +#ifndef __clang__ +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint64_t Elf64_Addr; +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#endif + +/* globals to store system table pointers */ +efi_handle_t IM = NULL; +efi_system_table_t *ST = NULL; +efi_boot_services_t *BS = NULL; +efi_runtime_services_t *RT = NULL; +efi_loaded_image_protocol_t *LIP = NULL; +#ifndef UEFI_NO_UTF8 +char *__argvutf8 = NULL; +#endif + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap(void) +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" +#ifndef __clang__ + " .globl _start\n" + "_start:\n" + " lea ImageBase(%rip), %rdi\n" + " lea _DYNAMIC(%rip), %rsi\n" + " call uefi_init\n" + " ret\n" + + /* fake a relocation record, so that EFI won't complain */ + " .data\n" + "dummy: .long 0\n" + " .section .reloc, \"a\"\n" + "label1:\n" + " .long dummy-label1\n" + " .long 10\n" + " .word 0\n" + ".text\n" +#else + " .globl __chkstk\n" + "__chkstk:\n" + " ret\n" +#endif + ); + + /* setjmp and longjmp */ + __asm__ __volatile__ ( + " .globl setjmp\n" + "setjmp:\n" + " pop %rsi\n" + " movq %rbx,0x00(%rdi)\n" + " movq %rsp,0x08(%rdi)\n" + " push %rsi\n" + " movq %rbp,0x10(%rdi)\n" + " movq %r12,0x18(%rdi)\n" + " movq %r13,0x20(%rdi)\n" + " movq %r14,0x28(%rdi)\n" + " movq %r15,0x30(%rdi)\n" + " movq %rsi,0x38(%rdi)\n" + " xor %rax,%rax\n" + " ret\n" + ); + __asm__ __volatile__ ( + " .globl longjmp\n" + "longjmp:\n" + " movl %esi, %eax\n" + " movq 0x00(%rdi), %rbx\n" + " movq 0x08(%rdi), %rsp\n" + " movq 0x10(%rdi), %rbp\n" + " movq 0x18(%rdi), %r12\n" + " movq 0x20(%rdi), %r13\n" + " movq 0x28(%rdi), %r14\n" + " movq 0x30(%rdi), %r15\n" + " xor %rdx,%rdx\n" + " mov $1,%rcx\n" + " cmp %rax,%rdx\n" + " cmove %rcx,%rax\n" + " jmp *0x38(%rdi)\n" + ); +} + +/** + * Initialize POSIX-UEFI and call the application's main() function + */ +efi_status_t uefi_init ( +#ifndef __clang__ + uintptr_t ldbase, Elf64_Dyn *dyn, efi_system_table_t *systab, efi_handle_t image +#else + efi_handle_t image, efi_system_table_t *systab +#endif +) { + efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; + efi_shell_parameters_protocol_t *shp = NULL; + efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID; + efi_shell_interface_protocol_t *shi = NULL; + efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + efi_status_t status; + int argc = 0, i, ret; + wchar_t **argv = NULL; +#ifndef UEFI_NO_UTF8 + int j; + char *s; +#endif +#ifndef __clang__ + long relsz = 0, relent = 0; + Elf64_Rel *rel = 0; + uintptr_t *addr; + /* handle relocations */ + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break; + case DT_RELASZ: relsz = dyn[i].d_un.d_val; break; + case DT_RELAENT: relent = dyn[i].d_un.d_val; break; + default: break; + } + } + if (rel && relent) { + while (relsz > 0) { + if(ELF64_R_TYPE (rel->r_info) == R_X86_64_RELATIVE) + { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + } +#else + (void)i; +#endif + /* make sure SSE is enabled, because some say there are buggy firmware in the wild not doing that */ + __asm__ __volatile__ ( + " movq %cr0, %rax\n" + " andb $0xF1, %al\n" + " movq %rax, %cr0\n" + " movq %cr4, %rax\n" + " orw $3 << 9, %ax\n" + " mov %rax, %cr4\n" + ); + /* failsafes, should never happen */ + if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || + !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) + return EFI_UNSUPPORTED; + /* save EFI pointers and loaded image into globals */ + IM = image; + ST = systab; + BS = systab->BootServices; + RT = systab->RuntimeServices; + BS->HandleProtocol(image, &lipGuid, (void **)&LIP); + /* get command line arguments */ + status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; } + else { + /* if shell 2.0 failed, fallback to shell 1.0 interface */ + status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; } + } + /* call main */ +#ifndef UEFI_NO_UTF8 + if(argc && argv) { + ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); + for(i = 0; i < argc; i++) + for(j = 0; argv[i] && argv[i][j]; j++) + ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); + if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } + else { + s = __argvutf8 + argc * (int)sizeof(uintptr_t); + *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); + for(i = 0; i < argc; i++) { + *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; + for(j = 0; argv[i] && argv[i][j]; j++) { + if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else + if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else + { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } + } + *s++ = 0; + } + } + } + ret = main(argc, (char**)__argvutf8); + if(__argvutf8) BS->FreePool(__argvutf8); +#else + ret = main(argc, argv); +#endif + return ret ? EFIERR(ret) : EFI_SUCCESS; +} diff --git a/Bootloader/Source/uefi/dirent.c b/Bootloader/Source/uefi/dirent.c new file mode 100644 index 0000000..402011c --- /dev/null +++ b/Bootloader/Source/uefi/dirent.c @@ -0,0 +1,76 @@ +/* + * dirent.c + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief Implementing functions which are defined in dirent.h + * + */ + +#include + +extern void __stdio_seterrno(efi_status_t status); +static struct dirent __dirent; + +DIR *opendir (const char_t *__name) +{ + DIR *dp = (DIR*)fopen(__name, CL("rd")); + if(dp) rewinddir(dp); + return dp; +} + +struct dirent *readdir (DIR *__dirp) +{ + efi_status_t status; + efi_file_info_t info; + uintn_t bs = sizeof(efi_file_info_t); + memset(&__dirent, 0, sizeof(struct dirent)); + status = __dirp->Read(__dirp, &bs, &info); + if(EFI_ERROR(status) || !bs) { + if(EFI_ERROR(status)) __stdio_seterrno(status); + else errno = 0; + return NULL; + } + __dirent.d_type = info.Attribute & EFI_FILE_DIRECTORY ? DT_DIR : DT_REG; +#ifndef UEFI_NO_UTF8 + __dirent.d_reclen = (unsigned short int)wcstombs(__dirent.d_name, info.FileName, FILENAME_MAX - 1); +#else + __dirent.d_reclen = strlen(info.FileName); + strncpy(__dirent.d_name, info.FileName, FILENAME_MAX - 1); +#endif + return &__dirent; +} + +void rewinddir (DIR *__dirp) +{ + if(__dirp) + __dirp->SetPosition(__dirp, 0); +} + +int closedir (DIR *__dirp) +{ + return fclose((FILE*)__dirp); +} + + diff --git a/Bootloader/Source/uefi/elf_aarch64_efi.lds b/Bootloader/Source/uefi/elf_aarch64_efi.lds new file mode 100644 index 0000000..836d982 --- /dev/null +++ b/Bootloader/Source/uefi/elf_aarch64_efi.lds @@ -0,0 +1,63 @@ +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_start) +SECTIONS +{ + .text 0x0 : { + _text = .; + *(.text.head) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.srodata) + *(.rodata*) + . = ALIGN(16); + } + _etext = .; + _text_size = . - _text; + .dynamic : { *(.dynamic) } + .data : ALIGN(4096) + { + _data = .; + *(.sdata) + *(.data) + *(.data1) + *(.data.*) + *(.got.plt) + *(.got) + + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + . = ALIGN(16); + _bss = .; + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(16); + _bss_end = .; + } + + .rela.dyn : { *(.rela.dyn) } + .rela.plt : { *(.rela.plt) } + .rela.got : { *(.rela.got) } + .rela.data : { *(.rela.data) *(.rela.data*) } + . = ALIGN(512); + _edata = .; + _data_size = . - _data; + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .note.gnu.build-id : { *(.note.gnu.build-id) } + /DISCARD/ : + { + *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff --git a/Bootloader/Source/uefi/elf_riscv64_efi.lds b/Bootloader/Source/uefi/elf_riscv64_efi.lds new file mode 100644 index 0000000..6f1936b --- /dev/null +++ b/Bootloader/Source/uefi/elf_riscv64_efi.lds @@ -0,0 +1,64 @@ +OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(_start) +SECTIONS +{ + .text 0x0 : { + _text = .; + *(.text.head) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.srodata) + *(.rodata*) + . = ALIGN(16); + } + _etext = .; + _text_size = . - _text; + .dynamic : { *(.dynamic) } + .data : ALIGN(4096) + { + _data = .; + *(.sdata) + *(.data) + *(.data1) + *(.data.*) + *(.got.plt) + *(.got) + + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + . = ALIGN(16); + _bss = .; + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(16); + _bss_end = .; + } + + .rela.text : { *(.rela.text) *(.rela.text*) } + .rela.dyn : { *(.rela.dyn) } + .rela.plt : { *(.rela.plt) } + .rela.got : { *(.rela.got) } + .rela.data : { *(.rela.data) *(.rela.data*) } + . = ALIGN(512); + _edata = .; + _data_size = . - _data; + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .note.gnu.build-id : { *(.note.gnu.build-id) } + /DISCARD/ : + { + *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff --git a/Bootloader/Source/uefi/elf_x86_64_efi.lds b/Bootloader/Source/uefi/elf_x86_64_efi.lds new file mode 100644 index 0000000..7be5902 --- /dev/null +++ b/Bootloader/Source/uefi/elf_x86_64_efi.lds @@ -0,0 +1,76 @@ +/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + . = 0; + ImageBase = .; + /* .hash and/or .gnu.hash MUST come first! */ + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + . = ALIGN(4096); + .eh_frame : + { + *(.eh_frame) + } + . = ALIGN(4096); + .text : + { + _text = .; + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + . = ALIGN(16); + } + _etext = .; + _text_size = . - _text; + . = ALIGN(4096); + .reloc : + { + *(.reloc) + } + . = ALIGN(4096); + .data : + { + _data = .; + *(.rodata*) + *(.got.plt) + *(.got) + *(.data*) + *(.sdata) + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + *(.rel.local) + } + .note.gnu.build-id : { *(.note.gnu.build-id) } + + _edata = .; + _data_size = . - _etext; + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rela : + { + *(.rela.data*) + *(.rela.got) + *(.rela.stab) + } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .ignored.reloc : + { + *(.rela.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff --git a/Bootloader/Source/uefi/qsort.c b/Bootloader/Source/uefi/qsort.c new file mode 100644 index 0000000..d6563c9 --- /dev/null +++ b/Bootloader/Source/uefi/qsort.c @@ -0,0 +1,154 @@ +/* + * qsort.c + * + * @brief from OpenBSD + */ + +/* $OpenBSD: qsort.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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 the University 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 REGENTS 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 REGENTS 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 + +static __inline char *med3(char *, char *, char *, __compar_fn_t cmp); +static __inline void swapfunc(char *, char *, int, int); +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; +static __inline void +swapfunc(char *a, char *b, int n, int swaptype) +{ + if (swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) +static __inline char * +med3(char *a, char *b, char *c, __compar_fn_t cmp) +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void qsort(void *aa, size_t n, size_t es, __compar_fn_t cmp) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + char *a = aa; +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - (int)es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/Bootloader/Source/uefi/stat.c b/Bootloader/Source/uefi/stat.c new file mode 100644 index 0000000..017a4f8 --- /dev/null +++ b/Bootloader/Source/uefi/stat.c @@ -0,0 +1,68 @@ +/* + * stat.c + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief Implementing functions which are defined in sys/stat.h + * + */ + +#include + +/* fstat is in stdio.c because we can't access static variables otherwise... */ + +int stat (const char_t *__file, struct stat *__buf) +{ + int ret; + FILE *f; + + if(!__file || !*__file || !__buf) { + errno = EINVAL; + return -1; + } + f = fopen(__file, CL("*")); + if(!f) { + memset(__buf, 0, sizeof(struct stat)); + return -1; + } + ret = fstat(f, __buf); + fclose(f); + return ret; +} + +extern int mkdir (const char_t *__path, mode_t __mode) +{ + FILE *f; + (void)__mode; + if(!__path || !*__path) { + errno = EINVAL; + return -1; + } + f = fopen(__path, CL("wd")); + if(!f) { + return -1; + } + fclose(f); + return 0; +} diff --git a/Bootloader/Source/uefi/stdio.c b/Bootloader/Source/uefi/stdio.c new file mode 100644 index 0000000..c536d44 --- /dev/null +++ b/Bootloader/Source/uefi/stdio.c @@ -0,0 +1,817 @@ +/* + * stdio.c + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief Implementing functions which are defined in stdio.h + * + */ + +#include + +static efi_file_handle_t *__root_dir = NULL; +static efi_serial_io_protocol_t *__ser = NULL; +static block_file_t *__blk_devs = NULL; +static uintn_t __blk_ndevs = 0; +extern time_t __mktime_efi(efi_time_t *t); +void __stdio_cleanup(void); +void __stdio_seterrno(efi_status_t status); +int __remove (const char_t *__filename, int isdir); + +void __stdio_cleanup(void) +{ +#ifndef UEFI_NO_UTF8 + if(__argvutf8) + BS->FreePool(__argvutf8); +#endif + if(__blk_devs) { + free(__blk_devs); + __blk_devs = NULL; + __blk_ndevs = 0; + } +} + +void __stdio_seterrno(efi_status_t status) +{ + switch((int)(status & 0xffff)) { + case EFI_WRITE_PROTECTED & 0xffff: errno = EROFS; break; + case EFI_ACCESS_DENIED & 0xffff: errno = EACCES; break; + case EFI_VOLUME_FULL & 0xffff: errno = ENOSPC; break; + case EFI_NOT_FOUND & 0xffff: errno = ENOENT; break; + case EFI_INVALID_PARAMETER & 0xffff: errno = EINVAL; break; + default: errno = EIO; break; + } +} + +int fstat (FILE *__f, struct stat *__buf) +{ + efi_guid_t infGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t); + efi_status_t status; + uintn_t i; + + if(!__f || !__buf) { + errno = EINVAL; + return -1; + } + memset(__buf, 0, sizeof(struct stat)); + if(__f == stdin) { + __buf->st_mode = S_IREAD | S_IFIFO; + return 0; + } + if(__f == stdout || __f == stderr) { + __buf->st_mode = S_IWRITE | S_IFIFO; + return 0; + } + if(__ser && __f == (FILE*)__ser) { + __buf->st_mode = S_IREAD | S_IWRITE | S_IFCHR; + return 0; + } + for(i = 0; i < __blk_ndevs; i++) + if(__f == (FILE*)__blk_devs[i].bio) { + __buf->st_mode = S_IREAD | S_IWRITE | S_IFBLK; + __buf->st_size = (off_t)__blk_devs[i].bio->Media->BlockSize * ((off_t)__blk_devs[i].bio->Media->LastBlock + 1); + __buf->st_blocks = __blk_devs[i].bio->Media->LastBlock + 1; + return 0; + } + status = __f->GetInfo(__f, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return -1; + } + __buf->st_mode = S_IREAD | + (info.Attribute & EFI_FILE_READ_ONLY ? 0 : S_IWRITE) | + (info.Attribute & EFI_FILE_DIRECTORY ? S_IFDIR : S_IFREG); + __buf->st_size = (off_t)info.FileSize; + __buf->st_blocks = (blkcnt_t)info.PhysicalSize; + __buf->st_atime = __mktime_efi(&info.LastAccessTime); + __buf->st_mtime = __mktime_efi(&info.ModificationTime); + __buf->st_ctime = __mktime_efi(&info.CreateTime); + return 0; +} + +int fclose (FILE *__stream) +{ + efi_status_t status = EFI_SUCCESS; + uintn_t i; + if(!__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) { + return 1; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) + return 1; + status = __stream->Close(__stream); + free(__stream); + return !EFI_ERROR(status); +} + +int fflush (FILE *__stream) +{ + efi_status_t status = EFI_SUCCESS; + uintn_t i; + if(!__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) { + return 1; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + return 1; + } + status = __stream->Flush(__stream); + return !EFI_ERROR(status); +} + +int __remove (const char_t *__filename, int isdir) +{ + efi_status_t status; + efi_guid_t infGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i; + /* little hack to support read and write mode for Delete() and stat() without create mode or checks */ + FILE *f = fopen(__filename, CL("*")); + if(errno) + return 1; + if(!f || f == stdin || f == stdout || f == stderr || (__ser && f == (FILE*)__ser)) { + errno = EBADF; + return 1; + } + for(i = 0; i < __blk_ndevs; i++) + if(f == (FILE*)__blk_devs[i].bio) { + errno = EBADF; + return 1; + } + if(isdir != -1) { + status = f->GetInfo(f, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) goto err; + if(isdir == 0 && (info.Attribute & EFI_FILE_DIRECTORY)) { + fclose(f); errno = EISDIR; + return -1; + } + if(isdir == 1 && !(info.Attribute & EFI_FILE_DIRECTORY)) { + fclose(f); errno = ENOTDIR; + return -1; + } + } + status = f->Delete(f); + if(EFI_ERROR(status)) { +err: __stdio_seterrno(status); + fclose(f); + return -1; + } + /* no need for fclose(f); */ + free(f); + return 0; +} + +int remove (const char_t *__filename) +{ + return __remove(__filename, -1); +} + +FILE *fopen (const char_t *__filename, const char_t *__modes) +{ + FILE *ret; + efi_status_t status; + efi_guid_t sfsGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; + efi_simple_file_system_protocol_t *sfs = NULL; + efi_guid_t infGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), par, i; +#ifndef UEFI_NO_UTF8 + wchar_t wcname[BUFSIZ]; +#endif + errno = 0; + if(!__filename || !*__filename || !__modes || (__modes[0] != CL('r') && __modes[0] != CL('w') && __modes[0] != CL('a') && + __modes[0] != CL('*')) || (__modes[1] != 0 && __modes[1] != CL('d') && __modes[1] != CL('+'))) { + errno = EINVAL; + return NULL; + } + /* fake some device names. UEFI has no concept of device files */ + if(!strcmp(__filename, CL("/dev/stdin"))) { + if(__modes[0] == CL('w') || __modes[0] == CL('a')) { errno = EPERM; return NULL; } + return stdin; + } + if(!strcmp(__filename, CL("/dev/stdout"))) { + if(__modes[0] == CL('r')) { errno = EPERM; return NULL; } + return stdout; + } + if(!strcmp(__filename, CL("/dev/stderr"))) { + if(__modes[0] == CL('r')) { errno = EPERM; return NULL; } + return stderr; + } + if(!memcmp(__filename, CL("/dev/serial"), 11 * sizeof(char_t))) { + par = (uintn_t)atol(__filename + 11); + if(!__ser) { + efi_guid_t serGuid = EFI_SERIAL_IO_PROTOCOL_GUID; + status = BS->LocateProtocol(&serGuid, NULL, (void**)&__ser); + if(EFI_ERROR(status) || !__ser) { errno = ENOENT; return NULL; } + } + __ser->SetAttributes(__ser, par > 9600 ? par : 115200, 0, 1000, NoParity, 8, OneStopBit); + return (FILE*)__ser; + } + if(!memcmp(__filename, CL("/dev/disk"), 9 * sizeof(char_t))) { + par = (uintn_t)atol(__filename + 9); + if(!__blk_ndevs) { + efi_guid_t bioGuid = EFI_BLOCK_IO_PROTOCOL_GUID; + efi_handle_t handles[128]; + uintn_t handle_size = sizeof(handles); + status = BS->LocateHandle(ByProtocol, &bioGuid, NULL, &handle_size, (efi_handle_t*)&handles); + if(!EFI_ERROR(status)) { + handle_size /= (uintn_t)sizeof(efi_handle_t); + /* workaround a bug in TianoCore, it reports zero size even though the data is in the buffer */ + if(handle_size < 1) + handle_size = (uintn_t)sizeof(handles) / sizeof(efi_handle_t); + __blk_devs = (block_file_t*)malloc(handle_size * sizeof(block_file_t)); + if(__blk_devs) { + memset(__blk_devs, 0, handle_size * sizeof(block_file_t)); + for(i = __blk_ndevs = 0; i < handle_size; i++) + if(handles[i] && !EFI_ERROR(BS->HandleProtocol(handles[i], &bioGuid, (void **) &__blk_devs[__blk_ndevs].bio)) && + __blk_devs[__blk_ndevs].bio && __blk_devs[__blk_ndevs].bio->Media && + __blk_devs[__blk_ndevs].bio->Media->BlockSize > 0) + __blk_ndevs++; + } else + __blk_ndevs = 0; + } + } + if(__blk_ndevs && par < __blk_ndevs) + return (FILE*)__blk_devs[par].bio; + errno = ENOENT; + return NULL; + } + if(!__root_dir && LIP) { + status = BS->HandleProtocol(LIP->DeviceHandle, &sfsGuid, (void **)&sfs); + if(!EFI_ERROR(status)) + status = sfs->OpenVolume(sfs, &__root_dir); + } + if(!__root_dir) { + errno = ENODEV; + return NULL; + } + ret = (FILE*)malloc(sizeof(FILE)); + if(!ret) return NULL; + /* normally write means read,write,create. But for remove (internal '*' mode), we need read,write without create + * also mode 'w' in POSIX means write-only (without read), but that's not working on certain firmware, we must + * pass read too. This poses a problem of truncating a write-only file, see issue #26, we have to do that manually */ +#ifndef UEFI_NO_UTF8 + mbstowcs((wchar_t*)&wcname, __filename, BUFSIZ - 1); + status = __root_dir->Open(__root_dir, &ret, (wchar_t*)&wcname, +#else + status = __root_dir->Open(__root_dir, &ret, (wchar_t*)__filename, +#endif + __modes[0] == CL('w') || __modes[0] == CL('a') ? (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE) : + EFI_FILE_MODE_READ | (__modes[0] == CL('*') || __modes[1] == CL('+') ? EFI_FILE_MODE_WRITE : 0), + __modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0); + if(EFI_ERROR(status)) { +err: __stdio_seterrno(status); + free(ret); return NULL; + } + if(__modes[0] == CL('*')) return ret; + status = ret->GetInfo(ret, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) goto err; + if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) { + ret->Close(ret); free(ret); errno = ENOTDIR; return NULL; + } + if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) { + ret->Close(ret); free(ret); errno = EISDIR; return NULL; + } + if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END); + if(__modes[0] == CL('w')) { + /* manually truncate file size + * See https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c + * function FileHandleSetSize */ + info.FileSize = 0; + ret->SetInfo(ret, &infGuid, fsiz, &info); + } + return ret; +} + +size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream) +{ + uintn_t bs = __size * __n, i, n; + efi_status_t status; + if(!__ptr || __size < 1 || __n < 1 || !__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return 0; + } + if(__ser && __stream == (FILE*)__ser) { + status = __ser->Read(__ser, &bs, __ptr); + } else { + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + n = __blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize; + bs = (bs / __blk_devs[i].bio->Media->BlockSize) * __blk_devs[i].bio->Media->BlockSize; + status = __blk_devs[i].bio->ReadBlocks(__blk_devs[i].bio, __blk_devs[i].bio->Media->MediaId, n, bs, __ptr); + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return 0; + } + __blk_devs[i].offset += bs; + return bs / __size; + } + status = __stream->Read(__stream, &bs, __ptr); + } + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return 0; + } + return bs / __size; +} + +size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__stream) +{ + uintn_t bs = __size * __n, n, i; + efi_status_t status; + if(!__ptr || __size < 1 || __n < 1 || !__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return 0; + } + if(__ser && __stream == (FILE*)__ser) { + status = __ser->Write(__ser, &bs, (void*)__ptr); + } else { + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + n = __blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize; + bs = (bs / __blk_devs[i].bio->Media->BlockSize) * __blk_devs[i].bio->Media->BlockSize; + status = __blk_devs[i].bio->WriteBlocks(__blk_devs[i].bio, __blk_devs[i].bio->Media->MediaId, n, bs, (void*)__ptr); + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return 0; + } + __blk_devs[i].offset += bs; + return bs / __size; + } + status = __stream->Write(__stream, &bs, (void *)__ptr); + } + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return 0; + } + return bs / __size; +} + +int fseek (FILE *__stream, long int __off, int __whence) +{ + off_t off = 0; + efi_status_t status; + efi_guid_t infoGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = sizeof(efi_file_info_t), i; + if(!__stream || (__whence != SEEK_SET && __whence != SEEK_CUR && __whence != SEEK_END)) { + errno = EINVAL; + return -1; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return -1; + } + if(__ser && __stream == (FILE*)__ser) { + errno = EBADF; + return -1; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + off = (uint64_t)__blk_devs[i].bio->Media->BlockSize * (uint64_t)__blk_devs[i].bio->Media->LastBlock; + switch(__whence) { + case SEEK_END: + __blk_devs[i].offset = off + __off; + break; + case SEEK_CUR: + __blk_devs[i].offset += __off; + break; + case SEEK_SET: + __blk_devs[i].offset = __off; + break; + } + if(__blk_devs[i].offset < 0) __blk_devs[i].offset = 0; + if(__blk_devs[i].offset > off) __blk_devs[i].offset = off; + __blk_devs[i].offset = (__blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize) * + __blk_devs[i].bio->Media->BlockSize; + return 0; + } + switch(__whence) { + case SEEK_END: + status = __stream->GetInfo(__stream, &infoGuid, &fsiz, &info); + if(!EFI_ERROR(status)) { + off = info.FileSize + __off; + status = __stream->SetPosition(__stream, off); + } + break; + case SEEK_CUR: + status = __stream->GetPosition(__stream, &off); + if(!EFI_ERROR(status)) { + off += __off; + status = __stream->SetPosition(__stream, off); + } + break; + default: + status = __stream->SetPosition(__stream, __off); + break; + } + return EFI_ERROR(status) ? -1 : 0; +} + +long int ftell (FILE *__stream) +{ + uint64_t off = 0; + uintn_t i; + efi_status_t status; + if(!__stream) { + errno = EINVAL; + return -1; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return -1; + } + if(__ser && __stream == (FILE*)__ser) { + errno = EBADF; + return -1; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + return (long int)__blk_devs[i].offset; + } + status = __stream->GetPosition(__stream, &off); + return EFI_ERROR(status) ? -1 : (long int)off; +} + +int feof (FILE *__stream) +{ + uint64_t off = 0; + efi_guid_t infGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i; + efi_status_t status; + if(!__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return 0; + } + if(__ser && __stream == (FILE*)__ser) { + errno = EBADF; + return 0; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + errno = EBADF; + return __blk_devs[i].offset == (off_t)__blk_devs[i].bio->Media->BlockSize * (off_t)__blk_devs[i].bio->Media->LastBlock; + } + status = __stream->GetPosition(__stream, &off); + if(EFI_ERROR(status)) { +err: __stdio_seterrno(status); + return 1; + } + status = __stream->GetInfo(__stream, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) goto err; + __stream->SetPosition(__stream, off); + return info.FileSize == off; +} + +int vsnprintf(char_t *dst, size_t maxlen, const char_t *fmt, __builtin_va_list args) +{ +#define needsescape(a) (a==CL('\"') || a==CL('\\') || a==CL('\a') || a==CL('\b') || a==CL('\033') || a==CL('\f') || \ + a==CL('\r') || a==CL('\n') || a==CL('\t') || a==CL('\v')) + efi_physical_address_t m; + uint8_t *mem; + uint64_t arg; + int64_t iarg; + int len, sign, i, j; + char_t *p, *orig=dst, *end = dst + maxlen - 1, tmpstr[24], pad, n; +#ifdef UEFI_NO_UTF8 + char *c; +#endif + if(dst==NULL || fmt==NULL) + return 0; + + arg = 0; + while(*fmt && dst < end) { + if(*fmt==CL('%')) { + fmt++; + if(*fmt==CL('%')) goto put; + len=0; pad=CL(' '); + if(*fmt==CL('0')) pad=CL('0'); + while(*fmt>=CL('0') && *fmt<=CL('9')) { + len *= 10; + len += *fmt-CL('0'); + fmt++; + } + if(*fmt==CL('l')) fmt++; + if(*fmt==CL('c')) { + arg = __builtin_va_arg(args, uint32_t); +#ifndef UEFI_NO_UTF8 + if(arg<0x80) { *dst++ = arg; } else + if(arg<0x800) { *dst++ = ((arg>>6)&0x1F)|0xC0; *dst++ = (arg&0x3F)|0x80; } else + { *dst++ = ((arg>>12)&0x0F)|0xE0; *dst++ = ((arg>>6)&0x3F)|0x80; *dst++ = (arg&0x3F)|0x80; } +#else + *dst++ = (wchar_t)(arg & 0xffff); +#endif + fmt++; + continue; + } else + if(*fmt==CL('d') || *fmt==CL('i') || *fmt==CL('u')) { + iarg = __builtin_va_arg(args, int64_t); + sign=0; + if(*fmt!=CL('u') && iarg<0) { + arg=-iarg; + sign++; + } else arg=(uint64_t)iarg; + i=23; + tmpstr[i]=0; + do { + tmpstr[--i]=CL('0')+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]=CL('-'); + } + if(len>0 && len<23) { + while(i && i>23-len) { + tmpstr[--i]=pad; + } + } + p=&tmpstr[i]; + goto copystring; + } else + if(*fmt==CL('p')) { + arg = __builtin_va_arg(args, uint64_t); + len = 16; pad = CL('0'); goto hex; + } else + if(*fmt==CL('x') || *fmt==CL('X')) { + arg = __builtin_va_arg(args, uint64_t); +hex: i=16; + tmpstr[i]=0; + do { + n=arg & 0xf; + /* 0-9 => '0'-'9', 10-15 => 'A'-'F' */ + tmpstr[--i]=n+(n>9?(*fmt==CL('X')?0x37:0x57):0x30); + arg>>=4; + } while(arg!=0 && i>0); + /* padding, only leading zeros */ + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]=CL('0'); + } + } + p=&tmpstr[i]; + goto copystring; + } else + if(*fmt==CL('s') || *fmt==CL('q')) { + p = __builtin_va_arg(args, char_t*); +copystring: if(p==NULL) { + p=CL("(null)"); + } + while(*p && dst + 2 < end) { + if(*fmt==CL('q') && needsescape(*p)) { + *dst++ = CL('\\'); + switch(*p) { + case CL('\a'): *dst++ = CL('a'); break; + case CL('\b'): *dst++ = CL('b'); break; + case 27: *dst++ = CL('e'); break; /* gcc 10.2 doesn't like CL('\e') in ansi mode */ + case CL('\f'): *dst++ = CL('f'); break; + case CL('\n'): *dst++ = CL('n'); break; + case CL('\r'): *dst++ = CL('r'); break; + case CL('\t'): *dst++ = CL('t'); break; + case CL('\v'): *dst++ = CL('v'); break; + default: *dst++ = *p++; break; + } + } else { + if(*p == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r'); + *dst++ = *p++; + } + } + } else +#ifdef UEFI_NO_UTF8 + if(*fmt==L'S' || *fmt==L'Q') { + c = __builtin_va_arg(args, char*); + if(c==NULL) goto copystring; + while(*p && dst + 2 < end) { + arg = *c; + if((*c & 128) != 0) { + if((*c & 32) == 0 ) { + arg = ((*c & 0x1F)<<6)|(*(c+1) & 0x3F); + c += 1; + } else + if((*c & 16) == 0 ) { + arg = ((*c & 0xF)<<12)|((*(c+1) & 0x3F)<<6)|(*(c+2) & 0x3F); + c += 2; + } else + if((*c & 8) == 0 ) { + arg = ((*c & 0x7)<<18)|((*(c+1) & 0x3F)<<12)|((*(c+2) & 0x3F)<<6)|(*(c+3) & 0x3F); + c += 3; + } else + arg = L'?'; + } + if(!arg) break; + if(*fmt==L'Q' && needsescape(arg)) { + *dst++ = L'\\'; + switch(arg) { + case L'\a': *dst++ = L'a'; break; + case L'\b': *dst++ = L'b'; break; + case 27: *dst++ = L'e'; break; /* gcc 10.2 doesn't like L'\e' in ansi mode */ + case L'\f': *dst++ = L'f'; break; + case L'\n': *dst++ = L'n'; break; + case L'\r': *dst++ = L'r'; break; + case L'\t': *dst++ = L't'; break; + case L'\v': *dst++ = L'v'; break; + default: *dst++ = arg; break; + } + } else { + if(arg == L'\n') *dst++ = L'\r'; + *dst++ = (wchar_t)(arg & 0xffff); + } + } + } else +#endif + if(*fmt==CL('D')) { + m = __builtin_va_arg(args, efi_physical_address_t); + for(j = 0; j < (len < 1 ? 1 : (len > 16 ? 16 : len)); j++) { + for(i = 44; i >= 0; i -= 4) { + n = (m >> i) & 15; *dst++ = n + (n>9?0x37:0x30); + if(dst >= end) goto zro; + } + *dst++ = CL(':'); if(dst >= end) goto zro; + *dst++ = CL(' '); if(dst >= end) goto zro; + mem = (uint8_t*)m; + for(i = 0; i < 16; i++) { + n = (mem[i] >> 4) & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro; + n = mem[i] & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro; + *dst++ = CL(' ');if(dst >= end) goto zro; + } + *dst++ = CL(' '); if(dst >= end) goto zro; + for(i = 0; i < 16; i++) { + *dst++ = (mem[i] < 32 || mem[i] >= 127 ? CL('.') : (char_t)mem[i]); + if(dst >= end) goto zro; + } + *dst++ = CL('\r'); if(dst >= end) goto zro; + *dst++ = CL('\n'); if(dst >= end) goto zro; + m += 16; + } + } + } else { +put: if(*fmt == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r'); + *dst++ = *fmt; + } + fmt++; + } +zro:*dst=0; + return (int)(dst-orig); +#undef needsescape +} + +int vsprintf(char_t *dst, const char_t *fmt, __builtin_va_list args) +{ + return vsnprintf(dst, BUFSIZ, fmt, args); +} + +int sprintf(char_t *dst, const char_t* fmt, ...) +{ + int ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + ret = vsnprintf(dst, BUFSIZ, fmt, args); + __builtin_va_end(args); + return ret; +} + +int snprintf(char_t *dst, size_t maxlen, const char_t* fmt, ...) +{ + int ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + ret = vsnprintf(dst, maxlen, fmt, args); + __builtin_va_end(args); + return ret; +} + +int vprintf(const char_t* fmt, __builtin_va_list args) +{ + int ret; + wchar_t dst[BUFSIZ]; +#ifndef UEFI_NO_UTF8 + char_t tmp[BUFSIZ]; + ret = vsnprintf(tmp, BUFSIZ, fmt, args); + mbstowcs(dst, tmp, BUFSIZ - 1); +#else + ret = vsnprintf(dst, BUFSIZ, fmt, args); +#endif + ST->ConOut->OutputString(ST->ConOut, (wchar_t *)&dst); + return ret; +} + +int printf(const char_t* fmt, ...) +{ + int ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + ret = vprintf(fmt, args); + __builtin_va_end(args); + return ret; +} + +int vfprintf (FILE *__stream, const char_t *__format, __builtin_va_list args) +{ + wchar_t dst[BUFSIZ]; + char_t tmp[BUFSIZ]; + uintn_t ret, i; +#ifndef UEFI_NO_UTF8 + ret = (uintn_t)vsnprintf(tmp, BUFSIZ, __format, args); + ret = mbstowcs(dst, tmp, BUFSIZ - 1); +#else + ret = vsnprintf(dst, BUFSIZ, __format, args); +#endif + if(ret < 1 || !__stream || __stream == stdin) return 0; + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + errno = EBADF; + return -1; + } + if(__stream == stdout) + ST->ConOut->OutputString(ST->ConOut, (wchar_t*)&dst); + else if(__stream == stderr) + ST->StdErr->OutputString(ST->StdErr, (wchar_t*)&dst); + else if(__ser && __stream == (FILE*)__ser) { +#ifdef UEFI_NO_UTF8 + wcstombs((char*)&tmp, dst, BUFSIZ - 1); +#endif + __ser->Write(__ser, &ret, (void*)&tmp); + } else +#ifndef UEFI_NO_UTF8 + __stream->Write(__stream, &ret, (void*)&tmp); +#else + __stream->Write(__stream, &ret, (void*)&dst); +#endif + return (int)ret; +} + +int fprintf (FILE *__stream, const char_t *__format, ...) +{ + int ret; + __builtin_va_list args; + __builtin_va_start(args, __format); + ret = vfprintf(__stream, __format, args); + __builtin_va_end(args); + return ret; +} + +int getchar_ifany (void) +{ + efi_input_key_t key = { 0 }; + efi_status_t status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); + return EFI_ERROR(status) ? 0 : key.UnicodeChar; +} + +int getchar (void) +{ + uintn_t idx; + BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &idx); + return getchar_ifany(); +} + +int putchar (int __c) +{ + wchar_t tmp[2]; + tmp[0] = (wchar_t)__c; + tmp[1] = 0; + ST->ConOut->OutputString(ST->ConOut, (__c == L'\n' ? (wchar_t*)L"\r\n" : (wchar_t*)&tmp)); + return (int)tmp[0]; +} diff --git a/Bootloader/Source/uefi/stdlib.c b/Bootloader/Source/uefi/stdlib.c new file mode 100644 index 0000000..81b33df --- /dev/null +++ b/Bootloader/Source/uefi/stdlib.c @@ -0,0 +1,365 @@ +/* + * stdlib.c + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief Implementing functions which are defined in stdlib.h + * + */ + +#include + +int errno = 0; +static uint64_t __srand_seed = 6364136223846793005ULL; +extern void __stdio_cleanup(void); +#ifndef UEFI_NO_TRACK_ALLOC +static uintptr_t *__stdlib_allocs = NULL; +static uintn_t __stdlib_numallocs = 0; +#endif + +int atoi(const char_t *s) +{ + return (int)atol(s); +} + +int64_t atol(const char_t *s) +{ + int64_t sign = 1; + if(!s || !*s) return 0; + if(*s == CL('-')) { sign = -1; s++; } + if(s[0] == CL('0')) { + if(s[1] == CL('x')) + return strtol(s + 2, NULL, 16) * sign; + if(s[1] >= CL('0') && s[1] <= CL('7')) + return strtol(s, NULL, 8) * sign; + } + return strtol(s, NULL, 10) * sign; +} + +int64_t strtol (const char_t *s, char_t **__endptr, int __base) +{ + int64_t v=0, sign = 1; + if(!s || !*s) return 0; + if(*s == CL('-')) { sign = -1; s++; } + while(!(*s < CL('0') || (__base < 10 && *s >= __base + CL('0')) || (__base >= 10 && ((*s > CL('9') && *s < CL('A')) || + (*s > CL('F') && *s < CL('a')) || *s > CL('f'))))) { + v *= __base; + if(*s >= CL('0') && *s <= (__base < 10 ? __base + CL('0') : CL('9'))) + v += (*s)-CL('0'); + else if(__base == 16 && *s >= CL('a') && *s <= CL('f')) + v += (*s)-CL('a')+10; + else if(__base == 16 && *s >= CL('A') && *s <= CL('F')) + v += (*s)-CL('A')+10; + s++; + } + if(__endptr) *__endptr = (char_t*)s; + return v * sign; +} + +void *malloc (size_t __size) +{ + void *ret = NULL; + efi_status_t status; +#ifndef UEFI_NO_TRACK_ALLOC + uintn_t i; + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != 0; i += 2); + if(i == __stdlib_numallocs) { + /* no free slots found, (re)allocate the housekeeping array */ + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (__stdlib_numallocs + 2) * sizeof(uintptr_t), &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; } + if(__stdlib_allocs) memcpy(ret, __stdlib_allocs, __stdlib_numallocs * sizeof(uintptr_t)); + __stdlib_allocs = (uintptr_t*)ret; + __stdlib_allocs[i] = __stdlib_allocs[i + 1] = 0; + __stdlib_numallocs += 2; + ret = NULL; + } +#endif + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; } +#ifndef UEFI_NO_TRACK_ALLOC + __stdlib_allocs[i] = (uintptr_t)ret; + __stdlib_allocs[i + 1] = (uintptr_t)__size; +#endif + return ret; +} + +void *calloc (size_t __nmemb, size_t __size) +{ + void *ret = malloc(__nmemb * __size); + if(ret) memset(ret, 0, __nmemb * __size); + return ret; +} + +void *realloc (void *__ptr, size_t __size) +{ + void *ret = NULL; + efi_status_t status; +#ifndef UEFI_NO_TRACK_ALLOC + uintn_t i; +#endif + if(!__ptr) return malloc(__size); + if(!__size) { free(__ptr); return NULL; } +#ifndef UEFI_NO_TRACK_ALLOC + /* get the slot which stores the old size for this buffer */ + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2); + if(i == __stdlib_numallocs) { errno = ENOMEM; return NULL; } + /* allocate a new buffer and copy data from old buffer */ + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; } + else { + memcpy(ret, (void*)__stdlib_allocs[i], __stdlib_allocs[i + 1] < __size ? __stdlib_allocs[i + 1] : __size); + if(__size > __stdlib_allocs[i + 1]) memset((uint8_t*)ret + __stdlib_allocs[i + 1], 0, __size - __stdlib_allocs[i + 1]); + /* free old buffer and store new buffer in slot */ + BS->FreePool((void*)__stdlib_allocs[i]); + __stdlib_allocs[i] = (uintptr_t)ret; + __stdlib_allocs[i + 1] = (uintptr_t)__size; + } +#else + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; } + /* this means out of bounds read, but fine with POSIX as the end of new buffer supposed to be left uninitialized) */ + memcpy(ret, (void*)__ptr, __size); + BS->FreePool((void*)__ptr); +#endif + return ret; +} + +void free (void *__ptr) +{ + efi_status_t status; +#ifndef UEFI_NO_TRACK_ALLOC + uintn_t i; +#endif + if(!__ptr) { errno = ENOMEM; return; } +#ifndef UEFI_NO_TRACK_ALLOC + /* find and clear the slot */ + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2); + if(i == __stdlib_numallocs) { errno = ENOMEM; return; } + __stdlib_allocs[i] = 0; + __stdlib_allocs[i + 1] = 0; + /* if there are only empty slots, free the housekeeping array too */ + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] == 0; i += 2); + if(i == __stdlib_numallocs) { BS->FreePool(__stdlib_allocs); __stdlib_allocs = NULL; __stdlib_numallocs = 0; } +#endif + status = BS->FreePool(__ptr); + if(EFI_ERROR(status)) errno = ENOMEM; +} + +void abort () +{ +#ifndef UEFI_NO_TRACK_ALLOC + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_allocs = NULL; + __stdlib_numallocs = 0; +#endif + __stdio_cleanup(); + BS->Exit(IM, EFI_ABORTED, 0, NULL); +} + +void exit (int __status) +{ +#ifndef UEFI_NO_TRACK_ALLOC + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_allocs = NULL; + __stdlib_numallocs = 0; +#endif + __stdio_cleanup(); + BS->Exit(IM, !__status ? 0 : (__status < 0 ? EFIERR(-__status) : EFIERR(__status)), 0, NULL); +} + +int exit_bs() +{ + efi_status_t status = 0; + efi_memory_descriptor_t *memory_map = NULL; + uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0; +#ifndef UEFI_NO_TRACK_ALLOC + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_allocs = NULL; + __stdlib_numallocs = 0; +#endif + __stdio_cleanup(); + while(cnt--) { + status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL); + if (status!=EFI_BUFFER_TOO_SMALL) break; + status = BS->ExitBootServices(IM, map_key); + if(!EFI_ERROR(status)) return 0; + } + return (int)(status & 0xffff); +} + +void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, __compar_fn_t cmp) +{ + uint64_t s=0, e=nmemb, m; + int ret; + while (s < e) { + m = s + (e-s)/2; + ret = cmp(key, (uint8_t*)base + m*size); + if (ret < 0) e = m; else + if (ret > 0) s = m+1; else + return (void *)((uint8_t*)base + m*size); + } + return NULL; +} + +int mblen(const char *s, size_t n) +{ + const char *e = s+n; + int c = 0; + if(s) { + while(s < e && *s) { + if((*s & 128) != 0) { + if((*s & 32) == 0 ) s++; else + if((*s & 16) == 0 ) s+=2; else + if((*s & 8) == 0 ) s+=3; + } + c++; + s++; + } + } + return c; +} + +int mbtowc (wchar_t * __pwc, const char *s, size_t n) +{ + wchar_t arg; + int ret = 1; + if(!s || !*s) return 0; + arg = (wchar_t)*s; + if((*s & 128) != 0) { + if((*s & 32) == 0 && n > 0) { arg = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); ret = 2; } else + if((*s & 16) == 0 && n > 1) { arg = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); ret = 3; } else + if((*s & 8) == 0 && n > 2) { arg = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); ret = 4; } + else return -1; + } + if(__pwc) *__pwc = arg; + return ret; +} + +int wctomb (char *s, wchar_t u) +{ + int ret = 0; + if(u<0x80) { + *s = u; + ret = 1; + } else if(u<0x800) { + *(s+0)=((u>>6)&0x1F)|0xC0; + *(s+1)=(u&0x3F)|0x80; + ret = 2; + } else { + *(s+0)=((u>>12)&0x0F)|0xE0; + *(s+1)=((u>>6)&0x3F)|0x80; + *(s+2)=(u&0x3F)|0x80; + ret = 3; + } + return ret; +} + +size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n) +{ + int r; + wchar_t *orig = __pwcs; + if(!__s || !*__s) return 0; + while(*__s) { + r = mbtowc(__pwcs, __s, __n - (size_t)(__pwcs - orig)); + if(r < 0) return (size_t)-1; + __pwcs++; + __s += r; + } + *__pwcs = 0; + return (size_t)(__pwcs - orig); +} + +size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n) +{ + int r; + char *orig = __s; + if(!__s || !__pwcs || !*__pwcs) return 0; + while(*__pwcs && ((size_t)(__s - orig + 4) < __n)) { + r = wctomb(__s, *__pwcs); + if(r < 0) return (size_t)-1; + __pwcs++; + __s += r; + } + *__s = 0; + return (size_t)(__s - orig); +} + +void srand(unsigned int __seed) +{ + __srand_seed = __seed - 1; +} + +int rand() +{ + efi_guid_t rngGuid = EFI_RNG_PROTOCOL_GUID; + efi_rng_protocol_t *rng = NULL; + efi_status_t status; + int ret = 0; + + __srand_seed = 6364136223846793005ULL*__srand_seed + 1; + status = BS->LocateProtocol(&rngGuid, NULL, (void**)&rng); + if(!EFI_ERROR(status) && rng) + rng->GetRNG(rng, NULL, (uintn_t)sizeof(int), (uint8_t*)&ret); + ret ^= (int)(__srand_seed>>33); + return ret; +} + +uint8_t *getenv(char_t *name, uintn_t *len) +{ + efi_guid_t globGuid = EFI_GLOBAL_VARIABLE; + uint8_t tmp[EFI_MAXIMUM_VARIABLE_SIZE], *ret; + uint32_t attr; + efi_status_t status; +#ifndef UEFI_NO_UTF8 + wchar_t wcname[256]; + mbstowcs((wchar_t*)&wcname, name, 256); + status = RT->GetVariable((wchar_t*)&wcname, &globGuid, &attr, len, &tmp); +#else + status = RT->GetVariable(name, &globGuid, &attr, len, &tmp); +#endif + if(EFI_ERROR(status) || *len < 1 || !(ret = malloc((*len) + 1))) { + *len = 0; + return NULL; + } + memcpy(ret, tmp, *len); + ret[*len] = 0; + return ret; +} + +int setenv(char_t *name, uintn_t len, uint8_t *data) +{ + efi_guid_t globGuid = EFI_GLOBAL_VARIABLE; + efi_status_t status; +#ifndef UEFI_NO_UTF8 + wchar_t wcname[256]; + mbstowcs((wchar_t*)&wcname, name, 256); + status = RT->SetVariable(wcname, &globGuid, 0, len, data); +#else + status = RT->SetVariable(name, &globGuid, 0, len, data); +#endif + return !EFI_ERROR(status); +} diff --git a/Bootloader/Source/uefi/string.c b/Bootloader/Source/uefi/string.c new file mode 100644 index 0000000..a6d0348 --- /dev/null +++ b/Bootloader/Source/uefi/string.c @@ -0,0 +1,262 @@ +/* + * string.c + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief Implementing functions which are defined in string.h + * + */ + +#include + +void *memcpy(void *dst, const void *src, size_t n) +{ + uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src; + if(src && dst && src != dst && n>0) { + while(n--) *a++ = *b++; + } + return dst; +} + +void *memmove(void *dst, const void *src, size_t n) +{ + uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src; + if(src && dst && src != dst && n>0) { + if(a>b && a0) *a--=*b--; + } else { + while(n--) *a++ = *b++; + } + } + return dst; +} + +void *memset(void *s, int c, size_t n) +{ + uint8_t *p=(uint8_t*)s; + if(s && n>0) { + while(n--) *p++ = (uint8_t)c; + } + return s; +} + +int memcmp(const void *s1, const void *s2, size_t n) +{ + uint8_t *a=(uint8_t*)s1,*b=(uint8_t*)s2; + if(s1 && s2 && s1 != s2 && n>0) { + while(n--) { + if(*a != *b) return *a - *b; + a++; b++; + } + } + return 0; +} + +void *memchr(const void *s, int c, size_t n) +{ + uint8_t *e, *p=(uint8_t*)s; + if(s && n>0) { + for(e=p+n; p0) { + for(e=p+n; p hl) return NULL; + hl -= nl - 1; + while(hl) { + if(!memcmp(c, needle, nl)) return c; + c++; hl--; + } + return NULL; +} + +void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl) +{ + uint8_t *c = (uint8_t*)haystack; + if(!haystack || !needle || !hl || !nl || nl > hl) return NULL; + hl -= nl; + c += hl; + while(hl) { + if(!memcmp(c, needle, nl)) return c; + c--; hl--; + } + return NULL; +} + +char_t *strcpy(char_t *dst, const char_t *src) +{ + char_t *s = dst; + if(src && dst && src != dst) { + while(*src) {*dst++=*src++;} *dst=0; + } + return s; +} + +char_t *strncpy(char_t *dst, const char_t *src, size_t n) +{ + char_t *s = dst; + const char_t *e = src+n; + if(src && dst && src != dst && n>0) { + while(*src && src0) { + dst += strlen(dst); + while(*src && src0) { + while(s1 + +static struct tm __tm; +time_t __mktime_efi(efi_time_t *t); + +/* from musl */ +static uint64_t __year_to_secs(uint64_t year, int *is_leap) +{ + int y, cycles, centuries, leaps, rem; + + if (year-2ULL <= 136) { + y = (int)year; + leaps = (y-68)>>2; + if (!((y-68)&3)) { + leaps--; + if (is_leap) *is_leap = 1; + } else if (is_leap) *is_leap = 0; + return 31536000ULL*(uint64_t)(y-70) + 86400ULL*(uint64_t)leaps; + } + + if (!is_leap) is_leap = &(int){0}; + cycles = (int)((year-100) / 400); + rem = (year-100) % 400; + if (rem < 0) { + cycles--; + rem += 400; + } + if (!rem) { + *is_leap = 1; + centuries = 0; + leaps = 0; + } else { + if (rem >= 200) { + if (rem >= 300) { centuries = 3; rem -= 300; } + else { centuries = 2; rem -= 200; } + } else { + if (rem >= 100) { centuries = 1; rem -= 100; } + else centuries = 0; + } + if (!rem) { + *is_leap = 0; + leaps = 0; + } else { + leaps = rem / 4; + rem %= 4; + *is_leap = !rem; + } + } + + leaps += 97*cycles + 24*centuries - *is_leap; + + return (uint64_t)(year-100) * 31536000ULL + (uint64_t)leaps * 86400ULL + 946684800ULL + 86400ULL; +} + +time_t __mktime_efi(efi_time_t *t) +{ + __tm.tm_year = t->Year + (/* workaround some buggy firmware*/ t->Year > 2000 ? -1900 : 98); + __tm.tm_mon = t->Month - 1; + __tm.tm_mday = t->Day; + __tm.tm_hour = t->Hour; + __tm.tm_min = t->Minute; + __tm.tm_sec = t->Second; + __tm.tm_isdst = t->Daylight; + return mktime(&__tm); +} + +/** + * This isn't POSIX, no arguments. Just returns the current time in struct tm + */ +struct tm *localtime (const time_t *__timer) +{ + efi_time_t t = {0}; + (void)__timer; + ST->RuntimeServices->GetTime(&t, NULL); + __mktime_efi(&t); + return &__tm; +} + +time_t mktime(const struct tm *tm) +{ + static const uint64_t secs_through_month[] = { + 0, 31*86400, 59*86400, 90*86400, + 120*86400, 151*86400, 181*86400, 212*86400, + 243*86400, 273*86400, 304*86400, 334*86400 }; + int is_leap; + uint64_t year = (uint64_t)tm->tm_year, t, adj; + int month = tm->tm_mon; + if (month >= 12 || month < 0) { + adj = (uint64_t)month / 12; + month %= 12; + if (month < 0) { + adj--; + month += 12; + } + year += adj; + } + t = __year_to_secs(year, &is_leap); + t += secs_through_month[month]; + if (is_leap && month >= 2) t += 86400; + t += 86400ULL * (uint64_t)(tm->tm_mday-1); + t += 3600ULL * (uint64_t)tm->tm_hour; + t += 60ULL * (uint64_t)tm->tm_min; + t += (uint64_t)tm->tm_sec; + return (time_t)t; +} + +time_t time(time_t *__timer) +{ + time_t ret; + efi_time_t t = {0}; + ST->RuntimeServices->GetTime(&t, NULL); + ret = __mktime_efi(&t); + if(__timer) *__timer = ret; + return ret; +} + diff --git a/Bootloader/Source/uefi/uefi.h b/Bootloader/Source/uefi/uefi.h new file mode 100644 index 0000000..d46ed95 --- /dev/null +++ b/Bootloader/Source/uefi/uefi.h @@ -0,0 +1,1446 @@ +/* + * uefi.h + * https://gitlab.com/bztsrc/posix-uefi + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief Main (and only) header file + * + */ + +#ifndef _UEFI_H_ +#define _UEFI_H_ + +/*** configuration ***/ +/* #define UEFI_NO_UTF8 */ /* use wchar_t in your application */ +/* #define UEFI_NO_TRACK_ALLOC */ /* do not track allocated buffers' size */ +/*** configuration ends ***/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* get these from the compiler or the efi headers, only define if we have neither */ +#if !defined(_STDINT_H) && !defined(_GCC_STDINT_H) && !defined(_EFI_INCLUDE_) +#define _STDINT_H +typedef char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +#ifndef __clang__ +typedef long int int64_t; +typedef unsigned long int uint64_t; +typedef unsigned long int uintptr_t; +#else +typedef long long int64_t; +typedef unsigned long long uint64_t; +typedef unsigned long long uintptr_t; +#endif +#endif +extern char c_assert1[sizeof(uint32_t) == 4 ? 1 : -1]; +extern char c_assert2[sizeof(uint64_t) == 8 ? 1 : -1]; +extern char c_assert3[sizeof(uintptr_t) == 8 ? 1 : -1]; + +#ifndef NULL +#define NULL ((void*)0) +#endif +/*** common defines and typedefs ***/ +typedef int64_t intn_t; +typedef uint8_t boolean_t; +#ifndef __cplusplus +typedef uint16_t wchar_t; +#endif +typedef uint64_t uintn_t; +typedef uint64_t size_t; +typedef uint64_t time_t; +typedef uint64_t mode_t; +typedef uint64_t off_t; +typedef uint64_t blkcnt_t; +typedef uint64_t efi_status_t; +typedef uint64_t efi_tpl_t; +typedef uint64_t efi_lba_t; +typedef uint64_t efi_physical_address_t; +typedef uint64_t efi_virtual_address_t; +typedef void *efi_handle_t; +typedef void *efi_event_t; +#ifndef UEFI_NO_UTF8 +typedef char char_t; +#define CL(a) a +extern char *__argvutf8; +#else +typedef wchar_t char_t; +#define CL(a) L ## a +#endif + +typedef struct { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} efi_guid_t; + +typedef struct { + uint8_t Type; + uint8_t SubType; + uint8_t Length[2]; +} efi_device_path_t; + +typedef struct { + uint32_t Type; + uint32_t Pad; + efi_physical_address_t PhysicalStart; + efi_virtual_address_t VirtualStart; + uint64_t NumberOfPages; + uint64_t Attribute; +} efi_memory_descriptor_t; + +typedef struct { + uint64_t Signature; + uint32_t Revision; + uint32_t HeaderSize; + uint32_t CRC32; + uint32_t Reserved; +} efi_table_header_t; + +/*** definitions only needed when efi.h (either from EDK II or gnu-efi) is NOT included ***/ + +#ifndef EFI_SPECIFICATION_MAJOR_REVISION + +/* efibind.h */ +#ifndef __WCHAR_TYPE__ +# define __WCHAR_TYPE__ short +#endif +#define EFIERR(a) (0x8000000000000000 | (unsigned int)(a)) +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFIERR_OEM(a) (0xc000000000000000 | (unsigned int)(a)) + +#define BAD_POINTER 0xFBFBFBFBFBFBFBFB +#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((uint64_t)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +#ifndef EFIAPI +# ifdef _MSC_EXTENSIONS +# define EFIAPI __cdecl +# elif defined(HAVE_USE_MS_ABI) +# define EFIAPI __attribute__((ms_abi)) +# else +# define EFIAPI +# endif +#endif + +/* efistdarg.h */ +typedef __builtin_va_list va_list; +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(d,s) __builtin_va_copy(d,s) + +/* efierr.h */ +#define EFIWARN(a) (a) +#define EFI_ERROR(a) (((intn_t) a) < 0) +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR EFIERR(1) +#define EFI_INVALID_PARAMETER EFIERR(2) +#define EFI_UNSUPPORTED EFIERR(3) +#define EFI_BAD_BUFFER_SIZE EFIERR(4) +#define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_NOT_READY EFIERR(6) +#define EFI_DEVICE_ERROR EFIERR(7) +#define EFI_WRITE_PROTECTED EFIERR(8) +#define EFI_OUT_OF_RESOURCES EFIERR(9) +#define EFI_VOLUME_CORRUPTED EFIERR(10) +#define EFI_VOLUME_FULL EFIERR(11) +#define EFI_NO_MEDIA EFIERR(12) +#define EFI_MEDIA_CHANGED EFIERR(13) +#define EFI_NOT_FOUND EFIERR(14) +#define EFI_ACCESS_DENIED EFIERR(15) +#define EFI_NO_RESPONSE EFIERR(16) +#define EFI_NO_MAPPING EFIERR(17) +#define EFI_TIMEOUT EFIERR(18) +#define EFI_NOT_STARTED EFIERR(19) +#define EFI_ALREADY_STARTED EFIERR(20) +#define EFI_ABORTED EFIERR(21) +#define EFI_ICMP_ERROR EFIERR(22) +#define EFI_TFTP_ERROR EFIERR(23) +#define EFI_PROTOCOL_ERROR EFIERR(24) +#define EFI_INCOMPATIBLE_VERSION EFIERR(25) +#define EFI_SECURITY_VIOLATION EFIERR(26) +#define EFI_CRC_ERROR EFIERR(27) +#define EFI_END_OF_MEDIA EFIERR(28) +#define EFI_END_OF_FILE EFIERR(31) +#define EFI_INVALID_LANGUAGE EFIERR(32) +#define EFI_COMPROMISED_DATA EFIERR(33) + +#define EFI_WARN_UNKOWN_GLYPH EFIWARN(1) +#define EFI_WARN_UNKNOWN_GLYPH EFIWARN(1) +#define EFI_WARN_DELETE_FAILURE EFIWARN(2) +#define EFI_WARN_WRITE_FAILURE EFIWARN(3) +#define EFI_WARN_BUFFER_TOO_SMALL EFIWARN(4) + +/* efisetjmp.h */ +#ifdef __x86_64__ +typedef struct { + uint64_t Rbx; + uint64_t Rsp; + uint64_t Rbp; + uint64_t Rdi; + uint64_t Rsi; + uint64_t R12; + uint64_t R13; + uint64_t R14; + uint64_t R15; + uint64_t Rip; + uint64_t MxCsr; + uint8_t XmmBuffer[160]; +} __attribute__((aligned(8))) jmp_buf[1]; +#endif +#ifdef __aarch64__ +typedef struct { + uint64_t X19; + uint64_t X20; + uint64_t X21; + uint64_t X22; + uint64_t X23; + uint64_t X24; + uint64_t X25; + uint64_t X26; + uint64_t X27; + uint64_t X28; + uint64_t FP; + uint64_t LR; + uint64_t IP0; + uint64_t reserved; + uint64_t D8; + uint64_t D9; + uint64_t D10; + uint64_t D11; + uint64_t D12; + uint64_t D13; + uint64_t D14; + uint64_t D15; +} __attribute__((aligned(8))) jmp_buf[1]; +#endif +#if defined(__riscv) && __riscv_xlen == 64 +typedef struct { + uint64_t pc; + uint64_t sp; + uint64_t regs[12]; + double fp[12]; +} __attribute__((aligned(8))) jmp_buf[1]; +#endif +extern uintn_t setjmp(jmp_buf env) __attribute__((returns_twice)); +extern void longjmp(jmp_buf env, uintn_t value) __attribute__((noreturn)); + +/* efidevp.h */ +#define EFI_DEVICE_PATH_PROTOCOL_GUID { 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define EFI_DP_TYPE_MASK 0x7F +#define EFI_DP_TYPE_UNPACKED 0x80 +#define END_DEVICE_PATH_TYPE 0x7f +#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff +#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 +#define END_DEVICE_PATH_LENGTH (sizeof(efi_device_path_t)) +#define DP_IS_END_TYPE(a) +#define DP_IS_END_SUBTYPE(a) ( ((a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) +#define DevicePathType(a) ( ((a)->Type) & EFI_DP_TYPE_MASK ) +#define DevicePathSubType(a) ( (a)->SubType ) +#define DevicePathNodeLength(a) ( ((a)->Length[0]) | ((a)->Length[1] << 8) ) +#define NextDevicePathNode(a) ( (efi_device_path_t *) ( ((uint8_t *) (a)) + DevicePathNodeLength(a))) +#define IsDevicePathEndType(a) ( DevicePathType(a) == END_DEVICE_PATH_TYPE ) +#define IsDevicePathEndSubType(a) ( (a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) +#define IsDevicePathEnd(a) ( IsDevicePathEndType(a) && IsDevicePathEndSubType(a) ) +#define IsDevicePathUnpacked(a) ( (a)->Type & EFI_DP_TYPE_UNPACKED ) +#define SetDevicePathNodeLength(a,l) { \ + (a)->Length[0] = (uint8_t) (l); \ + (a)->Length[1] = (uint8_t) ((l) >> 8); \ + } +#define SetDevicePathEndNode(a) { \ + (a)->Type = END_DEVICE_PATH_TYPE; \ + (a)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; \ + (a)->Length[0] = sizeof(efi_device_path_t); \ + (a)->Length[1] = 0; \ + } + +/* efiapi.h */ +#define EFI_SPECIFICATION_MAJOR_REVISION 1 +#define EFI_SPECIFICATION_MINOR_REVISION 02 + +#define TPL_APPLICATION 4 +#define TPL_CALLBACK 8 +#define TPL_NOTIFY 16 +#define TPL_HIGH_LEVEL 31 +#define EFI_TPL_APPLICATION TPL_APPLICATION +#define EFI_TPL_CALLBACK TPL_CALLBACK +#define EFI_TPL_NOTIFY TPL_NOTIFY +#define EFI_TPL_HIGH_LEVEL TPL_HIGH_LEVEL + +#define NextMemoryDescriptor(Ptr,Size) ((efi_memory_descriptor_t *) (((uint8_t *) Ptr) + Size)) + +#define EFI_PAGE_SIZE 4096 +#define EFI_PAGE_MASK 0xFFF +#define EFI_PAGE_SHIFT 12 + +#define EFI_SIZE_TO_PAGES(a) ( ((a) >> EFI_PAGE_SHIFT) + ((a) & EFI_PAGE_MASK ? 1 : 0) ) + +#define EFI_MEMORY_UC 0x0000000000000001 +#define EFI_MEMORY_WC 0x0000000000000002 +#define EFI_MEMORY_WT 0x0000000000000004 +#define EFI_MEMORY_WB 0x0000000000000008 +#define EFI_MEMORY_UCE 0x0000000000000010 +#define EFI_MEMORY_WP 0x0000000000001000 +#define EFI_MEMORY_RP 0x0000000000002000 +#define EFI_MEMORY_XP 0x0000000000004000 +#define EFI_MEMORY_RUNTIME 0x8000000000000000 +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 + +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_RUNTIME_CONTEXT 0x20000000 + +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 + +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define EVT_EFI_SIGNAL_MASK 0x000000FF +#define EVT_EFI_SIGNAL_MAX 4 + +#define EFI_EVENT_TIMER EVT_TIMER +#define EFI_EVENT_RUNTIME EVT_RUNTIME +#define EFI_EVENT_RUNTIME_CONTEXT EVT_RUNTIME_CONTEXT +#define EFI_EVENT_NOTIFY_WAIT EVT_NOTIFY_WAIT +#define EFI_EVENT_NOTIFY_SIGNAL EVT_NOTIFY_SIGNAL +#define EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES EVT_SIGNAL_EXIT_BOOT_SERVICES +#define EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE +#define EFI_EVENT_EFI_SIGNAL_MASK EVT_EFI_SIGNAL_MASK +#define EFI_EVENT_EFI_SIGNAL_MAX EVT_EFI_SIGNAL_MAX + +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + +#define EFI_OPTIONAL_PTR 0x00000001 +#define EFI_INTERNAL_FNC 0x00000002 +#define EFI_INTERNAL_PTR 0x00000004 + +#define EFI_GLOBAL_VARIABLE { 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C} } +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 +#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 +#define EFI_VARIABLE_APPEND_WRITE 0x00000040 +#define EFI_MAXIMUM_VARIABLE_SIZE 1024 + +#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 +#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 +#define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 + +#define MPS_TABLE_GUID { 0xeb9d2d2f, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } +#define ACPI_TABLE_GUID { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } +#define ACPI_20_TABLE_GUID { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } +#define SMBIOS_TABLE_GUID { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } +#define SMBIOS3_TABLE_GUID { 0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e,0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94} } +#define SAL_SYSTEM_TABLE_GUID { 0xeb9d2d32, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552 +#define EFI_RUNTIME_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) + +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 +#define EFI_BOOT_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) + +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 +#define EFI_SYSTEM_TABLE_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) + +/* eficon.h */ +#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID { 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN (EFI_BLUE | EFI_GREEN) +#define EFI_RED 0x04 +#define EFI_MAGENTA (EFI_BLUE | EFI_RED) +#define EFI_BROWN (EFI_GREEN | EFI_RED) +#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED) +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY (EFI_BRIGHT) +#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT) +#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT) +#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT) +#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT) +#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT) +#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT) +#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT) +#define EFI_TEXT_ATTR(f,b) ((f) | ((b) << 4)) +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN) +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) +#define BOXDRAW_HORIZONTAL 0x2500 +#define BOXDRAW_VERTICAL 0x2502 +#define BOXDRAW_DOWN_RIGHT 0x250c +#define BOXDRAW_DOWN_LEFT 0x2510 +#define BOXDRAW_UP_RIGHT 0x2514 +#define BOXDRAW_UP_LEFT 0x2518 +#define BOXDRAW_VERTICAL_RIGHT 0x251c +#define BOXDRAW_VERTICAL_LEFT 0x2524 +#define BOXDRAW_DOWN_HORIZONTAL 0x252c +#define BOXDRAW_UP_HORIZONTAL 0x2534 +#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c +#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 +#define BOXDRAW_DOUBLE_VERTICAL 0x2551 +#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 +#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 +#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 +#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 +#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 +#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 +#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 +#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 +#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a +#define BOXDRAW_UP_LEFT_DOUBLE 0x255b +#define BOXDRAW_UP_DOUBLE_LEFT 0x255c +#define BOXDRAW_DOUBLE_UP_LEFT 0x255d +#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e +#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f +#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 +#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 +#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 +#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 +#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 +#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 +#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 +#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 +#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 +#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 +#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a +#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b +#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c +#define BLOCKELEMENT_FULL_BLOCK 0x2588 +#define BLOCKELEMENT_LIGHT_SHADE 0x2591 +#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 +#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba +#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc +#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 +#define ARROW_UP 0x2191 +#define ARROW_DOWN 0x2193 + +#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID { 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define CHAR_NULL 0x0000 +#define CHAR_BACKSPACE 0x0008 +#define CHAR_TAB 0x0009 +#define CHAR_LINEFEED 0x000A +#define CHAR_CARRIAGE_RETURN 0x000D +#define SCAN_NULL 0x0000 +#define SCAN_UP 0x0001 +#define SCAN_DOWN 0x0002 +#define SCAN_RIGHT 0x0003 +#define SCAN_LEFT 0x0004 +#define SCAN_HOME 0x0005 +#define SCAN_END 0x0006 +#define SCAN_INSERT 0x0007 +#define SCAN_DELETE 0x0008 +#define SCAN_PAGE_UP 0x0009 +#define SCAN_PAGE_DOWN 0x000A +#define SCAN_F1 0x000B +#define SCAN_F2 0x000C +#define SCAN_F3 0x000D +#define SCAN_F4 0x000E +#define SCAN_F5 0x000F +#define SCAN_F6 0x0010 +#define SCAN_F7 0x0011 +#define SCAN_F8 0x0012 +#define SCAN_F9 0x0013 +#define SCAN_F10 0x0014 +#define SCAN_F11 0x0015 +#define SCAN_F12 0x0016 +#define SCAN_ESC 0x0017 + +/* efigpt.h */ +#define PRIMARY_PART_HEADER_LBA 1 +#define EFI_PTAB_HEADER_ID "EFI PART" +#define EFI_PART_USED_BY_EFI 0x0000000000000001 +#define EFI_PART_REQUIRED_TO_FUNCTION 0x0000000000000002 +#define EFI_PART_USED_BY_OS 0x0000000000000004 +#define EFI_PART_REQUIRED_BY_OS 0x0000000000000008 +#define EFI_PART_BACKUP_REQUIRED 0x0000000000000010 +#define EFI_PART_USER_DATA 0x0000000000000020 +#define EFI_PART_CRITICAL_USER_DATA 0x0000000000000040 +#define EFI_PART_REDUNDANT_PARTITION 0x0000000000000080 +#define EFI_PART_TYPE_UNUSED_GUID { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } +#define EFI_PART_TYPE_EFI_SYSTEM_PART_GUID { 0xc12a7328, 0xf81f, 0x11d2, {0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} } +#define EFI_PART_TYPE_LEGACY_MBR_GUID { 0x024dee41, 0x33e7, 0x11d3, {0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f} } + +/* Protocol GUIDs */ +#ifndef INTERNAL_SHELL_GUID +#define INTERNAL_SHELL_GUID { 0xd65a6b8c, 0x71e5, 0x4df0, {0xa9, 0x09, 0xf0, 0xd2, 0x99, 0x2b, 0x5a, 0xa9} } +#endif + +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} efi_allocate_type_t; + +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiPersistentMemory, + EfiUnacceptedMemoryType, + EfiMaxMemoryType +} efi_memory_type_t; + +typedef enum { + TimerCancel, + TimerPeriodic, + TimerRelative, + TimerTypeMax +} efi_timer_delay_t; + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} efi_locate_search_type_t; + +typedef enum { + EfiResetCold, + EfiResetWarm, + EfiResetShutdown +} efi_reset_type_t; + +#else + +#define efi_allocate_type_t EFI_ALLOCATE_TYPE +#define efi_memory_type_t EFI_MEMORY_TYPE +#define efi_timer_delay_t EFI_TIMER_DELAY +#define efi_locate_search_type_t EFI_LOCATE_SEARCH_TYPE +#define efi_reset_type_t EFI_RESET_TYPE + +#endif + +/*** standard input, output and error streams via ConIn, ConOut and StdErr ***/ +typedef struct { + uint16_t ScanCode; + wchar_t UnicodeChar; +} efi_input_key_t; + +typedef efi_status_t (EFIAPI *efi_input_reset_t)(void *This, boolean_t ExtendedVerification); +typedef efi_status_t (EFIAPI *efi_input_read_key_t)(void *This, efi_input_key_t *Key); + +typedef struct { + efi_input_reset_t Reset; + efi_input_read_key_t ReadKeyStroke; + efi_event_t WaitForKey; +} simple_input_interface_t; + +typedef efi_status_t (EFIAPI *efi_text_reset_t)(void *This, boolean_t ExtendedVerification); +typedef efi_status_t (EFIAPI *efi_text_output_string_t)(void *This, wchar_t *String); +typedef efi_status_t (EFIAPI *efi_text_test_string_t)(void *This, wchar_t *String); +typedef efi_status_t (EFIAPI *efi_text_query_mode_t)(void *This, uintn_t ModeNumber, uintn_t *Column, uintn_t *Row); +typedef efi_status_t (EFIAPI *efi_text_set_mode_t)(void *This, uintn_t ModeNumber); +typedef efi_status_t (EFIAPI *efi_text_set_attribute_t)(void *This, uintn_t Attribute); +typedef efi_status_t (EFIAPI *efi_text_clear_screen_t)(void *This); +typedef efi_status_t (EFIAPI *efi_text_set_cursor_t)(void *This, uintn_t Column, uintn_t Row); +typedef efi_status_t (EFIAPI *efi_text_enable_cursor_t)(void *This, boolean_t Enable); + +typedef struct { + int32_t MaxMode; + int32_t Mode; + int32_t Attribute; + int32_t CursorColumn; + int32_t CursorRow; + boolean_t CursorVisible; +} simple_text_output_mode_t; + +typedef struct { + efi_text_reset_t Reset; + efi_text_output_string_t OutputString; + efi_text_test_string_t TestString; + efi_text_query_mode_t QueryMode; + efi_text_set_mode_t SetMode; + efi_text_set_attribute_t SetAttribute; + efi_text_clear_screen_t ClearScreen; + efi_text_set_cursor_t SetCursorPosition; + efi_text_enable_cursor_t EnableCursor; + simple_text_output_mode_t *Mode; +} simple_text_output_interface_t; + +/*** Runtime Services ***/ +typedef struct { + uint16_t Year; /* 1998 - 2XXX */ + uint8_t Month; /* 1 - 12 */ + uint8_t Day; /* 1 - 31 */ + uint8_t Hour; /* 0 - 23 */ + uint8_t Minute; /* 0 - 59 */ + uint8_t Second; /* 0 - 59 */ + uint8_t Pad1; + uint32_t Nanosecond; /* 0 - 999,999,999 */ + int16_t TimeZone; /* -1440 to 1440 or 2047 */ + uint8_t Daylight; + uint8_t Pad2; +} efi_time_t; + +typedef struct { + uint32_t Resolution; + uint32_t Accuracy; + boolean_t SetsToZero; +} efi_time_capabilities_t; + +typedef struct { + efi_guid_t CapsuleGuid; + uint32_t HeaderSize; + uint32_t Flags; + uint32_t CapsuleImageSize; +} efi_capsule_header_t; + +#ifndef DataBlock +#define DataBlock ContinuationPointer +#endif +typedef struct { + uint64_t Length; + efi_physical_address_t ContinuationPointer; +} efi_capsule_block_descriptor_t; + +typedef efi_status_t (EFIAPI *efi_get_time_t)(efi_time_t *Time, efi_time_capabilities_t *Capabilities); +typedef efi_status_t (EFIAPI *efi_set_time_t)(efi_time_t *Time); +typedef efi_status_t (EFIAPI *efi_get_wakeup_time_t)(boolean_t *Enable, boolean_t *Pending, efi_time_t *Time); +typedef efi_status_t (EFIAPI *efi_set_wakeup_time_t)(boolean_t Enable, efi_time_t *Time); +typedef efi_status_t (EFIAPI *efi_set_virtual_address_map_t)(uintn_t MemoryMapSize, uintn_t DescriptorSize, + uint32_t DescriptorVersion, efi_memory_descriptor_t *VirtualMap); +typedef efi_status_t (EFIAPI *efi_convert_pointer_t)(uintn_t DebugDisposition, void **Address); +typedef efi_status_t (EFIAPI *efi_get_variable_t)(wchar_t *VariableName, efi_guid_t *VendorGuid, uint32_t *Attributes, + uintn_t *DataSize, void *Data); +typedef efi_status_t (EFIAPI *efi_get_next_variable_name_t)(uintn_t *VariableNameSize, wchar_t *VariableName, + efi_guid_t *VendorGuid); +typedef efi_status_t (EFIAPI *efi_set_variable_t)(wchar_t *VariableName, efi_guid_t *VendorGuid, uint32_t Attributes, + uintn_t DataSize, void *Data); +typedef efi_status_t (EFIAPI *efi_get_next_high_mono_t)(uint64_t *Count); +typedef efi_status_t (EFIAPI *efi_reset_system_t)(efi_reset_type_t ResetType, efi_status_t ResetStatus, uintn_t DataSize, + wchar_t *ResetData); +typedef efi_status_t (EFIAPI *efi_update_capsule_t)(efi_capsule_header_t **CapsuleHeaderArray, uintn_t CapsuleCount, + efi_physical_address_t ScatterGatherList); +typedef efi_status_t (EFIAPI *efi_query_capsule_capabilities_t)(efi_capsule_header_t **CapsuleHeaderArray, uintn_t CapsuleCount, + uint64_t *MaximumCapsuleSize, efi_reset_type_t *ResetType); +typedef efi_status_t (EFIAPI *efi_query_variable_info_t)(uint32_t Attributes, uint64_t *MaximumVariableStorageSize, + uint64_t *RemainingVariableStorageSize, uint64_t *MaximumVariableSize); + +typedef struct { + efi_table_header_t Hdr; + + efi_get_time_t GetTime; + efi_set_time_t SetTime; + efi_get_wakeup_time_t GetWakeupTime; + efi_set_wakeup_time_t SetWakeupTime; + + efi_set_virtual_address_map_t SetVirtualAddressMap; + efi_convert_pointer_t ConvertPointer; + + efi_get_variable_t GetVariable; + efi_get_next_variable_name_t GetNextVariableName; + efi_set_variable_t SetVariable; + + efi_get_next_high_mono_t GetNextHighMonotonicCount; + efi_reset_system_t ResetSystem; + + efi_update_capsule_t UpdateCapsule; + efi_query_capsule_capabilities_t QueryCapsuleCapabilities; + efi_query_variable_info_t QueryVariableInfo; +} efi_runtime_services_t; +extern efi_runtime_services_t *RT; +#define gRT RT + +/** Boot Services ***/ +typedef struct { + efi_handle_t AgentHandle; + efi_handle_t ControllerHandle; + uint32_t Attributes; + uint32_t OpenCount; +} efi_open_protocol_information_entry_t; + +typedef efi_tpl_t (EFIAPI *efi_raise_tpl_t)(efi_tpl_t NewTpl); +typedef efi_tpl_t (EFIAPI *efi_restore_tpl_t)(efi_tpl_t OldTpl); +typedef efi_status_t (EFIAPI *efi_allocate_pages_t)(efi_allocate_type_t Type, efi_memory_type_t MemoryType, + uintn_t NoPages, efi_physical_address_t *Memory); +typedef efi_status_t (EFIAPI *efi_free_pages_t)(efi_physical_address_t Memory, uintn_t NoPages); +typedef efi_status_t (EFIAPI *efi_get_memory_map_t)(uintn_t *MemoryMapSize, efi_memory_descriptor_t *MemoryMap, + uintn_t *MapKey, uintn_t *DescriptorSize, uint32_t *DescriptorVersion); +typedef efi_status_t (EFIAPI *efi_allocate_pool_t)(efi_memory_type_t PoolType, uintn_t Size, void **Buffer); +typedef efi_status_t (EFIAPI *efi_free_pool_t)(void *Buffer); +typedef void (EFIAPI *efi_event_notify_t)(efi_event_t Event, void *Context); +typedef efi_status_t (EFIAPI *efi_create_event_t)(uint32_t Type, efi_tpl_t NotifyTpl, efi_event_notify_t NotifyFunction, + void *NextContext, efi_event_t *Event); +typedef efi_status_t (EFIAPI *efi_set_timer_t)(efi_event_t Event, efi_timer_delay_t Type, uint64_t TriggerTime); +typedef efi_status_t (EFIAPI *efi_wait_for_event_t)(uintn_t NumberOfEvents, efi_event_t *Event, uintn_t *Index); +typedef efi_status_t (EFIAPI *efi_signal_event_t)(efi_event_t Event); +typedef efi_status_t (EFIAPI *efi_close_event_t)(efi_event_t Event); +typedef efi_status_t (EFIAPI *efi_check_event_t)(efi_event_t Event); +typedef efi_status_t (EFIAPI *efi_handle_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, void **Interface); +typedef efi_status_t (EFIAPI *efi_register_protocol_notify_t)(efi_guid_t *Protocol, efi_event_t Event, void **Registration); +typedef efi_status_t (EFIAPI *efi_locate_handle_t)(efi_locate_search_type_t SearchType, efi_guid_t *Protocol, + void *SearchKey, uintn_t *BufferSize, efi_handle_t *Buffer); +typedef efi_status_t (EFIAPI *efi_locate_device_path_t)(efi_guid_t *Protocol, efi_device_path_t **DevicePath, + efi_handle_t *Device); +typedef efi_status_t (EFIAPI *efi_install_configuration_table_t)(efi_guid_t *Guid, void *Table); +typedef efi_status_t (EFIAPI *efi_image_load_t)(boolean_t BootPolicy, efi_handle_t ParentImageHandle, efi_device_path_t *FilePath, + void *SourceBuffer, uintn_t SourceSize, efi_handle_t *ImageHandle); +typedef efi_status_t (EFIAPI *efi_image_start_t)(efi_handle_t ImageHandle, uintn_t *ExitDataSize, wchar_t **ExitData); +typedef efi_status_t (EFIAPI *efi_exit_t)(efi_handle_t ImageHandle, efi_status_t ExitStatus, uintn_t ExitDataSize, + wchar_t *ExitData); +typedef efi_status_t (EFIAPI *efi_exit_boot_services_t)(efi_handle_t ImageHandle, uintn_t MapKey); +typedef efi_status_t (EFIAPI *efi_get_next_monotonic_t)(uint64_t *Count); +typedef efi_status_t (EFIAPI *efi_stall_t)(uintn_t Microseconds); +typedef efi_status_t (EFIAPI *efi_set_watchdog_timer_t)(uintn_t Timeout, uint64_t WatchdogCode, uintn_t DataSize, + wchar_t *WatchdogData); +typedef efi_status_t (EFIAPI *efi_connect_controller_t)(efi_handle_t ControllerHandle, efi_handle_t *DriverImageHandle, + efi_device_path_t *RemainingDevicePath, boolean_t Recursive); +typedef efi_status_t (EFIAPI *efi_disconnect_controller_t)(efi_handle_t ControllerHandle, efi_handle_t DriverImageHandle, + efi_handle_t ChildHandle); +typedef efi_status_t (EFIAPI *efi_open_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, void **Interface, + efi_handle_t AgentHandle, efi_handle_t ControllerHandle, uint32_t Attributes); +typedef efi_status_t (EFIAPI *efi_close_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, efi_handle_t AgentHandle, + efi_handle_t ControllerHandle); +typedef efi_status_t (EFIAPI *efi_open_protocol_information_t)(efi_handle_t Handle, efi_guid_t *Protocol, + efi_open_protocol_information_entry_t**EntryBuffer, uintn_t *EntryCount); +typedef efi_status_t (EFIAPI *efi_protocols_per_handle_t)(efi_handle_t Handle, efi_guid_t ***ProtocolBuffer, + uintn_t *ProtocolBufferCount); +typedef efi_status_t (EFIAPI *efi_locate_handle_buffer_t)(efi_locate_search_type_t SearchType, efi_guid_t *Protocol, + void *SearchKey, uintn_t *NoHandles, efi_handle_t **Handles); +typedef efi_status_t (EFIAPI *efi_locate_protocol_t)(efi_guid_t *Protocol, void *Registration, void **Interface); +typedef efi_status_t (EFIAPI *efi_calculate_crc32_t)(void *Data, uintn_t DataSize, uint32_t *Crc32); + +typedef struct { + efi_table_header_t Hdr; + + efi_raise_tpl_t RaiseTPL; + efi_restore_tpl_t RestoreTPL; + + efi_allocate_pages_t AllocatePages; + efi_free_pages_t FreePages; + efi_get_memory_map_t GetMemoryMap; + efi_allocate_pool_t AllocatePool; + efi_free_pool_t FreePool; + + efi_create_event_t CreateEvent; + efi_set_timer_t SetTimer; + efi_wait_for_event_t WaitForEvent; + efi_signal_event_t SignalEvent; + efi_close_event_t CloseEvent; + efi_check_event_t CheckEvent; + + void* InstallProtocolInterface; /* not defined yet */ + void* ReinstallProtocolInterface; + void* UninstallProtocolInterface; + efi_handle_protocol_t HandleProtocol; + efi_handle_protocol_t PCHandleProtocol; + efi_register_protocol_notify_t RegisterProtocolNotify; + efi_locate_handle_t LocateHandle; + efi_locate_device_path_t LocateDevicePath; + efi_install_configuration_table_t InstallConfigurationTable; + + efi_image_load_t LoadImage; + efi_image_start_t StartImage; + efi_exit_t Exit; + void* UnloadImage; /* not defined in gnu-efi either */ + efi_exit_boot_services_t ExitBootServices; + + efi_get_next_monotonic_t GetNextHighMonotonicCount; + efi_stall_t Stall; + efi_set_watchdog_timer_t SetWatchdogTimer; + + efi_connect_controller_t ConnectController; + efi_disconnect_controller_t DisconnectController; + + efi_open_protocol_t OpenProtocol; + efi_close_protocol_t CloseProtocol; + efi_open_protocol_information_t OpenProtocolInformation; + + efi_protocols_per_handle_t ProtocolsPerHandle; + efi_locate_handle_buffer_t LocateHandleBuffer; + efi_locate_protocol_t LocateProtocol; + void* InstallMultipleProtocolInterfaces; + void* UninstallMultipleProtocolInterfaces; + + efi_calculate_crc32_t CalculateCrc32; +} efi_boot_services_t; +extern efi_boot_services_t *BS; +#define gBS BS + +/*** Loaded Image Protocol ***/ +#ifndef EFI_LOADED_IMAGE_PROTOCOL_GUID +#define EFI_LOADED_IMAGE_PROTOCOL_GUID { 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } +#define LOADED_IMAGE_PROTOCOL EFI_LOADED_IMAGE_PROTOCOL_GUID + +#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000 +#define EFI_IMAGE_INFORMATION_REVISION EFI_LOADED_IMAGE_PROTOCOL_REVISION +#endif + +typedef struct { + uint32_t Revision; + efi_handle_t ParentHandle; + void *SystemTable; + efi_handle_t DeviceHandle; + efi_device_path_t *FilePath; + void *Reserved; + uint32_t LoadOptionsSize; + void *LoadOptions; + void *ImageBase; + uint64_t ImageSize; + efi_memory_type_t ImageCodeType; + efi_memory_type_t ImageDataType; +} efi_loaded_image_protocol_t; +extern efi_loaded_image_protocol_t *LIP; +extern efi_handle_t IM; + +/*** System Table ***/ +typedef struct { + efi_guid_t VendorGuid; + void *VendorTable; +} efi_configuration_table_t; + +typedef struct { + efi_table_header_t Hdr; + + wchar_t *FirmwareVendor; + uint32_t FirmwareRevision; + + efi_handle_t ConsoleInHandle; + simple_input_interface_t *ConIn; + + efi_handle_t ConsoleOutHandle; + simple_text_output_interface_t *ConOut; + + efi_handle_t ConsoleErrorHandle; + simple_text_output_interface_t *StdErr; + + efi_runtime_services_t *RuntimeServices; + efi_boot_services_t *BootServices; + + uintn_t NumberOfTableEntries; + efi_configuration_table_t *ConfigurationTable; +} efi_system_table_t; +extern efi_system_table_t *ST; +#define gST ST + +/*** Simple File System Protocol ***/ +#ifndef EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID { 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000 +#define EFI_FILE_IO_INTERFACE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION + +#define EFI_FILE_MODE_READ 0x0000000000000001 +#define EFI_FILE_MODE_WRITE 0x0000000000000002 +#define EFI_FILE_MODE_CREATE 0x8000000000000000 + +#define EFI_FILE_READ_ONLY 0x0000000000000001 +#define EFI_FILE_HIDDEN 0x0000000000000002 +#define EFI_FILE_SYSTEM 0x0000000000000004 +#define EFI_FILE_RESERVED 0x0000000000000008 +#define EFI_FILE_DIRECTORY 0x0000000000000010 +#define EFI_FILE_ARCHIVE 0x0000000000000020 +#define EFI_FILE_VALID_ATTR 0x0000000000000037 + +#define EFI_FILE_PROTOCOL_REVISION 0x00010000 +#define EFI_FILE_HANDLE_REVISION EFI_FILE_PROTOCOL_REVISION +#endif + +#ifndef EFI_FILE_INFO_GUID +#define EFI_FILE_INFO_GUID { 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#endif + +#ifndef FILENAME_MAX +#define FILENAME_MAX 262 /* from FAT spec */ +#endif + +typedef struct { + uint64_t Size; + uint64_t FileSize; + uint64_t PhysicalSize; + efi_time_t CreateTime; + efi_time_t LastAccessTime; + efi_time_t ModificationTime; + uint64_t Attribute; + wchar_t FileName[FILENAME_MAX]; +} efi_file_info_t; + +typedef struct efi_file_handle_s efi_file_handle_t; + +typedef efi_status_t (EFIAPI *efi_volume_open_t)(void *This, efi_file_handle_t **Root); +typedef struct { + uint64_t Revision; + efi_volume_open_t OpenVolume; +} efi_simple_file_system_protocol_t; + +typedef efi_status_t (EFIAPI *efi_file_open_t)(efi_file_handle_t *File, efi_file_handle_t **NewHandle, wchar_t *FileName, + uint64_t OpenMode, uint64_t Attributes); +typedef efi_status_t (EFIAPI *efi_file_close_t)(efi_file_handle_t *File); +typedef efi_status_t (EFIAPI *efi_file_delete_t)(efi_file_handle_t *File); +typedef efi_status_t (EFIAPI *efi_file_read_t)(efi_file_handle_t *File, uintn_t *BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_file_write_t)(efi_file_handle_t *File, uintn_t *BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_file_get_pos_t)(efi_file_handle_t *File, uint64_t *Position); +typedef efi_status_t (EFIAPI *efi_file_set_pos_t)(efi_file_handle_t *File, uint64_t Position); +typedef efi_status_t (EFIAPI *efi_file_get_info_t)(efi_file_handle_t *File, efi_guid_t *InformationType, uintn_t *BufferSize, + void *Buffer); +typedef efi_status_t (EFIAPI *efi_file_set_info_t)(efi_file_handle_t *File, efi_guid_t *InformationType, uintn_t BufferSize, + void *Buffer); +typedef efi_status_t (EFIAPI *efi_file_flush_t)(efi_file_handle_t *File); + +struct efi_file_handle_s { + uint64_t Revision; + efi_file_open_t Open; + efi_file_close_t Close; + efi_file_delete_t Delete; + efi_file_read_t Read; + efi_file_write_t Write; + efi_file_get_pos_t GetPosition; + efi_file_set_pos_t SetPosition; + efi_file_get_info_t GetInfo; + efi_file_set_info_t SetInfo; + efi_file_flush_t Flush; +}; + +/*** Shell Parameter Protocols ***/ +#ifndef EFI_SHELL_PARAMETERS_PROTOCOL_GUID +#define EFI_SHELL_PARAMETERS_PROTOCOL_GUID { 0x752f3136, 0x4e16, 0x4fdc, {0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca} } +#endif + +typedef struct { + wchar_t **Argv; + uintn_t Argc; + efi_handle_t StdIn; + efi_handle_t StdOut; + efi_handle_t StdErr; +} efi_shell_parameters_protocol_t; + +#ifndef SHELL_INTERFACE_PROTOCOL_GUID +#define SHELL_INTERFACE_PROTOCOL_GUID { 0x47c7b223, 0xc42a, 0x11d2, {0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#endif + +typedef struct { + efi_handle_t ImageHandle; + void* *Info; + wchar_t **Argv; + uintn_t Argc; + wchar_t **RedirArgv; + uintn_t RedirArgc; + efi_handle_t StdIn; + efi_handle_t StdOut; + efi_handle_t StdErr; +} efi_shell_interface_protocol_t; + +/*** Random Number Generator ***/ +#ifndef EFI_RNG_PROTOCOL_GUID +#define EFI_RNG_PROTOCOL_GUID { 0x3152bca5, 0xeade, 0x433d, {0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44} } +#endif + +typedef efi_status_t (EFIAPI *efi_rng_get_info_t)(void *This, uintn_t *RNGAlgorithmListSize, efi_guid_t *RNGAlgorithmList); +typedef efi_status_t (EFIAPI *efi_rng_get_rng_t)(void *This, efi_guid_t *RNGAlgorithm, uintn_t RNGValueLength, uint8_t *RNGValue); + +typedef struct { + efi_rng_get_info_t GetInfo; + efi_rng_get_rng_t GetRNG; +} efi_rng_protocol_t; + +/*** Serial IO Protocol ***/ +#ifndef EFI_SERIAL_IO_PROTOCOL_GUID +#define EFI_SERIAL_IO_PROTOCOL_GUID { 0xBB25CF6F, 0xF1D4, 0x11D2, {0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD} } + +#define SERIAL_IO_INTERFACE_REVISION 0x00010000 +#define EFI_SERIAL_CLEAR_TO_SEND 0x0010 +#define EFI_SERIAL_DATA_SET_READY 0x0020 +#define EFI_SERIAL_RING_INDICATE 0x0040 +#define EFI_SERIAL_CARRIER_DETECT 0x0080 +#define EFI_SERIAL_REQUEST_TO_SEND 0x0002 +#define EFI_SERIAL_DATA_TERMINAL_READY 0x0001 +#define EFI_SERIAL_INPUT_BUFFER_EMPTY 0x0100 +#define EFI_SERIAL_OUTPUT_BUFFER_EMPTY 0x0200 +#define EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE 0x1000 +#define EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE 0x2000 +#define EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE 0x4000 + +typedef enum { + DefaultParity, + NoParity, + EvenParity, + OddParity, + MarkParity, + SpaceParity +} efi_parity_type_t; + +typedef enum { + DefaultStopBits, + OneStopBit, + OneFiveStopBits, + TwoStopBits +} efi_stop_bits_type_t; + +#else + +#define efi_parity_type_t EFI_PARITY_TYPE +#define efi_stop_bits_type_t EFI_STOP_BITS_TYPE + +#endif + +typedef struct { + uint32_t ControlMask; + uint32_t Timeout; + uint64_t BaudRate; + uint32_t ReceiveFifoDepth; + uint32_t DataBits; + uint32_t Parity; + uint32_t StopBits; +} efi_serial_io_mode_t; + +typedef efi_status_t (EFIAPI *efi_serial_reset_t)(void *This); +typedef efi_status_t (EFIAPI *efi_serial_set_attributes_t)(void *This, uint64_t BaudRate, uint32_t ReceiveFifoDepth, + uint32_t Timeout, efi_parity_type_t Parity, uint8_t DataBits, efi_stop_bits_type_t StopBits); +typedef efi_status_t (EFIAPI *efi_serial_set_control_bits_t)(void *This, uint32_t Control); +typedef efi_status_t (EFIAPI *efi_serial_get_control_bits_t)(void *This, uint32_t *Control); +typedef efi_status_t (EFIAPI *efi_serial_write_t)(void *This, uintn_t *BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_serial_read_t)(void *This, uintn_t *BufferSize, void *Buffer); + +typedef struct { + uint32_t Revision; + efi_serial_reset_t Reset; + efi_serial_set_attributes_t SetAttributes; + efi_serial_set_control_bits_t SetControl; + efi_serial_get_control_bits_t GetControl; + efi_serial_write_t Write; + efi_serial_read_t Read; + efi_serial_io_mode_t *Mode; +} efi_serial_io_protocol_t; + +/*** Block IO Protocol ***/ +#ifndef EFI_BLOCK_IO_PROTOCOL_GUID +#define EFI_BLOCK_IO_PROTOCOL_GUID { 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +#define EFI_BLOCK_IO_PROTOCOL_REVISION 0x00010000 +#define EFI_BLOCK_IO_INTERFACE_REVISION EFI_BLOCK_IO_PROTOCOL_REVISION + +#endif + +typedef struct { + uint32_t MediaId; + boolean_t RemovableMedia; + boolean_t MediaPresent; + boolean_t LogicalPartition; + boolean_t ReadOnly; + boolean_t WriteCaching; + uint32_t BlockSize; + uint32_t IoAlign; + efi_lba_t LastBlock; +} efi_block_io_media_t; + +typedef efi_status_t (EFIAPI *efi_block_reset_t)(void *This, boolean_t ExtendedVerification); +typedef efi_status_t (EFIAPI *efi_block_read_t)(void *This, uint32_t MediaId, efi_lba_t LBA, uintn_t BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_block_write_t)(void *This, uint32_t MediaId, efi_lba_t LBA, uintn_t BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_block_flush_t)(void *This); + +typedef struct { + uint64_t Revision; + efi_block_io_media_t *Media; + efi_block_reset_t Reset; + efi_block_read_t ReadBlocks; + efi_block_write_t WriteBlocks; + efi_block_flush_t FlushBlocks; +} efi_block_io_t; + +typedef struct { + off_t offset; + efi_block_io_t *bio; +} block_file_t; + +/*** Graphics Output Protocol (not used, but could be useful to have) ***/ +#ifndef EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID { 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } } + +typedef enum { + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax +} efi_gop_pixel_format_t; + +typedef enum { + EfiBltVideoFill, + EfiBltVideoToBltBuffer, + EfiBltBufferToVideo, + EfiBltVideoToVideo, + EfiGraphicsOutputBltOperationMax +} efi_gop_blt_operation_t; + +#else + +#define efi_gop_pixel_format_t EFI_GRAPHICS_PIXEL_FORMAT +#define efi_gop_blt_operation_t EFI_GRAPHICS_OUTPUT_BLT_OPERATION + +#endif + +typedef struct { + uint32_t RedMask; + uint32_t GreenMask; + uint32_t BlueMask; + uint32_t ReservedMask; +} efi_gop_pixel_bitmask_t; + +typedef struct { + uint32_t Version; + uint32_t HorizontalResolution; + uint32_t VerticalResolution; + efi_gop_pixel_format_t PixelFormat; + efi_gop_pixel_bitmask_t PixelInformation; + uint32_t PixelsPerScanLine; +} efi_gop_mode_info_t; + +typedef struct { + uint32_t MaxMode; + uint32_t Mode; + efi_gop_mode_info_t *Information; + uintn_t SizeOfInfo; + efi_physical_address_t FrameBufferBase; + uintn_t FrameBufferSize; +} efi_gop_mode_t; + +typedef efi_status_t (EFIAPI *efi_gop_query_mode_t)(void *This, uint32_t ModeNumber, uintn_t *SizeOfInfo, + efi_gop_mode_info_t **Info); +typedef efi_status_t (EFIAPI *efi_gop_set_mode_t)(void *This, uint32_t ModeNumber); +typedef efi_status_t (EFIAPI *efi_gop_blt_t)(void *This, uint32_t *BltBuffer, efi_gop_blt_operation_t BltOperation, + uintn_t SourceX, uintn_t SourceY, uintn_t DestinationX, uintn_t DestionationY, uintn_t Width, uintn_t Height, uintn_t Delta); + +typedef struct { + efi_gop_query_mode_t QueryMode; + efi_gop_set_mode_t SetMode; + efi_gop_blt_t Blt; + efi_gop_mode_t *Mode; +} efi_gop_t; + +/*** EDID Protocol (not used, but could be useful to have) ***/ +#ifndef EFI_EDID_ACTIVE_GUID +#define EFI_EDID_ACTIVE_GUID { 0xbd8c1056, 0x9f36, 0x44ec, { 0x92, 0xa8, 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86 } } +#define EFI_EDID_DISCOVERED_GUID { 0x1c0c34f6, 0xd380, 0x41fa, { 0xa0, 0x49, 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa } } +#endif + +typedef struct { + uint32_t SizeOfEdid; + uint8_t *Edid; +} efi_edid_t; + +/*** Simple Pointer Protocol (not used, but could be useful to have) ***/ +#ifndef EFI_SIMPLE_POINTER_PROTOCOL_GUID +#define EFI_SIMPLE_POINTER_PROTOCOL_GUID { 0x31878c87, 0xb75, 0x11d5, { 0x9a, 0x4f, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } +#endif + +typedef struct { + int32_t RelativeMovementX; + int32_t RelativeMovementY; + int32_t RelativeMovementZ; + boolean_t LeftButton; + boolean_t RightButton; +} efi_simple_pointer_state_t; + +typedef struct { + uint64_t ResolutionX; + uint64_t ResolutionY; + uint64_t ResolutionZ; + boolean_t LeftButton; + boolean_t RightButton; +} efi_simple_pointer_mode_t; + +typedef efi_status_t (EFIAPI *efi_simple_pointer_reset_t) (void *This, boolean_t ExtendedVerification); +typedef efi_status_t (EFIAPI *efi_simple_pointer_get_state_t) (void *This, efi_simple_pointer_state_t *State); + +typedef struct { + efi_simple_pointer_reset_t Reset; + efi_simple_pointer_get_state_t GetState; + efi_event_t WaitForInput; + efi_simple_pointer_mode_t *Mode; +} efi_simple_pointer_protocol_t; + +/*** Option ROM Protocol (not used, but could be useful to have) ***/ +#ifndef EFI_PCI_OPTION_ROM_TABLE_GUID +#define EFI_PCI_OPTION_ROM_TABLE_GUID { 0x7462660f, 0x1cbd, 0x48da, {0xad, 0x11, 0x91, 0x71, 0x79, 0x13, 0x83, 0x1c} } +#endif + +typedef struct { + efi_physical_address_t RomAddress; + efi_memory_type_t MemoryType; + uint32_t RomLength; + uint32_t Seg; + uint8_t Bus; + uint8_t Dev; + uint8_t Func; + boolean_t ExecutedLegacyBiosImage; + boolean_t DontLoadEfiRom; +} efi_pci_option_rom_descriptor_t; + +typedef struct { + uint64_t PciOptionRomCount; + efi_pci_option_rom_descriptor_t *PciOptionRomDescriptors; +} efi_pci_option_rom_table_t; + +/*** GPT partitioning table (not used, but could be useful to have) ***/ +typedef struct { + efi_table_header_t Header; + efi_lba_t MyLBA; + efi_lba_t AlternateLBA; + efi_lba_t FirstUsableLBA; + efi_lba_t LastUsableLBA; + efi_guid_t DiskGUID; + efi_lba_t PartitionEntryLBA; + uint32_t NumberOfPartitionEntries; + uint32_t SizeOfPartitionEntry; + uint32_t PartitionEntryArrayCRC32; +} efi_partition_table_header_t; + +typedef struct { + efi_guid_t PartitionTypeGUID; + efi_guid_t UniquePartitionGUID; + efi_lba_t StartingLBA; + efi_lba_t EndingLBA; + uint64_t Attributes; + wchar_t PartitionName[36]; +} efi_partition_entry_t; + +/*** POSIX definitions ***/ +#define abs(x) ((x)<0?-(x):(x)) +#define min(x,y) ((x)<(y)?(x):(y)) +#define max(x,y) ((x)>(y)?(x):(y)) + +/* dirent.h */ +#define IFTODT(mode) (((mode) & 0170000) >> 12) +#define DTTOIF(dirtype) ((dirtype) << 12) +#define DT_DIR 4 +#define DT_REG 8 +struct dirent { + unsigned short int d_reclen; + unsigned char d_type; + char_t d_name[FILENAME_MAX]; +}; +typedef struct efi_file_handle_s DIR; +extern DIR *opendir (const char_t *__name); +extern struct dirent *readdir (DIR *__dirp); +extern void rewinddir (DIR *__dirp); +extern int closedir (DIR *__dirp); + +/* errno.h */ +extern int errno; +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ + +/* stdlib.h */ +#define RAND_MAX 2147483647 +typedef int (*__compar_fn_t) (const void *, const void *); +extern int atoi (const char_t *__nptr); +extern int64_t atol (const char_t *__nptr); +extern int64_t strtol (const char_t *__nptr, char_t **__endptr, int __base); +extern void *malloc (size_t __size); +extern void *calloc (size_t __nmemb, size_t __size); +extern void *realloc (void *__ptr, size_t __size); +extern void free (void *__ptr); +extern void abort (void); +extern void exit (int __status); +/* exit Boot Services function. Returns 0 on success. */ +extern int exit_bs(void); +extern void *bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size, __compar_fn_t __compar); +extern void qsort (void *__base, size_t __nmemb, size_t __size, __compar_fn_t __compar); +extern int mblen (const char *__s, size_t __n); +extern int mbtowc (wchar_t * __pwc, const char * __s, size_t __n); +extern int wctomb (char *__s, wchar_t __wchar); +extern size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n); +extern size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n); +extern void srand(unsigned int __seed); +extern int rand(void); +extern uint8_t *getenv(char_t *name, uintn_t *len); +extern int setenv(char_t *name, uintn_t len, uint8_t *data); + +/* stdio.h */ +#ifndef BUFSIZ +#define BUFSIZ 8192 +#endif +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ +#define stdin (FILE*)ST->ConsoleInHandle +#define stdout (FILE*)ST->ConsoleOutHandle +#define stderr (FILE*)ST->ConsoleErrorHandle +typedef struct efi_file_handle_s FILE; +extern int fclose (FILE *__stream); +extern int fflush (FILE *__stream); +extern int remove (const char_t *__filename); +extern FILE *fopen (const char_t *__filename, const char_t *__modes); +extern size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream); +extern size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__s); +extern int fseek (FILE *__stream, long int __off, int __whence); +extern long int ftell (FILE *__stream); +extern int feof (FILE *__stream); +extern int fprintf (FILE *__stream, const char_t *__format, ...); +extern int printf (const char_t *__format, ...); +extern int sprintf (char_t *__s, const char_t *__format, ...); +extern int vfprintf (FILE *__s, const char_t *__format, __builtin_va_list __arg); +extern int vprintf (const char_t *__format, __builtin_va_list __arg); +extern int vsprintf (char_t *__s, const char_t *__format, __builtin_va_list __arg); +extern int snprintf (char_t *__s, size_t __maxlen, const char_t *__format, ...); +extern int vsnprintf (char_t *__s, size_t __maxlen, const char_t *__format, __builtin_va_list __arg); +extern int getchar (void); +/* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */ +extern int getchar_ifany (void); +extern int putchar (int __c); + +/* string.h */ +extern void *memcpy(void *__dest, const void *__src, size_t __n); +extern void *memmove(void *__dest, const void *__src, size_t __n); +extern void *memset(void *__s, int __c, size_t __n); +extern int memcmp(const void *__s1, const void *__s2, size_t __n); +extern void *memchr(const void *__s, int __c, size_t __n); +extern void *memrchr(const void *__s, int __c, size_t __n); +void *memmem(const void *haystack, size_t hl, const void *needle, size_t nl); +void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl); +extern char_t *strcpy (char_t *__dest, const char_t *__src); +extern char_t *strncpy (char_t *__dest, const char_t *__src, size_t __n); +extern char_t *strcat (char_t *__dest, const char_t *__src); +extern char_t *strncat (char_t *__dest, const char_t *__src, size_t __n); +extern int strcmp (const char_t *__s1, const char_t *__s2); +extern int strncmp (const char_t *__s1, const char_t *__s2, size_t __n); +extern char_t *strdup (const char_t *__s); +extern char_t *strchr (const char_t *__s, int __c); +extern char_t *strrchr (const char_t *__s, int __c); +extern char_t *strstr (const char_t *__haystack, const char_t *__needle); +extern char_t *strtok (char_t *__s, const char_t *__delim); +extern char_t *strtok_r (char_t *__s, const char_t *__delim, char_t **__save_ptr); +extern size_t strlen (const char_t *__s); + +/* sys/stat.h */ +#define S_IREAD 0400 /* Read by owner. */ +#define S_IWRITE 0200 /* Write by owner. */ +#define S_IFMT 0170000 /* These bits determine file type. */ +#define S_IFIFO 0010000 /* FIFO. */ +#define S_IFCHR 0020000 /* Character device. */ +#define S_IFDIR 0040000 /* Directory. */ +#define S_IFBLK 0060000 /* Block device. */ +#define S_IFREG 0100000 /* Regular file. */ +#define S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask)) +#define S_ISCHR(mode) S_ISTYPE((mode), S_IFCHR) +#define S_ISDIR(mode) S_ISTYPE((mode), S_IFDIR) +#define S_ISBLK(mode) S_ISTYPE((mode), S_IFBLK) +#define S_ISREG(mode) S_ISTYPE((mode), S_IFREG) +#define S_ISFIFO(mode) S_ISTYPE((mode), S_IFIFO) +struct stat { + mode_t st_mode; + off_t st_size; + blkcnt_t st_blocks; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; +extern int stat (const char_t *__file, struct stat *__buf); +extern int fstat (FILE *__f, struct stat *__buf); +extern int mkdir (const char_t *__path, mode_t __mode); + +/* time.h */ +struct tm { + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] (not set) */ + int tm_yday; /* Days in year.[0-365] (not set) */ + int tm_isdst; /* DST. [-1/0/1]*/ +}; +extern struct tm *localtime (const time_t *__timer); +extern time_t mktime(const struct tm *__tm); +extern time_t time(time_t *__timer); + +/* unistd.h */ +extern unsigned int sleep (unsigned int __seconds); +extern int usleep (unsigned long int __useconds); +extern int unlink (const wchar_t *__filename); +extern int rmdir (const wchar_t *__filename); + +#ifdef __cplusplus +} +#endif + +#endif /* _UEFI_H_ */ diff --git a/Bootloader/Source/uefi/unistd.c b/Bootloader/Source/uefi/unistd.c new file mode 100644 index 0000000..b8dccdd --- /dev/null +++ b/Bootloader/Source/uefi/unistd.c @@ -0,0 +1,65 @@ +/* + * unistd.c + * + * Copyright (C) 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief Implementing functions which are defined in unistd.h + * + */ + +#include + +int __remove(const wchar_t *__filename, int isdir); + +int usleep (unsigned long int __useconds) +{ + BS->Stall(__useconds); + return 0; +} + +unsigned int sleep (unsigned int __seconds) +{ + /* Issue 56: some real firmware is buggy and Stall doesn't work for large delays, so use a timer instead */ + uint64_t usec = (uint64_t)__seconds * 1000000UL; + uintn_t index = 0; + efi_event_t timer_event; + efi_status_t status = status = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer_event); + if(!EFI_ERROR(status)) { + BS->SetTimer(timer_event, TimerRelative, usec * 10UL); + BS->WaitForEvent(1, &timer_event, &index); + BS->CloseEvent(timer_event); + } else + BS->Stall(usec); + return 0; +} + +int unlink (const wchar_t *__filename) +{ + return __remove(__filename, 0); +} + +int rmdir (const wchar_t *__filename) +{ + return __remove(__filename, 1); +} diff --git a/Bootloader/justfile b/Bootloader/justfile new file mode 100644 index 0000000..affe7cd --- /dev/null +++ b/Bootloader/justfile @@ -0,0 +1,14 @@ +BUILD_DIR := env_var_or_default("BUILD_DIR", justfile_directory() + "/.build") +TEMP_DIR := env_var_or_default("TEMP_DIR", BUILD_DIR + "/temp") +build: + cmake -B {{TEMP_DIR}}/bootloader -S . \ + -DCMAKE_TOOLCHAIN_FILE=Source/cmake/aarch64-uefi.cmake \ + -DCMAKE_BUILD_TYPE=Release + + cmake --build {{TEMP_DIR}}/bootloader + + cp {{TEMP_DIR}}/bootloader/efi_bin/BOOTAA64.EFI {{BUILD_DIR}}/bootloader/BOOTAA64.EFI + @echo "✅ Bootloader ready at: {{BUILD_DIR}}/bootloader/BOOTAA64.EFI" + +clean: + rm -rf {{TEMP_DIR}}/bootloader \ No newline at end of file diff --git a/justfile b/justfile new file mode 100644 index 0000000..41eac04 --- /dev/null +++ b/justfile @@ -0,0 +1,58 @@ +set quiet := true + +OS_NAME := os() +ARCH_NAME := arch() + +OVMF_ARM := if OS_NAME == "macos" { + "/opt/homebrew/share/qemu/edk2-aarch64-code.fd" +} else { + "/usr/share/edk2/aarch64/QEMU_EFI.fd" +} + +ACCEL := if OS_NAME == "macos" { + if ARCH_NAME == "arm64" { "-accel hvf" } else { "" } +} else { + "" +} + +ACCEL_INFO := if ACCEL == "" { "none (TCG)" } else { ACCEL } + +CPU := if ARCH_NAME == "arm64" { "host" } else { + if ARCH_NAME == "aarch64" { "host" } else { "max" } +} + +export BUILD_DIR := justfile_directory() + "/.build" +export TEMP_DIR := BUILD_DIR + "/temp" +export BOOT_BIN := BUILD_DIR + "/bootloader/BOOTAA64.EFI" +export IMG_FILE := BUILD_DIR + "/termOS.img" + +mod Bootloader + +_prep: + @mkdir -p {{BUILD_DIR}}/bootloader + @mkdir -p {{TEMP_DIR}}/bootloader + +@build: _prep + @echo "🛠️ Building everything..." + just Bootloader build + +@image: build + @echo "💾 Creating image..." + @dd if=/dev/zero of={{IMG_FILE}} bs=1M count=64 status=none + @mkfs.fat -F 32 {{IMG_FILE}} > /dev/null + @mmd -i {{IMG_FILE}} ::/EFI ::/EFI/BOOT + @mcopy -i {{IMG_FILE}} {{BOOT_BIN}} ::/EFI/BOOT/BOOTAA64.EFI + +@run: image + @echo "🚀 Launching..." + # Создаем копию переменных, если её нет (чтобы не портить системный файл) + @cp /usr/share/edk2/aarch64/QEMU_VARS.fd {{TEMP_DIR}}/vars.fd + qemu-system-aarch64 {{ACCEL}} \ + -machine virt \ + -cpu {{CPU}} \ + -m 512M \ + -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/aarch64/QEMU_EFI.fd \ + -drive if=pflash,format=raw,file={{TEMP_DIR}}/vars.fd \ + -drive file={{IMG_FILE}},format=raw,if=none,id=hd0 \ + -device virtio-blk-device,drive=hd0 \ + -serial mon:stdio \ No newline at end of file