:: commit edd4a8de603055fc2b5c094464f02745a76897c7

mintsuki <mintsuki@protonmail.com> — 2021-03-02 09:23

parents: a7a168a682

Initial UEFI port

diff --git a/.gitignore b/.gitignore
index 67e67357..d94bee1a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,11 @@
 /bin
 /toolchain
+/gnu-efi
+/ovmf
 /**/*.o
 /**/*.d
 /**/*.a
+/**/*.EFI
 /**/*.bin
 /**/*.bin.gz
 /**/*.elf
@@ -14,3 +17,4 @@
 .vscode
 /stivale
 /test_image
+!/stage23/font.bin
diff --git a/Makefile b/Makefile
index 518dd382..e48f3a78 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ OBJCOPY = objcopy
 CFLAGS = -O2 -pipe -Wall -Wextra
 PREFIX = /usr/local
 DESTDIR =
+TARGET = bios
 
 PATH := $(shell pwd)/toolchain/bin:$(PATH)
 
@@ -27,31 +28,36 @@ install: all
 	install -m 644 bin/limine-cd.bin $(DESTDIR)$(PREFIX)/share/
 	install -m 644 bin/limine-pxe.bin $(DESTDIR)$(PREFIX)/share/
 
+ifeq ($(TARGET), bios)
 bootloader: | decompressor stage23
 	mkdir -p bin
 	cd stage1/hdd && nasm bootsect.asm -fbin -o ../../bin/limine-hdd.bin
 	cd stage1/cd  && nasm bootsect.asm -fbin -o ../../bin/limine-cd.bin
 	cd stage1/pxe && nasm bootsect.asm -fbin -o ../../bin/limine-pxe.bin
 	cp stage23/limine.sys ./bin/
+else ifeq ($(TARGET), uefi)
+bootloader: stage23
+	mkdir -p bin
+	cp stage23/BOOTX64.EFI ./bin/
+endif
 
 bootloader-clean: stage23-clean decompressor-clean
 
 distclean: clean bootloader-clean test-clean
 	rm -rf bin stivale toolchain
 
-tinf-clean:
-	cd tinf && rm -rf *.o *.d
-
 stivale:
 	git clone https://github.com/stivale/stivale.git
 
-stage23: tinf-clean stivale
-	$(MAKE) -C stage23 all
+stage23: stivale
+	cd tinf && rm -rf *.o *.d
+	$(MAKE) -C stage23 all TARGET=$(TARGET)
 
 stage23-clean:
 	$(MAKE) -C stage23 clean
 
-decompressor: tinf-clean
+decompressor:
+	cd tinf && rm -rf *.o *.d
 	$(MAKE) -C decompressor all
 
 decompressor-clean:
@@ -64,6 +70,14 @@ test-clean:
 toolchain:
 	./make_toolchain.sh ./toolchain -j`nproc`
 
+gnu-efi:
+	git clone https://git.code.sf.net/p/gnu-efi/code --branch=3.0.12 --depth=1 $@
+
+ovmf:
+	mkdir -p ovmf
+	wget https://efi.akeo.ie/OVMF/OVMF-X64.zip
+	cd ovmf && 7z x OVMF-X64.zip
+
 test.hdd:
 	rm -f test.hdd
 	dd if=/dev/zero bs=1M count=0 seek=64 of=test.hdd
@@ -109,12 +123,20 @@ fat32-test: | test-clean test.hdd bootloader all
 	sudo mount `cat loopback_dev`p1 test_image
 	sudo mkdir test_image/boot
 	sudo cp -rv bin/* test/* test_image/boot/
+ifeq ($(TARGET), uefi)
+	sudo mkdir -p test_image/EFI/BOOT
+	sudo cp bin/BOOTX64.EFI test_image/EFI/BOOT/
+endif
 	sync
 	sudo umount test_image/
 	sudo losetup -d `cat loopback_dev`
 	rm -rf test_image loopback_dev
 	bin/limine-install test.hdd
+ifeq ($(TARGET), bios)
 	qemu-system-x86_64 -net none -smp 4 -enable-kvm -cpu host -hda test.hdd -debugcon stdio
+else ifeq ($(TARGET), uefi)
+	qemu-system-x86_64 -L ovmf -bios ovmf/OVMF.fd -net none -smp 4 -enable-kvm -cpu host -hda test.hdd -debugcon stdio
+endif
 
 iso9660-test: | test-clean test.hdd bootloader all
 	$(MAKE) -C test
diff --git a/make_toolchain.sh b/make_toolchain.sh
index e2345577..86dc2b9c 100755
--- a/make_toolchain.sh
+++ b/make_toolchain.sh
@@ -3,9 +3,9 @@
 set -e
 set -x
 
-TARGET=i386-elf
+TARGET="i386-elf x86_64-elf"
 BINUTILSVERSION=2.36.1
-GCCVERSION=11-20210228
+GCCVERSION=10.2.0
 NASMVERSION=2.15.05
 GZIPVERSION=1.10
 
@@ -20,7 +20,7 @@ if [ ! -f binutils-$BINUTILSVERSION.tar.gz ]; then
     wget https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILSVERSION.tar.gz
 fi
 if [ ! -f gcc-$GCCVERSION.tar.xz ]; then
-    wget https://ftp.nluug.nl/languages/gcc/snapshots/$GCCVERSION/gcc-$GCCVERSION.tar.xz
+    wget https://ftp.gnu.org/gnu/gcc/gcc-$GCCVERSION/gcc-$GCCVERSION.tar.gz
 fi
 if [ ! -f nasm-$NASMVERSION.tar.gz ]; then
     wget https://www.nasm.us/pub/nasm/releasebuilds/$NASMVERSION/nasm-$NASMVERSION.tar.gz
@@ -34,28 +34,34 @@ mkdir build
 cd build
 
 tar -xf ../binutils-$BINUTILSVERSION.tar.gz
-tar -xf ../gcc-$GCCVERSION.tar.xz
+tar -xf ../gcc-$GCCVERSION.tar.gz
 tar -xf ../nasm-$NASMVERSION.tar.gz
 tar -xf ../gzip-$GZIPVERSION.tar.gz
 
+for i in $TARGET; do
+rm -rf build-binutils
 mkdir build-binutils
 cd build-binutils
-../binutils-$BINUTILSVERSION/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror --enable-64-bit-bfd
+../binutils-$BINUTILSVERSION/configure --target=$i --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror $([ $i = "x86_64-elf" ] && echo --enable-targets=x86_64-elf,x86_64-pe) --enable-64-bit-bfd
 make
 make install
 cd ..
+done
 
 cd gcc-$GCCVERSION
 contrib/download_prerequisites
 cd ..
+for i in $TARGET; do
+rm -rf build-gcc
 mkdir build-gcc
 cd build-gcc
-../gcc-$GCCVERSION/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c --without-headers
+../gcc-$GCCVERSION/configure --target=$i --prefix="$PREFIX" --disable-nls --enable-languages=c --without-headers
 make all-gcc
 make all-target-libgcc
 make install-gcc
 make install-target-libgcc
 cd ..
+done
 
 mkdir build-nasm
 cd build-nasm
diff --git a/stage23/Makefile b/stage23/Makefile
index c753cee3..68afb6fa 100644
--- a/stage23/Makefile
+++ b/stage23/Makefile
@@ -1,8 +1,18 @@
-CC = i386-elf-gcc
-LD = i386-elf-gcc
-OBJCOPY = i386-elf-objcopy
-OBJDUMP = i386-elf-objdump
-READELF = i386-elf-readelf
+TARGET = bios
+
+ifeq ($(TARGET), bios)
+	TOOLCHAIN=i386-elf
+else ifeq ($(TARGET), uefi)
+	TOOLCHAIN=x86_64-elf
+else
+	$(error Invalid toolchain)
+endif
+
+CC = $(TOOLCHAIN)-gcc
+LD = $(TOOLCHAIN)-gcc
+OBJCOPY = $(TOOLCHAIN)-objcopy
+OBJDUMP = $(TOOLCHAIN)-objdump
+READELF = $(TOOLCHAIN)-readelf
 
 COM_OUTPUT = false
 E9_OUTPUT = false
@@ -19,6 +29,7 @@ INTERNAL_CFLAGS := \
 	-fno-stack-protector \
 	-fno-pic \
 	-fno-omit-frame-pointer \
+	-fno-lto \
 	-Wno-address-of-packed-member \
 	-masm=intel \
 	-mgeneral-regs-only \
@@ -27,27 +38,60 @@ INTERNAL_CFLAGS := \
 	-DLIMINE_VERSION='"$(LIMINE_VERSION)"' \
 	-DCOM_OUTPUT=$(COM_OUTPUT) \
 	-DE9_OUTPUT=$(E9_OUTPUT) \
+	-D$(TARGET)=1 \
 	-I. \
 	-I..
 
+ifeq ($(TARGET), uefi)
+	INTERNAL_CFLAGS += \
+		-I../gnu-efi/inc \
+		-I../gnu-efi/inc/x86_64 \
+		-fpic \
+		-fshort-wchar \
+		-mno-red-zone \
+		-mcmodel=small
+endif
+
 LDFLAGS = -Os
 
 INTERNAL_LDFLAGS := \
-	-lgcc \
-	-static-libgcc \
+	-fno-lto \
 	-nostdlib \
-	-no-pie \
-	-z max-page-size=0x1000 \
-	-static
+	-z max-page-size=0x1000
+
+ifeq ($(TARGET), bios)
+	INTERNAL_LDFLAGS += \
+		-static \
+		-no-pie \
+		-lgcc \
+		-static-libgcc
+else ifeq ($(TARGET), uefi)
+	INTERNAL_LDFLAGS += \
+		-shared \
+		-z nocombreloc \
+		-Wl,-Bsymbolic
+endif
 
 .PHONY: all clean
 
 C_FILES := $(shell find -L ./ -type f -name '*.c' | sort)
+ifeq ($(TARGET), bios)
 ASM_FILES := $(shell find -L ./ -type f -name '*.asm' | sort)
+endif
 OBJ := $(ASM_FILES:.asm=.o) $(C_FILES:.c=.o)
+ifeq ($(TARGET), uefi)
+OBJ += sys/smp_trampoline.o ../gnu-efi/lib/x86_64/efi_stub.o
+endif
 HEADER_DEPS := $(C_FILES:.c=.d)
 
+ifeq ($(TARGET), bios)
 all: limine.sys stage2.bin stage2.bin.gz
+else ifeq ($(TARGET), uefi)
+all: BOOTX64.EFI
+endif
+
+BOOTX64.EFI: limine.elf
+	$(OBJCOPY) -I elf64-x86-64 -O efi-app-x86_64 limine.elf $@
 
 stage2.bin.gz: stage2.bin
 	gzip -n -9 < stage2.bin > stage2.bin.gz
@@ -56,30 +100,43 @@ stage2.bin: limine.sys
 	dd if=limine.sys bs=$$(( 0x$$($(READELF) -S limine.elf | grep .stage3.text | sed 's/^.*] //' | awk '{print $$3}' | sed 's/^0*//') - 0x8000 )) count=1 of=$@
 
 limine.map.o: limine_nomap.elf
