From d855c0a219a180497c2e50f9bc19bfce69b937a6 Mon Sep 17 00:00:00 2001 From: Ada Christine Date: Thu, 23 Jan 2025 00:24:57 +0000 Subject: it printfs with the efi interface --- Makefile | 9 +- README.md | 14 +-- api/lib/elf.h | 30 +++++- api/libc/stdlib.h | 3 + api/libc/wchar.h | 2 +- api/posix/sys/mman.h | 2 + boot/Makefile | 4 +- boot/config.h | 4 + boot/efi/bind.c | 52 +++++++++++ boot/efi/fexecve.c | 23 +++++ boot/efi/file.c | 2 +- boot/efi/handle.h | 19 ++++ boot/efi/image.c | 105 +++++---------------- boot/efi/start.c | 18 +++- boot/efi/status.h | 110 ++++++++++++++++++++++ boot/efi/system_table.h | 31 +++++++ boot/efi/table.h | 26 ++++++ debug.sh | 42 +-------- defaults.mk | 2 +- kc/core/Makefile | 2 + kjarna.txt | 6 ++ lib/elf64.c | 196 +++++++++++++++++++++++++++++++++------- lib/heap.c | 39 ++++++++ lldbscript | 7 ++ qemu.sh | 47 ++++++++++ service/Makefile | 2 +- service/arch/x86_64/rtld_link.S | 2 + service/config.h | 6 ++ service/kjarna.c | 9 ++ service/main.c | 39 +++++++- 30 files changed, 679 insertions(+), 174 deletions(-) create mode 100644 boot/config.h create mode 100644 boot/efi/bind.c create mode 100644 boot/efi/fexecve.c create mode 100644 boot/efi/handle.h create mode 100644 boot/efi/status.h create mode 100644 boot/efi/system_table.h create mode 100644 boot/efi/table.h create mode 100644 kjarna.txt create mode 100644 lib/heap.c create mode 100644 lldbscript create mode 100755 qemu.sh create mode 100644 service/config.h diff --git a/Makefile b/Makefile index e27f920..89bfa4d 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,11 @@ BOOT_FILE := $(BOOT_DIR)/kjarna.efi SERVICE_DIR := service SERVICE_FILE := $(SERVICE_DIR)/kjarna.os -TARGETS := $(SERVICE_FILE) $(BOOT_FILE) -DIRS := $(SERVICE_DIR) $(BOOT_DIR) +CORE_DIR := kc/core +CORE_FILE := $(CORE_DIR)/kernel.os + +TARGETS := $(SERVICE_FILE) $(BOOT_FILE) $(CORE_FILE) +DIRS := $(SERVICE_DIR) $(BOOT_DIR) $(CORE_DIR) DIRS_CLEAN := $(addprefix clean-,$(DIRS)) DIRS_DISTCLEAN := $(addprefix dist,$(DIRS_CLEAN)) @@ -23,5 +26,5 @@ $(DIRS_DISTCLEAN): distclean-%: $(TARGETS): $(MAKE) -C $(dir $@) -.PHONY: all clean distclean $(DIRS) $(DIRS_CLEAN) $(DIRS_DISTCLEAN) +.PHONY: all clean distclean $(TARGETS) $(DIRS) $(DIRS_CLEAN) $(DIRS_DISTCLEAN) diff --git a/README.md b/README.md index bb672a0..d8083ad 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -# sophia -uefi bootloader and kernel for x64 +# kjarna +uefi bootloader and kernel for x86\_64 ## how to use in order to use this you will require the following: -- clang 9.0+ -- gnu binutils -- qemu supporting x86\_64 -- an OVMF installation usable as a firmware for qemu +- clang 16.0+ +- gnu ld.bfd +- qemu +- OVMF generally it is only currently possible to build from a POSIX-like system. this is not a rule, but i do not currently support any other means @@ -22,6 +22,8 @@ please feel free to create your own fork and send a PR. sophia is copyright-free for educational and personal use +additional copyrights apply to included code and data + ## ACPICA copyright notice this project uses portions of the ACPI Component Architecture diff --git a/api/lib/elf.h b/api/lib/elf.h index 951fc25..ea0d6cc 100644 --- a/api/lib/elf.h +++ b/api/lib/elf.h @@ -5,13 +5,37 @@ #include #include +#include + #ifdef __x86_64__ # define elf_validate elf64_validate # define elf_size elf64_size #endif -bool elf64_validate(Elf64_Ehdr *ehdr, unsigned type, unsigned machine); -size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdr); -void *elf64_dt_ptr(void *base, Elf64_Dyn *dyntab, unsigned long dt_type); +struct linear_buffer +{ + char *base; + size_t length; +}; + +struct elf64_image +{ + struct linear_buffer buffer; + struct + { + Elf64_Ehdr *file; + Elf64_Phdr *segments; + Elf64_Shdr *sections; + } + headers; +}; + +bool elf64_validate(Elf64_Ehdr const *ehdr, unsigned type, unsigned machine); +bool elf64_validate_fd(int fd, unsigned type, unsigned machine); +size_t elf64_size(Elf64_Ehdr const *ehdr, Elf64_Phdr *phdr); +size_t elf64_size_fd(int fd); +ssize_t elf64_load_segments(int fd, size_t buffer_size, char buffer[buffer_size]); +void *elf64_dt_ptr(char *base, Elf64_Dyn *dyntab, unsigned long dt_type); uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type); +struct elf64_image elf64_open(const char *path); diff --git a/api/libc/stdlib.h b/api/libc/stdlib.h index 76a78eb..d1f3d3b 100644 --- a/api/libc/stdlib.h +++ b/api/libc/stdlib.h @@ -3,4 +3,7 @@ #include size_t mbstowcs(wchar_t *dst, const char *src, size_t length); +void *malloc(size_t size); +void *calloc(size_t count, size_t size); +void free(void *block); diff --git a/api/libc/wchar.h b/api/libc/wchar.h index 4dd339d..350c209 100644 --- a/api/libc/wchar.h +++ b/api/libc/wchar.h @@ -3,4 +3,4 @@ #include size_t wcslen(const wchar_t *s); - +wchar_t *wcsdup(const wchar_t *s); diff --git a/api/posix/sys/mman.h b/api/posix/sys/mman.h index dde74c0..dd8d6f5 100644 --- a/api/posix/sys/mman.h +++ b/api/posix/sys/mman.h @@ -1,5 +1,7 @@ #pragma once +#define MAP_FAILED ((void *) 1) + void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length); diff --git a/boot/Makefile b/boot/Makefile index 482744f..7f4be6b 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -19,8 +19,8 @@ LDFLAGS := --target=$(ARCH)-unknown-windows -nostdlib -ggdb \ all: $(IMAGE) -CRT_OBJS := start.o -LIB_OBJS := memcmp.o memset.o memcpy.o memmove.o string.o elf64.o +CRT_OBJS := start.o bind.o +LIB_OBJS := memcmp.o memset.o memcpy.o memmove.o string.o elf64.o printf.o stdio.o EFI_OBJS := file.o memory.o protocol.o image.o APP_OBJS := main.o diff --git a/boot/config.h b/boot/config.h new file mode 100644 index 0000000..b58bbd1 --- /dev/null +++ b/boot/config.h @@ -0,0 +1,4 @@ +#pragma once + +//#define DEBUG_WAIT + diff --git a/boot/efi/bind.c b/boot/efi/bind.c new file mode 100644 index 0000000..53522a5 --- /dev/null +++ b/boot/efi/bind.c @@ -0,0 +1,52 @@ +#include "kjarna_efi.h" + +int open(const char *path, int flags, int mode) +{ + return efi_open(path, flags, mode); +} + +int close(int fd) +{ + return efi_close(fd); +} + +off_t lseek(int fd, off_t offset, int whence) +{ + return efi_lseek(fd, offset, whence); +} + +ssize_t read(int fd, void *buffer, size_t length) +{ + return efi_read(fd, buffer, length); +} + +ssize_t write(int fd, const void *buffer, size_t length) +{ + return efi_write(fd, buffer, length); +} + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) +{ + return efi_mmap(addr, length, prot, flags, fd, offset); +} + +int munmap(void *addr, size_t length) +{ + return efi_munmap(addr, length); +} + +void *malloc(size_t size) +{ + return efi_alloc_pool(size); +} + +void *calloc(size_t count, size_t size) +{ + return efi_calloc_pool(count, size); +} + +void free(void *block) +{ + efi_free_pool(block); +} + diff --git a/boot/efi/fexecve.c b/boot/efi/fexecve.c new file mode 100644 index 0000000..57cb035 --- /dev/null +++ b/boot/efi/fexecve.c @@ -0,0 +1,23 @@ +#include +#include + +int fexecve(int fd, char *const argv[] char *const envp[]) +{ + (void)argv; + (void)envp; + + if (!elf64_validate_fd(fd, ET_DYN, EM_X86_64)) + { + return -1; + } + + size_t memsz; + + if ((memsz = elf64_size_fd(fd)) == 0) + { + return -1; + } + + +} + diff --git a/boot/efi/file.c b/boot/efi/file.c index 9178654..e45ce78 100644 --- a/boot/efi/file.c +++ b/boot/efi/file.c @@ -78,7 +78,7 @@ int efi_open(const char *path, int flags, int mode) { static EFI_GUID lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; static EFI_GUID sfsp_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; - + EFI_LOADED_IMAGE_PROTOCOL *lip = efi_get_protocol(efi_context->handle, &lip_guid); if (lip == nullptr) diff --git a/boot/efi/handle.h b/boot/efi/handle.h new file mode 100644 index 0000000..1381a30 --- /dev/null +++ b/boot/efi/handle.h @@ -0,0 +1,19 @@ +#pragma once + +extern "C" +{ + struct efi_handle + { + void *m_Value; + }; +} + +namespace Efi +{ + class Handle : private efi_handle + { + public: + Handle(efi_handle &); + }; +} + diff --git a/boot/efi/image.c b/boot/efi/image.c index 42dab7d..25e1911 100644 --- a/boot/efi/image.c +++ b/boot/efi/image.c @@ -2,7 +2,11 @@ #include #include #include +#include +#include #include +#include +#include #include "kjarna_efi.h" @@ -16,77 +20,26 @@ struct image_buffer size_t length; }; -static ssize_t read_ehdr(int fd, Elf64_Ehdr *ehdr) +static int create_image_buffer(int fd, struct image_buffer *buffer) { - ssize_t result; - - if (efi_lseek(fd, 0, SEEK_SET) == -1) - { - return -1; - } - else if ((result = efi_read(fd, ehdr, sizeof(*ehdr))) == -1) + if ((buffer->length = elf64_size_fd(fd)) == 0) { return -1; } - else if (!elf64_validate(ehdr, ET_DYN, EM_X86_64)) - { - return -1; - } - - return result; -} -static ssize_t read_phdrs(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs) -{ - if (efi_lseek(fd, ehdr->e_phoff, SEEK_SET) != -1) - { - return efi_read(fd, phdrs, ehdr->e_phnum * ehdr->e_phentsize); - } - - return -1; -} - -static void create_image_buffer(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs, struct image_buffer *buffer) -{ - buffer->length = elf64_size(ehdr, phdrs); - buffer->base = efi_mmap(nullptr, buffer->length, 0, 0, -1, 0); -} + printf("creating image buffer, %d bytes\n", buffer->length); -static ssize_t load_segment(int fd, Elf64_Phdr *phdr, char *buffer) -{ - if (efi_lseek(fd, phdr->p_offset, SEEK_SET) == -1) + if((buffer->base = mmap(nullptr, buffer->length, 0, 0, -1, 0)) == MAP_FAILED) { + buffer->length = 0; + buffer->base = nullptr; + return -1; } - int result = efi_read(fd, &buffer[phdr->p_offset], phdr->p_filesz); + printf("image buffer base %p\n", buffer->base); - if (result > 0 && phdr->p_memsz > phdr->p_filesz) - { - memset(&buffer[phdr->p_offset + phdr->p_filesz], 0, phdr->p_memsz - phdr->p_filesz); - } - - return result; -} - -static ssize_t load_segments(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs, char *buffer) -{ - int i; - - for (i = 0; i < ehdr->e_phnum; i++) - { - if (phdrs[i].p_type != PT_LOAD) - { - continue; - } - - if (load_segment(fd, &phdrs[i], buffer) == -1) - { - return -1; - } - } - - return i; + return 0; } static struct image_buffer load_image(void) @@ -97,37 +50,29 @@ static struct image_buffer load_image(void) struct image_buffer buffer = { nullptr, 0 }; - if ((image_fd = efi_open(image_entry_path, O_RDONLY, 0)) == -1) + if ((image_fd = open(image_entry_path, O_RDONLY, 0)) == -1) { return buffer; } - Elf64_Ehdr ehdr; - - if (read_ehdr(image_fd, &ehdr) == -1) + if (!elf64_validate_fd(image_fd, ET_DYN, EM_X86_64)) { return buffer; } - - Elf64_Phdr *phdrs = efi_calloc_pool(ehdr.e_phnum, ehdr.e_phentsize); - - if (phdrs == nullptr) + + if (create_image_buffer(image_fd, &buffer) < 0) { return buffer; } - else if(read_phdrs(image_fd, &ehdr, phdrs) != -1) - { - create_image_buffer(&ehdr, phdrs, &buffer); - } - if (buffer.base != nullptr && load_segments(image_fd, &ehdr, phdrs, buffer.base) == -1) + if (buffer.base != nullptr && elf64_load_segments(image_fd, buffer.length, buffer.base) < 0) { - efi_munmap(buffer.base, buffer.length); + printf("error detected: buffer {base: %p, length: %zu}\n", buffer.base, buffer.length); + munmap(buffer.base, buffer.length); buffer.base = nullptr; } - efi_close(image_fd); - efi_free_pool(phdrs); + close(image_fd); return buffer; } @@ -179,17 +124,17 @@ int image_start(void) image_entry(¶ms); } - if (efi_munmap(buffer.base, buffer.length) == -1) + if (munmap(buffer.base, buffer.length) == -1) { - efi_write(STDOUT_FILENO, "failed unmap\r\n", -1); + write(STDOUT_FILENO, "failed unmap\r\n", -1); if (efi_errno == EFI_NOT_FOUND) { - efi_write(STDOUT_FILENO, "not found\r\n", -1); + write(STDOUT_FILENO, "not found\r\n", -1); } else { - efi_write(STDOUT_FILENO, "bad alignment?\r\n", -1); + write(STDOUT_FILENO, "bad alignment?\r\n", -1); } } diff --git a/boot/efi/start.c b/boot/efi/start.c index 8ef8cbe..f1f4ec7 100644 --- a/boot/efi/start.c +++ b/boot/efi/start.c @@ -4,6 +4,9 @@ #include #include "../kjarna.h" +#include "../config.h" + +#include #include "kjarna_efi.h" struct efi_context const *efi_context; @@ -21,12 +24,25 @@ EFI_STATUS _start(EFI_HANDLE handle, EFI_SYSTEM_TABLE *system_table) system_table->ConOut->ClearScreen(system_table->ConOut); +#ifdef DEBUG_WAIT + EFI_GUID lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + EFI_LOADED_IMAGE_PROTOCOL *lip = efi_get_protocol(efi_context->handle, &lip_guid); + + printf("DEBUG: EFI_LOADED_IMAGE_PROTOCOL { .ImageBase = %p }\n", lip->ImageBase); + __asm__ volatile ("movq %0, %%rax" :: "r"(lip->ImageBase) : "rax"); + bool wait = true; + + while(wait) + { + __asm__ ("hlt"); + } +#endif + if (main(0, nullptr) != 0) { efi_errno = EFI_ABORTED; } - return _exit(efi_errno); } diff --git a/boot/efi/status.h b/boot/efi/status.h new file mode 100644 index 0000000..bcb6b96 --- /dev/null +++ b/boot/efi/status.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include + +namespace Efi +{ + class Status + { + using size_t = std::size_t; + using ssize_t = std::make_signed_t; + + size_t m_Value; + + constexpr Status(size_t value) + : m_Value(value) + { + } + + constexpr bool IsError() const + { + return static_cast(m_Value) < 0; + } + + constexpr bool IsWarning() const + { + return m_Value > 0; + } + + constexpr bool IsSuccess() const + { + return m_Value == 0; + } + + constexpr static Status ErrorStatus(size_t code) + { + auto errorBit = std::numeric_limits::min(); + return Status(static_cast(errorBit) | code); + } + + constexpr static Status WarningStatus(size_t code) + { + return Status(code); + } + + public: + + operator size_t() const + { + return m_Value; + } + + static const Status Success; + + class Warning + { + public: + + static const Status UnknownGlyph; + static const Status DeleteFailure; + static const Status WriteFailure; + static const Status BufferTooSmall; + static const Status StaleData; + static const Status FileSystem; + static const Status ResetRequired; + }; + + class Error + { + public: + + static const Status LoadError; + static const Status InvalidParameter; + static const Status Unsupported; + static const Status BadBufferSize; + static const Status BufferTooSmall; + static const Status NotReady; + static const Status DeviceError; + static const Status WriteProtected; + static const Status OutOfResources; + static const Status VolumeCorrupted; + static const Status VolumeFull; + static const Status NoMedia; + static const Status MediaChanged; + static const Status NotFound; + static const Status AccessDenied; + static const Status NoResponse; + static const Status NoMapping; + static const Status Timeout; + static const Status NotStarted; + static const Status AlreadyStarted; + static const Status Aborted; + static const Status IcmpError; + static const Status TftpError; + static const Status ProtocolError; + static const Status IncompatibleVersion; + static const Status SecurityViolation; + static const Status CrcError; + static const Status EndOfMedia; + static const Status EndOfFile; + static const Status InvalidLanguage; + static const Status CompromisedData; + static const Status IpAddressConflict; + static const Status HttpError; + }; + + }; +} + diff --git a/boot/efi/system_table.h b/boot/efi/system_table.h new file mode 100644 index 0000000..93e839d --- /dev/null +++ b/boot/efi/system_table.h @@ -0,0 +1,31 @@ +#pragma once + +#include "table.h" + +extern "C" +{ + struct efi_system_table + { + void *m_Value; + }; +} + +namespace Efi +{ + class SystemTable : private Table + { + char16_t *m_FirmwareVendor; + uint32_t m_FirmwareRevision; + Handle m_ConsoleInHandle; + void *m_ConIn; + Handle m_ConsoleOutHandle; + void *m_ConOut; + Handle m_StandardErrorHandle; + void *m_StdErr; + void *m_RuntimeServices; + void *m_BootServices; + size_t m_NumberOfTableEntries; + void *m_ConfigurationTable; + }; +} + diff --git a/boot/efi/table.h b/boot/efi/table.h new file mode 100644 index 0000000..660bd1e --- /dev/null +++ b/boot/efi/table.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +namespace Efi +{ + class TableHeader + { + using uint64_t = std::uint64_t; + using uint32_t = std::uint32_t; + using size_t = std::size_t; + + uint64_t m_Signature; + uint32_t m_Revision; + uint32_t m_HeaderSize; + uint32_t m_Crc32; + uint32_t m_Reserved; + }; + + class Table + { + TableHeader m_Header; + }; +} + diff --git a/debug.sh b/debug.sh index 7618ba6..4cb0f77 100755 --- a/debug.sh +++ b/debug.sh @@ -1,44 +1,4 @@ #!/usr/bin/env bash -BOOT_DIR=boot -BOOT_FILE=${BOOT_DIR}/kjarna.efi - -SERVICE_DIR=service -SERVICE_FILE=${SERVICE_DIR}/kjarna.os - -FIRMWARE_DIR=/usr/share/ovmf/x64 -FIRMWARE_FILE=${FIRMWARE_DIR}/OVMF_CODE.fd -FIRMWARE_VARS=${FIRMWARE_DIR}/OVMF_VARS.fd - -INSTALL_PREFIX=adasoft/sophia - -make -C ${SERVICE_DIR} && -make -C ${BOOT_DIR} && - -tempdir=$(mktemp -d) && -rundir=${tempdir}/run - -varsfile=${tempdir}/$(basename ${FIRMWARE_VARS}) - -efidir=${rundir}/efi -efibootdir=${efidir}/boot -bootdir=${efidir}/adasoft/kjarna -bootfile=${efibootdir}/BOOTX64.EFI -servdir=${rundir}/service/kjarna - -mkdir -p ${efidir} ${efibootdir} && -mkdir -p ${bootdir} ${servdir} && - -cp ${FIRMWARE_VARS} ${varsfile} && -cp ${BOOT_FILE} ${bootdir} && -cp ${BOOT_FILE} ${bootfile} && -cp ${SERVICE_FILE} ${servdir} && - -qemu-system-x86_64 -d int \ - -drive if=pflash,format=raw,unit=0,file=/usr/share/ovmf/x64/OVMF_CODE.fd,readonly=on \ - -drive if=pflash,format=raw,unit=1,file=${varsfile} \ - -net none -drive file=fat:rw:${rundir} -monitor stdio \ - -serial file:sophia.log -no-shutdown -no-reboot -s -S - -rm -rf ${tempdir} +lldb -s lldbscript diff --git a/defaults.mk b/defaults.mk index 73e8950..585e9ab 100644 --- a/defaults.mk +++ b/defaults.mk @@ -11,7 +11,7 @@ OBJCOPY := objcopy CFLAGS += -ffreestanding -mno-red-zone -ggdb -std=c2x \ -Wall -Wextra -Werror -fno-stack-protector \ - -Wpedantic -std=c2x + -Wpedantic CXXFLAGS += -ffreestanding -mno-red-zone -ggdb \ -Wall -Wextra -Werror -fno-stack-protector diff --git a/kc/core/Makefile b/kc/core/Makefile index f56fc7c..dbbeef1 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -9,6 +9,8 @@ TARGET := kernel.os CPPFLAGS += -I../../api -I../api -I../../lib -I. CFLAGS += -mcmodel=small -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden -g +LDSCRIPT := ../kc.ld + AOBJS := entry_x86_64.o reloc_x86_64.o dynamic_x86_64.o COBJS := mmu.o cpu_task.o irq.o exceptions.o cpu.o msr.o mmu.o port.o POBJS := pic8259.o pic8259_isr.o pit8253.o i8042.o diff --git a/kjarna.txt b/kjarna.txt new file mode 100644 index 0000000..de81165 --- /dev/null +++ b/kjarna.txt @@ -0,0 +1,6 @@ +Kjarna Design Overview + +kjarna.efi - EFI symbol provider +native.os - Native symbol provider +kjarna.os - System executive + diff --git a/lib/elf64.c b/lib/elf64.c index e880179..b5afc18 100644 --- a/lib/elf64.c +++ b/lib/elf64.c @@ -1,43 +1,130 @@ #include +#include #include +#include -bool elf64_validate(Elf64_Ehdr *ehdr, unsigned type, unsigned machine) +static bool is_valid_ident(Elf_Byte const e_ident[EI_NIDENT]) { - if (ehdr->e_ident[EI_MAG0] != ELFMAG0 - || ehdr->e_ident[EI_MAG1] != ELFMAG1 - || ehdr->e_ident[EI_MAG2] != ELFMAG2 - || ehdr->e_ident[EI_MAG3] != ELFMAG3 - || ehdr->e_ident[EI_CLASS] != ELFCLASS64 - || ehdr->e_ident[EI_DATA] != ELFDATA2LSB - || ehdr->e_ident[EI_VERSION] != EV_CURRENT - || ehdr->e_machine != machine - || ehdr->e_type != type) - { - return false; - } + return (e_ident[EI_MAG1] == ELFMAG1 + && e_ident[EI_MAG1] == ELFMAG1 + && e_ident[EI_MAG2] == ELFMAG2 + && e_ident[EI_MAG3] == ELFMAG3 + && e_ident[EI_CLASS] == ELFCLASS64 + && e_ident[EI_DATA] == ELFDATA2LSB + && e_ident[EI_VERSION] == EV_CURRENT); +} + +bool elf64_validate(Elf64_Ehdr const *ehdr, unsigned type, unsigned machine) +{ + return (is_valid_ident(ehdr->e_ident) + && ehdr->e_type == type + && ehdr->e_machine == machine); +} + +static ssize_t read_ehdr(int fd, Elf64_Ehdr *ehdr) +{ + ssize_t pos = lseek(fd, 0, SEEK_CUR); + + ssize_t result; + + if ((result = lseek(fd, 0, SEEK_SET)) == 0) + { + result = read(fd, ehdr, sizeof(*ehdr)); + } + + lseek(fd, pos, SEEK_SET); + + return result; +} + +static ssize_t read_phdr(int fd, Elf64_Ehdr *ehdr, int phdr_index, Elf64_Phdr *phdr) +{ + if (phdr_index > ehdr->e_phnum) + { + return -1; + } + + ssize_t pos = lseek(fd, 0, SEEK_CUR); + + ssize_t offset = ehdr->e_phoff + ehdr->e_phentsize * phdr_index; + + ssize_t result; + + if ((result = lseek(fd, offset, SEEK_SET)) == offset) + { + result = read(fd, phdr, ehdr->e_phentsize); + } + + lseek(fd, pos, SEEK_SET); + + return result; +} + +static ssize_t read_phdrs(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr phdrs[ehdr->e_phnum]) +{ + ssize_t result = 0; + + for (int i = 0; result >= 0 && i < ehdr->e_phnum; i++) + { + result = read_phdr(fd, ehdr, i, &phdrs[i]); + } + + return result; +} + +bool elf64_validate_fd(int fd, unsigned type, unsigned machine) +{ + Elf64_Ehdr ehdr; + read_ehdr(fd, &ehdr); + return elf64_validate(&ehdr, type, machine); +} + +static bool is_loadable(Elf64_Phdr const *phdr) +{ + return phdr != nullptr && phdr->p_type == PT_LOAD; +} + +static size_t aligned_size(Elf64_Phdr const *phdr) +{ + size_t size = phdr->p_offset + phdr->p_memsz; + return (size + phdr->p_align - 1) & ~(phdr->p_align - 1); +} + +static size_t segment_memsz(Elf64_Phdr const *phdr) +{ + return is_loadable(phdr) ? aligned_size(phdr) : 0; +} + +size_t elf64_size(Elf64_Ehdr const *ehdr, Elf64_Phdr *phdrs) +{ + size_t size = 0; + + for (int i = 0; i < ehdr->e_phnum; i++) + { + size_t size_next = segment_memsz(&phdrs[i]); + size = size_next > size ? size_next : size; + } - return true; + return size; } -size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs) +size_t elf64_size_fd(int fd) { - size_t size = 0; + size_t size = 0; - for (int i = 0; i < ehdr->e_phnum; i++) - { - if (phdrs[i].p_type != PT_LOAD) - { - continue; - } + Elf64_Ehdr ehdr; + Elf64_Phdr phdr; - size = phdrs[i].p_offset + phdrs[i].p_memsz; - if (phdrs[i].p_align > 1) - { - size = (size + phdrs[i].p_align - 1) & ~(phdrs[i].p_align - 1); - } - } + ssize_t result = read_ehdr(fd, &ehdr); - return size; + for (int i = 0; result >= 0 && i < ehdr.e_phnum; i++) + { + result = read_phdr(fd, &ehdr, i, &phdr); + size_t size_next = segment_memsz(&phdr); + size = size_next > size ? size_next : size; + } + + return result > 0 ? size : 0; } static Elf64_Dyn *get_dynent(Elf64_Dyn *dyntab, unsigned long dt_type) @@ -55,7 +142,7 @@ static Elf64_Dyn *get_dynent(Elf64_Dyn *dyntab, unsigned long dt_type) return nullptr; } -void *elf64_dt_ptr(void *base, Elf64_Dyn *dyntab, unsigned long dt_type) +void *elf64_dt_ptr(char *base, Elf64_Dyn *dyntab, unsigned long dt_type) { Elf64_Dyn *dynent = get_dynent(dyntab, dt_type); @@ -64,7 +151,7 @@ void *elf64_dt_ptr(void *base, Elf64_Dyn *dyntab, unsigned long dt_type) return nullptr; } - return dynent->d_ptr + (char *)base; + return dynent->d_ptr + base; } uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type) @@ -79,3 +166,50 @@ uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type) return dynent->d_val; } +static ssize_t load_segment(int fd, Elf64_Phdr *phdr, size_t buffer_size, char buffer[buffer_size]) +{ + if (!is_loadable(phdr)) + { + return 0; + } + + ssize_t pos = lseek(fd, 0, SEEK_CUR); + + ssize_t result; + + if ((result = lseek(fd, phdr->p_offset, SEEK_SET)) >= 0) + { + result = read(fd, &buffer[phdr->p_offset], phdr->p_memsz); + } + + lseek(fd, pos, SEEK_SET); + + return result; +} + +ssize_t elf64_load_segments(int fd, size_t buffer_size, char buffer[buffer_size]) +{ + Elf64_Ehdr *ehdr = (Elf64_Ehdr *)&buffer[0]; + + ssize_t result; + + if ((result = read_ehdr(fd, ehdr)) < 0) + { + return result; + } + + Elf64_Phdr *phdrs = (Elf64_Phdr *)&buffer[ehdr->e_phoff]; + + if ((result = read_phdrs(fd, ehdr, phdrs)) < 0) + { + return result; + } + + for (int i = 0; result > 0 && i < ehdr->e_phnum; i++) + { + result = load_segment(fd, &phdrs[i], buffer_size, buffer); + } + + return result; +} + diff --git a/lib/heap.c b/lib/heap.c new file mode 100644 index 0000000..8331a17 --- /dev/null +++ b/lib/heap.c @@ -0,0 +1,39 @@ +#include +#include + +struct heap_node +{ + struct heap_node *next; + size_t size; +}; + +struct heap_head +{ + struct heap_node *first; + size_t total_bytes; + size_t ready_bytes; +}; + +void *malloc(size_t size) +{ + (void)size; + return nullptr; +} + +void *calloc(size_t count, size_t size) +{ + void *block = malloc(count * size); + + if (block != nullptr) + { + memset(block, 0, count * size); + } + + return block; +} + +void free(void *block) +{ + (void)block; +} + diff --git a/lldbscript b/lldbscript new file mode 100644 index 0000000..13842b8 --- /dev/null +++ b/lldbscript @@ -0,0 +1,7 @@ +target create --no-dependents --arch x86_64 boot/kjarna.efi --symfile boot/kjarna.pdb +target modules add service/kjarna.os +gdb-remote localhost:1234 +target modules load --file kjarna.efi .text 0x63ec000 .data 0x63f1000 +target modules load --file kjarna.os --slide 0x63dc000 +b efi_open + diff --git a/qemu.sh b/qemu.sh new file mode 100755 index 0000000..09b0121 --- /dev/null +++ b/qemu.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +BOOT_DIR=boot +BOOT_FILE=${BOOT_DIR}/kjarna.efi + +SERVICE_DIR=service +SERVICE_FILE=${SERVICE_DIR}/kjarna.os + +CORE_DIR=kc/core +CORE_FILE=${CORE_DIR}/kernel.os + +FIRMWARE_DIR=/usr/share/ovmf/x64 +FIRMWARE_FILE=${FIRMWARE_DIR}/OVMF_CODE.4m.fd +FIRMWARE_VARS=${FIRMWARE_DIR}/OVMF_VARS.4m.fd + +INSTALL_PREFIX=adasoft/sophia + +make && + +tempdir=$(mktemp -d) && +rundir=${tempdir}/run + +varsfile=${tempdir}/$(basename ${FIRMWARE_VARS}) + +efidir=${rundir}/efi +efibootdir=${efidir}/boot +bootdir=${efidir}/adasoft/kjarna +bootfile=${efibootdir}/BOOTX64.EFI +servdir=${rundir}/service/kjarna + +mkdir -p ${efidir} ${efibootdir} && +mkdir -p ${bootdir} ${servdir} && + +cp ${FIRMWARE_VARS} ${varsfile} && +cp ${BOOT_FILE} ${bootdir} && +cp ${BOOT_FILE} ${bootfile} && +cp ${SERVICE_FILE} ${servdir} && +cp ${CORE_FILE} ${servdir} && + +qemu-system-x86_64 -d int \ + -drive if=pflash,format=raw,unit=0,file=${FIRMWARE_FILE},readonly=on \ + -drive if=pflash,format=raw,unit=1,file=${varsfile} \ + -net none -drive file=fat:rw:${rundir} -monitor stdio \ + -serial file:sophia.log -no-shutdown -no-reboot -s + +rm -rf ${tempdir} + diff --git a/service/Makefile b/service/Makefile index 0917b8c..09ff0be 100644 --- a/service/Makefile +++ b/service/Makefile @@ -17,7 +17,7 @@ LDSCRIPT := kjarna.ld CRT_OBJS := start.o rtld_link.o dynamic.o elf64.o kjarna.o LIB_OBJS := memcmp.o memcpy.o memmove.o memset.o string.o stdio.o \ - printf.o + printf.o heap.o APP_OBJS := main.o OBJS := $(CRT_OBJS) $(LIB_OBJS) $(APP_OBJS) diff --git a/service/arch/x86_64/rtld_link.S b/service/arch/x86_64/rtld_link.S index 7300a18..9f86030 100644 --- a/service/arch/x86_64/rtld_link.S +++ b/service/arch/x86_64/rtld_link.S @@ -2,6 +2,8 @@ .extern kc_dynamic_link +// TODO: investigate whether saving r9, r8, rcx and rdx is actually necessary here + .hidden _rtld_link .global _rtld_link .type _rtld_link, @function diff --git a/service/config.h b/service/config.h new file mode 100644 index 0000000..18aa6f8 --- /dev/null +++ b/service/config.h @@ -0,0 +1,6 @@ +#pragma once + +#define KJARNA_REVISION 2 + +const char * const HAL_PATH = "/system/kernel.os"; + diff --git a/service/kjarna.c b/service/kjarna.c index 6b37d1e..1240c97 100644 --- a/service/kjarna.c +++ b/service/kjarna.c @@ -8,6 +8,15 @@ int kjarna_entry(struct kjarna_entry_params *params) { entry_params = params; + __asm__ ("leaq kc_image_base(%%rip), %%rax" ::: "rax"); + + bool wait = true; + + while(wait) + { + __asm__ volatile("hlt"); + } + return main(params->argc, params->argv); } diff --git a/service/main.c b/service/main.c index 12a5522..c022b87 100644 --- a/service/main.c +++ b/service/main.c @@ -1,7 +1,42 @@ #include #include +#include +#include -#define KJARNA_REVISION 1 +#include "config.h" +#include + +/* +static int open_kernel(void) +{ + int kernel_fd = open(HAL_PATH, 0, 0); + + printf("kernel path: %s\n", HAL_PATH); + + if (kernel_fd < 0) + { + printf("error: could not open kernel core\n"); + return -1; + } + + Elf64_Ehdr ehdr; + + if (!elf64_validate_fd(kernel_fd, ET_DYN, EM_X86_64)) + { + printf("error: could not validate elf header\n"); + close(kernel_fd); + return -1; + } + + printf("kernel: elf x86_64 dynamic object found\r\n"); + + ssize_t kernel_size = elf64_size_fd(fd); + + printf("kernel image size %zd\n", kernel_size); + + return kernel_fd; +} +*/ int main(int argc, char **argv) { @@ -10,8 +45,6 @@ int main(int argc, char **argv) printf("kjarna %d\n", KJARNA_REVISION); - while (1); - return 0; } -- cgit v1.3.1-1-g115d