commit 5ccc01e7a53e1ba2c68b8f02a72696d6bdedbd45
Author: Mikołaj Lenczewski <mblenczewski@gmail.com>
Date: Thu, 27 Jun 2024 21:21:57 +0000
Initial commit
Diffstat:
22 files changed, 1740 insertions(+), 0 deletions(-)
diff --git a/.editorconfig b/.editorconfig
@@ -0,0 +1,21 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+
+guidelines = 80, 120, 160
+
+[*.{c,h,s}]
+indent_style = tab
+indent_size = 8
+
+[*.{sh}]
+indent_style = tab
+indent_size = 8
+
+[*.{md,txt}]
+indent_style = space
+indent_size = 2
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,7 @@
+bin/
+obj/
+mnt/
+
+serial.log
+
+**/.*.swp
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,18 @@
+The MIT-Zero License
+
+Copyright (c) 2023 Mikołaj Lenczewski <mblenczewski@gmail.com>
+
+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.
+
+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.
diff --git a/README b/README
@@ -0,0 +1,2 @@
+ekern
+==============================================================================
diff --git a/build.sh b/build.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+. "$(dirname $0)/toolchain.sh"
+
+BIN="$ROOT/bin"
+OBJ="$ROOT/obj"
+MNT="$ROOT/mnt/$ARCH"
+
+set -ex
+
+mkdir -p $BIN $OBJ $MNT
+
+# build eboot (bin/eboot-$ARCH.efi)
+
+clang -o $OBJ/boot-$ARCH.o -c $ROOT/src/boot.c \
+ --target=x86_64-unknown-windows -ffreestanding -mno-red-zone $CPPFLAGS
+
+clang -o $BIN/boot-$ARCH.efi $OBJ/boot-$ARCH.o \
+ --target=x86_64-unknown-windows -nostdlib -Wl,-subsystem:efi_application -Wl,-entry:efi_main -fuse-ld=lld-link
+
+# build ekern (bin/ekern-$ARCH.sys)
+
+$CC -o $OBJ/start.o -c $ROOT/src/kernel.c $CFLAGS $CPPFLAGS
+$CC -o $OBJ/kernel-$ARCH.o -c $ROOT/src/kernel-$ARCH.c $CFLAGS $CPPFLAGS
+$LD -o $BIN/kernel-$ARCH.elf -T $ROOT/src/kernel.ld $OBJ/start.o $OBJ/kernel-$ARCH.o
+$OBJCOPY -O binary $BIN/kernel-$ARCH.elf $BIN/kernel-$ARCH.sys
+
+# build UEFI image (bin/uefi.sys)
+
+cat $BIN/boot-$ARCH.efi > $BIN/uefi.sys
+# cat $BIN/boot-$ARCH.efi $BIN/kernel-$ARCH.sys > $BIN/uefi.sys
+
+# build euser (mnt/$ARCH/* and bin/euser-$ARCH.img)
+
+dd if=/dev/zero of=$BIN/euser-$ARCH.img bs=1048576 count=64 >/dev/null 2>&1
+
+for program in $USERLAND; do
+ (
+ set +x
+ BIN="$(realpath "$BIN")";
+ OBJ="$(realpath "$OBJ")";
+ MNT="$(realpath "$MNT")";
+ set -x
+ cd "$ROOT/euser/$program";
+ . "./build.sh"
+ )
+done
+
+# create bootable disk image (bin/disk.img)
+# ---
+# see: https://wiki.osdev.org/Bootable_Disk
+
+dd if=/dev/zero of=$BIN/disk.img bs=1M count=64 >/dev/null 2>&1
+
+cat <<'EOF' | sfdisk $BIN/disk.img
+label: gpt
+unit: sectors
+
+type=U, start=2048, size=2048, bootable
+type=L, start=4096
+EOF
+
+## format efi partition
+dd if=/dev/zero of=$BIN/esp.img bs=512 count=2048 >/dev/null 2>&1
+
+mformat -i $BIN/esp.img
+mmd -i $BIN/esp.img ::/EFI ::/EFI/BOOT
+mcopy -i $BIN/esp.img $BIN/uefi.sys ::/EFI/BOOT/BOOT$UEFIARCH.EFI
+
+dd if=$BIN/esp.img of=$BIN/disk.img bs=512 seek=2048 count=2048 conv=notrunc >/dev/null 2>&1
+
+## format data partition
+## TODO: format remaining data partition instead of writing raw bytes
+dd if=$BIN/euser-$ARCH.img of=$BIN/disk.img bs=512 seek=4096 conv=notrunc >/dev/null 2>&1
+
+# run qemu emulator
+
+"$ROOT/scripts/qemu-$ARCH.sh" $ROOT/bin/disk.img
diff --git a/clean.sh b/clean.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+. "$(dirname $0)/config.sh"
+
+set -ex
+
+rm -rf bin obj mnt
diff --git a/config.sh b/config.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+ROOT="$(dirname $0)"
+
+# target architecture, one of: amd64 aarch64 riscv64
+ARCH=amd64
+
+# uefi architecture, corresponds to target arch: X64
+UEFIARCH=X64
+
+# userland programs to compile, any under euser/
+#USERLAND="$USERLAND asm-example"
+#USERLAND="$USERLAND c-example"
+#USERLAND="$USERLAND cpp-example"
diff --git a/docs/acpi-6.5.pdf b/docs/acpi-6.5.pdf
Binary files differ.
diff --git a/docs/uefi-2.10.pdf b/docs/uefi-2.10.pdf
Binary files differ.
diff --git a/euser/asm-example/build.sh b/euser/asm-example/build.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+SOURCE=""
+case $ARCH in
+ amd64|aarch64)
+ SOURCE="example-$ARCH.asm"
+ ;;
+
+ *)
+ echo "Unsupported architecture: $ARCH"
+ exit 0
+ ;;
+esac
+
+set -ex
+
+$AS -o $MNT/asm-example.bin $SOURCE $ASMFLAGS
diff --git a/euser/c-example/build.sh b/euser/c-example/build.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -ex
+
+$CC -o $MNT/c-example.bin example.c $CFLAGS $CPPFLAGS $LDFLAGS
diff --git a/euser/c-example/example.c b/euser/c-example/example.c
diff --git a/euser/cpp-example/build.sh b/euser/cpp-example/build.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -ex
+
+$CXX -o $MNT/cpp-example.bin example.cpp $CXXFLAGS $CPPFLAGS $LDFLAGS
diff --git a/include/efi.h b/include/efi.h
@@ -0,0 +1,888 @@
+#ifndef EFI_H
+#define EFI_H
+
+/* generated from the uefi-2.10 docs */
+
+#define IN
+#define OUT
+#define OPTIONAL
+#define CONST const
+
+#define EFIAPI
+
+#include <stdalign.h>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef int8_t b8;
+
+#define true 1
+#define false 0
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+// typedef uint128_t u128;
+typedef uintmax_t umm;
+
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64;
+// typedef int128_t s128;
+typedef intmax_t smm;
+
+typedef unsigned char c8;
+typedef uint16_t c16;
+
+typedef struct efi_guid {
+ alignas(u32) u8 vs[16];
+} efi_guid_t;
+
+#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
+((struct efi_guid) {.vs = { \
+ ((a) >> 24) & 0xff, ((a) >> 16) & 0xff, ((a) >> 8) & 0xff, (a) & 0xff, \
+ ((b) >> 8) & 0xff, (b) & 0xff, \
+ ((c) >> 8) & 0xff, (c) & 0xff, \
+ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7), \
+}})
+
+typedef umm efi_status_t;
+
+#define EFI_ERROR 0x8000000000000000
+#define EFI_WARNING 0x0000000000000000
+
+#define EFIERR(err) (EFI_ERROR | (err))
+#define EFIWARN(err) (EFI_WARNING | (err))
+
+enum efi_status {
+ EFI_SUCCESS = 0,
+
+ EFI_WARN_UNKNOWN_GLYPH = EFIWARN(1),
+ EFI_WARN_DELETE_FAILURE = EFIWARN(2),
+ EFI_WARN_WRITE_FAILURE = EFIWARN(3),
+ EFI_WARN_BUFFER_TOO_SMALL = EFIWARN(4),
+ EFI_WARN_STALE_DATA = EFIWARN(5),
+ EFI_WARN_FILE_SYSTEM = EFIWARN(6),
+ EFI_WARN_RESET_REQUIRED = EFIWARN(7),
+
+ EFI_LOAD_ERROR = EFIERR(1),
+ EFI_INVALID_PARAMETER = EFIERR(2),
+ EFI_UNSUPPORTED = EFIERR(3),
+ EFI_BAD_BUFFER_SIZE = EFIERR(4),
+ EFI_BUFFER_TOO_SMALL = EFIERR(5),
+ EFI_NOT_READY = EFIERR(6),
+ EFI_DEVICE_ERROR = EFIERR(7),
+ EFI_WRITE_PROTECTED = EFIERR(8),
+ EFI_OUT_OF_RESOURCES = EFIERR(9),
+ EFI_VOLUME_CORRUPTED = EFIERR(10),
+ EFI_VOLUME_FULL = EFIERR(11),
+ EFI_NO_MEDIA = EFIERR(12),
+ EFI_MEDIA_CHANGED = EFIERR(13),
+ EFI_NOT_FOUND = EFIERR(14),
+ EFI_ACCESS_DENIED = EFIERR(15),
+ EFI_NO_RESPONSE = EFIERR(16),
+ EFI_NO_MAPPING = EFIERR(17),
+ EFI_TIMEOUT = EFIERR(18),
+ EFI_NOT_STARTED = EFIERR(19),
+ EFI_ALREADY_STARTED = EFIERR(20),
+ EFI_ABORTED = EFIERR(21),
+ EFI_ICMP_ERROR = EFIERR(22),
+ EFI_TFTP_ERROR = EFIERR(23),
+ EFI_PROTOCOL_ERROR = EFIERR(24),
+ EFI_INCOMPATIBLE_VERSION = EFIERR(25),
+ EFI_SECURITY_VIOLATION = EFIERR(26),
+ EFI_CRC_ERROR = EFIERR(27),
+ EFI_END_OF_MEDIA = EFIERR(28),
+ EFI_END_OF_FILE = EFIERR(31),
+ EFI_INVALID_LANGUAGE = EFIERR(32),
+ EFI_COMPROMISED_DATA = EFIERR(33),
+ EFI_IP_ADDRESS_CONFLICT = EFIERR(34),
+ EFI_HTTP_ERROR = EFIERR(35),
+};
+
+typedef void *efi_handle_t;
+typedef void *efi_event_t;
+typedef u64 efi_lba_t;
+typedef umm efi_tpl_t;
+
+struct efi_table_header {
+ u64 signature;
+ u32 revision;
+ u32 header_size;
+ u32 crc32;
+ u32 reserved0;
+};
+
+/* system table
+ * ---
+ * see: https://uefi.org/specs/UEFI/2.10/04_EFI_System_Table.html
+ */
+
+struct efi_system_table {
+ struct efi_table_header hdr;
+
+ c16 *firmware_vendor;
+ u32 firmware_revision;
+
+ efi_handle_t console_in_handle;
+ struct efi_simple_text_input_protocol *con_in;
+
+ efi_handle_t console_out_handle;
+ struct efi_simple_text_output_protocol *con_out;
+
+ efi_handle_t standard_error_handle;
+ struct efi_simple_text_output_protocol *std_err;
+
+ struct efi_runtime_services *runtime_services;
+ struct efi_boot_services *boot_services;
+
+ umm number_of_table_entries;
+ struct efi_configuration_table *configuration_table;
+};
+
+/* boot services
+ * ---
+ * see: https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html
+ */
+
+#define EVT_TIMER 0x80000000
+#define EVT_RUNTIME 0x40000000
+
+#define EVT_NOTIFY_WAIT 0x00000100
+#define EVT_NOTIFY_SIGNAL 0x00000200
+
+#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201
+#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202
+
+typedef umm efi_tpl_t;
+
+#define TPL_APPLICATION 4
+#define TPL_CALLBACK 8
+#define TPL_NOTIFY 16
+#define TPL_HIGH_LEVEL 31
+
+#define EFI_EVENT_NOTIFY(name) \
+ void (EFIAPI name) (IN efi_event_t event, \
+ IN void *context)
+
+typedef EFI_EVENT_NOTIFY(efi_event_notify_t);
+
+#define EFI_CREATE_EVENT(name) \
+ efi_status_t (EFIAPI name) (IN u32 type, \
+ IN efi_tpl_t notify_tpl, \
+ IN efi_event_notify_t * OPTIONAL notify_function, \
+ IN void * OPTIONAL notify_context, \
+ OUT efi_event_t *event)
+
+#define EFI_EVENT_GROUP_EXIT_BOOT_SERVICES \
+ ((efi_guid_t) {.vs = {0x27abf055, 0xb1b84c26, 0x8048748f, 0x37baa2df}})
+
+#define EFI_EVENT_GROUP_BEFORE_EXIT_BOOT_SERVICES \
+ ((efi_guid_t) {.vs = {0x8be0e274, 0x39704b44, 0x80c51ab9, 0x502f3bfc}})
+
+#define EFI_EVENT_GROUP_VIRTUAL_ADDRESS_CHANGE \
+ ((efi_guid_t) {.vs = {0x13fa7698, 0xc83149c7, 0x87ea8f43, 0xfcc25196}})
+
+#define EFI_EVENT_GROUP_MEMORY_MAP_CHANGE \
+ ((efi_guid_t) {.vs = {0x78bee926, 0x692f48fd, 0x9edb0142, 0x2ef0d7ab}})
+
+#define EFI_EVENT_GROUP_READY_TO_BOOT \
+ ((efi_guid_t) {.vs = {0x7ce88fb3, 0x4bd74679, 0x87a8a8d8, 0xdee50d2b}})
+
+#define EFI_EVENT_GROUP_AFTER_READY_TO_BOOT \
+ ((efi_guid_t) {.vs = {0x3a2a00ad, 0x98b94cdf, 0xa4787027, 0x77f1c10b}})
+
+#define EFI_EVENT_GROUP_RESET_SYSTEM \
+ ((efi_guid_t) {.vs = {0x62ddaba56, 0x13fb485a, 0xa8daa3dd, 0x7912cb6b}})
+
+#define EFI_CREATE_EVENT_EX(name) \
+ efi_status_t (EFIAPI name) (IN u32 type, \
+ IN efi_tpl_t notify_tpl, \
+ IN efi_event_notify_t * OPTIONAL notify_function, \
+ IN void CONST * OPTIONAL notify_context, \
+ IN efi_guid_t CONST * OPTIONAL event_group, \
+ OUT efi_event_t *event)
+
+
+#define EFI_CLOSE_EVENT(name) \
+ efi_status_t (EFIAPI name) (IN efi_event_t event)
+
+#define EFI_SIGNAL_EVENT(name) \
+ efi_status_t (EFIAPI name) (IN efi_event_t event)
+
+#define EFI_WAIT_FOR_EVENT(name) \
+ efi_status_t (EFIAPI name) (IN umm number_of_events, \
+ IN efi_event_t *event, \
+ OUT umm *index)
+
+#define EFI_CHECK_EVENT(name) \
+ efi_status_t (EFIAPI name) (IN efi_event_t event)
+
+enum efi_timer_delay {
+ EFI_TIMER_CANCEL,
+ EFI_TIMER_PERIODIC,
+ EFI_TIMER_RELATIVE,
+};
+
+#define EFI_SET_TIMER(name) \
+ efi_status_t (EFIAPI name) (IN efi_event_t event, \
+ IN enum efi_timer_delay type, \
+ IN u64 trigger_time)
+
+#define EFI_RAISE_TPL(name) \
+ efi_tpl_t (EFIAPI name) (IN efi_tpl_t new_tpl)
+
+#define EFI_RESTORE_TPL(name) \
+ void (EFIAPI name) (IN efi_tpl_t old_tpl)
+
+enum efi_allocate_type {
+ EFI_ALLOCATE_ANY_PAGES,
+ EFI_ALLOCATE_MAX_ADDRESS,
+ EFI_ALLOCATE_ADDRESS,
+ EFI_MAX_ALLOCATE_TYPE,
+};
+
+enum efi_memory_type {
+ EFI_RESERVED_MEMORY_TYPE,
+ EFI_LOADER_CODE,
+ EFI_LOADER_DATA,
+ EFI_BOOT_SERVICES_CODE,
+ EFI_BOOT_SERVICES_DATA,
+ EFI_RUNTIME_SERVICES_CODE,
+ EFI_RUNTIME_SERVICES_DATA,
+ EFI_CONVENTIONAL_MEMORY,
+ EFI_UNUSABLE_MEMORY,
+ EFI_ACPI_RECLAIM_MEMORY,
+ EFI_ACPI_MEMORY_NVS,
+ EFI_MEMORY_MAPPED_IO,
+ EFI_MEMORY_MAPPED_IO_PORT_SPACE,
+ EFI_PAL_CODE,
+ EFI_PERSISTENT_MEMORY,
+ EFI_UNACCEPTED_MEMORY_TYPE,
+ EFI_MAX_MEMORY_TYPE,
+};
+
+typedef u64 efi_physical_address_t;
+
+#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_NV 0x0000000000008000
+#define EFI_MEMORY_MORE_RELIABLE 0x0000000000010000
+#define EFI_MEMORY_RO 0x0000000000020000
+#define EFI_MEMORY_SP 0x0000000000040000
+#define EFI_MEMORY_CPU_CRYPTO 0x0000000000080000
+#define EFI_MEMORY_RUNTIME 0x8000000000000000
+#define EFI_MEMORY_ISA_VALID 0x4000000000000000
+#define EFI_MEMORY_ISA_MASK 0x0FFFF00000000000
+
+typedef u64 efi_virtual_address_t;
+
+#define EFI_MEMORY_DESCRIPTOR_VERSION 1
+
+struct efi_memory_descriptor {
+ u32 type;
+ efi_physical_address_t physical_start;
+ efi_virtual_address_t virtual_start;
+ u64 number_of_pages;
+ u64 attribute;
+};
+
+#define EFI_ALLOCATE_PAGES(name) \
+ efi_status_t (EFIAPI name) (IN enum efi_allocate_type type, \
+ IN enum efi_memory_type memory_type, \
+ IN umm pages, \
+ IN OUT efi_physical_address_t *memory)
+
+#define EFI_FREE_PAGES(name) \
+ efi_status_t (EFIAPI name) (IN efi_physical_address_t memory, \
+ IN umm pages)
+
+#define EFI_GET_MEMORY_MAP(name) \
+ efi_status_t (EFIAPI name) (IN OUT umm *memory_map_size, \
+ OUT struct efi_memory_descriptor *memory_map, \
+ OUT umm *map_key, \
+ OUT umm *descriptor_size, \
+ OUT u32 *descriptor_version)
+
+#define EFI_ALLOCATE_POOL(name) \
+ efi_status_t (EFIAPI name) (IN enum efi_memory_type pool_type, \
+ IN umm size, \
+ OUT void **buffer)
+
+#define EFI_FREE_POOL(name) \
+ efi_status_t (EFIAPI name) (IN void *buffer)
+
+enum efi_interface_type {
+ EFI_NATIVE_INTERFACE,
+};
+
+#define EFI_INSTALL_PROTOCOL_INTERFACE(name) \
+ efi_status_t (EFIAPI name) (IN OUT efi_handle_t *handle, \
+ IN efi_guid_t *protocol, \
+ IN enum efi_interface_type interface_type, \
+ IN void *interface)
+
+#define EFI_UNINSTALL_PROTOCOL_INTERFACE(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t handle, \
+ IN efi_guid_t *protocol, \
+ IN void *interface)
+
+#define EFI_REINSTALL_PROTOCOL_INTERFACE(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t handle, \
+ IN efi_guid_t *protocol, \
+ IN void *old_interface, \
+ IN void *new_interface)
+
+#define EFI_REGISTER_PROTOCOL_NOTIFY(name) \
+ efi_status_t (EFIAPI name) (IN efi_guid_t *protocol, \
+ IN efi_event_t event, \
+ OUT void **registration)
+
+enum efi_locate_search_type {
+ EFI_ALL_HANDLES,
+ EFI_BY_REGISTER_NOTIFY,
+ EFI_BY_PROTOCOL,
+};
+
+#define EFI_LOCATE_HANDLE(name) \
+ efi_status_t (EFIAPI name) (IN enum efi_locate_search_type search_type, \
+ IN efi_guid_t *OPTIONAL protocol, \
+ IN void *OPTIONAL search_key, \
+ IN OUT umm *buffer_size, \
+ OUT efi_handle_t *buffer)
+
+#define EFI_HANDLE_PROTOCOL(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t handle, \
+ IN efi_guid_t *protocol, \
+ OUT void **interface)
+
+// TODO: implement definitions
+struct efi_device_path_protocol {
+ u8 type;
+ u8 subtype;
+ u8 length[2];
+};
+
+#define EFI_LOCATE_DEVICE_PATH(name) \
+ efi_status_t (EFIAPI name) (IN efi_guid_t *protocol, \
+ IN OUT struct efi_device_path_protocol **device_path, \
+ OUT efi_handle_t *device)
+
+#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_OPEN_PROTOCOL(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t handle, \
+ IN efi_guid_t *protocol, \
+ OUT void **OPTIONAL interface, \
+ IN efi_handle_t agent_handle, \
+ IN efi_handle_t controller_handle, \
+ IN u32 attributes)
+
+#define EFI_CLOSE_PROTOCOL(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t handle, \
+ IN efi_guid_t *protocol, \
+ IN efi_handle_t agent_handle, \
+ IN efi_handle_t controller_handle)
+
+struct efi_open_protocol_information_entry {
+ efi_handle_t agent_handle;
+ efi_handle_t controller_handle;
+ u32 attributes;
+ u32 open_count;
+};
+
+#define EFI_OPEN_PROTOCOL_INFORMATION(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t handle, \
+ IN efi_guid_t *protocol, \
+ OUT struct efi_open_protocol_information_entry **entry_buffer, \
+ OUT umm *entry_count)
+
+#define EFI_CONNECT_CONTROLLER(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t controller_handle, \
+ IN efi_handle_t *OPTIONAL driver_image_handle, \
+ IN struct efi_device_path_protocol *OPTIONAL remaining_device_path, \
+ IN b8 recursive)
+
+#define EFI_DISCONNECT_CONTROLLER(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t controller_handle, \
+ IN efi_handle_t OPTIONAL driver_image_handle, \
+ IN efi_handle_t OPTIONAL child_handle)
+
+#define EFI_PROTOCOLS_PER_HANDLE(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t handle, \
+ OUT efi_guid_t ***protocol_buffer, \
+ OUT umm *protocol_buffer_count)
+
+#define EFI_LOCATE_HANDLE_BUFFER(name) \
+ efi_status_t (EFIAPI name) (IN enum efi_locate_search_type search_type, \
+ IN efi_guid_t *OPTIONAL protocol, \
+ IN void *OPTIONAL search_key, \
+ OUT umm *no_handles, \
+ OUT efi_handle_t **buffer)
+
+#define EFI_LOCATE_PROTOCOL(name) \
+ efi_status_t (EFIAPI name) (IN efi_guid_t *protocol, \
+ IN void *OPTIONAL registration, \
+ OUT void **interface)
+
+#define EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES(name) \
+ efi_status_t (EFIAPI name) (IN OUT efi_handle_t *handle, ...)
+
+#define EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t handle, ...)
+
+#define EFI_IMAGE_LOAD(name) \
+ efi_status_t (EFIAPI name) (IN b8 boot_policy, \
+ IN efi_handle_t parent_image_handle, \
+ IN struct efi_device_path_protocol *OPTIONAL device_path, \
+ IN void *OPTIONAL source_buffer, \
+ IN umm source_size, \
+ OUT efi_handle_t *image_handle)
+
+#define EFI_IMAGE_START(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t image_handle, \
+ OUT umm *exit_data_size, \
+ OUT c16 **OPTIONAL exit_data)
+
+#define EFI_IMAGE_UNLOAD(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t image_handle)
+
+#define EFI_IMAGE_ENTRY_POINT(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t image_handle, \
+ IN struct efi_system_table *system_table)
+
+#define EFI_EXIT(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t image_handle, \
+ IN efi_status_t exit_status, \
+ IN umm exit_data_size, \
+ IN c16 *OPTIONAL exit_data)
+
+#define EFI_EXIT_BOOT_SERVICES(name) \
+ efi_status_t (EFIAPI name) (IN efi_handle_t image_handle, \
+ IN umm map_key)
+
+#define EFI_SET_WATCHDOG_TIMER(name) \
+ efi_status_t (EFIAPI name) (IN umm timeout, \
+ IN u64 watchdog_code, \
+ IN umm data_size, \
+ IN c16 *OPTIONAL watchdog_data)
+
+#define EFI_STALL(name) \
+ efi_status_t (EFIAPI name) (IN umm microseconds)
+
+#define EFI_COPY_MEM(name) \
+ efi_status_t (EFIAPI name) (IN void *destination, \
+ IN void *source, \
+ IN umm length)
+
+#define EFI_SET_MEM(name) \
+ efi_status_t (EFIAPI name) (IN void *buffer, \
+ IN umm size, \
+ IN u8 value)
+
+#define EFI_GET_NEXT_MONOTONIC_COUNT(name) \
+ efi_status_t (EFIAPI name) (OUT u64 *count)
+
+#define EFI_INSTALL_CONFIGURATION_TABLE(name) \
+ efi_status_t (EFIAPI name) (IN efi_guid_t *guid, \
+ IN void *table)
+
+#define EFI_CALCULATE_CRC32(name) \
+ efi_status_t (EFIAPI name) (IN void *data, \
+ IN umm data_size, \
+ OUT u32 *crc32)
+
+struct efi_boot_services {
+ struct efi_table_header hdr;
+
+ EFI_RAISE_TPL(*raise_tpl);
+ EFI_RESTORE_TPL(*restore_tpl);
+
+ EFI_ALLOCATE_PAGES(*allocate_pages);
+ EFI_FREE_PAGES(*free_pages);
+ EFI_GET_MEMORY_MAP(*get_memory_map);
+ EFI_ALLOCATE_POOL(*allocate_pool);
+ EFI_FREE_POOL(*free_pool);
+
+ EFI_CREATE_EVENT(*create_event);
+ EFI_SET_TIMER(*set_timer);
+ EFI_WAIT_FOR_EVENT(*wait_for_event);
+ EFI_SIGNAL_EVENT(*signal_event);
+ EFI_CLOSE_EVENT(*close_event);
+ EFI_CHECK_EVENT(*check_event);
+
+ EFI_INSTALL_PROTOCOL_INTERFACE(*install_protocol_interface);
+ EFI_REINSTALL_PROTOCOL_INTERFACE(*reinstall_protocol_interface);
+ EFI_UNINSTALL_PROTOCOL_INTERFACE(*uninstall_protocol_interface);
+ EFI_HANDLE_PROTOCOL(*handle_protocol);
+ void *reserved0;
+ EFI_REGISTER_PROTOCOL_NOTIFY(*register_protocol_notify);
+ EFI_LOCATE_HANDLE(*locate_handle);
+ EFI_LOCATE_DEVICE_PATH(*locate_device_path);
+ EFI_INSTALL_CONFIGURATION_TABLE(*install_configuration_table);
+
+ EFI_IMAGE_LOAD(*load_image);
+ EFI_IMAGE_START(*start_image);
+ EFI_EXIT(*exit);
+ EFI_IMAGE_UNLOAD(*unload_image);
+ EFI_EXIT_BOOT_SERVICES(*exit_boot_services);
+
+ EFI_GET_NEXT_MONOTONIC_COUNT(*get_next_monotonic_count);
+ EFI_STALL(*stall);
+ EFI_SET_WATCHDOG_TIMER(*set_watchdog_timer);
+
+ // EFI 1.1+
+ EFI_CONNECT_CONTROLLER(*connect_controller);
+ EFI_DISCONNECT_CONTROLLER(*disconnect_controller);
+
+ EFI_OPEN_PROTOCOL(*open_protocol);
+ EFI_CLOSE_PROTOCOL(*close_protocol);
+ EFI_OPEN_PROTOCOL_INFORMATION(*open_protocol_information);
+ EFI_PROTOCOLS_PER_HANDLE(*protocols_per_handle);
+ EFI_LOCATE_HANDLE_BUFFER(*locate_handle_buffer);
+ EFI_LOCATE_PROTOCOL(*locate_protocol);
+ EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES(*install_multiple_protocol_interfaces);
+ EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES(*uninstall_multiple_protocol_interfaces);
+
+ EFI_CALCULATE_CRC32(*calculate_crc32);
+
+ EFI_COPY_MEM(*copy_mem);
+ EFI_SET_MEM(*set_mem);
+
+ // UEFI 2.0+
+ EFI_CREATE_EVENT_EX(*create_event_ex);
+};
+
+
+
+/* runtime services
+ * ---
+ * see: https://uefi.org/specs/UEFI/2.10/08_Services_Runtime_Services.html
+ */
+
+struct efi_time {
+ u16 year; // 1999 - 9999
+ u8 month; // 1 - 12
+ u8 day; // 1 - 31
+ u8 hour; // 0 - 23
+ u8 minute; // 0 - 59
+ u8 second; // 0 - 59
+ u8 pad1;
+ u32 nanosecond; // 0 - 999,999,999
+ s16 timezone; // -1440 - 1440 or 2047
+ u8 daylight;
+ u8 pad2;
+};
+
+#define EFI_TIME_ADJUST_DAYLIGHT 0x01
+#define EFI_TIME_IN_DAYLIGHT 0x02
+
+#define EFI_TIME_UNSPECIFIED_TIMEZONE 0x07ff
+
+#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
+
+// NOTE: deprecated
+//#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
+
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
+#define EFI_VARIABLE_APPEND_WRITE 0x00000040
+#define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS 0x00000080
+
+#define EFI_VARIABLE_AUTHENTICATION_3_CERT_ID_SHA256 1
+
+struct efi_variable_authentication_3_cert_id {
+ u8 type;
+ u32 id_size;
+ u8 id[];
+};
+
+#define EFI_GET_VARIABLE(name) \
+ efi_status_t (EFIAPI name) (IN c16 *variable_name, \
+ IN efi_guid_t *vendor_guid, \
+ OUT u32 *OPTIONAL attributes, \
+ IN OUT umm *data_size, \
+ OUT void *OPTIONAL data)
+
+#define EFI_GET_NEXT_VARIABLE_NAME(name) \
+ efi_status_t (EFIAPI name) (IN OUT umm *variable_name_size, \
+ IN OUT c16 *variable_name, \
+ IN OUT efi_guid_t *vendor_guid)
+
+struct win_certificate_uefi_guid {
+ u8 pad0; // TODO
+};
+
+struct efi_variable_authentication {
+ u64 monotonic_count;
+ struct win_certificate_uefi_guid auth_info;
+};
+
+struct efi_variable_authentication_2 {
+ struct efi_time time_stamp;
+ struct win_certificate_uefi_guid auth_info;
+};
+
+#define EFI_VARIABLE_AUTHENTICATION_3_TIMESTAMP_TYPE 1
+#define EFI_VARIABLE_AUTHENTICATION_3_NONCE_TYPE 2
+
+struct efi_variable_authentication_3 {
+ u8 version;
+ u8 type;
+ u32 metadata_size;
+ u32 flags;
+};
+
+struct efi_variable_authentication_3_nonce {
+ u32 nonce_size;
+ u8 nonce[];
+};
+
+#define EFI_SET_VARIABLE(name) \
+ efi_status_t (EFIAPI name) (IN c16 *variable_name, \
+ IN efi_guid_t *vendor_guid, \
+ IN u32 attributes, \
+ IN umm data_size, \
+ IN void *data)
+
+#define EFI_QUERY_VARIABLE_INFO(name) \
+ efi_status_t (EFIAPI name) (IN u32 attributes, \
+ OUT u64 *maximum_variable_storage_size, \
+ OUT u64 *remaining_variable_storage_size, \
+ OUT u64 *maximum_variable_size)
+
+struct efi_time_capabilities {
+ u32 resolution;
+ u32 accuracy;
+ b8 sets_to_zero;
+};
+
+#define EFI_GET_TIME(name) \
+ efi_status_t (EFIAPI name) (OUT struct efi_time *time, \
+ OUT struct efi_time_capabilities * OPTIONAL capabilities)
+
+#define EFI_SET_TIME(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_time *time)
+
+#define EFI_GET_WAKEUP_TIME(name) \
+ efi_status_t (EFIAPI name) (OUT b8 *enabled, \
+ OUT b8 *pending, \
+ OUT struct efi_time *time)
+
+#define EFI_SET_WAKEUP_TIME(name) \
+ efi_status_t (EFIAPI name) (IN b8 enable, \
+ IN struct efi_time * OPTIONAL time)
+
+#define EFI_SET_VIRTUAL_ADDRESS_MAP(name) \
+ efi_status_t (EFIAPI name) (IN umm memory_map_size, \
+ IN umm descriptor_size, \
+ IN u32 descriptor_version, \
+ IN struct efi_memory_descriptor *virtual_map)
+
+#define EFI_OPTIONAL_PTR 0x00000001
+
+#define EFI_CONVERT_POINTER(name) \
+ efi_status_t (EFIAPI name) (IN umm debug_disposition, \
+ IN void **address)
+
+enum efi_reset_type {
+ EFI_RESET_COLD,
+ EFI_RESET_WARM,
+ EFI_RESET_SHUTDOWN,
+ EFI_RESET_PLATFORM_SPECIFIC,
+};
+
+#define EFI_RESET_SYSTEM(name) \
+ void (EFIAPI name) (IN enum efi_reset_type reset_type, \
+ IN efi_status_t reset_status, \
+ IN umm data_size, \
+ IN void *OPTIONAL reset_data)
+
+#define EFI_GET_NEXT_HIGH_MONO_COUNT(name) \
+ efi_status_t (EFIAPI name) (OUT u32 *high_count)
+
+struct efi_capsule_block_descriptor {
+ u64 length;
+ union {
+ efi_physical_address_t data_block;
+ efi_physical_address_t continuation_pointer;
+ };
+};
+
+struct efi_capsule_header {
+ efi_guid_t capsule_guid;
+ u32 header_size;
+ u32 flags;
+ u32 capsule_image_size;
+};
+
+#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000
+#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000
+#define CAPSULE_FLAGS_INITIATE_RESET 0x00040000
+
+struct efi_capsule_table {
+ u32 capsule_array_number;
+ void *capsule_ptr[];
+};
+
+#define EFI_UPDATE_CAPSULE(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_capsule_header **capsule_header_array, \
+ IN umm capsule_count, \
+ IN efi_physical_address_t OPTIONAL scatter_gather_list)
+
+#define EFI_QUERY_CAPSULE_CAPABILITIES(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_capsule_header **capsule_header_array, \
+ IN umm capsule_count, \
+ OUT u64 *maxiumum_capsule_size, \
+ OUT enum efi_reset_type *reset_type)
+
+struct efi_runtime_services {
+ struct efi_table_header hdr;
+
+ EFI_GET_TIME(*get_time);
+ EFI_SET_TIME(*set_time);
+ EFI_GET_WAKEUP_TIME(*get_wakeup_time);
+ EFI_SET_WAKEUP_TIME(*set_wakeup_time);
+
+ EFI_SET_VIRTUAL_ADDRESS_MAP(*set_virtual_address_map);
+ EFI_CONVERT_POINTER(*convert_pointer);
+
+ EFI_GET_VARIABLE(*get_variable);
+ EFI_GET_NEXT_VARIABLE_NAME(*get_next_variable_name);
+ EFI_SET_VARIABLE(*set_variable);
+
+ EFI_GET_NEXT_HIGH_MONO_COUNT(*get_next_high_monotonic_count);
+ EFI_RESET_SYSTEM(*reset_system);
+
+ // UEFI 2.0+
+ EFI_UPDATE_CAPSULE(*update_capsule);
+ EFI_QUERY_CAPSULE_CAPABILITIES(*query_capsule_capabilities);
+
+ EFI_QUERY_VARIABLE_INFO(*query_variable_info);
+};
+
+/* configuration table
+ * ---
+ * see: https://uefi.org/specs/UEFI/2.10/04_EFI_System_Table.html#efi-configuration-table-properties-table
+ */
+
+struct efi_configuration_table {
+ efi_guid_t vendor_guid;
+ void *vendor_table;
+};
+
+/* protocols
+ * ===========================================================================
+ */
+
+/* input protocol
+ * ---
+ * see: https://uefi.org/specs/UEFI/2.10/12_Protocols_Console_Support.html#simple-text-input-protocol
+ */
+
+#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \
+ (efi_guid_t) {.vs = {0x387477c1, 0x69c711d2, 0x8e3900a0, 0xc969723b}}
+
+struct efi_input_key {
+ u16 scan_code;
+ c16 unicode_char;
+};
+
+#define EFI_INPUT_RESET(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_input_protocol *this, \
+ IN b8 extended_verification)
+
+#define EFI_INPUT_READ_KEY(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_input_protocol *this, \
+ OUT struct efi_input_key *key)
+
+struct efi_simple_text_input_protocol {
+ EFI_INPUT_RESET(*reset);
+ EFI_INPUT_READ_KEY(*read_key_stroke);
+ efi_event_t wait_for_key;
+};
+
+/* output protocol
+ * ---
+ * see: https://uefi.org/specs/UEFI/2.10/12_Protocols_Console_Support.html#simple-text-output-protocol
+ */
+
+#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \
+ (efi_guid_t) {.vs = {0x387477c2, 0x69c711d2, 0x8e3900a0, 0xc969723b}}
+
+#define EFI_TEXT_RESET(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this, \
+ IN b8 extended_verification)
+
+#define EFI_TEXT_STRING(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this, \
+ IN c16 *string)
+
+#define EFI_TEXT_TEST_STRING(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this, \
+ IN c16 *string)
+
+#define EFI_TEXT_QUERY_MODE(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this, \
+ IN umm mode_number, \
+ OUT umm *columns, \
+ OUT umm *rows)
+
+#define EFI_TEXT_SET_MODE(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this, \
+ IN umm mode)
+
+#define EFI_TEXT_SET_ATTRIBUTE(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this, \
+ IN umm attribute)
+
+#define EFI_TEXT_CLEAR_SCREEN(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this)
+
+#define EFI_TEXT_SET_CURSOR_POSITION(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this, \
+ IN umm column, \
+ IN umm row)
+
+#define EFI_TEXT_ENABLE_CURSOR(name) \
+ efi_status_t (EFIAPI name) (IN struct efi_simple_text_output_protocol *this, \
+ IN b8 visible)
+
+struct efi_simple_text_output_mode {
+ s32 max_mode;
+ s32 mode;
+ s32 attribute;
+ s32 cursor_column;
+ s32 cursor_row;
+ b8 cursor_visible;
+};
+
+struct efi_simple_text_output_protocol {
+ EFI_TEXT_RESET(*reset);
+ EFI_TEXT_STRING(*output_string);
+ EFI_TEXT_TEST_STRING(*test_string);
+ EFI_TEXT_QUERY_MODE(*query_mode);
+ EFI_TEXT_SET_MODE(*set_mode);
+ EFI_TEXT_SET_ATTRIBUTE(*set_attribute);
+ EFI_TEXT_CLEAR_SCREEN(*clear_screen);
+ EFI_TEXT_SET_CURSOR_POSITION(*set_cursor_position);
+ EFI_TEXT_ENABLE_CURSOR(*enable_cursor);
+ struct efi_simple_text_output_mode *mode;
+};
+
+#endif /* EFI_H */
diff --git a/scripts/qemu-amd64.sh b/scripts/qemu-amd64.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# NOTE: replace this with the path to a downloaded OVMF image
+OVMF_CODE="/usr/share/edk2-ovmf/OVMF_CODE.fd"
+OVMF_VARS="/usr/share/edk2-ovmf/OVMF_VARS.fd"
+
+# params:
+# $1 - disk image
+
+qemu-system-x86_64 \
+ -drive if=pflash,format=raw,unit=0,file=$OVMF_CODE,readonly=on \
+ -drive if=pflash,format=raw,unit=1,file=$OVMF_VARS,readonly=on \
+ -drive if=none,format=raw,id=disk0,file="$1" \
+ -device ahci,id=ahci \
+ -device ide-hd,drive=disk0,bus=ahci.0 \
+ -net none \
+ -nographic
+
+ #-machine q35 \
+ #-m 64 \
+ #-smp sockets=1,cpus=4 \
+
+ #-chardev stdio,id=char0,logfile="serial.log",signal=off \
+ #-serial chardev:char0 \
diff --git a/src/boot-amd64.asm b/src/boot-amd64.asm
@@ -0,0 +1,547 @@
+.intel_syntax
+
+.globl EntryPoint
+
+.equ EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, 10
+
+.equ IMAGE_MACHINE_x64, 0x8664
+
+.equ IMAGE_FILE_EXECUTABLE_IMAGE, 0x0002
+.equ IMAGE_FILE_LARGE_ADDRESS_AWARE, 0x0020
+.equ IMAGE_FILE_DEBUG_STRIPPED, 0x0200
+
+.equ PE32PLUS_MAGIC, 0x020b
+
+.equ IMAGE_SCN_CNT_CODE, 0x00000020
+.equ IMAGE_SCN_CNT_DATA, 0x00000040
+.equ IMAGE_SCN_MEM_SHARED, 0x10000000
+.equ IMAGE_SCN_MEM_EXECUTE, 0x20000000
+.equ IMAGE_SCN_MEM_READ, 0x40000000
+.equ IMAGE_SCN_MEM_WRITE, 0x80000000
+
+.code64
+
+.section .header, "a", %progbits
+BEGIN:
+
+HEADER:
+
+MSDOS_HDR:
+MSDOS_HDR.e_magic: .byte 'M', 'Z', 0x00, 0x00
+.fill 14, 4, 0x00000000
+MSDOS_HDR.e_lfanew: .int (PE_HDR - MSDOS_HDR)
+MSDOS_HDR_END:
+
+MSDOS_STUB:
+.fill 16, 4, 0x00000000
+MSDOS_STUB_END:
+
+PE_HDR:
+PE_HDR.PEMagic: .byte 'P', 'E', 0x00, 0x00
+PE_HDR.Machine: .short IMAGE_MACHINE_x64
+PE_HDR.NumberOfSections: .short 2
+PE_HDR.TimeDateStamp: .int 1717539955
+PE_HDR.PointerToSymbolTable: .int 0
+PE_HDR.NumberOfSymbols: .int 0
+PE_HDR.SizeOfOptionalHeader: .short (PEOPT_HDR_END - PEOPT_HDR)
+PE_HDR.Characteristics: .short (IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_LARGE_ADDRESS_AWARE | IMAGE_FILE_EXECUTABLE_IMAGE)
+PE_HDR_END:
+
+PEOPT_HDR:
+PEOPT_HDR.PEOptMagic: .short PE32PLUS_MAGIC
+PEOPT_HDR.MajorLinkerVersion: .byte 0
+PEOPT_HDR.MinorLinkerVersion: .byte 0
+PEOPT_HDR.SizeOfCode: .int (CODE_END - CODE)
+PEOPT_HDR.SizeOfData: .int (DATA_END - DATA)
+PEOPT_HDR.SizeOfBss: .int 0
+PEOPT_HDR.AddressOfEntryPoint: .int (EntryPoint - BEGIN)
+PEOPT_HDR.BaseOfCode: .int (CODE - BEGIN)
+
+PEOPT_HDR.BaseOfData: /* missing due to 64-bit ImageBase in 64-bit PEs*/
+PEOPT_HDR.ImageBase: .quad 0x40000
+PEOPT_HDR.SectionAlignment: .int 0x1000
+PEOPT_HDR.FileAlignment: .int 0x1000
+PEOPT_HDR.MajorOSVersion: .short 0
+PEOPT_HDR.MinorOSVersion: .short 0
+PEOPT_HDR.MajorImageVersion: .short 0
+PEOPT_HDR.MinorImageVersion: .short 0
+PEOPT_HDR.MajorSubsystemVersion:.short 0
+PEOPT_HDR.MinorSubsystemVersion:.short 0
+PEOPT_HDR.Win32VersionValue: .int 0
+PEOPT_HDR.SizeOfImage: .int (END - BEGIN)
+PEOPT_HDR.SizeOfHeaders: .int (HEADER_END - HEADER)
+PEOPT_HDR.Checksum: .int 0
+PEOPT_HDR.Subsystem: .short EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
+PEOPT_HDR.DllCharacteristics: .short 0
+PEOPT_HDR.SizeOfStackReserve: .quad 0x200000
+PEOPT_HDR.SizeOfStackCommit: .quad 0x1000
+PEOPT_HDR.SizeOfHeapReserve: .quad 0x200000
+PEOPT_HDR.SizeOfHeapCommit: .quad 0x1000
+PEOPT_HDR.LoaderFlags: .int 0
+PEOPT_HDR.NumberOfRvaAndSizes: .int 0
+
+PEOPT_HDR_END:
+
+SECTIONS_HDR:
+
+SECTION_CODE:
+SECTION_CODE.Name: .byte '.', 't', 'e', 'x', 't', 0x00, 0x00, 0x00
+SECTION_CODE.VirtualSize: .int (CODE_END - CODE)
+SECTION_CODE.VirtualAddress: .int (CODE - BEGIN)
+SECTION_CODE.SizeOfRawData: .int (CODE_END - CODE)
+SECTION_CODE.PointerToRawData: .int (CODE - BEGIN)
+SECTION_CODE.PointerToRelocs: .int 0
+SECTION_CODE.PointerToLineNums: .int 0
+SECTION_CODE.NumberOfRelocs: .short 0
+SECTION_CODE.NumberOfLineNums: .short 0
+SECTION_CODE.Characteristics: .int (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)
+
+SECTION_DATA:
+SECTION_DATA.Name: .byte '.', 'd', 'a', 't', 'a', 0x00, 0x00, 0x00
+SECTION_DATA.VirtualSize: .int (DATA_END - DATA)
+SECTION_DATA.VirtualAddress: .int (DATA - BEGIN)
+SECTION_DATA.SizeOfRawData: .int (DATA_END - DATA)
+SECTION_DATA.PointerToRawData: .int (DATA - BEGIN)
+SECTION_DATA.PointerToRelocs: .int 0
+SECTION_DATA.PointerToLineNums: .int 0
+SECTION_DATA.NumberOfRelocs: .short 0
+SECTION_DATA.NumberOfLineNums: .short 0
+SECTION_DATA.Characteristics: .int (IMAGE_SCN_CNT_DATA | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)
+
+SECTIONS_HDR_END:
+
+HEADER_END:
+
+.align 16
+.section .text, "ax", %progbits
+
+CODE:
+
+.equ EFI_SUCCESS, 0
+
+.equ EFI_ERROR, 0x8000000000000000
+.equ EFI_LOAD_ERROR, 1
+.equ EFI_INVALID_PARAMETER, 2
+.equ EFI_UNSUPPORTED, 3
+.equ EFI_BUFFER_TOO_SMALL, 4
+.equ EFI_NOT_FOUND, 14
+
+.equ EFI_WARNING, 0x0000000000000000
+
+/* typedef void *EFI_HANDLE;
+ * typedef EFI_HANDLE EFI_IMAGE_HANDLE;
+ *
+ * typedef struct {
+ * u64 Signature;
+ * u32 Revision;
+ * u32 HeaderSize;
+ * u32 CRC32;
+ * u32 Reserved;
+ * } EFI_TABLE_HEADER;
+ */
+.equ EFI_TABLE_HEADER_SZ, 24
+
+/* typedef struct {
+ * EFI_GUID VendorGuid;
+ * void *VendorTable;
+ * } EFI_CONFIGURATION_TABLE;
+ *
+ * typedef struct {
+ * EFI_TABLE_HEADER Hdr;
+ * c16 *FirmwareVendor;
+ * u32 FirmwareRevision;
+ * EFI_HANDLE ConsoleInHandle;
+ * EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ * EFI_HANDLE ConsoleOutHandle;
+ * EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ * EFI_HANDLE StandardErrorHandle;
+ * EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
+ * EFI_RUNTIME_SERVICES *RuntimeServices;
+ * EFI_BOOT_SERVICES *BootServices;
+ * umm NumberOfTableEntries;
+ * EFI_CONFIGURATION_TABLE *ConfigurationTable;
+ * } EFI_SYSTEM_TABLE;
+ */
+.equ EFI_SYSTEM_TABLE_CON_IN, (EFI_TABLE_HEADER_SZ + 24)
+.equ EFI_SYSTEM_TABLE_CON_OUT, (EFI_TABLE_HEADER_SZ + 40)
+.equ EFI_SYSTEM_TABLE_STD_ERR, (EFI_TABLE_HEADER_SZ + 56)
+.equ EFI_SYSTEM_TABLE_RUNTIME_SERVICES, (EFI_TABLE_HEADER_SZ + 64)
+.equ EFI_SYSTEM_TABLE_BOOT_SERVICES, (EFI_TABLE_HEADER_SZ + 72)
+.equ EFI_SYSTEM_TABLE_NUBER_OF_TABLE_ENTS, (EFI_TABLE_HEADER_SZ + 80)
+.equ EFI_SYSTEM_TABLE_CONFIGURATION_TABLE, (EFI_TABLE_HEADER_SZ + 88)
+
+/* typedef struct {
+ * EFI_INPUT_RESET Reset;
+ * EFI_INPUT_READ_KEY ReadKeyStroke;
+ * EFI_EVENT WaitForKey;
+ * } EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
+ *
+ * typedef struct {
+ * s32 MaxMode;
+ *
+ * s32 Mode;
+ * s32 Attribute;
+ * s32 CursorColumn;
+ * s32 CursorRow;
+ * b8 CursorVisible;
+ * } SIMPLE_TEXT_OUTPUT_MODE;
+ *
+ * typedef struct {
+ * EFI_TEXT_RESET Reset;
+ * EFI_TEXT_STRING OutputString;
+ * EFI_TEXT_TEST_STRING TestString;
+ * EFI_TEXT_QUERY_MODE QueryMode;
+ * EFI_TEXT_SET_MODE SetMode;
+ * EFI_TEXT_SET_ATTRIBUTE SetAttribute;
+ * EFI_TEXT_CLEAR_SCREEN ClearScreen;
+ * EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition;
+ * EFI_TEXT_ENABLE_CURSOR EnableCursor;
+ * SIMPLE_TEXT_OUTPUT_MODE *Mode;
+ * } EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
+ */
+.equ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_RESET, 0
+.equ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUT_STRING, 8
+.equ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_SET_ATTRIBUTE, 40
+.equ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_CLEAR_SCREEN, 48
+
+.equ EFI_FG_WHITE, 0x0F
+
+.equ EFI_BG_BLACK, 0x00
+.equ EFI_BG_RED, 0x40
+
+/* typedef struct {
+ * EFI_TABLE_HEADER Hdr;
+ *
+ * EFI_GET_TIME GetTime;
+ * EFI_SET_TIME SetTime;
+ * EFI_GET_WAKEUP_TIME GetWakeupTime;
+ * EFI_SET_WAKEUP_TIME SetWakeupTime;
+ *
+ * EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap;
+ * EFI_CONVERT_POINTER ConvertPointer;
+ *
+ * EFI_GET_VARIABLE GetVariable;
+ * EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName;
+ * EFI_SET_VARIABLE SetVariable;
+ *
+ * EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHightMonotonicCount;
+ * EFI_RESET_SYSTEM ResetSystem;
+ *
+ * // UEFI 2.0+ specified fields
+ * } EFI_RUNTIME_SERVICES;
+ */
+.equ EFI_RUNTIME_SERVICES_RESET_SYSTEM, (EFI_TABLE_HEADER_SZ + 80)
+
+.equ EFI_RESET_COLD, 0
+.equ EFI_RESET_WARM, 1
+.equ EFI_RESET_SHUTDOWN, 2
+.equ EFI_RESET_PLATFORM_SPECIFIC, 3
+
+/* typedef struct {
+ * EFI_TABLE_HEADER Hdr;
+ *
+ * EFI_RAISE_TPL RaiseTPL;
+ * EFI_RESTORE_TPL RestoreTPL;
+ *
+ * EFI_ALLOCATE_PAGES AllocatePages;
+ * EFI_FREE_PAGES FreePages;
+ * EFI_GET_MEMORY_MAP GetMemoryMap;
+ * EFI_ALLOCATE_POOL AllocatePool;
+ * EFI_FREE_POOL FreePool;
+ *
+ * EFI_CREATE_EVENT CreateEvent;
+ * EFI_SET_TIMER SetTimer;
+ * EFI_WAIT_FOR_EVENT WaitForEvent;
+ * EFI_SIGNAL_EVENT SignalEvent;
+ * EFI_CLOSE_EVENT CloseEvent;
+ * EFI_CHECK_EVENT CheckEvent;
+ *
+ * EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface;
+ * EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface;
+ * EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface;
+ * EFI_HANDLE_PROTOCOL HandleProtocol;
+ * void *Reserved;
+ * EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify;
+ * EFI_LOCATE_HANDLE LocateHandle;
+ * EFI_LOCATE_DEVICE_PATH LocateDevicePath;
+ * EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable;
+ *
+ * EFI_IMAGE_LOAD LoadImage;
+ * EFI_IMAGE_START StartImage;
+ * EFI_EXIT Exit;
+ * EFI_IMAGE_UNLOAD UnloadImage;
+ * EFI_EXIT_BOOT_SERVICES ExitBootServices;
+ *
+ * EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount;
+ * EFI_STALL Stall;
+ * EFI_SET_WATCHDOG_TIMER SetWatchdogTimer;
+ *
+ * // EFI 1.1+ specified fields
+ * EFI_CONNECT_CONTROLLER ConnectController;
+ * EFI_DISCONNECT_CONTROLLER DisconnectController;
+ *
+ * EFI_OPEN_PROTOCOL OpenProtocol;
+ * EFI_CLOSE_PROTOCOL CloseProtocol;
+ * EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation;
+ *
+ * EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle;
+ * EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer;
+ * EFI_LOCATE_PROTOCOL LocateProtocol;
+ * EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces;
+ * EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces;
+ *
+ * EFI_CALCULATE_CRC32 CalculateCRC32;
+ *
+ * EFI_COPY_MEM CopyMem;
+ * EFI_SET_MEM SetMem;
+ *
+ * // UEFI 2.0+ specified fields
+ * } EFI_BOOT_SERVICES;
+ */
+.equ EFI_BOOT_SERVICES_GET_MEMORY_MAP, (EFI_TABLE_HEADER_SZ + 40)
+.equ EFI_BOOT_SERVICES_EXIT, (EFI_TABLE_HEADER_SZ + 192)
+.equ EFI_BOOT_SERVICES_EXIT_BOOT_SERVICES, (EFI_TABLE_HEADER_SZ + 208)
+.equ EFI_BOOT_SERVICES_STALL, (EFI_TABLE_HEADER_SZ + 224)
+.equ EFI_BOOT_SERVICES_LOCATE_PROTOCOL, (EFI_TABLE_HEADER_SZ + 296)
+
+.equ MICROS, 1000000
+
+/* we get called with the following state:
+ * rcx: EFI_HANDLE
+ * rdx: EFI_SYSTEM_TABLE *
+ * rsp: 8 byte offset, <retaddr>
+ *
+ * NOTE: UEFI requires a 16-byte aligned stack, and due to the return address
+ * being passed on the stack, we have an 8-byte offset. UEFI also expects
+ * a 32-byte shadow space to allow pushing all 4 potential arg registers.
+ */
+EntryPoint:
+
+ /* NOTE: fix up the stack due to the following rules:
+ * sub rsp, (a + b*8)
+ * - a : realign stack pointer to 16-bytes, accounting for the passed retaddr
+ * - b : we need to reserve shadow space for preserved registers
+ */
+ sub rsp, (8 + 8*8)
+
+ mov rax, [rdx + EFI_SYSTEM_TABLE_CON_OUT]
+ mov rax, [rax + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_RESET]
+ mov rcx, [rdx + EFI_SYSTEM_TABLE_CON_OUT]
+ xor rdx, rdx
+ call rax
+
+ mov rax, [rdx + EFI_SYSTEM_TABLE_CON_OUT]
+ mov rax, [rax + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUT_STRING]
+ mov rcx, [rdx + EFI_SYSTEM_TABLE_CON_OUT]
+ lea rdx, [MSG_LOAD_KERNEL]
+ call rax
+
+wait:
+ jmp wait
+
+ add rsp, (8 + 8*8)
+ ret
+
+ mov EFI_IMAGE_HANDLE, rcx
+ mov EFI_SYSTEM_TABLE, rdx
+
+ mov rax, [rdx + EFI_SYSTEM_TABLE_CON_OUT]
+ mov EFI_STDOUT, rax
+
+ mov rax, [rdx + EFI_SYSTEM_TABLE_RUNTIME_SERVICES]
+ mov EFI_RUNTIME_SERVICES, rax
+
+ mov rax, [rdx + EFI_SYSTEM_TABLE_BOOT_SERVICES]
+ mov EFI_BOOT_SERVICES, rax
+
+ mov rax, [rdx + EFI_SYSTEM_TABLE_CONFIGURATION_TABLE]
+ mov EFI_CONFIGURATION_TABLE, rax
+
+ jmp load_kernel
+
+get_memory_map:
+ /* typedef struct {
+ * u32 Type;
+ * EFI_PHYSICAL_ADDRESS PhysicalStart;
+ * EFI_VIRTUAL_ADDRESS VirtualStart;
+ * u64 NumberOfPages;
+ * u64 Attribute;
+ * } EFI_MEMORY_DESCRIPTOR;
+ *
+ * typedef EFI_STATUS (EFIAPI *EFI_GET_MEMORY_MAP) (
+ * IN OUT umm *MemoryMapSize,
+ * OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ * OUT umm *MapKey,
+ * OUT umm *DescriptorSize,
+ * OUT u32 *DescriptorVersion
+ * );
+ */
+ lea rcx, MEMORY_MAP_SIZE
+ lea rdx, MEMORY_MAP
+ lea r8, MEMORY_MAP_KEY
+ lea r9, MEMORY_DESCRIPTOR_SIZE
+ lea rax, MEMORY_DESCRIPTOR_VERSION
+ mov [rsp+32], rax
+ mov rax, EFI_BOOT_SERVICES
+ call [rax + EFI_BOOT_SERVICES_GET_MEMORY_MAP]
+ cmp al, EFI_BUFFER_TOO_SMALL /* correct buffer size returned in [MEMORY_MAP_SIZE] */
+ je get_memory_map
+
+ cmp rax, EFI_SUCCESS
+ jne failure
+
+ /* typedef EFI_STATUS (EFIAPI *EFI_EXIT_BOOT_SERVICES) (
+ * IN EFI_HANDLE ImageHandle,
+ * IN umm MapKey
+ * );
+ */
+ mov rcx, EFI_IMAGE_HANDLE
+ mov rdx, MEMORY_MAP_KEY
+ mov rax, EFI_BOOT_SERVICES
+ call [rax + EFI_BOOT_SERVICES_EXIT_BOOT_SERVICES]
+ cmp rax, EFI_SUCCESS /* was our memory map key invalid? */
+ jne get_memory_map
+
+load_kernel:
+
+ /* typedef EFI_STATUS (EFIAPI *EFI_TEXT_RESET) (
+ * IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ * IN b8 ExtendedVerification
+ * );
+ */
+ mov rcx, EFI_STDOUT
+ mov rdx, 1
+ call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_RESET]
+ cmp rax, EFI_SUCCESS
+ jne failure
+
+ /* typedef EFI_STATUS (EFIAPI *EFI_TEXT_SET_ATTRIBUTE) (
+ * IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ * IN umm Attribute
+ * );
+ */
+ mov rcx, EFI_STDOUT
+ mov rdx, EFI_FG_WHITE | EFI_BG_BLACK
+ call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_SET_ATTRIBUTE]
+ cmp rax, EFI_SUCCESS
+ jne failure
+
+ /* typedef EFI_STATUS (EFIAPI *EFI_TEXT_OUTPUT_CLEAR_SCREEN) (
+ * IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ * );
+ */
+ mov rcx, EFI_STDOUT
+ call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_CLEAR_SCREEN]
+ cmp rax, EFI_SUCCESS
+ jne failure
+
+ /* typedef EFI_STATUS (EFIAPI *EFI_TEXT_OUTPUT_STRING) (
+ * IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ * IN c16 *String
+ * );
+ */
+ mov rcx, EFI_STDOUT
+ lea rdx, MSG_LOAD_KERNEL
+ call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUT_STRING]
+ cmp rax, EFI_SUCCESS
+ jne failure
+
+ /* typedef EFI_STATUS (EFIAPI *EFI_STALL) (
+ * IN umm Microseconds
+ * );
+ */
+ mov rcx, 10 * MICROS
+ mov rax, [EFI_BOOT_SERVICES]
+ call [rax + EFI_BOOT_SERVICES_STALL]
+
+ /* TODO: enable efi framebuffer for drawing */
+
+ /* typedef EFI_STATUS (EFIAPI *EFI_RESET_SYSTEM) (
+ * IN EFI_RESET_TYPE ResetType,
+ * IN EFI_STATUS ExitStatus,
+ * IN umm DataSize,
+ * IN c16 *ResetData OPTIONAL
+ * );
+ */
+ mov rcx, EFI_RESET_SHUTDOWN
+ mov rdx, EFI_SUCCESS
+ mov r8, 0
+ mov r9, 0
+ mov rax, [EFI_RUNTIME_SERVICES]
+ call [rax + EFI_RUNTIME_SERVICES_RESET_SYSTEM]
+
+ /* EFI_RESET_SYSTEM does not return */
+
+ mov rax, EFI_SUCCESS
+ jmp exit
+
+failure:
+ mov rcx, [EFI_STDOUT]
+ lea rdx, [MSG_FAILURE]
+ call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUT_STRING]
+
+ /* typedef EFI_STATUS (EFIAPI *EFI_EXIT) (
+ * IN EFI_HANDLE ImageHandle,
+ * IN EFI_STATUS ExitStatus,
+ * IN umm ExitDataSize,
+ * IN c16 *ExitData OPTIONAL
+ * );
+ */
+ mov rcx, [EFI_IMAGE_HANDLE]
+ mov rdx, EFI_ERROR | EFI_LOAD_ERROR
+ mov r8, 0
+ mov r9, 0
+ mov rax, [EFI_BOOT_SERVICES]
+ call [rax + EFI_BOOT_SERVICES_EXIT]
+
+ /* EFI_EXIT does not return */
+
+ mov rax, EFI_ERROR | EFI_LOAD_ERROR
+ jmp exit
+
+exit:
+ add rsp, (8 + 8*8) /* undo UEFI stack constraints */
+ retn
+
+CODE_END:
+
+.align 4096
+.section .data, "aw", %progbits
+
+DATA:
+
+MSG_LOAD_KERNEL: .short 'U', 'E', 'F', 'I', 13, 10, 0
+
+.align 16
+EFI_IMAGE_HANDLE: .quad 0
+EFI_SYSTEM_TABLE: .quad 0
+
+EFI_STDOUT: .quad 0
+
+EFI_RUNTIME_SERVICES: .quad 0
+EFI_BOOT_SERVICES: .quad 0
+EFI_CONFIGURATION_TABLE: .quad 0
+
+MEMORY_MAP_SIZE: .quad (32 * 1024) /* initially requested memory map buffer size */
+MEMORY_MAP: .quad 0x200000 /* address at which to place the memory map */
+MEMORY_MAP_KEY: .quad 0
+MEMORY_DESCRIPTOR_SIZE: .quad 0
+MEMORY_DESCRIPTOR_VERSION: .quad 0
+
+/* all strings are in unicode */
+.align 16
+MSG_FAILURE: .short 'F', 'A', 'I', 'L', 13, 10, 0
+
+/*
+.align 16
+MSG_LOAD_KERNEL: .short 'U', 'E', 'F', 'I', 13, 10, 0
+*/
+
+DATA_END:
+
+.align 4096
+PAYLOAD:
+
+PAYLOAD_END:
+
+END:
diff --git a/src/boot.c b/src/boot.c
@@ -0,0 +1,24 @@
+#include "efi.h"
+
+EFI_IMAGE_ENTRY_POINT(efi_main)
+{
+ efi_status_t status;
+
+#if 1
+ status = system_table->con_out->reset(system_table->con_out, false);
+ if (status != 0)
+ return status;
+
+ status = system_table->con_out->clear_screen(system_table->con_out);
+ if (status != 0)
+ return status;
+#endif
+
+ status = system_table->con_out->output_string(system_table->con_out, u"UEFI");
+ if (status != 0)
+ return status;
+
+ system_table->runtime_services->reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
+
+ return EFI_SUCCESS;
+}
diff --git a/src/boot.ld b/src/boot.ld
@@ -0,0 +1,18 @@
+ENTRY(EntryPoint)
+
+SECTIONS
+{
+ . = 0x40000;
+
+ .header : {
+ *(.header)
+ }
+
+ .text : {
+ *(.text)
+ }
+
+ .data : {
+ *(.data)
+ }
+}
diff --git a/src/kernel-amd64.c b/src/kernel-amd64.c
@@ -0,0 +1,4 @@
+void
+kmain(void)
+{
+}
diff --git a/src/kernel.c b/src/kernel.c
@@ -0,0 +1,7 @@
+extern void kmain(void);
+
+void
+_start(void)
+{
+ kmain();
+}
diff --git a/src/kernel.ld b/src/kernel.ld
@@ -0,0 +1,20 @@
+SECTIONS
+{
+ . = 0x100000;
+
+ .text : {
+ *(.text)
+ }
+
+ .data : {
+ *(.data)
+ }
+
+ .rodata : {
+ *(.rodata)
+ }
+
+ .bss : {
+ *(.bss)
+ }
+}
diff --git a/toolchain.sh b/toolchain.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+. "$(dirname $0)/config.sh"
+
+TARGET=""
+case $ARCH in
+ amd64)
+ TARGET="x86_64-unknown-elf"
+ ;;
+
+ aarch64)
+ TARGET="aarch64-unknown-elf"
+ ;;
+
+ riscv64)
+ TARGET="riscv64-unknown-elf"
+ ;;
+
+ *)
+ echo "Unsupported architecture: $ARCH. Please see config.sh for all supported architectures"
+ exit 1
+ ;;
+esac
+
+export CC="clang"
+export CXX="clang++"
+export LD="ld.lld"
+export OBJCOPY="llvm-objcopy"
+
+export ASFLAGS="--target=$TARGET"
+export CFLAGS="--target=$TARGET -ffreestanding -nostdlib -nostdinc"
+export CXXFLAGS="--target=$TARGET -ffreestanding -nostdlib -nostdinc"
+export CPPFLAGS="-DEARCH=$ARCH -Iinclude"
+export LDFLAGS=""