+ifeq ($(TARGET), bios)
 	./gensyms.sh $(OBJDUMP) limine_nomap.elf limine
+else ifeq ($(TARGET), uefi)
+	./gensyms64.sh $(OBJDUMP) limine_nomap.elf limine
+endif
 
 limine.sys: limine.elf
 	$(OBJCOPY) -O binary $< $@
 
 limine_nomap.elf: $(OBJ)
-	$(LD) $(OBJ) font.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o $@
+	$(LD) $(OBJ) font.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap_$(TARGET).ld -o $@
+ifeq ($(TARGET), bios)
 	$(LD) $(OBJ) font.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Wl,--gc-sections -Tlinker_stage2only.ld -o limine_stage2only.elf || \
 		( echo "This error means that stage 2 was trying to use stage 3 symbols before loading stage 3" && \
 		  false )
+endif
 
 font.o:
 	$(OBJCOPY) -B i8086 -I binary -O default font.bin $@
 
 limine.elf: $(OBJ) font.o limine.map.o
-	$(LD) $(OBJ) font.o limine.map.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker.ld -o $@
+	$(LD) $(OBJ) font.o limine.map.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_$(TARGET).ld -o $@
 
 -include $(HEADER_DEPS)
 
 %.o: %.c
 	$(CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
+%.o: %.S
+	$(CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
 
+ifeq ($(TARGET), bios)
 %.o: %.asm
 	nasm $< -f elf32 -o $@
+else ifeq ($(TARGET), uefi)
+%.o: %.asm
+	nasm $< -f elf64 -o $@
+endif
 
 clean:
 	rm -f limine.elf limine_nomap.elf limine_stage2only.elf font.o limine.map.o limine.sys stage2.bin stage2.bin.gz $(OBJ) $(HEADER_DEPS)
diff --git a/stage23/drivers/disk.h b/stage23/drivers/disk.h
index eade9f5f..c5a6b1fd 100644
--- a/stage23/drivers/disk.h
+++ b/stage23/drivers/disk.h
@@ -2,6 +2,7 @@
 #define __DRIVERS__DISK_H__
 
 #include <stdint.h>
+#include <lib/part.h>
 
 struct bios_drive_params {
     uint16_t buf_size;
@@ -16,5 +17,6 @@ struct bios_drive_params {
 
 int disk_get_sector_size(int drive);
 int disk_read(int drive, void *buffer, uint64_t loc, uint64_t count);
+size_t disk_create_index(struct volume **ret);
 
 #endif
diff --git a/stage23/drivers/disk.s2.c b/stage23/drivers/disk.s2.c
index 1b641449..08806c71 100644
--- a/stage23/drivers/disk.s2.c
+++ b/stage23/drivers/disk.s2.c
@@ -1,3 +1,5 @@
+#if defined(bios)
+
 #include <stdint.h>
 #include <stddef.h>
 #include <drivers/disk.h>
@@ -103,3 +105,98 @@ int disk_read(int drive, void *buffer, uint64_t loc, uint64_t count) {
 
     return 0;
 }
+
+size_t disk_create_index(struct volume **ret) {
+    struct volume *volume_index;
+    size_t volume_count = 0, volume_index_i = 0;
+
+    for (uint8_t drive = 0x80; drive; drive++) {
+        struct rm_regs r = {0};
+        struct bios_drive_params drive_params;
+
+        r.eax = 0x4800;
+        r.edx = drive;
+        r.ds  = rm_seg(&drive_params);
+        r.esi = rm_off(&drive_params);
+
+        drive_params.buf_size = sizeof(struct bios_drive_params);
+
+        rm_int(0x13, &r, &r);
+
+        if (r.eflags & EFLAGS_CF)
+            continue;
+
+        print("Found BIOS drive %x\n", drive);
+        print(" ... %X total %u-byte sectors\n",
+              drive_params.lba_count, drive_params.bytes_per_sect);
+
+        volume_count++;
+
+        struct volume block;
+
+        block.drive = drive;
+        block.sector_size = drive_params.bytes_per_sect;
+        block.first_sect = 0;
+        block.sect_count = drive_params.lba_count;
+
+        for (int part = 0; ; part++) {
+            struct volume p;
+            int ret = part_get(&p, &block, part);
+
+            if (ret == END_OF_TABLE || ret == INVALID_TABLE)
+                break;
+            if (ret == NO_PARTITION)
+                continue;
+
+            volume_count++;
+        }
+    }
+
+    volume_index = ext_mem_alloc(sizeof(struct volume) * volume_count);
+
+    for (uint8_t drive = 0x80; drive; drive++) {
+        struct rm_regs r = {0};
+        struct bios_drive_params drive_params;
+
+        r.eax = 0x4800;
+        r.edx = drive;
+        r.ds  = rm_seg(&drive_params);
+        r.esi = rm_off(&drive_params);
+
+        drive_params.buf_size = sizeof(struct bios_drive_params);
+
+        rm_int(0x13, &r, &r);
+
+        if (r.eflags & EFLAGS_CF)
+            continue;
+
+        struct volume *block = &volume_index[volume_index_i++];
+
+        block->drive = drive;
+        block->partition = -1;
+        block->sector_size = drive_params.bytes_per_sect;
+        block->first_sect = 0;
+        block->sect_count = drive_params.lba_count;
+
+        if (gpt_get_guid(&block->guid, block)) {
+            block->guid_valid = true;
+        }
+
+        for (int part = 0; ; part++) {
+            struct volume p;
+            int ret = part_get(&p, block, part);
+
+            if (ret == END_OF_TABLE || ret == INVALID_TABLE)
+                break;
+            if (ret == NO_PARTITION)
+                continue;
+
+            volume_index[volume_index_i++] = p;
+        }
+    }
+
+    *ret = volume_index;
+    return volume_count;
+}
+
+#endif
diff --git a/stage23/drivers/gop.c b/stage23/drivers/gop.c
new file mode 100644
index 00000000..1acaca9f
--- /dev/null
+++ b/stage23/drivers/gop.c
@@ -0,0 +1,19 @@
+#if defined (uefi)
+
+#include <efi.h>
+#include <lib/blib.h>
+#include <drivers/gop.h>
+
+bool init_gop(struct fb_info *ret,
+              uint16_t target_width, uint16_t target_height, uint16_t target_bpp) {
+    (void)ret; (void)target_width; (void)target_height; (void)target_bpp;
+
+    EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+    EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
+
+    uefi_call_wrapper(gBS->LocateProtocol, 3, &gop_guid, NULL, (void **)&gop);
+
+    for (;;);
+}
+
+#endif
diff --git a/stage23/drivers/gop.h b/stage23/drivers/gop.h
new file mode 100644
index 00000000..704cce2f
--- /dev/null
+++ b/stage23/drivers/gop.h
@@ -0,0 +1,16 @@
+#ifndef __DRIVERS__GOP_H__
+#define __DRIVERS__GOP_H__
+
+#if defined (uefi)
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <efi.h>
+#include <lib/fb.h>
+
+bool init_gop(struct fb_info *ret,
+              uint16_t target_width, uint16_t target_height, uint16_t target_bpp);
+
+#endif
+
+#endif
diff --git a/stage23/drivers/vbe.c b/stage23/drivers/vbe.c
index 2cb420b5..3f2519ad 100644
--- a/stage23/drivers/vbe.c
+++ b/stage23/drivers/vbe.c
@@ -1,3 +1,5 @@
+#if defined (bios)
+
 #include <stddef.h>
 #include <stdint.h>
 #include <stdbool.h>
@@ -263,3 +265,5 @@ retry:
 
     return false;
 }
+
+#endif
diff --git a/stage23/drivers/vga_textmode.s2.c b/stage23/drivers/vga_textmode.s2.c
index bd8677d1..99cad37f 100644
--- a/stage23/drivers/vga_textmode.s2.c
+++ b/stage23/drivers/vga_textmode.s2.c
@@ -1,3 +1,5 @@
+#if defined (bios)
+
 #include <stdint.h>
 #include <stddef.h>
 #include <stdbool.h>
@@ -167,3 +169,5 @@ void text_putchar(uint8_t c) {
             draw_cursor();
     }
 }
+
+#endif
diff --git a/stage23/entry.s2.c b/stage23/entry.s2.c
index 5e009207..a78ce59e 100644
--- a/stage23/entry.s2.c
+++ b/stage23/entry.s2.c
@@ -22,11 +22,14 @@
 
 extern uint64_t stage3_build_id;
 
-uint8_t boot_drive;
+drive_t boot_drive;
 int     boot_partition = -1;
 
 bool booted_from_pxe = false;
 bool booted_from_cd = false;
+
+#if defined (bios)
+
 bool stage3_loaded = false;
 
 extern symbol stage3_addr;
@@ -105,3 +108,5 @@ void entry(uint8_t _boot_drive, int boot_from) {
 
     stage3(boot_from);
 }
+
+#endif
diff --git a/stage23/entry.s3.c b/stage23/entry.s3.c
index c575b5ad..ef581180 100644
--- a/stage23/entry.s3.c
+++ b/stage23/entry.s3.c
@@ -20,6 +20,18 @@
 #include <pxe/pxe.h>
 #include <pxe/tftp.h>
 
+#if defined (uefi)
+EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
+    (void)ImageHandle;
+
+    gST = SystemTable;
+    gBS = SystemTable->BootServices;
+    gRT = SystemTable->RuntimeServices;
+
+    for (;;);
+}
+#endif
+
 __attribute__((section(".stage3_build_id")))
 uint64_t stage3_build_id = BUILD_ID;
 
diff --git a/stage23/fs/echfs.h b/stage23/fs/echfs.h
index 517e71fe..92f221c9 100644
--- a/stage23/fs/echfs.h
+++ b/stage23/fs/echfs.h
@@ -21,7 +21,6 @@ struct echfs_dir_entry {
 } __attribute__((packed));
 
 struct echfs_file_handle {
-    int disk;
     struct volume part;
     uint64_t block_size;
     uint64_t block_count;
diff --git a/stage23/fs/echfs.s2.c b/stage23/fs/echfs.s2.c
index 50df73d7..89a838de 100644
--- a/stage23/fs/echfs.s2.c
+++ b/stage23/fs/echfs.s2.c
@@ -69,7 +69,6 @@ bool echfs_get_guid(struct guid *guid, struct volume *part) {
 int echfs_open(struct echfs_file_handle *ret, struct volume *part, const char *path) {
     const char *fullpath = path;
 
-    ret->disk = part->drive;
     ret->part = *part;
 
     struct echfs_identity_table id_table;
diff --git a/stage23/fs/fat32.h b/stage23/fs/fat32.h
index a560289d..abd56adb 100644
--- a/stage23/fs/fat32.h
+++ b/stage23/fs/fat32.h
@@ -5,7 +5,6 @@
 #include <lib/part.h>
 
 struct fat32_context {
-    int drive;
     struct volume part;
     uint8_t sectors_per_cluster;
     uint16_t reserved_sectors;
diff --git a/stage23/fs/fat32.s2.c b/stage23/fs/fat32.s2.c
index cc43f8f4..a9edf310 100644
--- a/stage23/fs/fat32.s2.c
+++ b/stage23/fs/fat32.s2.c
@@ -69,7 +69,6 @@ struct fat32_lfn_entry {
 
 static int fat32_init_context(struct fat32_context* context, struct volume *part) {
     context->part  = *part;
-    context->drive = part->drive;
 
     struct fat32_bpb bpb;
     volume_read(&context->part, &bpb, 0, sizeof(struct fat32_bpb));
diff --git a/stage23/gensyms64.sh b/stage23/gensyms64.sh
new file mode 100755
index 00000000..ffad0834
--- /dev/null
+++ b/stage23/gensyms64.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+set -e
+
+TMP1=$(mktemp)
+TMP2=$(mktemp)
+TMP3=$(mktemp)
+TMP4=$(mktemp)
+
+$1 -t "$2" | sed '/\bd\b/d' | sort > "$TMP1"
+grep "\.text" < "$TMP1" | cut -d' ' -f1 > "$TMP2"
+grep "\.text" < "$TMP1" | awk 'NF{ print $NF }' > "$TMP3"
+
+echo "section .map" > "$TMP4"
+echo "global $3_map" >> "$TMP4"
+echo "$3_map:" >> "$TMP4"
+
+paste -d'$' "$TMP2" "$TMP3" | sed 's/^/dq 0x/g' | sed 's/$/", 0/g' | sed 's/\$/\ndb "/g' >> "$TMP4"
+
+echo "dq 0xffffffffffffffff" >> "$TMP4"
+
+nasm -f elf64 "$TMP4" -o $3.map.o
+
+rm "$TMP1" "$TMP2" "$TMP3" "$TMP4"
diff --git a/stage23/lib/acpi.c b/stage23/lib/acpi.c
index 15c41c6b..bd18f5a6 100644
--- a/stage23/lib/acpi.c
+++ b/stage23/lib/acpi.c
@@ -45,16 +45,16 @@ void *acpi_get_table(const char *signature, int index) {
 
     struct rsdt *rsdt;
     if (use_xsdt)
-        rsdt = (struct rsdt *)(size_t)rsdp->xsdt_addr;
+        rsdt = (struct rsdt *)(uintptr_t)rsdp->xsdt_addr;
     else
-        rsdt = (struct rsdt *)rsdp->rsdt_addr;
+        rsdt = (struct rsdt *)(uintptr_t)rsdp->rsdt_addr;
 
     for (size_t i = 0; i < rsdt->length - sizeof(struct sdt); i++) {
         struct sdt *ptr;
         if (use_xsdt)
-            ptr = (struct sdt *)(size_t)((uint64_t *)rsdt->ptrs_start)[i];
+            ptr = (struct sdt *)(uintptr_t)((uint64_t *)rsdt->ptrs_start)[i];
         else
-            ptr = (struct sdt *)((uint32_t *)rsdt->ptrs_start)[i];
+            ptr = (struct sdt *)(uintptr_t)((uint32_t *)rsdt->ptrs_start)[i];
 
         if (!memcmp(ptr->signature, signature, 4)
          && !acpi_checksum(ptr, ptr->length)
diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c
index bdd62d66..6eee5e33 100644
--- a/stage23/lib/blib.c
+++ b/stage23/lib/blib.c
@@ -8,6 +8,12 @@
 #include <lib/real.h>
 #include <fs/file.h>
 
+#if defined (uefi)
+EFI_SYSTEM_TABLE *gST;
+EFI_BOOT_SERVICES *gBS;
+EFI_RUNTIME_SERVICES *gRT;
+#endif
+
 bool parse_resolution(int *width, int *height, int *bpp, const char *buf) {
     int res[3] = {0};
 
diff --git a/stage23/lib/blib.h b/stage23/lib/blib.h
index b02c74c9..cedff14c 100644
--- a/stage23/lib/blib.h
+++ b/stage23/lib/blib.h
@@ -5,8 +5,18 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <fs/file.h>
+#include <lib/part.h>
+#if defined (uefi)
+#  include <efi.h>
+#endif
+
+#if defined (uefi)
+extern EFI_SYSTEM_TABLE *gST;
+extern EFI_BOOT_SERVICES *gBS;
+extern EFI_RUNTIME_SERVICES *gRT;
+#endif
 
-extern uint8_t boot_drive;
+extern drive_t boot_drive;
 extern int     boot_partition;
 
 extern bool booted_from_pxe;
diff --git a/stage23/lib/builtins.s2.asm b/stage23/lib/builtins.s2.asm
deleted file mode 100644
index 924cbe16..00000000
--- a/stage23/lib/builtins.s2.asm
+++ /dev/null
@@ -1,75 +0,0 @@
-section .text
-
-global memcpy
-memcpy:
-    push esi
-    push edi
-    mov eax, dword [esp+12]
-    mov edi, eax
-    mov esi, dword [esp+16]
-    mov ecx, dword [esp+20]
-    rep movsb
-    pop edi
-    pop esi
-    ret
-
-global memset
-memset:
-    push edi
-    mov edx, dword [esp+8]
-    mov edi, edx
-    mov eax, dword [esp+12]
-    mov ecx, dword [esp+16]
-    rep stosb
-    mov eax, edx
-    pop edi
-    ret
-
-global memmove
-memmove:
-    push esi
-    push edi
-    mov eax, dword [esp+12]
-    mov edi, eax
-    mov esi, dword [esp+16]
-    mov ecx, dword [esp+20]
-
-    cmp edi, esi
-    ja .copy_backwards
-
-    rep movsb
-    jmp .done
-
-  .copy_backwards:
-    lea edi, [edi+ecx-1]
-    lea esi, [esi+ecx-1]
-    std
-    rep movsb
-    cld
-
-  .done:
-    pop edi
-    pop esi
-    ret
-
-global memcmp
-memcmp:
-    push esi
-    push edi
-    mov edi, dword [esp+12]
-    mov esi, dword [esp+16]
-    mov ecx, dword [esp+20]
-    repe cmpsb
-    jecxz .equal
-    mov al, byte [edi-1]
-    sub al, byte [esi-1]
-    movsx eax, al
-    jmp .done
-
-  .equal:
-    mov eax, ecx
-
-  .done:
-    pop edi
-    pop esi
-    ret
diff --git a/stage23/lib/config.c b/stage23/lib/config.c
index c9c7fa9b..f4d1bc05 100644
--- a/stage23/lib/config.c
+++ b/stage23/lib/config.c
@@ -34,6 +34,7 @@ int init_config_disk(struct volume *part) {
     return init_config(config_size);
 }
 
+#if defined (bios)
 int init_config_pxe(void) {
     struct tftp_file_handle cfg;
     if (tftp_open(&cfg, 0, 69, "limine.cfg")
@@ -47,6 +48,7 @@ int init_config_pxe(void) {
 
     return init_config(cfg.file_size);
 }
+#endif
 
 #define NOT_CHILD      (-1)
 #define DIRECT_CHILD   0
diff --git a/stage23/lib/elf.c b/stage23/lib/elf.c
index f4c52b9c..b8b60d7d 100644
--- a/stage23/lib/elf.c
+++ b/stage23/lib/elf.c
@@ -311,16 +311,16 @@ int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top, uin
 
         memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true, true);
 
-        fread(fd, (void *)(uint32_t)load_vaddr, phdr.p_offset, phdr.p_filesz);
+        fread(fd, (void *)(uintptr_t)load_vaddr, phdr.p_offset, phdr.p_filesz);
 
         size_t to_zero = (size_t)(phdr.p_memsz - phdr.p_filesz);
 
         if (to_zero) {
-            void *ptr = (void *)(uint32_t)(load_vaddr + phdr.p_filesz);
+            void *ptr = (void *)(uintptr_t)(load_vaddr + phdr.p_filesz);
             memset(ptr, 0, to_zero);
         }
 
-        if (elf64_apply_relocations(fd, &hdr, (void *)(uint32_t)load_vaddr, phdr.p_vaddr, phdr.p_memsz, slide))
+        if (elf64_apply_relocations(fd, &hdr, (void *)(uintptr_t)load_vaddr, phdr.p_vaddr, phdr.p_memsz, slide))
             return -1;
     }
 
@@ -364,12 +364,12 @@ int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top, uin
 
         memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true, true);
 
-        fread(fd, (void *)phdr.p_paddr, phdr.p_offset, phdr.p_filesz);
+        fread(fd, (void *)(uintptr_t)phdr.p_paddr, phdr.p_offset, phdr.p_filesz);
 
         size_t to_zero = (size_t)(phdr.p_memsz - phdr.p_filesz);
 
         if (to_zero) {
-            void *ptr = (void *)(phdr.p_paddr + phdr.p_filesz);
+            void *ptr = (void *)(uintptr_t)(phdr.p_paddr + phdr.p_filesz);
             memset(ptr, 0, to_zero);
         }
     }
diff --git a/stage23/lib/fb.c b/stage23/lib/fb.c
index 23a424b0..82ba9280 100644
--- a/stage23/lib/fb.c
+++ b/stage23/lib/fb.c
@@ -2,8 +2,13 @@
 #include <stdbool.h>
 #include <lib/fb.h>
 #include <drivers/vbe.h>
+#include <drivers/gop.h>
 
 bool fb_init(struct fb_info *ret,
              uint16_t target_width, uint16_t target_height, uint16_t target_bpp) {
+#if defined (bios)
     return init_vbe(ret, target_width, target_height, target_bpp);
+#elif defined (uefi)
+    return init_gop(ret, target_width, target_height, target_bpp);
+#endif
 }
diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c
index 2ef88ce5..c5798fae 100644
--- a/stage23/lib/gterm.c
+++ b/stage23/lib/gterm.c
@@ -363,7 +363,7 @@ bool gterm_init(int *_rows, int *_cols, uint32_t *_colours, int _margin, int _ma
      || fbinfo.blue_mask_shift  != 0)
         return false;
 
-    gterm_framebuffer = (void *)fbinfo.framebuffer_addr;
+    gterm_framebuffer = (void *)(uintptr_t)fbinfo.framebuffer_addr;
     gterm_width       = fbinfo.framebuffer_width;
     gterm_height      = fbinfo.framebuffer_height;
     gterm_bpp         = fbinfo.framebuffer_bpp;
diff --git a/stage23/lib/libc.s2.c b/stage23/lib/libc.s2.c
index 56854437..3b378523 100644
--- a/stage23/lib/libc.s2.c
+++ b/stage23/lib/libc.s2.c
@@ -19,6 +19,56 @@ int tolower(int c) {
     return c;
 }
 
+void *memcpy(void *dest, const void *src, size_t n) {
+    uint8_t *pdest = dest;
+    const uint8_t *psrc = src;
+
+    for (size_t i = 0; i < n; i++) {
+        pdest[i] = psrc[i];
+    }
+
+    return dest;
+}
+
+void *memset(void *s, int c, size_t n) {
+    uint8_t *p = s;
+
+    for (size_t i = 0; i < n; i++) {
+        p[i] = (uint8_t)c;
+    }
+
+    return s;
+}
+
+void *memmove(void *dest, const void *src, size_t n) {
+    uint8_t *pdest = dest;
+    const uint8_t *psrc = src;
+
+    if (src > dest) {
+        for (size_t i = 0; i < n; i++) {
+            pdest[i] = psrc[i];
+        }
+    } else if (src < dest) {
+        for (size_t i = n; i > 0; i--) {
+            pdest[i-1] = psrc[i-1];
+        }
+    }
+
+    return dest;
+}
+
+int memcmp(const void *s1, const void *s2, size_t n) {
+    const uint8_t *p1 = s1;
+    const uint8_t *p2 = s2;
+
+    for (size_t i = 0; i < n; i++) {
+        if (p1[i] != p2[i])
+            return p1[i] < p2[i] ? -1 : 1;
+    }
+
+    return 0;
+}
+
 char *strcpy(char *dest, const char *src) {
     size_t i;
 
diff --git a/stage23/lib/panic.s2.c b/stage23/lib/panic.s2.c
index d86b4e5f..fbb58eb3 100644
--- a/stage23/lib/panic.s2.c
+++ b/stage23/lib/panic.s2.c
@@ -17,5 +17,9 @@ __attribute__((noreturn)) void panic(const char *fmt, ...) {
     print("\n");
     print_stacktrace(NULL);
 
+#if defined (bios)
     rm_hcf();
+#elif defined (uefi)
+    for (;;) asm ("hlt");
+#endif
 }
diff --git a/stage23/lib/part.h b/stage23/lib/part.h
index 38dfbc7f..9243f51b 100644
--- a/stage23/lib/part.h
+++ b/stage23/lib/part.h
@@ -4,13 +4,22 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <lib/guid.h>
+#if defined (uefi)
+#  include <efi.h>
+#endif
 
 #define NO_PARTITION  (-1)
 #define INVALID_TABLE (-2)
 #define END_OF_TABLE  (-3)
 
+#if defined (bios)
+typedef int drive_t;
+#elif defined (uefi)
+typedef EFI_HANDLE drive_t;
+#endif
+
 struct volume {
-    int drive;
+    drive_t drive;
     int partition;
     int sector_size;
     uint64_t first_sect;
@@ -23,9 +32,11 @@ struct volume {
 
 void volume_create_index(void);
 
+bool gpt_get_guid(struct guid *guid, struct volume *volume);
+
 int part_get(struct volume *part, struct volume *volume, int partition);
 bool volume_get_by_guid(struct volume *part, struct guid *guid);
-bool volume_get_by_coord(struct volume *part, int drive, int partition);
+bool volume_get_by_coord(struct volume *part, drive_t drive, int partition);
 
 int volume_read(struct volume *part, void *buffer, uint64_t loc, uint64_t count);
 
diff --git a/stage23/lib/part.s2.c b/stage23/lib/part.s2.c
index 4ef76441..17af8d3e 100644
--- a/stage23/lib/part.s2.c
+++ b/stage23/lib/part.s2.c
@@ -1,14 +1,26 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <lib/part.h>
-#include <drivers/disk.h>
+#if defined (bios)
+#  include <drivers/disk.h>
+#include <lib/real.h>
+#endif
 #include <lib/libc.h>
 #include <lib/blib.h>
-#include <lib/real.h>
 #include <lib/print.h>
 #include <mm/pmm.h>
 #include <fs/file.h>
 
+size_t volume_get_sector_size(struct volume *volume) {
+#if defined (bios)
+    return disk_get_sector_size(volume->drive);
+#elif defined (uefi)
+    (void)volume;
+    return -1;
+#endif
+
+}
+
 struct gpt_table_header {
     // the head
     char     signature[8];
@@ -46,10 +58,10 @@ struct gpt_entry {
     uint16_t partition_name[36];
 } __attribute__((packed));
 
-static bool gpt_get_guid(struct guid *guid, struct volume *volume) {
+bool gpt_get_guid(struct guid *guid, struct volume *volume) {
     struct gpt_table_header header = {0};
 
-    int sector_size = disk_get_sector_size(volume->drive);
+    int sector_size = volume_get_sector_size(volume);
 
     // read header, located after the first block
     volume_read(volume, &header, sector_size * 1, sizeof(header));
@@ -69,7 +81,7 @@ static bool gpt_get_guid(struct guid *guid, struct volume *volume) {
 static int gpt_get_part(struct volume *ret, struct volume *volume, int partition) {
     struct gpt_table_header header = {0};
 
-    int sector_size = disk_get_sector_size(volume->drive);
+    int sector_size = volume_get_sector_size(volume);
 
     // read header, located after the first block
     volume_read(volume, &header, sector_size * 1, sizeof(header));
@@ -155,7 +167,7 @@ static int mbr_get_logical_part(struct volume *ret, struct volume *extended_part
 
     ret->drive       = extended_part->drive;
     ret->partition   = partition + 4;
-    ret->sector_size = disk_get_sector_size(extended_part->drive);
+    ret->sector_size = volume_get_sector_size(extended_part);
     ret->first_sect  = extended_part->first_sect + ebr_sector + entry.first_sect;
     ret->sect_count  = entry.sect_count;
 
@@ -174,7 +186,7 @@ static int mbr_get_logical_part(struct volume *ret, struct volume *extended_part
 
 static int mbr_get_part(struct volume *ret, struct volume *volume, int partition) {
     // Check if actually valid mbr
-    uint16_t hint;
+    uint16_t hint = 0;
     volume_read(volume, &hint, 444, sizeof(uint16_t));
     if (hint && hint != 0x5a5a)
         return INVALID_TABLE;
@@ -196,7 +208,7 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
 
             extended_part.drive       = volume->drive;
             extended_part.partition   = i;
-            extended_part.sector_size = disk_get_sector_size(volume->drive);
+            extended_part.sector_size = volume_get_sector_size(volume);
             extended_part.first_sect  = entry.first_sect;
             extended_part.sect_count  = entry.sect_count;
 
@@ -217,7 +229,7 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
 
     ret->drive       = volume->drive;
     ret->partition   = partition;
-    ret->sector_size = disk_get_sector_size(volume->drive);
+    ret->sector_size = volume_get_sector_size(volume);
     ret->first_sect  = entry.first_sect;
     ret->sect_count  = entry.sect_count;
 
@@ -252,92 +264,11 @@ static struct volume *volume_index = NULL;
 static size_t volume_index_i = 0;
 
 void volume_create_index(void) {
-    size_t volume_count = 0;
-
-    for (uint8_t drive = 0x80; drive; drive++) {
-        struct rm_regs r = {0};
-        struct bios_drive_params drive_params;
-
-        r.eax = 0x4800;
-        r.edx = drive;
-        r.ds  = rm_seg(&drive_params);
-        r.esi = rm_off(&drive_params);
-
-        drive_params.buf_size = sizeof(struct bios_drive_params);
-
-        rm_int(0x13, &r, &r);
+#if defined (bios)
+    volume_index_i = disk_create_index(&volume_index);
+#elif defined (uefi)
 
-        if (r.eflags & EFLAGS_CF)
-            continue;
-
-        print("Found BIOS drive %x\n", drive);
-        print(" ... %X total %u-byte sectors\n",
-              drive_params.lba_count, drive_params.bytes_per_sect);
-
-        volume_count++;
-
-        struct volume block;
-
-        block.drive = drive;
-        block.sector_size = drive_params.bytes_per_sect;
-        block.first_sect = 0;
-        block.sect_count = drive_params.lba_count;
-
-        for (int part = 0; ; part++) {
-            struct volume p;
-            int ret = part_get(&p, &block, part);
-
-            if (ret == END_OF_TABLE || ret == INVALID_TABLE)
-                break;
-            if (ret == NO_PARTITION)
-                continue;
-
-            volume_count++;
-        }
-    }
-
-    volume_index = ext_mem_alloc(sizeof(struct volume) * volume_count);
-
-    for (uint8_t drive = 0x80; drive; drive++) {
-        struct rm_regs r = {0};
-        struct bios_drive_params drive_params;
-
-        r.eax = 0x4800;
-        r.edx = drive;
-        r.ds  = rm_seg(&drive_params);
-        r.esi = rm_off(&drive_params);
-
-        drive_params.buf_size = sizeof(struct bios_drive_params);
-
-        rm_int(0x13, &r, &r);
-
-        if (r.eflags & EFLAGS_CF)
-            continue;
-
-        struct volume *block = &volume_index[volume_index_i++];
-
-        block->drive = drive;
-        block->partition = -1;
-        block->sector_size = drive_params.bytes_per_sect;
-        block->first_sect = 0;
-        block->sect_count = drive_params.lba_count;
-
-        if (gpt_get_guid(&block->guid, block)) {
-            block->guid_valid = true;
-        }
-
-        for (int part = 0; ; part++) {
-            struct volume p;
-            int ret = part_get(&p, block, part);
-
-            if (ret == END_OF_TABLE || ret == INVALID_TABLE)
-                break;
-            if (ret == NO_PARTITION)
-                continue;
-
-            volume_index[volume_index_i++] = p;
-        }
-    }
+#endif
 }
 
 bool volume_get_by_guid(struct volume *part, struct guid *guid) {
@@ -358,7 +289,7 @@ found:
     return true;
 }
 
-bool volume_get_by_coord(struct volume *part, int drive, int partition) {
+bool volume_get_by_coord(struct volume *part, drive_t drive, int partition) {
     size_t i;
     for (i = 0; i < volume_index_i; i++) {
         if (volume_index[i].drive == drive
@@ -373,6 +304,11 @@ found:
 }
 
 int volume_read(struct volume *part, void *buffer, uint64_t loc, uint64_t count) {
+#if defined (bios)
     return disk_read(part->drive, buffer,
                      loc + (part->first_sect * part->sector_size), count);
+#elif defined (uefi)
+    (void)part; (void)buffer; (void)loc; (void)count;
+    return -1;
+#endif
 }
diff --git a/stage23/lib/readline.c b/stage23/lib/readline.c
index 42713d90..8b7b5a6d 100644
--- a/stage23/lib/readline.c
+++ b/stage23/lib/readline.c
@@ -4,10 +4,14 @@
 #include <lib/libc.h>
 #include <lib/blib.h>
 #include <lib/term.h>
-#include <lib/real.h>
+#if defined (bios)
+#  include <lib/real.h>
+#elif defined (uefi)
+#  include <efi.h>
+#endif
 
-int getchar_internal(uint32_t eax) {
-    switch ((eax >> 8) & 0xff) {
+int getchar_internal(uint8_t scancode, uint8_t ascii) {
+    switch (scancode) {
         case 0x44:
             return GETCHAR_F10;
         case 0x4b:
@@ -29,19 +33,33 @@ int getchar_internal(uint32_t eax) {
         case 0x51:
             return GETCHAR_PGDOWN;
     }
-    char c = eax & 0xff;
-    switch (c) {
+    switch (ascii) {
         case '\r':
             return '\n';
     }
-    return c;
+    return ascii;
 }
 
+#if defined (bios)
 int getchar(void) {
     struct rm_regs r = {0};
     rm_int(0x16, &r, &r);
-    return getchar_internal(r.eax);
+    return getchar_internal((r.eax >> 8) & 0xff, r.eax);
 }
+#endif
+
+#if defined (uefi)
+int getchar(void) {
+    EFI_INPUT_KEY key = {0};
+    uefi_call_wrapper(gST->ConIn->ReadKeyStroke, 2, gST->ConIn, &key);
+    return getchar_internal(key.ScanCode, key.UnicodeChar);
+}
+
+int pit_sleep_and_quit_on_keypress(uint32_t pit_ticks) {
+    (void)pit_ticks;
+    return getchar();
+}
+#endif
 
 static void reprint_string(int x, int y, const char *s) {
     int orig_x, orig_y;
diff --git a/stage23/lib/term.c b/stage23/lib/term.c
index 441c924b..dbe0d832 100644
--- a/stage23/lib/term.c
+++ b/stage23/lib/term.c
@@ -10,8 +10,10 @@ void term_vbe(uint32_t *colours, int margin, int margin_gradient, struct image *
     term_deinit();
 
     if (!gterm_init(&term_rows, &term_cols, colours, margin, margin_gradient, background)) {
+#if defined (bios)
         // Failed to set VBE properly, default to text mode
         term_textmode();
+#endif
         return;
     }
 
diff --git a/stage23/lib/term.s2.c b/stage23/lib/term.s2.c
index 2058deba..469fafe0 100644
--- a/stage23/lib/term.s2.c
+++ b/stage23/lib/term.s2.c
@@ -23,6 +23,7 @@ void (*term_double_buffer_flush)(void);
 
 int term_rows, term_cols;
 
+#if defined (bios)
 void term_textmode(void) {
     term_deinit();
     init_vga_textmode(&term_rows, &term_cols);
@@ -41,11 +42,14 @@ void term_textmode(void) {
 
     term_backend = TEXTMODE;
 }
+#endif
 
 void term_deinit(void) {
+#if defined (bios)
     struct rm_regs r = {0};
     r.eax = 0x0003;
     rm_int(0x10, &r, &r);
+#endif
 
     term_backend = NOT_READY;
 }
diff --git a/stage23/lib/time.c b/stage23/lib/time.c
index 7120dc95..1660c635 100644
--- a/stage23/lib/time.c
+++ b/stage23/lib/time.c
@@ -1,7 +1,11 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <lib/time.h>
-#include <lib/real.h>
+#if defined (bios)
+#  include <lib/real.h>
+#elif defined (uefi)
+#  include <efi.h>
+#endif
 #include <lib/blib.h>
 
 // Julian date calculation from https://en.wikipedia.org/wiki/Julian_day
@@ -22,6 +26,7 @@ static uint64_t get_unix_epoch(uint8_t seconds, uint8_t minutes, uint8_t  hours,
     return (jdn_diff * (60 * 60 * 24)) + hours * 3600 + minutes * 60 + seconds;
 }
 
+#if defined (bios)
 uint64_t time(void) {
     struct rm_regs r = {0};
 
@@ -42,3 +47,14 @@ uint64_t time(void) {
 
     return get_unix_epoch(second, minute, hour, day, month, year);
 }
+#endif
+
+#if defined (uefi)
+uint64_t time(void) {
+    EFI_TIME time;
+    uefi_call_wrapper(gRT->GetTime, 2, &time, NULL);
+
+    return get_unix_epoch(time.Second, time.Minute, time.Hour,
+                          time.Day, time.Month, time.Year);
+}
+#endif
diff --git a/stage23/lib/trace.s2.c b/stage23/lib/trace.s2.c
index 2c502949..c4bf7183 100644
--- a/stage23/lib/trace.s2.c
+++ b/stage23/lib/trace.s2.c
@@ -11,33 +11,41 @@
 extern symbol limine_map;
 
 char *trace_address(size_t *off, size_t addr) {
+#if defined (bios)
     if (!stage3_loaded)
         return NULL;
+#endif
 
-    uint32_t prev_addr = 0;
-    char    *prev_sym  = NULL;
+    uintptr_t prev_addr = 0;
+    char     *prev_sym  = NULL;
 
     for (size_t i = 0;;) {
-        if (*((uint32_t *)&limine_map[i]) >= addr) {
+        if (*((uintptr_t *)&limine_map[i]) >= addr) {
             *off = addr - prev_addr;
             return prev_sym;
         }
-        prev_addr = *((uint32_t *)&limine_map[i]);
-        i += sizeof(uint32_t);
+        prev_addr = *((uintptr_t *)&limine_map[i]);
+        i += sizeof(uintptr_t);
         prev_sym  = &limine_map[i];
         while (limine_map[i++] != 0);
     }
 }
 
 void print_stacktrace(size_t *base_ptr) {
+#if defined (bios)
     if (!stage3_loaded) {
         print("trace: Stack trace omitted because stage 3 was not loaded yet.\n");
         return;
     }
+#endif
 
     if (base_ptr == NULL) {
         asm volatile (
+#if defined (bios)
             "mov %0, ebp"
+#elif defined (uefi)
+            "mov %0, rbp"
+#endif
             : "=g"(base_ptr)
             :: "memory"
         );
diff --git a/stage23/lib/uri.c b/stage23/lib/uri.c
index 883dc09e..d355556b 100644
--- a/stage23/lib/uri.c
+++ b/stage23/lib/uri.c
@@ -54,6 +54,7 @@ bool uri_resolve(char *uri, char **resource, char **root, char **path) {
     return true;
 }
 
+#if defined (bios)
 // BIOS partitions are specified in the <BIOS drive>:<partition> form.
 // The drive may be omitted, the partition cannot.
 static bool parse_bios_partition(char *loc, uint8_t *drive, uint8_t *partition) {
@@ -106,6 +107,7 @@ static bool uri_bios_dispatch(struct file_handle *fd, char *loc, char *path) {
 
     return true;
 }
+#endif
 
 static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path) {
     struct guid guid;
@@ -127,6 +129,7 @@ static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path
     return true;
 }
 
+#if defined (bios)
 static bool uri_tftp_dispatch(struct file_handle *fd, char *root, char *path) {
     uint32_t ip;
     if (!strcmp(root, "")) {
@@ -149,10 +152,13 @@ static bool uri_tftp_dispatch(struct file_handle *fd, char *root, char *path) {
     fd->size = cfg->file_size;
     return true;
 }
+#endif
 
 static bool uri_boot_dispatch(struct file_handle *fd, char *s_part, char *path) {
+#if defined (bios)
     if (booted_from_pxe)
         return uri_tftp_dispatch(fd, s_part, path);
+#endif
 
     int partition;
 
@@ -194,16 +200,21 @@ bool uri_open(struct file_handle *fd, char *uri) {
         resource++;
     }
 
-    if (!strcmp(resource, "bios")) {
+    if (0) {
+#if defined (bios)
+    } else if (!strcmp(resource, "bios")) {
         ret = uri_bios_dispatch(fd, root, path);
+#endif
     } else if (!strcmp(resource, "boot")) {
         ret = uri_boot_dispatch(fd, root, path);
     } else if (!strcmp(resource, "guid")) {
         ret = uri_guid_dispatch(fd, root, path);
     } else if (!strcmp(resource, "uuid")) {
         ret = uri_guid_dispatch(fd, root, path);
+#if defined (bios)
     } else if (!strcmp(resource, "tftp")) {
         ret = uri_tftp_dispatch(fd, root, path);
+#endif
     } else {
         panic("Resource `%s` not valid.", resource);
     }
diff --git a/stage23/linker.ld b/stage23/linker_bios.ld
similarity index 100%
rename from stage23/linker.ld
rename to stage23/linker_bios.ld
diff --git a/stage23/linker_nomap.ld b/stage23/linker_nomap_bios.ld
similarity index 100%
rename from stage23/linker_nomap.ld
rename to stage23/linker_nomap_bios.ld
diff --git a/stage23/linker_nomap_uefi.ld b/stage23/linker_nomap_uefi.ld
new file mode 100644
index 00000000..16e400d2
--- /dev/null
+++ b/stage23/linker_nomap_uefi.ld
@@ -0,0 +1,33 @@
+OUTPUT_FORMAT(elf64-x86-64)
+ENTRY(efi_main)
+
+SECTIONS
+{
+    . = 4K;
+
+    .text : {
+        *(.text*)
+    }
+
+    .data : {
+        *(.realmode*)
+        *(.data*)
+    }
+
+    .rodata : {
+        *(.rodata*)
+    }
+
+    .map : {
+        limine_map = .;
+    }
+
+    .bss : {
+        *(COMMON)
+        *(.bss*)
+    }
+
+    /DISCARD/ : {
+        *(*)
+    }
+}
diff --git a/stage23/linker_uefi.ld b/stage23/linker_uefi.ld
new file mode 100644
index 00000000..283366d4
--- /dev/null
+++ b/stage23/linker_uefi.ld
@@ -0,0 +1,33 @@
+OUTPUT_FORMAT(elf64-x86-64)
+ENTRY(efi_main)
+
+SECTIONS
+{
+    . = 4K;
+
+    .text : {
+        *(.text*)
+    }
+
+    .data : {
+        *(.realmode*)
+        *(.data*)
+    }
+
+    .rodata : {
+        *(.rodata*)
+    }
+
+    .map : {
+        *(.map*)
+    }
+
+    .bss : {
+        *(COMMON)
+        *(.bss*)
+    }
+
+    /DISCARD/ : {
+        *(*)
+    }
+}
diff --git a/stage23/mm/mtrr.c b/stage23/mm/mtrr.c
index 34efbea4..4c900f20 100644
--- a/stage23/mm/mtrr.c
+++ b/stage23/mm/mtrr.c
@@ -118,7 +118,7 @@ void mtrr_save(void) {
     uint8_t var_reg_count = ia32_mtrrcap & 0xff;
 
     if (!saved_mtrr)
-        saved_mtrr = conv_mem_alloc(var_reg_count * sizeof(struct mtrr));
+        saved_mtrr = ext_mem_alloc(var_reg_count * sizeof(struct mtrr));
 
     for (uint8_t i = 0; i < var_reg_count; i++) {
         saved_mtrr[i].base = rdmsr(0x200 + i * 2);
diff --git a/stage23/mm/pmm.s2.c b/stage23/mm/pmm.s2.c
index 0cbda451..4baa5414 100644
--- a/stage23/mm/pmm.s2.c
+++ b/stage23/mm/pmm.s2.c
@@ -6,6 +6,9 @@
 #include <lib/blib.h>
 #include <lib/libc.h>
 #include <lib/print.h>
+#if defined (uefi)
+#  include <efi.h>
+#endif
 
 #define PAGE_SIZE   4096
 #define MEMMAP_BASE ((size_t)0x100000)
@@ -183,6 +186,7 @@ struct e820_entry_t *get_memmap(size_t *entries) {
     return memmap;
 }
 
+#if defined (bios)
 void init_memmap(void) {
     for (size_t i = 0; i < e820_entries; i++) {
         if (memmap_entries == MEMMAP_MAX_ENTRIES) {
@@ -196,6 +200,7 @@ void init_memmap(void) {
 
     allocations_disallowed = false;
 }
+#endif
 
 void *ext_mem_alloc(size_t count) {
     return ext_mem_alloc_type(count, MEMMAP_BOOTLOADER_RECLAIMABLE);
@@ -209,6 +214,7 @@ void *ext_mem_alloc_type(size_t count, uint32_t type) {
     return ext_mem_alloc_aligned_type(count, 4, type);
 }
 
+#if defined (bios)
 // Allocate memory top down, hopefully without bumping into kernel or modules
 void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type) {
     if (allocations_disallowed)
@@ -251,6 +257,24 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
 
     panic("High memory allocator: Out of memory");
 }
+#endif
+
+#if defined (uefi)
+void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type) {
+    (void)type;
+
+    void *ret;
+
+    if (alignment && alignment % 4096 == 0) {
+        uefi_call_wrapper(gBS->AllocatePages, 4, 0, 2, DIV_ROUNDUP(count, 4096),
+                          &ret);
+    } else {
+        uefi_call_wrapper(gBS->AllocatePool, 3, 4, count, &ret);
+    }
+
+    return ret;
+}
+#endif
 
 bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool do_panic) {
     uint64_t top = base + length;
@@ -317,6 +341,7 @@ bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free
     return false;
 }
 
+#if defined (bios)
 extern symbol bss_end;
 static size_t bump_allocator_base = (size_t)bss_end;
 static size_t bump_allocator_limit = 0x70000;
@@ -338,3 +363,4 @@ void *conv_mem_alloc_aligned(size_t count, size_t alignment) {
 
     return ret;
 }
+#endif
diff --git a/stage23/protos/chainload.c b/stage23/protos/chainload.c
index 8bcc66eb..73092258 100644
--- a/stage23/protos/chainload.c
+++ b/stage23/protos/chainload.c
@@ -1,3 +1,5 @@
+#if defined (bios)
+
 #include <stddef.h>
 #include <stdint.h>
 #include <protos/chainload.h>
@@ -84,3 +86,5 @@ void chainload(char *config) {
 
     spinup(drive);
 }
+
+#endif
diff --git a/stage23/protos/linux.c b/stage23/protos/linux.c
index 86cafdbe..5803942e 100644
--- a/stage23/protos/linux.c
+++ b/stage23/protos/linux.c
@@ -1,3 +1,5 @@
+#if defined (bios)
+
 #include <stdint.h>
 #include <stddef.h>
 #include <protos/linux.h>
@@ -194,3 +196,5 @@ void linux_load(char *config, char *cmdline) {
 
     spinup(real_mode_code_seg, kernel_entry_seg, real_mode_and_heap_size);
 }
+
+#endif
diff --git a/stage23/protos/stivale.c b/stage23/protos/stivale.c
index a596f0bc..42a8db34 100644
--- a/stage23/protos/stivale.c
+++ b/stage23/protos/stivale.c
@@ -249,6 +249,7 @@ __attribute__((noreturn)) void stivale_spinup(
                  uint64_t entry_point, void *stivale_struct, uint64_t stack) {
     mtrr_restore();
 
+#if defined (bios)
     if (bits == 64) {
         // If we're going 64, we might as well call this BIOS interrupt
         // to tell the BIOS that we are entering Long Mode, since it is in
@@ -258,10 +259,12 @@ __attribute__((noreturn)) void stivale_spinup(
         r.ebx = 0x02;   // Long mode only
         rm_int(0x15, &r, &r);
     }
+#endif
 
     pic_mask_all();
     pic_flush();
 
+#if defined (bios)
     if (bits == 64) {
         if (level5pg) {
             // Enable CR4.LA57
@@ -367,5 +370,11 @@ __attribute__((noreturn)) void stivale_spinup(
             : "memory"
         );
     }
+#elif defined (uefi)
+    (void)bits; (void)level5pg; (void)pagemap; (void)entry_point;
+    (void)stivale_struct; (void)stack;
+
+#endif
+
     for (;;);
 }
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index a2129035..ed0e0be7 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -327,6 +327,7 @@ void stivale2_load(char *config, char *cmdline, bool pxe) {
     }
     }
 
+#if defined (bios)
     //////////////////////////////////////////////
     // Create PXE struct tag
     //////////////////////////////////////////////
@@ -336,7 +337,11 @@ void stivale2_load(char *config, char *cmdline, bool pxe) {
         tag->server_ip = get_boot_server_info();
         append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
     }
+#else
+    (void)pxe;
+#endif
 
+#if defined (bios)
     //////////////////////////////////////////////
     // Create memmap struct tag
     //////////////////////////////////////////////
@@ -356,6 +361,7 @@ void stivale2_load(char *config, char *cmdline, bool pxe) {
 
     append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
     }
+#endif
 
     //////////////////////////////////////////////
     // List tags
diff --git a/stage23/pxe/pxe.c b/stage23/pxe/pxe.c
index e3b5051e..60070f48 100644
--- a/stage23/pxe/pxe.c
+++ b/stage23/pxe/pxe.c
@@ -1,3 +1,5 @@
+#if defined (bios)
+
 #include <lib/print.h>
 #include <lib/real.h>
 #include <pxe/pxe.h>
@@ -41,3 +43,5 @@ void pxe_init(void) {
     set_pxe_fp(bangpxe->rm_entry);
     print("Successfully initialized pxe");
 }
+
+#endif
diff --git a/stage23/pxe/tftp.c b/stage23/pxe/tftp.c
index 51693506..aab56e94 100644
--- a/stage23/pxe/tftp.c
+++ b/stage23/pxe/tftp.c
@@ -1,3 +1,5 @@
+#if defined (bios)
+
 #include <pxe/tftp.h>
 #include <pxe/pxe.h>
 #include <lib/real.h>
@@ -23,13 +25,13 @@ int tftp_open(struct tftp_file_handle *handle, uint32_t server_ip, uint16_t serv
         struct bootph *ph = (struct bootph*)(void *) (((((uint32_t)cachedinfo.buffer) >> 16) << 4) + (((uint32_t)cachedinfo.buffer) & 0xFFFF));
         server_ip = ph->sip;
     }
-  
+
     struct PXENV_UNDI_GET_INFORMATION undi_info = { 0 };
     ret = pxe_call(UNDI_GET_INFORMATION, ((uint16_t)rm_seg(&undi_info)), (uint16_t)rm_off(&undi_info));
     if (ret) {
         return -1;
     }
-   
+
     //TODO figure out a more proper way to do this.
     uint16_t mtu = undi_info.MaxTranUnit - 48;
 
@@ -106,3 +108,5 @@ int tftp_read(void* fd, void *buf, uint64_t loc, uint64_t count) {
     memcpy(buf, handle->data + loc, count);
     return 0;
 }
+
+#endif
diff --git a/stage23/sys/a20.s2.c b/stage23/sys/a20.s2.c
index 571f7d6c..e3e1f8c2 100644
--- a/stage23/sys/a20.s2.c
+++ b/stage23/sys/a20.s2.c
@@ -1,3 +1,5 @@
+#if defined (bios)
+
 #include <stdint.h>
 #include <stddef.h>
 #include <stdbool.h>
@@ -52,3 +54,5 @@ bool a20_enable(void) {
 
     return false;
 }
+
+#endif
diff --git a/stage23/sys/e820.s2.c b/stage23/sys/e820.s2.c
index c275be26..3fe10629 100644
--- a/stage23/sys/e820.s2.c
+++ b/stage23/sys/e820.s2.c
@@ -1,3 +1,5 @@
+#if defined (bios)
+
 #include <stdint.h>
 #include <stddef.h>
 #include <sys/e820.h>
@@ -43,3 +45,5 @@ load_up:
     e820_map = conv_mem_alloc(sizeof(struct e820_entry_t) * e820_entries);
     goto load_up;
 }
+
+#endif
diff --git a/stage23/sys/smp.c b/stage23/sys/smp.c
index 6b5d166f..322cc719 100644
--- a/stage23/sys/smp.c
+++ b/stage23/sys/smp.c
@@ -207,7 +207,7 @@ struct smp_information *init_smp(size_t    header_hack_size,
 
                 // Try to start the AP
                 if (!smp_start_ap(lapic->lapic_id, &gdtr, info_struct,
-                                  longmode, lv5, (uint32_t)pagemap.top_level,
+                                  longmode, lv5, (uintptr_t)pagemap.top_level,
                                   x2apic)) {
                     print("smp: FAILED to bring-up AP\n");
                     continue;
@@ -244,7 +244,7 @@ struct smp_information *init_smp(size_t    header_hack_size,
 
                 // Try to start the AP
                 if (!smp_start_ap(x2apic->x2apic_id, &gdtr, info_struct,
-                                  longmode, lv5, (uint32_t)pagemap.top_level,
+                                  longmode, lv5, (uintptr_t)pagemap.top_level,
                                   true)) {
                     print("smp: FAILED to bring-up AP\n");
                     continue;
tab: 248 wrap: offon