summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2025-01-23 00:24:57 +0000
committerAda Christine <adachristine18@gmail.com>2025-01-23 00:24:57 +0000
commitd855c0a219a180497c2e50f9bc19bfce69b937a6 (patch)
tree1ff8523d41b222fb356fb3404d2a53c26a7d6a3d
parentedd52bd1464ee9ae4f0cdf7ff90a20ca175580fe (diff)
it printfs with the efi interface
-rw-r--r--Makefile9
-rw-r--r--README.md14
-rw-r--r--api/lib/elf.h30
-rw-r--r--api/libc/stdlib.h3
-rw-r--r--api/libc/wchar.h2
-rw-r--r--api/posix/sys/mman.h2
-rw-r--r--boot/Makefile4
-rw-r--r--boot/config.h4
-rw-r--r--boot/efi/bind.c52
-rw-r--r--boot/efi/fexecve.c23
-rw-r--r--boot/efi/file.c2
-rw-r--r--boot/efi/handle.h19
-rw-r--r--boot/efi/image.c105
-rw-r--r--boot/efi/start.c18
-rw-r--r--boot/efi/status.h110
-rw-r--r--boot/efi/system_table.h31
-rw-r--r--boot/efi/table.h26
-rwxr-xr-xdebug.sh42
-rw-r--r--defaults.mk2
-rw-r--r--kc/core/Makefile2
-rw-r--r--kjarna.txt6
-rw-r--r--lib/elf64.c196
-rw-r--r--lib/heap.c39
-rw-r--r--lldbscript7
-rwxr-xr-xqemu.sh47
-rw-r--r--service/Makefile2
-rw-r--r--service/arch/x86_64/rtld_link.S2
-rw-r--r--service/config.h6
-rw-r--r--service/kjarna.c9
-rw-r--r--service/main.c39
30 files changed, 679 insertions, 174 deletions
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 <stdbool.h>
#include <stddef.h>
+#include <posix/sys/types.h>
+
#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 <stddef.h>
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 <stddef.h>
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 <posix/unistd.h>
+#include <api/elf/elf64.h>
+
+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 <posix/fcntl.h>
#include <kjarna/interface.h>
#include <libc/string.h>
+#include <libc/stdio.h>
+#include <libc/stdlib.h>
#include <lib/elf.h>
+#include <posix/unistd.h>
+#include <posix/sys/mman.h>
#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(&params);
}
- 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 <efi/tables.h>
#include "../kjarna.h"
+#include "../config.h"
+
+#include <libc/stdio.h>
#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 <cstddef>
+#include <limits>
+#include <type_traits>
+
+namespace Efi
+{
+ class Status
+ {
+ using size_t = std::size_t;
+ using ssize_t = std::make_signed_t<size_t>;
+
+ size_t m_Value;
+
+ constexpr Status(size_t value)
+ : m_Value(value)
+ {
+ }
+
+ constexpr bool IsError() const
+ {
+ return static_cast<ssize_t>(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<ssize_t>::min();
+ return Status(static_cast<size_t>(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 <cstddef>
+#include <cstdint>
+
+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 <stdbool.h>
+#include <libc/stdlib.h>
#include <lib/elf.h>
+#include <posix/unistd.h>
-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 <string.h>
+#include <stdlib.h>
+
+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 <unistd.h>
#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
-#define KJARNA_REVISION 1
+#include "config.h"
+#include <lib/elf.h>
+
+/*
+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;
}