From 51cfcb98bde7e78b4817a9060885b25b6c3d354c Mon Sep 17 00:00:00 2001 From: Ada Christine Date: Fri, 18 Mar 2022 12:24:48 +0000 Subject: now using clang, native PE UEFI loader image. made an ugly hack to get into the shim. it's probably ok. --- .gitignore | 1 + README.md | 4 +-- api/loader/efi/shim.h | 13 +++++--- defaults.mk | 10 +++--- efi.mk | 31 ++---------------- kc/boot/Makefile | 3 ++ kc/core/Makefile | 2 +- kc/defaults.mk | 8 +++-- kc/dynamic_x86_64.c | 13 +++++--- kc/entry_x86_64.S | 8 +++++ kc/kc.ld | 2 +- loader/Makefile | 16 +++++---- loader/main_efi.c | 91 ++++++++++++++++++++++++++++++++++++++------------- rules.mk | 8 ++--- 14 files changed, 127 insertions(+), 83 deletions(-) diff --git a/.gitignore b/.gitignore index 62b87a1..a2bec76 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ *.efi *.log *.kate-swp +*.pdb diff --git a/README.md b/README.md index e68d251..203a4aa 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ whoever is outside my house yelling "comment your code!" i will never comment my in order to use this you will require the following: -- a gcc cross-compiler targeting x86\_64-elf. instructions [here](https://wiki.osdev.org/GCC_Cross-Compiler) +- clang 9.0+ - qemu supporting x86\_64 - an OVMF installation usable as a firmware for qemu -- gnu-efi +- gnu-efi for EFI headers generally it is only currently possible to build from a POSIX-like system. this is not a rule, but i do not currently support any other means diff --git a/api/loader/efi/shim.h b/api/loader/efi/shim.h index 0255361..dcdf077 100644 --- a/api/loader/efi/shim.h +++ b/api/loader/efi/shim.h @@ -23,11 +23,14 @@ struct efi_loader_image UINTN buffer_size; }; -typedef EFI_STATUS (*efi_image_func)(struct efi_loader_image *image); -typedef EFI_STATUS (*efi_page_alloc_func)(EFI_MEMORY_TYPE type, +typedef EFI_STATUS (EFIAPI *efi_image_func)(struct efi_loader_image *image); +typedef EFI_STATUS (EFIAPI *efi_page_alloc_func)( + EFI_MEMORY_TYPE type, UINTN size, EFI_PHYSICAL_ADDRESS *base); -typedef EFI_STATUS (*efi_page_free_func)(EFI_PHYSICAL_ADDRESS base, UINTN size); +typedef EFI_STATUS (EFIAPI *efi_page_free_func)( + EFI_PHYSICAL_ADDRESS base, + UINTN size); struct efi_loader_interface { @@ -42,6 +45,6 @@ struct efi_loader_interface efi_image_func image_load; }; -typedef EFI_STATUS (*efi_shim_entry_func)(struct efi_loader_image *image, - struct efi_loader_interface *interface); +typedef EFI_STATUS +(__attribute__((sysv_abi)) *efi_shim_entry_func)(struct efi_loader_interface *interface); diff --git a/defaults.mk b/defaults.mk index 16193f2..2cc7ac1 100644 --- a/defaults.mk +++ b/defaults.mk @@ -3,10 +3,10 @@ ARCH := x86_64 ABI := elf TARGET := $(ARCH)-$(ABI) -CC := $(TARGET)-gcc -CXX := $(TARGET)-g++ -AS := $(TARGET)-as -LD := $(TARGET)-ld +CC := clang +CXX := clang++ +AS := clang +LD := ld.bfd OBJCOPY := objcopy CFLAGS += -ffreestanding -mno-red-zone -ggdb -std=c2x \ @@ -17,6 +17,4 @@ CXXFLAGS += -ffreestanding -mno-red-zone -ggdb \ -Wall -Wextra -Werror -fno-stack-protector LDFLAGS += -nostdlib -LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) -LOADLIBES += -lgcc diff --git a/efi.mk b/efi.mk index 4067e44..60cf1d6 100644 --- a/efi.mk +++ b/efi.mk @@ -21,32 +21,7 @@ EFILDSCRIPT := $(EFILIBDIR)/elf_$(GNUEFIARCH)_efi.lds CPPFLAGS += -I$(EFIAPIDIR) -I$(EFIAPIDIR)/protocol -I$(EFIAPIDIR)/$(GNUEFIARCH) \ -DGNU_EFI_USE_MS_ABI -DEFI_CALL_WRAPPER -DEFI_DEBUG -CFLAGS += -fPIC -fshort-wchar -maccumulate-outgoing-args -mno-avx -mno-sse \ - -mno-mmx -funsigned-char -Wno-pointer-sign - -OBJCOPY.efi = $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \ - -j .dynsm -j .rel -j .rela -j .reloc \ - --target=efi-app-$(GNUEFIARCH) $< $@ - -OBJCOPY.debug.efi = $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \ - -j .dynsym -j .rel -j .rela -j .reloc -j .debug_info \ - -j .debug_abbrev -j .debug_loc -j .debug_aranges \ - -j .debug_line -j .debug_macinfo -j .debug_str \ - --target=efi-app-$(GNUEFIARCH) $< $@ - -LINK._efi.so = $(LD) $(LDFLAGS) -znocombreloc -Bsymbolic -shared --no-undefined \ - $(LIBDIRS) -L$(EFILIBDIR) -T $(EFILDSCRIPT) \ - $(filter %.o, $^) -lgnuefi -lefi $(LOADLIBES) -o $@ - -%.efi: %_efi.so - $(OBJCOPY.info) - @$(OBJCOPY.efi) - -%.debug.efi: %_efi.so - $(OBJCOPY.info) - @$(OBJCOPY.debug.efi) - -%_efi.so: $(EFILDSCRIPT) $(EFICRT) - $(LINK.info) - @$(LINK._efi.so) +%.efi: + $(CC.info) + @$(CC) $(LDFLAGS) -o $@ $^ diff --git a/kc/boot/Makefile b/kc/boot/Makefile index 297b6df..b90f183 100644 --- a/kc/boot/Makefile +++ b/kc/boot/Makefile @@ -8,6 +8,9 @@ TARGET := efi.os .DEFAULT: $(TARGET) CPPFLAGS += -I../../api -I ../api -I../../lib + +CFLAGS += -fshort-wchar + OBJS := entry_x86_64.o reloc_x86_64.o dynamic_x86_64.o \ kc_main.o elf64.o memcmp.o memcpy.o \ memmove.o memset.o loader_paging.o diff --git a/kc/core/Makefile b/kc/core/Makefile index 4d373cd..394b2dc 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -19,7 +19,7 @@ IOBJS := # __attribute__((interrupt)) requires -mgeneral-regs-only $(GOBJS): CFLAGS += -mgeneral-regs-only -$(GOBJS): CFLAGS += -mcmodel=small -fPIC +$(GOBJS): CFLAGS += -mcmodel=small OBJS := $(SOBJS) $(GOBJS) $(IOBJS) DEPS := $(patsubst %.o,%.d,$(OBJS)) diff --git a/kc/defaults.mk b/kc/defaults.mk index 0b6c4ba..ec6dfd3 100644 --- a/kc/defaults.mk +++ b/kc/defaults.mk @@ -1,7 +1,9 @@ -LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) LDSCRIPT := ../kc.ld + +CFLAGS += -fPIC -fvisibility=hidden -mgeneral-regs-only + LDFLAGS += -z max-page-size=4096 --export-dynamic -pic \ - -z separate-code -pie -Bsymbolic -shared -LOADLIBES := -lgcc + -z separate-code -pie -Bsymbolic -shared \ + -z execstack -g diff --git a/kc/dynamic_x86_64.c b/kc/dynamic_x86_64.c index 6b7abd7..a573283 100644 --- a/kc/dynamic_x86_64.c +++ b/kc/dynamic_x86_64.c @@ -9,10 +9,10 @@ void kc_dynamic_init(void *base, Elf64_Dyn *dyn) size_t entsize; }; - struct rela reladyn = {NULL,}; - struct rela relaplt = {NULL,}; + struct rela reladyn = {NULL, 0, 0}; + struct rela relaplt = {NULL, 0, 0}; - Elf64_Addr *gotplt; + Elf64_Addr *gotplt = NULL; while (dyn && dyn->d_tag != DT_NULL) { @@ -46,8 +46,11 @@ void kc_dynamic_init(void *base, Elf64_Dyn *dyn) // peform relocations // - gotplt[1] = (uintptr_t)NULL; - gotplt[2] = (uintptr_t)kc_resolve_symbol; + if (gotplt) + { + gotplt[1] = (uintptr_t)NULL; + gotplt[2] = (uintptr_t)kc_resolve_symbol; + } kc_reloc(base, relaplt.entries, relaplt.size, relaplt.entsize); kc_reloc(base, reladyn.entries, reladyn.size, reladyn.entsize); } diff --git a/kc/entry_x86_64.S b/kc/entry_x86_64.S index 8431044..c426335 100644 --- a/kc/entry_x86_64.S +++ b/kc/entry_x86_64.S @@ -6,14 +6,22 @@ .global kc_entry .type kc_entry, @function kc_entry: + push %rbp push %rdi push %rsi + mov %rsp, %rbp + and $-0x10, %rsp lea kc_image_base(%rip), %rdi lea _DYNAMIC(%rip), %rsi call kc_dynamic_init + mov %rbp, %rsp pop %rsi pop %rdi + mov %rsp, %rbp + and $-0x10, %rsp call kc_main + mov %rbp, %rsp + pop %rbp ret .size kc_entry, . - kc_entry diff --git a/kc/kc.ld b/kc/kc.ld index dbce342..97d6a2a 100644 --- a/kc/kc.ld +++ b/kc/kc.ld @@ -4,7 +4,7 @@ SECTIONS { PROVIDE_HIDDEN(kc_image_base = .); - . = sizeof_headers; + . = SIZEOF_HEADERS; .rela.plt : { diff --git a/loader/Makefile b/loader/Makefile index 5e1c8ac..d273258 100644 --- a/loader/Makefile +++ b/loader/Makefile @@ -4,18 +4,22 @@ include ../efi.mk VPATH := ../lib IMAGE := loader.efi -BUILD := $(IMAGE) $(IMAGE:.efi=.debug.efi) CPPFLAGS += -I../api -I../lib -all: $(BUILD) +CFLAGS += --target=$(GNUEFIARCH)-unknown-windows -fshort-wchar -mno-avx \ + -mno-sse -mno-mmx -funsigned-char -Wno-pointer-sign -ggdb -OBJS := main_efi.o elf64.o memcmp.o memmove.o kprintf.o strtoull.o +LDFLAGS := --target=$(GNUEFIARCH)-unknown-windows -nostdlib -ggdb \ + -Wl,-entry:efi_main,-subsystem:efi_application -fuse-ld=lld-link + +all: $(IMAGE) + +OBJS := main_efi.o elf64.o memcmp.o memmove.o kprintf.o strtoull.o memset.o \ + memcpy.o DEPS := $(OBJS:.o=.d) -IMAGE_SO := $(IMAGE:.efi=_efi.so) -$(IMAGE_SO): $(OBJS) -.INTERMEDIATE: $(IMAGE_SO) +$(IMAGE): $(OBJS) CLEANLIST := $(wildcard $(BUILD) $(OBJS)) DCLEANLIST := $(CLEANLIST) $(wildcard $(DEPS)) diff --git a/loader/main_efi.c b/loader/main_efi.c index 0b7dc3b..3b50c36 100644 --- a/loader/main_efi.c +++ b/loader/main_efi.c @@ -32,6 +32,9 @@ static struct efi_loader_image shim_image = .path = L"\\adasoft\\sophia\\efi.os" }; +static CHAR16 *linebuf; +static CHAR16 *linebuf_ptr; + static VOID *AllocatePool(UINTN size) { EFI_STATUS status; @@ -65,16 +68,7 @@ static VOID FreePool(void *block) } } -static struct efi_loader_interface loader_interface = -{ - NULL, - NULL, - &alloc_page, - &free_page, - &open_image, - &allocate_image, - &load_image -}; +static struct efi_loader_interface loader_interface; static const CHAR16 *efi_status_strings[] = { @@ -129,14 +123,18 @@ static const CHAR16 *efi_warning_strings[] = int kfputc(int c, FILE *f) { (void)f; - CHAR16 s[2] = {0,}; - EFI_STATUS status; + EFI_STATUS status = EFI_SUCCESS; if (loader_interface.system_table) { EFI_SIMPLE_TEXT_OUT_PROTOCOL *out = gST->ConOut; - s[0] = c; - status = out->OutputString(out, s); + *linebuf_ptr++ = c; + if (((linebuf_ptr - linebuf) == EFI_PAGE_SIZE - 2) || (c == L'\n')) + { + *linebuf_ptr++ = 0; + status = out->OutputString(out, linebuf); + linebuf_ptr = linebuf; + } } else { @@ -153,13 +151,54 @@ int kfputc(int c, FILE *f) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) { + loader_interface = (struct efi_loader_interface){ + image_handle, + system_table, + alloc_page, + free_page, + open_image, + allocate_image, + load_image + }; + gST = system_table; gBS = system_table->BootServices; - loader_interface.image_handle = image_handle; - loader_interface.system_table = system_table; EFI_STATUS status; + if EFI_ERROR((status = alloc_page( + EfiLoaderData, + EFI_PAGE_SIZE, + (EFI_PHYSICAL_ADDRESS *)&linebuf))) + { + gST->ConOut->OutputString( + gST->ConOut, + L"error allocating for line buffer"); + return status; + } + else + { + gBS->SetMem(linebuf, EFI_PAGE_SIZE, 0); + linebuf_ptr = linebuf; + } + + kprintf("loader interface %p\r\n" + "image_handle %p\r\n" + "system_table %p\r\n" + "page_alloc %p\r\n" + "page_free %p\r\n" + "image_open %p\r\n" + "image_alloc %p\r\n" + "image_load %p\r\n", + &loader_interface, + loader_interface.image_handle, + loader_interface.system_table, + loader_interface.page_alloc, + loader_interface.page_free, + loader_interface.image_open, + loader_interface.image_alloc, + loader_interface.image_load); + if (EFI_ERROR((status = open_image(&shim_image)))) { kprintf("error opening shim image: %ls\r\n", @@ -214,7 +253,7 @@ EFI_STATUS alloc_page(EFI_MEMORY_TYPE type, EFI_STATUS free_page(EFI_PHYSICAL_ADDRESS base, UINTN size) { - return gBS->FreePages(base, size); + return gBS->FreePages(base, EFI_SIZE_TO_PAGES(size)); } @@ -304,7 +343,6 @@ EFI_STATUS open_image(struct efi_loader_image *image) { phdrs_size = ehdr.e_phentsize * ehdr.e_phnum; phdrs = AllocatePool(phdrs_size); - ASSERT(phdrs); } else { @@ -366,8 +404,6 @@ static EFI_STATUS read_image(struct efi_loader_image *image, EFI_STATUS status; - ASSERT(buffer); - if (!EFI_ERROR((status = image->file->SetPosition(image->file, offset)))) { *buffer = (void *)(image->buffer_base + offset); @@ -425,12 +461,23 @@ EFI_STATUS load_image(struct efi_loader_image *image) static EFI_STATUS enter_shim(void) { - EFI_STATUS status; + EFI_STATUS status = EFI_ABORTED; Elf64_Ehdr *ehdr = (Elf64_Ehdr *)shim_image.buffer_base; kc_entry_func entry; entry = (kc_entry_func)(shim_image.buffer_base + ehdr->e_entry); - status = entry(&loader_interface); + kprintf("entering shim @%p\r\n", entry); + + __asm__ volatile + ( + "mov %0, %%rax\n\t" + "lea %1, %%rdi\n\t" + "call *%%rax\n\t" + : + : "m"(entry), "m"(loader_interface) + : "%rax", "%rdi" + ); + return status; } diff --git a/rules.mk b/rules.mk index 2115028..756184e 100644 --- a/rules.mk +++ b/rules.mk @@ -15,7 +15,7 @@ COMPILE.info = $(info $$(CC) $@) %.os: $(LINK.info) - @$(LINK.os) + $(LINK.os) %.debug.os: %.os $(OBJCOPY) --only-keep-debug $< $@ @@ -23,15 +23,15 @@ COMPILE.info = $(info $$(CC) $@) %.o: %.c $(COMPILE.info) - @$(COMPILE.c) -MMD -MP + $(COMPILE.c) -MMD -MP %.o: %.cpp $(COMPILE.info) - @$(COMPILE.cpp) -MMD -MP + $(COMPILE.cpp) -MMD -MP %.o: %.S $(COMPILE.info) - @$(COMPILE.S) -MMD -MP + $(COMPILE.S) -MMD -MP clean: $(info $$(RM) $(CLEANLIST)) -- cgit v1.3.1-1-g115d