From: Michael D. Lowis Date: Fri, 17 Sep 2021 17:57:14 +0000 (-0400) Subject: refactored to isolate UEFI logic from Kernel core X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=1f1da03e3b95c5cf6e9beec0bd5dbcc044d6904d;p=proto%2Fuefi.git refactored to isolate UEFI logic from Kernel core --- diff --git a/.gitignore b/.gitignore index c8118cb..310d193 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ boot.img kernel.efi tags +BOOTX64.EFI diff --git a/Makefile b/Makefile index 7692f86..c05f02e 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,73 @@ -TARGET = kernel.efi -OVMF = /usr/share/qemu/OVMF.fd -#OVMF = /usr/share/edk2-ovmf/OVMF_CODE.fd +ARCH = x86_64 +EFIARCH = efi-app-$(ARCH) +TARGET = BOOTX64.EFI -include uefi/Makefile +CC = gcc +LD = ld +OBJCOPY = objcopy +AR = ar -.PHONY: all run clean +CFLAGS = \ + -fshort-wchar \ + -fno-strict-aliasing \ + -ffreestanding \ + -fno-stack-protector \ + -fno-stack-check \ + -mno-red-zone \ + -maccumulate-outgoing-args \ + -Wno-builtin-declaration-mismatch \ + -fpic \ + -fPIC -all: boot.img +CPPFLAGS = \ + -I./core/ \ + -I./uefi \ + -I/usr/include \ + -D__$(ARCH)__ \ + -DHAVE_USE_MS_ABI + +LDFLAGS = \ + -nostdlib \ + -shared \ + -Bsymbolic \ + -Luefi + +LIBS = \ + -o $(TARGET).so \ + -T uefi/elf_$(ARCH)_efi.lds + +# get source files, generate object names +SRCS = $(wildcard core/*.c uefi/*.c) +OBJS = $(SRCS:.c=.o) + +.PHONY: all clean run + +all: $(TARGET) clean: find -name '*.o' -delete rm -f kernel.efi uefi/libuefi.a boot.img run: boot.img - qemu-system-x86_64 -bios $(OVMF) -cpu qemu64 boot.img + qemu-system-$(ARCH) -bios $(OVMF) -cpu qemu64 boot.img boot.img: $(TARGET) dd if=/dev/zero of=boot.img bs=1k count=1440 mformat -i boot.img -f 1440 :: mmd -i boot.img ::/EFI mmd -i boot.img ::/EFI/BOOT - mcopy -i boot.img kernel.efi ::/EFI/BOOT/BOOTX64.EFI + mcopy -i boot.img BOOTX64.EFI ::/EFI/BOOT/BOOTX64.EFI + +$(TARGET): $(TARGET).so + $(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 $^ $@ || echo target: $(EFIARCH) + rm $(TARGET).so + +$(TARGET).so: $(OBJS) + $(LD) $(LDFLAGS) $^ $(LIBS) + @rm *.lib 2>/dev/null || true + +%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +%.o: %.S + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ diff --git a/uefi/font.c b/core/font.c similarity index 99% rename from uefi/font.c rename to core/font.c index e32d081..84fbb4c 100644 --- a/uefi/font.c +++ b/core/font.c @@ -1,4 +1,5 @@ -#include +#include +#include uint8_t Font[4096] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/core/kernel.h b/core/kernel.h new file mode 100644 index 0000000..c390b6b --- /dev/null +++ b/core/kernel.h @@ -0,0 +1,28 @@ +/* + Graphics Support +*/ +#define FONT_WIDTH 8 +#define FONT_HEIGHT 16 +extern uint8_t Font[]; + +void Video_PutGlyph(int x, int y, char c); + +static inline void Video_PutPixel(int x, int y, uint32_t pixel) +{ + int offset = (sizeof(pixel) * Video.stride * y) + (sizeof(pixel) * x); + *(Video.buffer + offset) = pixel; +} + +/* + Terminal/Console Driver +*/ +void Term_Clear(void); +void Term_PutChar(int c); +void Term_PutString(char* s); +void Term_PutInt(int64_t val); +void Term_PutHex(uint64_t val); +void Term_PutHex8(uint8_t val); +void Term_PutHex16(uint16_t val); +void Term_PutHex32(uint32_t val); +void Term_PutHex64(uint64_t val); +void Term_PutNewline(void); \ No newline at end of file diff --git a/core/main.c b/core/main.c new file mode 100644 index 0000000..39c0e66 --- /dev/null +++ b/core/main.c @@ -0,0 +1,13 @@ +#include + +int main (int argc, char** argv) +{ + + /* loop forever */ + for (;;) + { +// BS->Stall(1000000); + } + + return 0; +} diff --git a/uefi/term.c b/core/term.c similarity index 77% rename from uefi/term.c rename to core/term.c index 4132341..e08ca70 100644 --- a/uefi/term.c +++ b/core/term.c @@ -1,11 +1,29 @@ -#include +#include +#include static char* Digits = "0123456789abcdef"; +static void PutGlyph(int x, int y, char c) +{ + char* glyph = &Font[c * FONT_HEIGHT]; + for (int row = 0; row < 16; row++) + { + char piece = glyph[row]; + for (int col = 0; col < 8; col++, piece <<= 1) + { + Video_PutPixel( + (x * FONT_WIDTH) + col, + (y * FONT_HEIGHT) + row, + (piece & 0x80) ? 0xFFFFFFFF : 0x00000000); + } + } +} + + void Term_PutChar(int c) { - wchar_t tmp[2] = { (wchar_t)c, 0 }; - ST->ConOut->OutputString(ST->ConOut, (c == '\n' ? (wchar_t*)L"\r\n" : tmp)); +// wchar_t tmp[2] = { (wchar_t)c, 0 }; +// ST->ConOut->OutputString(ST->ConOut, (c == '\n' ? (wchar_t*)L"\r\n" : tmp)); } void Term_PutString(char* s) diff --git a/core/video.c b/core/video.c new file mode 100644 index 0000000..581f5ac --- /dev/null +++ b/core/video.c @@ -0,0 +1,2 @@ +#include + diff --git a/main.c b/main.c deleted file mode 100644 index 190f4ff..0000000 --- a/main.c +++ /dev/null @@ -1,34 +0,0 @@ -#include - -static void PutIntField(char* label, int val) -{ - Term_PutString(label); - Term_PutInt(val); - Term_PutNewline(); -} - -int main (int argc, char** argv) -{ - Video_Init(); -// -// char glyph = 0; -// for (int y = 0; y < 16; y++) -// { -// for (int x = 0; x < 16; x++) -// { -// Video_PutGlyph( -// x, -// y, -// glyph++ -// ); -// } -// } - - /* loop forever */ - for (;;) - { - BS->Stall(1000000); - } - - return 0; -} diff --git a/uefi/Makefile b/uefi/Makefile index cd0dd50..056c47d 100644 --- a/uefi/Makefile +++ b/uefi/Makefile @@ -1,7 +1,7 @@ # detect architecture -MYARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +HOST_ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) ifeq ($(ARCH),) -ARCH = $(MYARCH) + ARCH = $(HOST_ARCH) endif # get source files, generate object names @@ -18,46 +18,38 @@ TMP = $(LIBSRCS:.c=.o) LIBOBJS = $(TMP:.S=.o) # detect toolchain -ifeq ($(wildcard /usr/bin/clang),) -USE_GCC = 1 -endif -ifneq ($(USE_GCC),) + ifeq ($(ARCH),x86_64) -CFLAGS += -maccumulate-outgoing-args + CFLAGS += -maccumulate-outgoing-args endif + CFLAGS += -Wno-builtin-declaration-mismatch -fpic -fPIC LDFLAGS += -nostdlib -shared -Bsymbolic -Luefi uefi/crt_$(ARCH).o LIBS += -o $(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 +ifneq ($(ARCH),$(HOST_ARCH)) + CC = $(ARCH)-elf-gcc + LD = $(ARCH)-elf-ld + OBJCOPY ?= $(ARCH)-elf-objcopy else -CC = gcc -LD = ld -OBJCOPY ?= objcopy + CC = gcc + LD = ld + OBJCOPY ?= objcopy endif + ifeq ($(ARCH),aarch64) -EFIARCH = pei-aarch64-little + EFIARCH = pei-aarch64-little else -EFIARCH = efi-app-$(ARCH) + EFIARCH = efi-app-$(ARCH) 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:$(TARGET) -CC = clang -LD = lld-link -OBJCOPY = true -endif # recipies ifeq ($(wildcard uefi/Makefile),) -ALLTARGETS = crt_$(ARCH).o libuefi.a build + ALLTARGETS = crt_$(ARCH).o libuefi.a build else -ALLTARGETS = uefi/crt_$(ARCH).o uefi/libuefi.a $(OBJS) $(TARGET) + ALLTARGETS = uefi/crt_$(ARCH).o uefi/libuefi.a $(OBJS) $(TARGET) endif all: $(ALLTARGETS) $(EXTRA) @@ -84,3 +76,6 @@ $(TARGET).so: $(OBJS) %.o: %.S $(CC) $(CFLAGS) -c $< -o $@ + +dump: + @echo CFLAGS = $(CFLAGS) \ No newline at end of file diff --git a/uefi/crt_x86_64.c b/uefi/crt_x86_64.c index f7832f5..54a82b5 100644 --- a/uefi/crt_x86_64.c +++ b/uefi/crt_x86_64.c @@ -1,34 +1,4 @@ -/* - * 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() - * - * Simplified by Mike Lowis 2021. - */ - +#include #include /* this is implemented by the application */ @@ -66,51 +36,77 @@ efi_boot_services_t *BS = NULL; efi_runtime_services_t *RT = NULL; efi_loaded_image_protocol_t *LIP = NULL; -#if USE_UTF8 -char *__argvutf8 = NULL; -#endif +/* platform specific globals */ +VideoConfig Video = {0}; -/* we only need one .o file, so use inline Assembly here */ -void bootstrap() +static void video_init(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" + /* get a handle to the graphics protocol */ + efi_gop_t *gop = NULL; + efi_guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + BS->LocateProtocol(&gopGuid, NULL, (void**)&gop); - /* 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 - ); + /* query mode 0 to see if mode needs to be set first */ + uintn_t info_size = 0; + efi_gop_mode_info_t *info = NULL; + uintn_t status = gop->QueryMode(gop, 0, &info_size, &info); + + /* some machines need mode set explicitly first */ + if (status == EFI_NOT_STARTED) + { + status = gop->SetMode(gop, 0); + } + + /* + OK, now we have real info for possible modes, pick the max mode. + We assume this one is the best resolution. + */ + if (status == EFI_SUCCESS) + { + status = gop->SetMode(gop, 17); /* pick a smaller resolution for QEMU */ +// status = gop->SetMode(gop, gop->Mode->MaxMode-1); + } + + /* + Now let's save off the info we need to draw pixels and glyphs. + The code in this file assumes 32 bits per pixel. + */ + Video.buffer = (uint32_t*)(gop->Mode->FrameBufferBase); + Video.stride = gop->Mode->Information->PixelsPerScanLine; } -/** - * Initialize POSIX-UEFI and call the application's main() function +/* + * crt_x86_64.c : bootstrap() and uefi_init() + * + * 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() + * */ -int 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 -) { + +int uefi_init(uintptr_t ldbase, Elf64_Dyn *dyn, efi_system_table_t *systab, efi_handle_t image) +{ efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; efi_shell_parameters_protocol_t *shp = NULL; efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID; @@ -118,7 +114,7 @@ int uefi_init ( efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; efi_guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; efi_status_t status; -#ifndef __clang__ + long relsz = 0, relent = 0; Elf64_Rel *rel = 0; uintptr_t *addr; @@ -134,14 +130,11 @@ int uefi_init ( 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; break; } + { addr = (uintptr_t*)(ldbase + rel->r_offset); *addr += ldbase; break; } 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__ ( @@ -152,11 +145,41 @@ int uefi_init ( " orw $3 << 9, %ax\n" " mov %rax, %cr4\n" ); + /* save EFI pointers and loaded image into globals */ IM = image; ST = systab; BS = systab->BootServices; RT = systab->RuntimeServices; BS->HandleProtocol(image, &lipGuid, (void **)&LIP); + + /* perform some initialization for the kernel */ + video_init(); + return main(0, 0); } + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap() +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" + " .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" + ); +} diff --git a/uefi/platform.h b/uefi/platform.h new file mode 100644 index 0000000..32cd983 --- /dev/null +++ b/uefi/platform.h @@ -0,0 +1,29 @@ +/* define standard type definitions */ +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; +typedef long long int64_t; +typedef unsigned long long uint64_t; +typedef long long intptr_t; +typedef unsigned long long uintptr_t; + +/* sanity check type definitions */ +extern char check_u16[sizeof(uint16_t) == 2 ? 1 : -1]; +extern char check_u32[sizeof(uint32_t) == 4 ? 1 : -1]; +extern char check_u64[sizeof(uint64_t) == 8 ? 1 : -1]; +extern char check_uptr[sizeof(uintptr_t) == 8 ? 1 : -1]; + +#define NULL ((void*)0) + +/* video memory configuration info */ +typedef struct { + uint32_t* buffer; + uint32_t stride; + uint32_t width; + uint32_t height; +} VideoConfig; + +extern VideoConfig Video; \ No newline at end of file diff --git a/uefi/uefi.h b/uefi/uefi.h index 1ac5f1d..7454fa5 100644 --- a/uefi/uefi.h +++ b/uefi/uefi.h @@ -39,32 +39,6 @@ extern "C" { /* comment out this if you want to use wchar_t in your application */ #define USE_UTF8 1 -/* get these from the compiler */ -#ifndef _STDINT_H -#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; @@ -1232,33 +1206,6 @@ typedef struct { #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) -#define FONT_WIDTH 8 -#define FONT_HEIGHT 16 -extern uint8_t Font[]; - -extern uint32_t* VideoMem; -extern uint32_t VideoStride; - -void Video_Init(void); -void Video_PutGlyph(int x, int y, char c); - -static inline void Video_PutPixel(int x, int y, uint32_t pixel) -{ - int offset = (sizeof(pixel) * VideoStride * y) + (sizeof(pixel) * x); - *(VideoMem + offset) = pixel; -} - -void Term_Clear(void); -void Term_PutChar(int c); -void Term_PutString(char* s); -void Term_PutInt(int64_t val); -void Term_PutHex(uint64_t val); -void Term_PutHex8(uint8_t val); -void Term_PutHex16(uint16_t val); -void Term_PutHex32(uint32_t val); -void Term_PutHex64(uint64_t val); -void Term_PutNewline(void); - #ifdef __cplusplus } #endif diff --git a/uefi/video.c b/uefi/video.c deleted file mode 100644 index 468de43..0000000 --- a/uefi/video.c +++ /dev/null @@ -1,56 +0,0 @@ -#include - -uint32_t* VideoMem = NULL; -uint32_t VideoStride = 0; - -void Video_Init(void) -{ - /* get a handle to the graphics protocol */ - efi_gop_t *gop = NULL; - efi_guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; - BS->LocateProtocol(&gopGuid, NULL, (void**)&gop); - - /* query mode 0 to see if mode needs to be set first */ - uintn_t info_size = 0; - efi_gop_mode_info_t *info = NULL; - uintn_t status = gop->QueryMode(gop, 0, &info_size, &info); - - /* some machines need mode set explicitly first */ - if (status == EFI_NOT_STARTED) - { - status = gop->SetMode(gop, 0); - } - - /* - OK, now we have real info for possible modes, pick the max mode. - We assume this one is the best resolution. - */ - if (status == EFI_SUCCESS) - { - status = gop->SetMode(gop, 17); /* pick a smaller resolution for QEMU */ -// status = gop->SetMode(gop, gop->Mode->MaxMode-1); - } - - /* - Now let's save off the info we need to draw pixels and glyphs. - The code in this file assumes 32 bits per pixel. - */ - VideoMem = (uint32_t*)(gop->Mode->FrameBufferBase); - VideoStride = gop->Mode->Information->PixelsPerScanLine; -} - -void Video_PutGlyph(int x, int y, char c) -{ - char* glyph = &Font[c * FONT_HEIGHT]; - for (int row = 0; row < 16; row++) - { - char piece = glyph[row]; - for (int col = 0; col < 8; col++, piece <<= 1) - { - Video_PutPixel( - (x * FONT_WIDTH) + col, - (y * FONT_HEIGHT) + row, - (piece & 0x80) ? 0xFFFFFFFF : 0x00000000); - } - } -}