From 141c5e76d12439d2675d2c76e850bb344dea3142 Mon Sep 17 00:00:00 2001 From: karina Date: Mon, 20 Apr 2026 19:29:57 +0400 Subject: [PATCH 01/49] build: now SwiftLSP correctly see bootinfo: --- Kernel/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 507246e..479c26b 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -110,6 +110,8 @@ set(SWIFT_ARGS "\"-module-name\"" "\"${KERNEL_MODULE_NAME}\"" "\"-parse-as-library\"" "\"-import-bridging-header\"" "\"${_BRIDGING_HEADER}\"" + "\"-Xcc\"" "\"-I${CMAKE_CURRENT_SOURCE_DIR}/../Common\"" + "\"-resource-dir\"" "\"${SWIFT_RESOURCE_DIR}\"" ) foreach(_src IN LISTS SWIFT_SOURCES) list(APPEND SWIFT_ARGS "\"${_src}\"") -- 2.52.0 From 0c1585a169bd07ea84112939f723a2dfa9b342da Mon Sep 17 00:00:00 2001 From: karina Date: Mon, 20 Apr 2026 20:51:47 +0400 Subject: [PATCH 02/49] wip: transfer to laptop --- Kernel/CMakeLists.txt | 2 +- Kernel/Source/kernel.swift | 21 +-------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 479c26b..80567d6 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.20) project(ksOSKernel LANGUAGES ASM C) set(KERNEL_MODULE_NAME "Kernel") diff --git a/Kernel/Source/kernel.swift b/Kernel/Source/kernel.swift index 0ed9ce8..a438c9e 100644 --- a/Kernel/Source/kernel.swift +++ b/Kernel/Source/kernel.swift @@ -1,23 +1,4 @@ @_cdecl("kmain") public func kernelMain(_ bootInfo: UnsafeMutablePointer) { - let fb = bootInfo.pointee.framebuffer - - let pixels = fb.base! - - let width = Int(fb.width) - let height = Int(fb.height) - let total = width * height - let stripe = total / 5 - - var i = 0 - while i < total { - let s = i / stripe - let color: UInt32 - if s == 0 || s >= 4 { color = 0x5BCEFA } - else if s == 2 { color = 0xFFFFFF } - else { color = 0xF5A7B8 } - pixels[i] = color - i &+= 1 - } - kprint("Meow prrr meow nyaaa\n") + kprint("Test nya") } -- 2.52.0 From 5e225f8f7f63bed32e732a34bb1d868bab921999 Mon Sep 17 00:00:00 2001 From: Karina Date: Mon, 20 Apr 2026 21:12:27 +0400 Subject: [PATCH 03/49] chore: add vanilla edk2 download for linux --- justfile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/justfile b/justfile index bcd4fbc..0566df1 100644 --- a/justfile +++ b/justfile @@ -17,9 +17,10 @@ CPU := if ARCH_NAME == "aarch64" { "host" } else { "max" } OVMF_ARM := if OS_NAME == "macos" { HB_PREFIX + "/share/qemu/edk2-aarch64-code.fd" } else { - env_var_or_default("OVMF_PATH", "/usr/share/edk2/aarch64/QEMU_EFI.fd") + BUILD_DIR + "/edk2/edk2-aarch64-code.fd" } + DISPLAY_FLAGS := if OS_NAME == "macos" { "-display cocoa,show-cursor=on" } else { @@ -43,6 +44,14 @@ _prep: @mkdir -p {{BUILD_DIR}}/Bootloader @mkdir -p {{TEMP_DIR}}/Bootloader @mkdir -p {{BUILD_DIR}}/Kernel + @if [ "{{OS_NAME}}" != "macos" ]; then \ + mkdir -p {{BUILD_DIR}}/edk2; \ + if [ ! -f "{{OVMF_ARM}}" ]; then \ + echo "⬇️ Downloading vanilla EDK2 for Linux..."; \ + curl -sL -o "{{OVMF_ARM}}.bz2" "https://github.com/qemu/qemu/raw/master/pc-bios/edk2-aarch64-code.fd.bz2"; \ + bzip2 -d "{{OVMF_ARM}}.bz2"; \ + fi \ + fi @build: _prep @echo "🛠️ Building everything..." -- 2.52.0 From a331d395d5bb713ff948e9bee4ca91d20422aef8 Mon Sep 17 00:00:00 2001 From: karina Date: Mon, 20 Apr 2026 23:03:36 +0400 Subject: [PATCH 04/49] refactor: drop posix-uefi from bootloader Replace the vendored POSIX-UEFI runtime with a small local EFI entry and header so the bootloader depends only on the UEFI interfaces it actually uses. Made-with: Cursor --- Bootloader/CMakeLists.txt | 33 +- Bootloader/Source/main.c | 266 ++-- Bootloader/Source/uefi/Makefile | 135 -- Bootloader/Source/uefi/crt_aarch64.c | 239 --- Bootloader/Source/uefi/crt_riscv64.c | 270 ---- Bootloader/Source/uefi/crt_x86_64.c | 241 --- Bootloader/Source/uefi/dirent.c | 76 - Bootloader/Source/uefi/efi_entry.c | 23 + Bootloader/Source/uefi/elf_aarch64_efi.lds | 63 - Bootloader/Source/uefi/elf_riscv64_efi.lds | 64 - Bootloader/Source/uefi/elf_x86_64_efi.lds | 76 - Bootloader/Source/uefi/qsort.c | 154 -- Bootloader/Source/uefi/stat.c | 68 - Bootloader/Source/uefi/stdio.c | 817 ---------- Bootloader/Source/uefi/stdlib.c | 365 ----- Bootloader/Source/uefi/string.c | 262 ---- Bootloader/Source/uefi/time.c | 146 -- Bootloader/Source/uefi/uefi.h | 1614 ++++---------------- Bootloader/Source/uefi/unistd.c | 65 - 19 files changed, 482 insertions(+), 4495 deletions(-) delete mode 100644 Bootloader/Source/uefi/Makefile delete mode 100644 Bootloader/Source/uefi/crt_aarch64.c delete mode 100644 Bootloader/Source/uefi/crt_riscv64.c delete mode 100644 Bootloader/Source/uefi/crt_x86_64.c delete mode 100644 Bootloader/Source/uefi/dirent.c create mode 100644 Bootloader/Source/uefi/efi_entry.c delete mode 100644 Bootloader/Source/uefi/elf_aarch64_efi.lds delete mode 100644 Bootloader/Source/uefi/elf_riscv64_efi.lds delete mode 100644 Bootloader/Source/uefi/elf_x86_64_efi.lds delete mode 100644 Bootloader/Source/uefi/qsort.c delete mode 100644 Bootloader/Source/uefi/stat.c delete mode 100644 Bootloader/Source/uefi/stdio.c delete mode 100644 Bootloader/Source/uefi/stdlib.c delete mode 100644 Bootloader/Source/uefi/string.c delete mode 100644 Bootloader/Source/uefi/time.c delete mode 100644 Bootloader/Source/uefi/unistd.c diff --git a/Bootloader/CMakeLists.txt b/Bootloader/CMakeLists.txt index 930f51c..d8ee154 100644 --- a/Bootloader/CMakeLists.txt +++ b/Bootloader/CMakeLists.txt @@ -1,45 +1,32 @@ cmake_minimum_required(VERSION 3.20) project(ksOS_bootloader LANGUAGES C ASM) -set(UEFI_COMPILE_OPTIONS +set(UEFI_COMPILE_OPTIONS -std=c23 -target aarch64-unknown-windows-msvc -Wall -Wextra -fno-builtin ) -set(POSIX_UEFI_SOURCES - Source/uefi/crt_aarch64.c - Source/uefi/dirent.c - Source/uefi/qsort.c - Source/uefi/stat.c - Source/uefi/stdio.c - Source/uefi/stdlib.c - Source/uefi/string.c - Source/uefi/time.c - Source/uefi/unistd.c +add_executable(BOOTAA64 + Source/uefi/efi_entry.c + Source/main.c ) - -add_library(posix_uefi_lib OBJECT ${POSIX_UEFI_SOURCES}) -target_compile_options(posix_uefi_lib PRIVATE ${UEFI_COMPILE_OPTIONS}) -target_include_directories(posix_uefi_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Source/uefi) - - -add_executable(BOOTAA64 Source/main.c) target_compile_options(BOOTAA64 PRIVATE ${UEFI_COMPILE_OPTIONS}) - -target_link_libraries(BOOTAA64 PRIVATE posix_uefi_lib) +target_include_directories(BOOTAA64 PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/Source + ${CMAKE_CURRENT_SOURCE_DIR}/Source/uefi +) target_link_options(BOOTAA64 PRIVATE -fuse-ld=lld -target aarch64-unknown-windows-msvc -nostdlib -Wl,-subsystem:efi_application - -Wl,-include:uefi_init - -Wl,-entry:uefi_init + -Wl,-entry:efi_main ) -set_target_properties(BOOTAA64 PROPERTIES +set_target_properties(BOOTAA64 PROPERTIES SUFFIX ".EFI" OUTPUT_NAME "BOOTAA64" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/efi_bin" diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index 2f5d06c..05a954f 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -1,144 +1,210 @@ -#include "uefi/uefi.h" // IWYU pragma: keep +#include "uefi/uefi.h" #include "../../Common/bootinfo.h" -void print(wchar_t* msg) { - ST->ConOut->OutputString(ST->ConOut, msg); +#define PAGE_SIZE 0x1000 +#define WSTR(str) ((wchar_t*)L##str) + +static wchar_t* kernel_path = WSTR("ksOSKernel.bin"); +static efi_guid_t dtb_guid = { + 0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0} +}; + +static void print(const wchar_t* msg) { + ST->ConOut->OutputString(ST->ConOut, (wchar_t*)msg); } -efi_status_t die() { - while(1) __asm__ volatile("wfi"); +static efi_status_t die(void) { + while (1) { + __asm__ volatile("wfi"); + } + return EFI_ABORTED; } -int compare_guid(efi_guid_t* a, efi_guid_t* b) { - uint8_t* p1 = (uint8_t*)a; - uint8_t* p2 = (uint8_t*)b; - for (int i = 0; i < 16; i++) { - if (p1[i] != p2[i]) return 0; +static efi_status_t fail(const wchar_t* msg) { + print(msg); + return die(); +} + +static int guid_equal(const efi_guid_t* lhs, const efi_guid_t* rhs) { + const uint8_t* lhs_bytes = (const uint8_t*)lhs; + const uint8_t* rhs_bytes = (const uint8_t*)rhs; + + for (int i = 0; i < 16; ++i) { + if (lhs_bytes[i] != rhs_bytes[i]) { + return 0; + } } + return 1; } -int main() -{ - efi_gop_t* gop = NULL; - efi_guid_t gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; - ST->BootServices->LocateProtocol(&gop_guid, 0, (void**)&gop); - - efi_guid_t dtb_guid = {0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}}; - void* dtbAddress = NULL; - - for (uintn_t i = 0; i < ST->NumberOfTableEntries; i++) { - if (compare_guid(&ST->ConfigurationTable[i].VendorGuid, &dtb_guid)) { - dtbAddress = ST->ConfigurationTable[i].VendorTable; - break; +static void* find_configuration_table(const efi_guid_t* guid) { + for (uintn_t i = 0; i < ST->NumberOfTableEntries; ++i) { + if (guid_equal(&ST->ConfigurationTable[i].VendorGuid, guid)) { + return ST->ConfigurationTable[i].VendorTable; } } - if (!dtbAddress) { - print(L"Failed to find DTB!\r\n"); - return die(); - } + return NULL; +} - efi_loaded_image_protocol_t* loaded_image; - efi_guid_t lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; - gBS->HandleProtocol(IM, &lip_guid, (void**)&loaded_image); - - efi_simple_file_system_protocol_t* fs; - efi_guid_t sfsp_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; - gBS->HandleProtocol(loaded_image->DeviceHandle, &sfsp_guid, (void**)&fs); - - efi_file_handle_t* root; - fs->OpenVolume(fs, &root); - - efi_file_handle_t* kernel_file; - uintn_t kinfo_size = 0; - efi_file_info_t* kfile_info = NULL; - efi_guid_t fi_guid = EFI_FILE_INFO_GUID; - - efi_status_t status = root->Open(root, &kernel_file, L"ksOSKernel.bin", EFI_FILE_MODE_READ, 0); +static efi_status_t open_root_volume(efi_file_handle_t** root) { + efi_loaded_image_protocol_t* loaded_image = NULL; + efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + efi_status_t status = gBS->HandleProtocol(IM, &loaded_image_guid, (void**)&loaded_image); if (EFI_ERROR(status)) { - print(L"Cant find ksOSKernel.bin\r\n"); - return die(); + return status; } - status = kernel_file->GetInfo(kernel_file, &fi_guid, &kinfo_size, NULL); - if (status == EFI_BUFFER_TOO_SMALL) { - gBS->AllocatePool(EfiLoaderData, kinfo_size, (void**)&kfile_info); - status = kernel_file->GetInfo(kernel_file, &fi_guid, &kinfo_size, kfile_info); - } - - uint64_t kernel_size = kfile_info->FileSize; - uintn_t kernel_size_read = (uintn_t)kernel_size; - - uintn_t kernel_pages = (kernel_size + 0xFFF) / 0x1000; - efi_physical_address_t kernel_addr = 0; - - status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel_pages, &kernel_addr); + efi_simple_file_system_protocol_t* fs = NULL; + efi_guid_t filesystem_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; + status = gBS->HandleProtocol(loaded_image->DeviceHandle, &filesystem_guid, (void**)&fs); if (EFI_ERROR(status)) { - print(L"Failed to allocate ANY memory for kernel!\r\n"); - return die(); + return status; } - kernel_file->Read(kernel_file, &kernel_size_read, (void*)kernel_addr); \ - printf("Kernel loaded at %p\r\n", (void*)kernel_addr); + return fs->OpenVolume(fs, root); +} - Bootinfo* bootInfo = (Bootinfo*)malloc(sizeof(Bootinfo)); - bootInfo->magic = BOOTINFO_MAGIC; +static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** file_info) { + efi_guid_t file_info_guid = EFI_FILE_INFO_GUID; + uintn_t file_info_size = 0; + efi_status_t status = file->GetInfo(file, &file_info_guid, &file_info_size, NULL); + if (status != EFI_BUFFER_TOO_SMALL) { + return status; + } - bootInfo->kernelInfo.kernelAddress = (void*)kernel_addr; - bootInfo->kernelInfo.kernelSize = kernel_size; + status = gBS->AllocatePool(EfiLoaderData, file_info_size, (void**)file_info); + if (EFI_ERROR(status)) { + return status; + } - bootInfo->framebuffer.base = (BIUInt32*)gop->Mode->FrameBufferBase; - bootInfo->framebuffer.baseSize = gop->Mode->FrameBufferSize; - bootInfo->framebuffer.height = gop->Mode->Information->VerticalResolution; - bootInfo->framebuffer.width = gop->Mode->Information->HorizontalResolution; - bootInfo->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine; + return file->GetInfo(file, &file_info_guid, &file_info_size, *file_info); +} - bootInfo->dtb = dtbAddress; - printf("DTB located at: %p\r\n", (void*)dtbAddress); - +static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size) { + efi_file_handle_t* kernel_file = NULL; + efi_file_info_t* kernel_info = NULL; + efi_status_t status = root->Open(root, &kernel_file, kernel_path, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(status)) { + return status; + } + + status = read_file_info(kernel_file, &kernel_info); + if (EFI_ERROR(status)) { + return status; + } + + *kernel_size = kernel_info->FileSize; + + uintn_t bytes_to_read = (uintn_t)*kernel_size; + uintn_t kernel_pages = (*kernel_size + PAGE_SIZE - 1) / PAGE_SIZE; + *kernel_addr = 0; + + status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel_pages, kernel_addr); + if (EFI_ERROR(status)) { + return status; + } + + status = kernel_file->Read(kernel_file, &bytes_to_read, (void*)*kernel_addr); + if (EFI_ERROR(status) || bytes_to_read != (uintn_t)*kernel_size) { + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +static efi_status_t populate_memory_map(Bootinfo* boot_info) { uintn_t map_size = 0; - efi_memory_descriptor_t *map = NULL; - uintn_t map_key; - uintn_t desc_size; - uint32_t desc_version; + efi_memory_descriptor_t* map = NULL; + uintn_t map_key = 0; + uintn_t descriptor_size = 0; + uint32_t descriptor_version = 0; + efi_status_t status = gBS->GetMemoryMap(&map_size, NULL, &map_key, &descriptor_size, &descriptor_version); + if (status != EFI_BUFFER_TOO_SMALL) { + return status; + } - print(L"Almost ready to jump :D. Working with memory map\r\n"); - - gBS->GetMemoryMap(&map_size, NULL, &map_key, &desc_size, &desc_version); - map_size += 4096; - // woah letsgoo + map_size += PAGE_SIZE; status = gBS->AllocatePool(EfiLoaderData, map_size, (void**)&map); if (EFI_ERROR(status)) { - print(L"Failed to allocate pool\r\n"); + return status; } - do { - status = gBS->GetMemoryMap(&map_size, map, &map_key, &desc_size, &desc_version); + while (1) { + status = gBS->GetMemoryMap(&map_size, map, &map_key, &descriptor_size, &descriptor_version); if (EFI_ERROR(status)) { - break; + return status; } - - bootInfo->memoryMap.descriptorSize = desc_size; - bootInfo->memoryMap.descriptorVersion = desc_version; - bootInfo->memoryMap.mapSize = map_size; - bootInfo->memoryMap.mapKey = map_key; - bootInfo->memoryMap.map = map; + + boot_info->memoryMap.descriptorSize = descriptor_size; + boot_info->memoryMap.descriptorVersion = descriptor_version; + boot_info->memoryMap.mapSize = map_size; + boot_info->memoryMap.mapKey = map_key; + boot_info->memoryMap.map = map; status = gBS->ExitBootServices(IM, map_key); if (status == EFI_SUCCESS) { - break; // FUCK OFF; + return EFI_SUCCESS; } - map_size += 2 * desc_size; - } while (EFI_ERROR(status)); - typedef void (__attribute__((sysv_abi)) *kentry)(Bootinfo*); - kentry kmain = (kentry)kernel_addr; + map_size += 2 * descriptor_size; + } +} - kmain(bootInfo); // yay! :D +efi_status_t bootloader_main(void) { + efi_gop_t* gop = NULL; + efi_guid_t gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + efi_status_t status = ST->BootServices->LocateProtocol(&gop_guid, 0, (void**)&gop); + if (EFI_ERROR(status) || gop == NULL) { + return fail(WSTR("Failed to locate GOP\r\n")); + } + void* dtb_address = find_configuration_table(&dtb_guid); + if (dtb_address == NULL) { + return fail(WSTR("Failed to find DTB\r\n")); + } + + efi_file_handle_t* root = NULL; + status = open_root_volume(&root); + if (EFI_ERROR(status)) { + return fail(WSTR("Failed to open boot volume\r\n")); + } + + efi_physical_address_t kernel_addr = 0; + uint64_t kernel_size = 0; + status = load_kernel(root, &kernel_addr, &kernel_size); + if (EFI_ERROR(status)) { + return fail(WSTR("Failed to load ksOSKernel.bin\r\n")); + } + + Bootinfo* boot_info = NULL; + status = gBS->AllocatePool(EfiLoaderData, sizeof(Bootinfo), (void**)&boot_info); + if (EFI_ERROR(status) || boot_info == NULL) { + return fail(WSTR("Failed to allocate boot info\r\n")); + } + + boot_info->magic = BOOTINFO_MAGIC; + boot_info->kernelInfo.kernelAddress = (void*)kernel_addr; + boot_info->kernelInfo.kernelSize = kernel_size; + boot_info->framebuffer.base = (BIUInt32*)gop->Mode->FrameBufferBase; + boot_info->framebuffer.baseSize = gop->Mode->FrameBufferSize; + boot_info->framebuffer.height = gop->Mode->Information->VerticalResolution; + boot_info->framebuffer.width = gop->Mode->Information->HorizontalResolution; + boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine; + boot_info->dtb = dtb_address; + + print(WSTR("Almost ready to jump. Reading memory map\r\n")); + status = populate_memory_map(boot_info); + if (EFI_ERROR(status)) { + return fail(WSTR("Failed to exit boot services\r\n")); + } + + typedef void (*kernel_entry_t)(Bootinfo*); + kernel_entry_t kernel_main = (kernel_entry_t)kernel_addr; + kernel_main(boot_info); return EFI_SUCCESS; } \ No newline at end of file diff --git a/Bootloader/Source/uefi/Makefile b/Bootloader/Source/uefi/Makefile deleted file mode 100644 index 64952c1..0000000 --- a/Bootloader/Source/uefi/Makefile +++ /dev/null @@ -1,135 +0,0 @@ -# detect architecture -MYARCH = $(shell uname -m | sed s,i[3456789]86,ia32, | sed s,amd,x86_,) -ifeq ($(ARCH),) -ARCH = $(MYARCH) -endif - -# get source files, generate object names -ifeq ($(SRCS),) -SRCS = $(wildcard *.c) $(wildcard *.S) -endif -ifeq ($(OBJS),) -TMP = $(SRCS:.c=.o) -OBJS = $(TMP:.S=.o) -endif -ifneq ($(OUTDIR),) -# OUTDIR is not used with uefi/*.o deliberately -OUTDIR:=$(addsuffix /,$(OUTDIR)) -endif -CFLAGS += -fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -I. -I./uefi \ - -I/usr/include -I/usr/include/efi -I/usr/include/efi/protocol -I/usr/include/efi/$(ARCH) -D__$(ARCH)__ -ifeq ($(ARCH),x86_64) -CFLAGS += -DHAVE_USE_MS_ABI -mno-red-zone -endif - -# for libuefi.a -LIBSRCS = $(filter-out $(wildcard crt_*.c),$(wildcard *.c)) $(wildcard *.S) -TMP2 = $(LIBSRCS:.c=.o) -LIBOBJS = $(TMP2:.S=.o) -MAKE ?= make - -# detect toolchain -ifeq ($(wildcard /usr/bin/clang)$(wildcard /usr/local/bin/clang)$(wildcard /usr/lib/llvm/*/bin/clang)$(wildcard /gnu/store/*/bin/clang),) -USE_GCC = 1 -endif -ifneq ($(USE_GCC),) -ifeq ($(ARCH),x86_64) -CFLAGS += -maccumulate-outgoing-args -endif -CFLAGS += -Wno-builtin-declaration-mismatch -fpic -fPIC -LDFLAGS += -nostdlib -shared -Bsymbolic -Luefi uefi/crt_$(ARCH).o -LIBS += -o $(addprefix $(OUTDIR),$(TARGET).so) -luefi -T uefi/elf_$(ARCH)_efi.lds -# see if we're cross-compiling -ifneq ($(ARCH),$(MYARCH)) -CC = $(ARCH)-elf-gcc -LD = $(ARCH)-elf-ld -OBJCOPY ?= $(ARCH)-elf-objcopy -else -CC = gcc -LD = ld -OBJCOPY ?= objcopy -endif -ifeq ($(ARCH),aarch64) -EFIARCH = pei-aarch64-little -else -ifeq ($(ARCH),riscv64) -EFIARCH = pei-riscv64-little -else -EFIARCH = efi-app-$(ARCH) -endif -endif -AR ?= ar -else -CFLAGS += --target=$(ARCH)-pc-win32-coff -Wno-builtin-requires-header -Wno-incompatible-library-redeclaration -Wno-long-long -LDFLAGS += -subsystem:efi_application -nodefaultlib -dll -entry:uefi_init uefi/*.o -LIBS = -out:$(addprefix $(OUTDIR),$(TARGET)) -CC = clang -LD = lld -flavor link -OBJCOPY = true -endif - -# recipies -ifeq ($(wildcard uefi/Makefile),) -ALLTARGETS = crt_$(ARCH).o libuefi.a buildlib -else -ALLTARGETS = uefi/crt_$(ARCH).o uefi/libuefi.a $(OBJS) $(TARGET) -endif - -all: $(OUTDIR) $(EXTRA) $(ALLTARGETS) $(ALSO) - -ifneq ($(OUTDIR),) -$(OUTDIR): - @mkdir -p $(OUTDIR) -endif - -uefi/libuefi.a: - @$(MAKE) --no-print-directory -C uefi libuefi.a USE_GCC=$(USE_GCC) ARCH=$(ARCH) - -libuefi.lib: $(LIBOBJS) - -libuefi.a: $(LIBOBJS) - @rm $@ 2>/dev/null || true - $(AR) -rsv $@ $(LIBOBJS) >/dev/null - -$(TARGET): $(addprefix $(OUTDIR),$(TARGET).so) -ifneq ($(USE_GCC),) - $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target $(EFIARCH) --subsystem=10 $^ $(addprefix $(OUTDIR),$@) || echo target: $(EFIARCH) - @rm $(addprefix $(OUTDIR),$(TARGET).so) -endif - -$(addprefix $(OUTDIR),$(TARGET).so): $(addprefix $(OUTDIR),$(OBJS)) $(EXTRA) - $(LD) $(LDFLAGS) $^ $(LIBS) - @rm $(addprefix $(OUTDIR),*.lib) 2>/dev/null || true - -uefi/%.o: uefi/%.c - $(CC) $(CFLAGS) -c $< -o $@ - -%.o: %.c - $(CC) $(CFLAGS) -c $< -o $(addprefix $(OUTDIR),$@) - -%.o: %.S - $(CC) $(CFLAGS) -c $< -o $(addprefix $(OUTDIR),$@) - -buildlib: - @mkdir ../build ../build/uefi 2>/dev/null || true - @cp crt_$(ARCH).o ../build/uefi/crt0.o - @cp elf_$(ARCH)_efi.lds ../build/uefi/link.ld -ifneq ($(USE_GCC),) - @cp libuefi.a uefi.h ../build/uefi -else - @cp uefi.h ../build/uefi - @cp libuefi.a ../build/uefi/libuefi.dll.a -endif - -clean: - @rm $(addprefix $(OUTDIR),$(TARGET)) *.o *.a *.lib *.elf $(LIBOBJS) 2>/dev/null || true -ifneq ($(OUTDIR),) - @rm -rf $(OUTDIR) -endif - -distclean: clean -ifeq ($(wildcard uefi/Makefile),) - @rm -rf ../build 2>/dev/null || true -else - @rm uefi/*.o uefi/libuefi.a 2>/dev/null || true -endif diff --git a/Bootloader/Source/uefi/crt_aarch64.c b/Bootloader/Source/uefi/crt_aarch64.c deleted file mode 100644 index 82324a5..0000000 --- a/Bootloader/Source/uefi/crt_aarch64.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * crt_aarch64.c - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief C runtime, bootstraps an EFI application to call standard main() - * - */ - -#include - -/* this is implemented by the application */ -extern int main(int argc, char_t **argv); - -/* definitions for elf relocations */ -#ifndef __clang__ -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; -typedef uint64_t Elf64_Addr; -typedef struct -{ - Elf64_Sxword d_tag; /* Dynamic entry type */ - union - { - Elf64_Xword d_val; /* Integer value */ - Elf64_Addr d_ptr; /* Address value */ - } d_un; -} Elf64_Dyn; -#define DT_NULL 0 /* Marks end of dynamic section */ -#define DT_RELA 7 /* Address of Rela relocs */ -#define DT_RELASZ 8 /* Total size of Rela relocs */ -#define DT_RELAENT 9 /* Size of one Rela reloc */ -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ -} Elf64_Rel; -#define ELF64_R_TYPE(i) ((i) & 0xffffffff) -#define R_AARCH64_RELATIVE 1027 /* Adjust by program base */ -#endif - -/* globals to store system table pointers */ -efi_handle_t IM = NULL; -efi_system_table_t *ST = NULL; -efi_boot_services_t *BS = NULL; -efi_runtime_services_t *RT = NULL; -efi_loaded_image_protocol_t *LIP = NULL; -#ifndef UEFI_NO_UTF8 -char *__argvutf8 = NULL; -#endif - -/* we only need one .o file, so use inline Assembly here */ -void bootstrap(void) -{ - __asm__ __volatile__ ( - /* call init in C */ - " .align 4\n" -#ifndef __clang__ - " .globl _start\n" - "_start:\n" - " ldr x2, =ImageBase\n" - " adrp x3, _DYNAMIC\n" - " add x3, x3, #:lo12:_DYNAMIC\n" - " bl uefi_init\n" - " ret\n" - - /* fake a relocation record, so that EFI won't complain */ - " .data\n" - "dummy: .long 0\n" - " .section .reloc, \"a\"\n" - "label1:\n" - " .long dummy-label1\n" - " .long 10\n" - " .word 0\n" - ".text\n" -#else - " .globl __chkstk\n" - "__chkstk:\n" - " ret\n" -#endif - ); - - /* setjmp and longjmp */ - __asm__ __volatile__ ( - " .p2align 3\n" - " .globl setjmp\n" - "setjmp:\n" - " mov x16, sp\n" - " stp x19, x20, [x0, #0]\n" - " stp x21, x22, [x0, #16]\n" - " stp x23, x24, [x0, #32]\n" - " stp x25, x26, [x0, #48]\n" - " stp x27, x28, [x0, #64]\n" - " stp x29, x30, [x0, #80]\n" - " str x16, [x0, #96]\n" - " stp d8, d9, [x0, #112]\n" - " stp d10, d11, [x0, #128]\n" - " stp d12, d13, [x0, #144]\n" - " stp d14, d15, [x0, #160]\n" - " mov w0, #0\n" - " ret\n" - ); - __asm__ __volatile__ ( - " .globl longjmp\n" - "longjmp:\n" - " ldp x19, x20, [x0, #0]\n" - " ldp x21, x22, [x0, #16]\n" - " ldp x23, x24, [x0, #32]\n" - " ldp x25, x26, [x0, #48]\n" - " ldp x27, x28, [x0, #64]\n" - " ldp x29, x30, [x0, #80]\n" - " ldr x16, [x0, #96]\n" - " ldp d8, d9, [x0, #112]\n" - " ldp d10, d11, [x0, #128]\n" - " ldp d12, d13, [x0, #144]\n" - " ldp d14, d15, [x0, #160]\n" - " mov sp, x16\n" - " cmp w1, #0\n" - " mov w0, #1\n" - " csel w0, w1, w0, ne\n" - " br x30\n" - ); -} - -/** - * Initialize POSIX-UEFI and call the application's main() function - */ -efi_status_t uefi_init ( - efi_handle_t image, efi_system_table_t *systab -#ifndef __clang__ - , uintptr_t ldbase, Elf64_Dyn *dyn -#endif -) { - efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; - efi_shell_parameters_protocol_t *shp = NULL; - efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID; - efi_shell_interface_protocol_t *shi = NULL; - efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; - efi_status_t status; - int argc = 0, i, ret; - wchar_t **argv = NULL; -#ifndef UEFI_NO_UTF8 - int j; - char *s; -#endif -#ifndef __clang__ - long relsz = 0, relent = 0; - Elf64_Rel *rel = 0; - uintptr_t *addr; - /* handle relocations */ - for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { - switch (dyn[i].d_tag) { - case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break; - case DT_RELASZ: relsz = dyn[i].d_un.d_val; break; - case DT_RELAENT: relent = dyn[i].d_un.d_val; break; - default: break; - } - } - if (rel && relent) { - while (relsz > 0) { - if(ELF64_R_TYPE (rel->r_info) == R_AARCH64_RELATIVE) - { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; } - rel = (Elf64_Rel*) ((char *) rel + relent); - relsz -= relent; - } - } -#else - (void)i; -#endif - /* failsafes, should never happen */ - if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || - !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) - return EFI_UNSUPPORTED; - /* save EFI pointers and loaded image into globals */ - IM = image; - ST = systab; - BS = systab->BootServices; - RT = systab->RuntimeServices; - BS->HandleProtocol(image, &lipGuid, (void **)&LIP); - /* get command line arguments */ - status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; } - else { - /* if shell 2.0 failed, fallback to shell 1.0 interface */ - status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; } - } - /* call main */ -#ifndef UEFI_NO_UTF8 - if(argc && argv) { - ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); - for(i = 0; i < argc; i++) - for(j = 0; argv[i] && argv[i][j]; j++) - ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); - status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); - if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } - else { - s = __argvutf8 + argc * (int)sizeof(uintptr_t); - *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); - for(i = 0; i < argc; i++) { - *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; - for(j = 0; argv[i] && argv[i][j]; j++) { - if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else - if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else - { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } - } - *s++ = 0; - } - } - } - ret = main(argc, (char**)__argvutf8); - if(__argvutf8) BS->FreePool(__argvutf8); - return ret; -#else - ret = main(argc, argv); -#endif - return ret ? EFIERR(ret) : EFI_SUCCESS; -} diff --git a/Bootloader/Source/uefi/crt_riscv64.c b/Bootloader/Source/uefi/crt_riscv64.c deleted file mode 100644 index 77b52ae..0000000 --- a/Bootloader/Source/uefi/crt_riscv64.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * crt_riscv64.c - * - * Copyright (C) 2023 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief C runtime, bootstraps an EFI application to call standard main() - * - */ - -#include - -/* this is implemented by the application */ -extern int main(int argc, char_t **argv); - -/* definitions for elf relocations */ -#ifndef __clang__ -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; -typedef uint64_t Elf64_Addr; -typedef struct -{ - Elf64_Sxword d_tag; /* Dynamic entry type */ - union - { - Elf64_Xword d_val; /* Integer value */ - Elf64_Addr d_ptr; /* Address value */ - } d_un; -} Elf64_Dyn; -#define DT_NULL 0 /* Marks end of dynamic section */ -#define DT_RELA 7 /* Address of Rela relocs */ -#define DT_RELASZ 8 /* Total size of Rela relocs */ -#define DT_RELAENT 9 /* Size of one Rela reloc */ -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ -} Elf64_Rel; -#define ELF64_R_TYPE(i) ((i) & 0xffffffff) -#define R_RISCV_RELATIVE 3 /* Adjust by program base */ -#endif - -/* globals to store system table pointers */ -efi_handle_t IM = NULL; -efi_system_table_t *ST = NULL; -efi_boot_services_t *BS = NULL; -efi_runtime_services_t *RT = NULL; -efi_loaded_image_protocol_t *LIP = NULL; -#ifndef UEFI_NO_UTF8 -char *__argvutf8 = NULL; -#endif - -/* we only need one .o file, so use inline Assembly here */ -void bootstrap(void) -{ - __asm__ __volatile__ ( - /* call init in C */ - " .align 4\n" -#ifndef __clang__ - " .globl _start\n" - "_start:\n" - " lla a2, ImageBase\n" - " lui a3, %hi(_DYNAMIC)\n" - " addi a3, a3, %lo(_DYNAMIC)\n" - " call uefi_init\n" - " ret\n" - - /* fake a relocation record, so that EFI won't complain */ - " .data\n" - "dummy: .long 0\n" - " .section .reloc, \"a\"\n" - "label1:\n" - " .long dummy-label1\n" - " .long 10\n" - " .word 0\n" - ".text\n" -#else - " .globl __chkstk\n" - "__chkstk:\n" - " ret\n" -#endif - ); - - /* setjmp and longjmp */ - __asm__ __volatile__ ( - " .p2align 3\n" - " .globl setjmp\n" - "setjmp:\n" - " sd ra, 0(a0)\n" - " sd sp, 8(a0)\n" - " sd s0, 16(a0)\n" - " sd s1, 24(a0)\n" - " sd s2, 32(a0)\n" - " sd s3, 40(a0)\n" - " sd s4, 48(a0)\n" - " sd s5, 56(a0)\n" - " sd s6, 64(a0)\n" - " sd s7, 72(a0)\n" - " sd s8, 80(a0)\n" - " sd s9, 88(a0)\n" - " sd s10, 96(a0)\n" - " sd s11, 104(a0)\n" -#ifndef __riscv_float_abi_soft - " fsd fs0, 112(a0)\n" - " fsd fs1, 120(a0)\n" - " fsd fs2, 128(a0)\n" - " fsd fs3, 136(a0)\n" - " fsd fs4, 144(a0)\n" - " fsd fs5, 152(a0)\n" - " fsd fs6, 160(a0)\n" - " fsd fs7, 168(a0)\n" - " fsd fs8, 176(a0)\n" - " fsd fs9, 184(a0)\n" - " fsd fs10,192(a0)\n" - " fsd fs11,200(a0)\n" -#endif - " li a0, 0\n" - " ret\n" - ); - __asm__ __volatile__ ( - " .globl longjmp\n" - "longjmp:\n" - " ld ra, 0(a0)\n" - " ld sp, 8(a0)\n" - " ld s0, 16(a0)\n" - " ld s1, 24(a0)\n" - " ld s2, 32(a0)\n" - " ld s3, 40(a0)\n" - " ld s4, 48(a0)\n" - " ld s5, 56(a0)\n" - " ld s6, 64(a0)\n" - " ld s7, 72(a0)\n" - " ld s8, 80(a0)\n" - " ld s9, 88(a0)\n" - " ld s10, 96(a0)\n" - " ld s11, 104(a0)\n" -#ifndef __riscv_float_abi_soft - " fld fs0, 112(a0)\n" - " fld fs1, 120(a0)\n" - " fld fs2, 128(a0)\n" - " fld fs3, 136(a0)\n" - " fld fs4, 144(a0)\n" - " fld fs5, 152(a0)\n" - " fld fs6, 160(a0)\n" - " fld fs7, 168(a0)\n" - " fld fs8, 176(a0)\n" - " fld fs9, 184(a0)\n" - " fld fs10,192(a0)\n" - " fld fs11,200(a0)\n" -#endif - " seqz a0, a1\n" - " add a0, a0, a1\n" - " ret\n" - ); -} - -/** - * Initialize POSIX-UEFI and call the application's main() function - */ -efi_status_t uefi_init ( - efi_handle_t image, efi_system_table_t *systab -#ifndef __clang__ - , uintptr_t ldbase, Elf64_Dyn *dyn -#endif -) { - efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; - efi_shell_parameters_protocol_t *shp = NULL; - efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID; - efi_shell_interface_protocol_t *shi = NULL; - efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; - efi_status_t status; - int argc = 0, i, ret; - wchar_t **argv = NULL; -#ifndef UEFI_NO_UTF8 - int j; - char *s; -#endif -#ifndef __clang__ - long relsz = 0, relent = 0; - Elf64_Rel *rel = 0; - uintptr_t *addr; - /* handle relocations */ - for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { - switch (dyn[i].d_tag) { - case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break; - case DT_RELASZ: relsz = dyn[i].d_un.d_val; break; - case DT_RELAENT: relent = dyn[i].d_un.d_val; break; - default: break; - } - } - if (rel && relent) { - while (relsz > 0) { - if(ELF64_R_TYPE (rel->r_info) == R_RISCV_RELATIVE) - { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; } - rel = (Elf64_Rel*) ((char *) rel + relent); - relsz -= relent; - } - } -#else - (void)i; -#endif - /* failsafes, should never happen */ - if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || - !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) - return EFI_UNSUPPORTED; - /* save EFI pointers and loaded image into globals */ - IM = image; - ST = systab; - BS = systab->BootServices; - RT = systab->RuntimeServices; - BS->HandleProtocol(image, &lipGuid, (void **)&LIP); - /* get command line arguments */ - status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; } - else { - /* if shell 2.0 failed, fallback to shell 1.0 interface */ - status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; } - } - /* call main */ -#ifndef UEFI_NO_UTF8 - if(argc && argv) { - ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); - for(i = 0; i < argc; i++) - for(j = 0; argv[i] && argv[i][j]; j++) - ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); - status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); - if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } - else { - s = __argvutf8 + argc * (int)sizeof(uintptr_t); - *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); - for(i = 0; i < argc; i++) { - *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; - for(j = 0; argv[i] && argv[i][j]; j++) { - if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else - if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else - { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } - } - *s++ = 0; - } - } - } - ret = main(argc, (char**)__argvutf8); - if(__argvutf8) BS->FreePool(__argvutf8); - return ret; -#else - ret = main(argc, argv); -#endif - return ret ? EFIERR(ret) : EFI_SUCCESS; -} diff --git a/Bootloader/Source/uefi/crt_x86_64.c b/Bootloader/Source/uefi/crt_x86_64.c deleted file mode 100644 index b146bb3..0000000 --- a/Bootloader/Source/uefi/crt_x86_64.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * crt_x86_64.c - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief C runtime, bootstraps an EFI application to call standard main() - * - */ - -#include - -/* this is implemented by the application */ -extern int main(int argc, char_t **argv); - -/* definitions for elf relocations */ -#ifndef __clang__ -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; -typedef uint64_t Elf64_Addr; -typedef struct -{ - Elf64_Sxword d_tag; /* Dynamic entry type */ - union - { - Elf64_Xword d_val; /* Integer value */ - Elf64_Addr d_ptr; /* Address value */ - } d_un; -} Elf64_Dyn; -#define DT_NULL 0 /* Marks end of dynamic section */ -#define DT_RELA 7 /* Address of Rela relocs */ -#define DT_RELASZ 8 /* Total size of Rela relocs */ -#define DT_RELAENT 9 /* Size of one Rela reloc */ -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ -} Elf64_Rel; -#define ELF64_R_TYPE(i) ((i) & 0xffffffff) -#define R_X86_64_RELATIVE 8 /* Adjust by program base */ -#endif - -/* globals to store system table pointers */ -efi_handle_t IM = NULL; -efi_system_table_t *ST = NULL; -efi_boot_services_t *BS = NULL; -efi_runtime_services_t *RT = NULL; -efi_loaded_image_protocol_t *LIP = NULL; -#ifndef UEFI_NO_UTF8 -char *__argvutf8 = NULL; -#endif - -/* we only need one .o file, so use inline Assembly here */ -void bootstrap(void) -{ - __asm__ __volatile__ ( - /* call init in C */ - " .align 4\n" -#ifndef __clang__ - " .globl _start\n" - "_start:\n" - " lea ImageBase(%rip), %rdi\n" - " lea _DYNAMIC(%rip), %rsi\n" - " call uefi_init\n" - " ret\n" - - /* fake a relocation record, so that EFI won't complain */ - " .data\n" - "dummy: .long 0\n" - " .section .reloc, \"a\"\n" - "label1:\n" - " .long dummy-label1\n" - " .long 10\n" - " .word 0\n" - ".text\n" -#else - " .globl __chkstk\n" - "__chkstk:\n" - " ret\n" -#endif - ); - - /* setjmp and longjmp */ - __asm__ __volatile__ ( - " .globl setjmp\n" - "setjmp:\n" - " pop %rsi\n" - " movq %rbx,0x00(%rdi)\n" - " movq %rsp,0x08(%rdi)\n" - " push %rsi\n" - " movq %rbp,0x10(%rdi)\n" - " movq %r12,0x18(%rdi)\n" - " movq %r13,0x20(%rdi)\n" - " movq %r14,0x28(%rdi)\n" - " movq %r15,0x30(%rdi)\n" - " movq %rsi,0x38(%rdi)\n" - " xor %rax,%rax\n" - " ret\n" - ); - __asm__ __volatile__ ( - " .globl longjmp\n" - "longjmp:\n" - " movl %esi, %eax\n" - " movq 0x00(%rdi), %rbx\n" - " movq 0x08(%rdi), %rsp\n" - " movq 0x10(%rdi), %rbp\n" - " movq 0x18(%rdi), %r12\n" - " movq 0x20(%rdi), %r13\n" - " movq 0x28(%rdi), %r14\n" - " movq 0x30(%rdi), %r15\n" - " xor %rdx,%rdx\n" - " mov $1,%rcx\n" - " cmp %rax,%rdx\n" - " cmove %rcx,%rax\n" - " jmp *0x38(%rdi)\n" - ); -} - -/** - * Initialize POSIX-UEFI and call the application's main() function - */ -efi_status_t uefi_init ( -#ifndef __clang__ - uintptr_t ldbase, Elf64_Dyn *dyn, efi_system_table_t *systab, efi_handle_t image -#else - efi_handle_t image, efi_system_table_t *systab -#endif -) { - efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; - efi_shell_parameters_protocol_t *shp = NULL; - efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID; - efi_shell_interface_protocol_t *shi = NULL; - efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; - efi_status_t status; - int argc = 0, i, ret; - wchar_t **argv = NULL; -#ifndef UEFI_NO_UTF8 - int j; - char *s; -#endif -#ifndef __clang__ - long relsz = 0, relent = 0; - Elf64_Rel *rel = 0; - uintptr_t *addr; - /* handle relocations */ - for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { - switch (dyn[i].d_tag) { - case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break; - case DT_RELASZ: relsz = dyn[i].d_un.d_val; break; - case DT_RELAENT: relent = dyn[i].d_un.d_val; break; - default: break; - } - } - if (rel && relent) { - while (relsz > 0) { - if(ELF64_R_TYPE (rel->r_info) == R_X86_64_RELATIVE) - { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; } - rel = (Elf64_Rel*) ((char *) rel + relent); - relsz -= relent; - } - } -#else - (void)i; -#endif - /* make sure SSE is enabled, because some say there are buggy firmware in the wild not doing that */ - __asm__ __volatile__ ( - " movq %cr0, %rax\n" - " andb $0xF1, %al\n" - " movq %rax, %cr0\n" - " movq %cr4, %rax\n" - " orw $3 << 9, %ax\n" - " mov %rax, %cr4\n" - ); - /* failsafes, should never happen */ - if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || - !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) - return EFI_UNSUPPORTED; - /* save EFI pointers and loaded image into globals */ - IM = image; - ST = systab; - BS = systab->BootServices; - RT = systab->RuntimeServices; - BS->HandleProtocol(image, &lipGuid, (void **)&LIP); - /* get command line arguments */ - status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; } - else { - /* if shell 2.0 failed, fallback to shell 1.0 interface */ - status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; } - } - /* call main */ -#ifndef UEFI_NO_UTF8 - if(argc && argv) { - ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); - for(i = 0; i < argc; i++) - for(j = 0; argv[i] && argv[i][j]; j++) - ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); - status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); - if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } - else { - s = __argvutf8 + argc * (int)sizeof(uintptr_t); - *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); - for(i = 0; i < argc; i++) { - *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; - for(j = 0; argv[i] && argv[i][j]; j++) { - if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else - if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else - { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } - } - *s++ = 0; - } - } - } - ret = main(argc, (char**)__argvutf8); - if(__argvutf8) BS->FreePool(__argvutf8); -#else - ret = main(argc, argv); -#endif - return ret ? EFIERR(ret) : EFI_SUCCESS; -} diff --git a/Bootloader/Source/uefi/dirent.c b/Bootloader/Source/uefi/dirent.c deleted file mode 100644 index 402011c..0000000 --- a/Bootloader/Source/uefi/dirent.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * dirent.c - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief Implementing functions which are defined in dirent.h - * - */ - -#include - -extern void __stdio_seterrno(efi_status_t status); -static struct dirent __dirent; - -DIR *opendir (const char_t *__name) -{ - DIR *dp = (DIR*)fopen(__name, CL("rd")); - if(dp) rewinddir(dp); - return dp; -} - -struct dirent *readdir (DIR *__dirp) -{ - efi_status_t status; - efi_file_info_t info; - uintn_t bs = sizeof(efi_file_info_t); - memset(&__dirent, 0, sizeof(struct dirent)); - status = __dirp->Read(__dirp, &bs, &info); - if(EFI_ERROR(status) || !bs) { - if(EFI_ERROR(status)) __stdio_seterrno(status); - else errno = 0; - return NULL; - } - __dirent.d_type = info.Attribute & EFI_FILE_DIRECTORY ? DT_DIR : DT_REG; -#ifndef UEFI_NO_UTF8 - __dirent.d_reclen = (unsigned short int)wcstombs(__dirent.d_name, info.FileName, FILENAME_MAX - 1); -#else - __dirent.d_reclen = strlen(info.FileName); - strncpy(__dirent.d_name, info.FileName, FILENAME_MAX - 1); -#endif - return &__dirent; -} - -void rewinddir (DIR *__dirp) -{ - if(__dirp) - __dirp->SetPosition(__dirp, 0); -} - -int closedir (DIR *__dirp) -{ - return fclose((FILE*)__dirp); -} - - diff --git a/Bootloader/Source/uefi/efi_entry.c b/Bootloader/Source/uefi/efi_entry.c new file mode 100644 index 0000000..d6e1ec9 --- /dev/null +++ b/Bootloader/Source/uefi/efi_entry.c @@ -0,0 +1,23 @@ +#include "uefi.h" + +efi_handle_t IM = NULL; +efi_system_table_t* ST = NULL; +efi_boot_services_t* BS = NULL; +efi_runtime_services_t* RT = NULL; + +efi_status_t bootloader_main(void); + +void __chkstk(void) {} + +efi_status_t EFIAPI efi_main(efi_handle_t image, efi_system_table_t* system_table) { + if (image == NULL || system_table == NULL || system_table->BootServices == NULL) { + return EFI_UNSUPPORTED; + } + + IM = image; + ST = system_table; + BS = system_table->BootServices; + RT = system_table->RuntimeServices; + + return bootloader_main(); +} diff --git a/Bootloader/Source/uefi/elf_aarch64_efi.lds b/Bootloader/Source/uefi/elf_aarch64_efi.lds deleted file mode 100644 index 836d982..0000000 --- a/Bootloader/Source/uefi/elf_aarch64_efi.lds +++ /dev/null @@ -1,63 +0,0 @@ -OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") -OUTPUT_ARCH(aarch64) -ENTRY(_start) -SECTIONS -{ - .text 0x0 : { - _text = .; - *(.text.head) - *(.text) - *(.text.*) - *(.gnu.linkonce.t.*) - *(.srodata) - *(.rodata*) - . = ALIGN(16); - } - _etext = .; - _text_size = . - _text; - .dynamic : { *(.dynamic) } - .data : ALIGN(4096) - { - _data = .; - *(.sdata) - *(.data) - *(.data1) - *(.data.*) - *(.got.plt) - *(.got) - - /* the EFI loader doesn't seem to like a .bss section, so we stick - it all into .data: */ - . = ALIGN(16); - _bss = .; - *(.sbss) - *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - . = ALIGN(16); - _bss_end = .; - } - - .rela.dyn : { *(.rela.dyn) } - .rela.plt : { *(.rela.plt) } - .rela.got : { *(.rela.got) } - .rela.data : { *(.rela.data) *(.rela.data*) } - . = ALIGN(512); - _edata = .; - _data_size = . - _data; - - . = ALIGN(4096); - .dynsym : { *(.dynsym) } - . = ALIGN(4096); - .dynstr : { *(.dynstr) } - . = ALIGN(4096); - .note.gnu.build-id : { *(.note.gnu.build-id) } - /DISCARD/ : - { - *(.rel.reloc) - *(.eh_frame) - *(.note.GNU-stack) - } - .comment 0 : { *(.comment) } -} diff --git a/Bootloader/Source/uefi/elf_riscv64_efi.lds b/Bootloader/Source/uefi/elf_riscv64_efi.lds deleted file mode 100644 index 6f1936b..0000000 --- a/Bootloader/Source/uefi/elf_riscv64_efi.lds +++ /dev/null @@ -1,64 +0,0 @@ -OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") -OUTPUT_ARCH(riscv) -ENTRY(_start) -SECTIONS -{ - .text 0x0 : { - _text = .; - *(.text.head) - *(.text) - *(.text.*) - *(.gnu.linkonce.t.*) - *(.srodata) - *(.rodata*) - . = ALIGN(16); - } - _etext = .; - _text_size = . - _text; - .dynamic : { *(.dynamic) } - .data : ALIGN(4096) - { - _data = .; - *(.sdata) - *(.data) - *(.data1) - *(.data.*) - *(.got.plt) - *(.got) - - /* the EFI loader doesn't seem to like a .bss section, so we stick - it all into .data: */ - . = ALIGN(16); - _bss = .; - *(.sbss) - *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - . = ALIGN(16); - _bss_end = .; - } - - .rela.text : { *(.rela.text) *(.rela.text*) } - .rela.dyn : { *(.rela.dyn) } - .rela.plt : { *(.rela.plt) } - .rela.got : { *(.rela.got) } - .rela.data : { *(.rela.data) *(.rela.data*) } - . = ALIGN(512); - _edata = .; - _data_size = . - _data; - - . = ALIGN(4096); - .dynsym : { *(.dynsym) } - . = ALIGN(4096); - .dynstr : { *(.dynstr) } - . = ALIGN(4096); - .note.gnu.build-id : { *(.note.gnu.build-id) } - /DISCARD/ : - { - *(.rel.reloc) - *(.eh_frame) - *(.note.GNU-stack) - } - .comment 0 : { *(.comment) } -} diff --git a/Bootloader/Source/uefi/elf_x86_64_efi.lds b/Bootloader/Source/uefi/elf_x86_64_efi.lds deleted file mode 100644 index 7be5902..0000000 --- a/Bootloader/Source/uefi/elf_x86_64_efi.lds +++ /dev/null @@ -1,76 +0,0 @@ -/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */ -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") -OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) -SECTIONS -{ - . = 0; - ImageBase = .; - /* .hash and/or .gnu.hash MUST come first! */ - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - . = ALIGN(4096); - .eh_frame : - { - *(.eh_frame) - } - . = ALIGN(4096); - .text : - { - _text = .; - *(.text) - *(.text.*) - *(.gnu.linkonce.t.*) - . = ALIGN(16); - } - _etext = .; - _text_size = . - _text; - . = ALIGN(4096); - .reloc : - { - *(.reloc) - } - . = ALIGN(4096); - .data : - { - _data = .; - *(.rodata*) - *(.got.plt) - *(.got) - *(.data*) - *(.sdata) - /* the EFI loader doesn't seem to like a .bss section, so we stick - it all into .data: */ - *(.sbss) - *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - *(.rel.local) - } - .note.gnu.build-id : { *(.note.gnu.build-id) } - - _edata = .; - _data_size = . - _etext; - . = ALIGN(4096); - .dynamic : { *(.dynamic) } - . = ALIGN(4096); - .rela : - { - *(.rela.data*) - *(.rela.got) - *(.rela.stab) - } - . = ALIGN(4096); - .dynsym : { *(.dynsym) } - . = ALIGN(4096); - .dynstr : { *(.dynstr) } - . = ALIGN(4096); - .ignored.reloc : - { - *(.rela.reloc) - *(.eh_frame) - *(.note.GNU-stack) - } - .comment 0 : { *(.comment) } -} diff --git a/Bootloader/Source/uefi/qsort.c b/Bootloader/Source/uefi/qsort.c deleted file mode 100644 index d6563c9..0000000 --- a/Bootloader/Source/uefi/qsort.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * qsort.c - * - * @brief from OpenBSD - */ - -/* $OpenBSD: qsort.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - -static __inline char *med3(char *, char *, char *, __compar_fn_t cmp); -static __inline void swapfunc(char *, char *, int, int); -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) { \ - long i = (n) / sizeof (TYPE); \ - TYPE *pi = (TYPE *) (parmi); \ - TYPE *pj = (TYPE *) (parmj); \ - do { \ - TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; -static __inline void -swapfunc(char *a, char *b, int n, int swaptype) -{ - if (swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -} -#define swap(a, b) \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype) -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) -static __inline char * -med3(char *a, char *b, char *c, __compar_fn_t cmp) -{ - return cmp(a, b) < 0 ? - (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) - :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); -} - -void qsort(void *aa, size_t n, size_t es, __compar_fn_t cmp) -{ - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - char *a = aa; -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) { - for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pm = (char *)a + (n / 2) * es; - if (n > 7) { - pl = (char *)a; - pn = (char *)a + (n - 1) * es; - if (n > 40) { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp); - pm = med3(pm - d, pm, pm + d, cmp); - pn = med3(pn - 2 * d, pn - d, pn, cmp); - } - pm = med3(pl, pm, pn, cmp); - } - swap(a, pm); - pa = pb = (char *)a + es; - - pc = pd = (char *)a + (n - 1) * es; - for (;;) { - while (pb <= pc && (r = cmp(pb, a)) <= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = cmp(pc, a)) >= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - break; - swap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pn = (char *)a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min(pd - pc, pn - pd - (int)es); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > (int)es) - qsort(a, r / es, es, cmp); - if ((r = pd - pc) > (int)es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -/* qsort(pn - r, r / es, es, cmp);*/ -} diff --git a/Bootloader/Source/uefi/stat.c b/Bootloader/Source/uefi/stat.c deleted file mode 100644 index 017a4f8..0000000 --- a/Bootloader/Source/uefi/stat.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * stat.c - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief Implementing functions which are defined in sys/stat.h - * - */ - -#include - -/* fstat is in stdio.c because we can't access static variables otherwise... */ - -int stat (const char_t *__file, struct stat *__buf) -{ - int ret; - FILE *f; - - if(!__file || !*__file || !__buf) { - errno = EINVAL; - return -1; - } - f = fopen(__file, CL("*")); - if(!f) { - memset(__buf, 0, sizeof(struct stat)); - return -1; - } - ret = fstat(f, __buf); - fclose(f); - return ret; -} - -extern int mkdir (const char_t *__path, mode_t __mode) -{ - FILE *f; - (void)__mode; - if(!__path || !*__path) { - errno = EINVAL; - return -1; - } - f = fopen(__path, CL("wd")); - if(!f) { - return -1; - } - fclose(f); - return 0; -} diff --git a/Bootloader/Source/uefi/stdio.c b/Bootloader/Source/uefi/stdio.c deleted file mode 100644 index c536d44..0000000 --- a/Bootloader/Source/uefi/stdio.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * stdio.c - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief Implementing functions which are defined in stdio.h - * - */ - -#include - -static efi_file_handle_t *__root_dir = NULL; -static efi_serial_io_protocol_t *__ser = NULL; -static block_file_t *__blk_devs = NULL; -static uintn_t __blk_ndevs = 0; -extern time_t __mktime_efi(efi_time_t *t); -void __stdio_cleanup(void); -void __stdio_seterrno(efi_status_t status); -int __remove (const char_t *__filename, int isdir); - -void __stdio_cleanup(void) -{ -#ifndef UEFI_NO_UTF8 - if(__argvutf8) - BS->FreePool(__argvutf8); -#endif - if(__blk_devs) { - free(__blk_devs); - __blk_devs = NULL; - __blk_ndevs = 0; - } -} - -void __stdio_seterrno(efi_status_t status) -{ - switch((int)(status & 0xffff)) { - case EFI_WRITE_PROTECTED & 0xffff: errno = EROFS; break; - case EFI_ACCESS_DENIED & 0xffff: errno = EACCES; break; - case EFI_VOLUME_FULL & 0xffff: errno = ENOSPC; break; - case EFI_NOT_FOUND & 0xffff: errno = ENOENT; break; - case EFI_INVALID_PARAMETER & 0xffff: errno = EINVAL; break; - default: errno = EIO; break; - } -} - -int fstat (FILE *__f, struct stat *__buf) -{ - efi_guid_t infGuid = EFI_FILE_INFO_GUID; - efi_file_info_t info; - uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t); - efi_status_t status; - uintn_t i; - - if(!__f || !__buf) { - errno = EINVAL; - return -1; - } - memset(__buf, 0, sizeof(struct stat)); - if(__f == stdin) { - __buf->st_mode = S_IREAD | S_IFIFO; - return 0; - } - if(__f == stdout || __f == stderr) { - __buf->st_mode = S_IWRITE | S_IFIFO; - return 0; - } - if(__ser && __f == (FILE*)__ser) { - __buf->st_mode = S_IREAD | S_IWRITE | S_IFCHR; - return 0; - } - for(i = 0; i < __blk_ndevs; i++) - if(__f == (FILE*)__blk_devs[i].bio) { - __buf->st_mode = S_IREAD | S_IWRITE | S_IFBLK; - __buf->st_size = (off_t)__blk_devs[i].bio->Media->BlockSize * ((off_t)__blk_devs[i].bio->Media->LastBlock + 1); - __buf->st_blocks = __blk_devs[i].bio->Media->LastBlock + 1; - return 0; - } - status = __f->GetInfo(__f, &infGuid, &fsiz, &info); - if(EFI_ERROR(status)) { - __stdio_seterrno(status); - return -1; - } - __buf->st_mode = S_IREAD | - (info.Attribute & EFI_FILE_READ_ONLY ? 0 : S_IWRITE) | - (info.Attribute & EFI_FILE_DIRECTORY ? S_IFDIR : S_IFREG); - __buf->st_size = (off_t)info.FileSize; - __buf->st_blocks = (blkcnt_t)info.PhysicalSize; - __buf->st_atime = __mktime_efi(&info.LastAccessTime); - __buf->st_mtime = __mktime_efi(&info.ModificationTime); - __buf->st_ctime = __mktime_efi(&info.CreateTime); - return 0; -} - -int fclose (FILE *__stream) -{ - efi_status_t status = EFI_SUCCESS; - uintn_t i; - if(!__stream) { - errno = EINVAL; - return 0; - } - if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) { - return 1; - } - for(i = 0; i < __blk_ndevs; i++) - if(__stream == (FILE*)__blk_devs[i].bio) - return 1; - status = __stream->Close(__stream); - free(__stream); - return !EFI_ERROR(status); -} - -int fflush (FILE *__stream) -{ - efi_status_t status = EFI_SUCCESS; - uintn_t i; - if(!__stream) { - errno = EINVAL; - return 0; - } - if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) { - return 1; - } - for(i = 0; i < __blk_ndevs; i++) - if(__stream == (FILE*)__blk_devs[i].bio) { - return 1; - } - status = __stream->Flush(__stream); - return !EFI_ERROR(status); -} - -int __remove (const char_t *__filename, int isdir) -{ - efi_status_t status; - efi_guid_t infGuid = EFI_FILE_INFO_GUID; - efi_file_info_t info; - uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i; - /* little hack to support read and write mode for Delete() and stat() without create mode or checks */ - FILE *f = fopen(__filename, CL("*")); - if(errno) - return 1; - if(!f || f == stdin || f == stdout || f == stderr || (__ser && f == (FILE*)__ser)) { - errno = EBADF; - return 1; - } - for(i = 0; i < __blk_ndevs; i++) - if(f == (FILE*)__blk_devs[i].bio) { - errno = EBADF; - return 1; - } - if(isdir != -1) { - status = f->GetInfo(f, &infGuid, &fsiz, &info); - if(EFI_ERROR(status)) goto err; - if(isdir == 0 && (info.Attribute & EFI_FILE_DIRECTORY)) { - fclose(f); errno = EISDIR; - return -1; - } - if(isdir == 1 && !(info.Attribute & EFI_FILE_DIRECTORY)) { - fclose(f); errno = ENOTDIR; - return -1; - } - } - status = f->Delete(f); - if(EFI_ERROR(status)) { -err: __stdio_seterrno(status); - fclose(f); - return -1; - } - /* no need for fclose(f); */ - free(f); - return 0; -} - -int remove (const char_t *__filename) -{ - return __remove(__filename, -1); -} - -FILE *fopen (const char_t *__filename, const char_t *__modes) -{ - FILE *ret; - efi_status_t status; - efi_guid_t sfsGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; - efi_simple_file_system_protocol_t *sfs = NULL; - efi_guid_t infGuid = EFI_FILE_INFO_GUID; - efi_file_info_t info; - uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), par, i; -#ifndef UEFI_NO_UTF8 - wchar_t wcname[BUFSIZ]; -#endif - errno = 0; - if(!__filename || !*__filename || !__modes || (__modes[0] != CL('r') && __modes[0] != CL('w') && __modes[0] != CL('a') && - __modes[0] != CL('*')) || (__modes[1] != 0 && __modes[1] != CL('d') && __modes[1] != CL('+'))) { - errno = EINVAL; - return NULL; - } - /* fake some device names. UEFI has no concept of device files */ - if(!strcmp(__filename, CL("/dev/stdin"))) { - if(__modes[0] == CL('w') || __modes[0] == CL('a')) { errno = EPERM; return NULL; } - return stdin; - } - if(!strcmp(__filename, CL("/dev/stdout"))) { - if(__modes[0] == CL('r')) { errno = EPERM; return NULL; } - return stdout; - } - if(!strcmp(__filename, CL("/dev/stderr"))) { - if(__modes[0] == CL('r')) { errno = EPERM; return NULL; } - return stderr; - } - if(!memcmp(__filename, CL("/dev/serial"), 11 * sizeof(char_t))) { - par = (uintn_t)atol(__filename + 11); - if(!__ser) { - efi_guid_t serGuid = EFI_SERIAL_IO_PROTOCOL_GUID; - status = BS->LocateProtocol(&serGuid, NULL, (void**)&__ser); - if(EFI_ERROR(status) || !__ser) { errno = ENOENT; return NULL; } - } - __ser->SetAttributes(__ser, par > 9600 ? par : 115200, 0, 1000, NoParity, 8, OneStopBit); - return (FILE*)__ser; - } - if(!memcmp(__filename, CL("/dev/disk"), 9 * sizeof(char_t))) { - par = (uintn_t)atol(__filename + 9); - if(!__blk_ndevs) { - efi_guid_t bioGuid = EFI_BLOCK_IO_PROTOCOL_GUID; - efi_handle_t handles[128]; - uintn_t handle_size = sizeof(handles); - status = BS->LocateHandle(ByProtocol, &bioGuid, NULL, &handle_size, (efi_handle_t*)&handles); - if(!EFI_ERROR(status)) { - handle_size /= (uintn_t)sizeof(efi_handle_t); - /* workaround a bug in TianoCore, it reports zero size even though the data is in the buffer */ - if(handle_size < 1) - handle_size = (uintn_t)sizeof(handles) / sizeof(efi_handle_t); - __blk_devs = (block_file_t*)malloc(handle_size * sizeof(block_file_t)); - if(__blk_devs) { - memset(__blk_devs, 0, handle_size * sizeof(block_file_t)); - for(i = __blk_ndevs = 0; i < handle_size; i++) - if(handles[i] && !EFI_ERROR(BS->HandleProtocol(handles[i], &bioGuid, (void **) &__blk_devs[__blk_ndevs].bio)) && - __blk_devs[__blk_ndevs].bio && __blk_devs[__blk_ndevs].bio->Media && - __blk_devs[__blk_ndevs].bio->Media->BlockSize > 0) - __blk_ndevs++; - } else - __blk_ndevs = 0; - } - } - if(__blk_ndevs && par < __blk_ndevs) - return (FILE*)__blk_devs[par].bio; - errno = ENOENT; - return NULL; - } - if(!__root_dir && LIP) { - status = BS->HandleProtocol(LIP->DeviceHandle, &sfsGuid, (void **)&sfs); - if(!EFI_ERROR(status)) - status = sfs->OpenVolume(sfs, &__root_dir); - } - if(!__root_dir) { - errno = ENODEV; - return NULL; - } - ret = (FILE*)malloc(sizeof(FILE)); - if(!ret) return NULL; - /* normally write means read,write,create. But for remove (internal '*' mode), we need read,write without create - * also mode 'w' in POSIX means write-only (without read), but that's not working on certain firmware, we must - * pass read too. This poses a problem of truncating a write-only file, see issue #26, we have to do that manually */ -#ifndef UEFI_NO_UTF8 - mbstowcs((wchar_t*)&wcname, __filename, BUFSIZ - 1); - status = __root_dir->Open(__root_dir, &ret, (wchar_t*)&wcname, -#else - status = __root_dir->Open(__root_dir, &ret, (wchar_t*)__filename, -#endif - __modes[0] == CL('w') || __modes[0] == CL('a') ? (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE) : - EFI_FILE_MODE_READ | (__modes[0] == CL('*') || __modes[1] == CL('+') ? EFI_FILE_MODE_WRITE : 0), - __modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0); - if(EFI_ERROR(status)) { -err: __stdio_seterrno(status); - free(ret); return NULL; - } - if(__modes[0] == CL('*')) return ret; - status = ret->GetInfo(ret, &infGuid, &fsiz, &info); - if(EFI_ERROR(status)) goto err; - if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) { - ret->Close(ret); free(ret); errno = ENOTDIR; return NULL; - } - if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) { - ret->Close(ret); free(ret); errno = EISDIR; return NULL; - } - if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END); - if(__modes[0] == CL('w')) { - /* manually truncate file size - * See https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c - * function FileHandleSetSize */ - info.FileSize = 0; - ret->SetInfo(ret, &infGuid, fsiz, &info); - } - return ret; -} - -size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream) -{ - uintn_t bs = __size * __n, i, n; - efi_status_t status; - if(!__ptr || __size < 1 || __n < 1 || !__stream) { - errno = EINVAL; - return 0; - } - if(__stream == stdin || __stream == stdout || __stream == stderr) { - errno = ESPIPE; - return 0; - } - if(__ser && __stream == (FILE*)__ser) { - status = __ser->Read(__ser, &bs, __ptr); - } else { - for(i = 0; i < __blk_ndevs; i++) - if(__stream == (FILE*)__blk_devs[i].bio) { - n = __blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize; - bs = (bs / __blk_devs[i].bio->Media->BlockSize) * __blk_devs[i].bio->Media->BlockSize; - status = __blk_devs[i].bio->ReadBlocks(__blk_devs[i].bio, __blk_devs[i].bio->Media->MediaId, n, bs, __ptr); - if(EFI_ERROR(status)) { - __stdio_seterrno(status); - return 0; - } - __blk_devs[i].offset += bs; - return bs / __size; - } - status = __stream->Read(__stream, &bs, __ptr); - } - if(EFI_ERROR(status)) { - __stdio_seterrno(status); - return 0; - } - return bs / __size; -} - -size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__stream) -{ - uintn_t bs = __size * __n, n, i; - efi_status_t status; - if(!__ptr || __size < 1 || __n < 1 || !__stream) { - errno = EINVAL; - return 0; - } - if(__stream == stdin || __stream == stdout || __stream == stderr) { - errno = ESPIPE; - return 0; - } - if(__ser && __stream == (FILE*)__ser) { - status = __ser->Write(__ser, &bs, (void*)__ptr); - } else { - for(i = 0; i < __blk_ndevs; i++) - if(__stream == (FILE*)__blk_devs[i].bio) { - n = __blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize; - bs = (bs / __blk_devs[i].bio->Media->BlockSize) * __blk_devs[i].bio->Media->BlockSize; - status = __blk_devs[i].bio->WriteBlocks(__blk_devs[i].bio, __blk_devs[i].bio->Media->MediaId, n, bs, (void*)__ptr); - if(EFI_ERROR(status)) { - __stdio_seterrno(status); - return 0; - } - __blk_devs[i].offset += bs; - return bs / __size; - } - status = __stream->Write(__stream, &bs, (void *)__ptr); - } - if(EFI_ERROR(status)) { - __stdio_seterrno(status); - return 0; - } - return bs / __size; -} - -int fseek (FILE *__stream, long int __off, int __whence) -{ - off_t off = 0; - efi_status_t status; - efi_guid_t infoGuid = EFI_FILE_INFO_GUID; - efi_file_info_t info; - uintn_t fsiz = sizeof(efi_file_info_t), i; - if(!__stream || (__whence != SEEK_SET && __whence != SEEK_CUR && __whence != SEEK_END)) { - errno = EINVAL; - return -1; - } - if(__stream == stdin || __stream == stdout || __stream == stderr) { - errno = ESPIPE; - return -1; - } - if(__ser && __stream == (FILE*)__ser) { - errno = EBADF; - return -1; - } - for(i = 0; i < __blk_ndevs; i++) - if(__stream == (FILE*)__blk_devs[i].bio) { - off = (uint64_t)__blk_devs[i].bio->Media->BlockSize * (uint64_t)__blk_devs[i].bio->Media->LastBlock; - switch(__whence) { - case SEEK_END: - __blk_devs[i].offset = off + __off; - break; - case SEEK_CUR: - __blk_devs[i].offset += __off; - break; - case SEEK_SET: - __blk_devs[i].offset = __off; - break; - } - if(__blk_devs[i].offset < 0) __blk_devs[i].offset = 0; - if(__blk_devs[i].offset > off) __blk_devs[i].offset = off; - __blk_devs[i].offset = (__blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize) * - __blk_devs[i].bio->Media->BlockSize; - return 0; - } - switch(__whence) { - case SEEK_END: - status = __stream->GetInfo(__stream, &infoGuid, &fsiz, &info); - if(!EFI_ERROR(status)) { - off = info.FileSize + __off; - status = __stream->SetPosition(__stream, off); - } - break; - case SEEK_CUR: - status = __stream->GetPosition(__stream, &off); - if(!EFI_ERROR(status)) { - off += __off; - status = __stream->SetPosition(__stream, off); - } - break; - default: - status = __stream->SetPosition(__stream, __off); - break; - } - return EFI_ERROR(status) ? -1 : 0; -} - -long int ftell (FILE *__stream) -{ - uint64_t off = 0; - uintn_t i; - efi_status_t status; - if(!__stream) { - errno = EINVAL; - return -1; - } - if(__stream == stdin || __stream == stdout || __stream == stderr) { - errno = ESPIPE; - return -1; - } - if(__ser && __stream == (FILE*)__ser) { - errno = EBADF; - return -1; - } - for(i = 0; i < __blk_ndevs; i++) - if(__stream == (FILE*)__blk_devs[i].bio) { - return (long int)__blk_devs[i].offset; - } - status = __stream->GetPosition(__stream, &off); - return EFI_ERROR(status) ? -1 : (long int)off; -} - -int feof (FILE *__stream) -{ - uint64_t off = 0; - efi_guid_t infGuid = EFI_FILE_INFO_GUID; - efi_file_info_t info; - uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i; - efi_status_t status; - if(!__stream) { - errno = EINVAL; - return 0; - } - if(__stream == stdin || __stream == stdout || __stream == stderr) { - errno = ESPIPE; - return 0; - } - if(__ser && __stream == (FILE*)__ser) { - errno = EBADF; - return 0; - } - for(i = 0; i < __blk_ndevs; i++) - if(__stream == (FILE*)__blk_devs[i].bio) { - errno = EBADF; - return __blk_devs[i].offset == (off_t)__blk_devs[i].bio->Media->BlockSize * (off_t)__blk_devs[i].bio->Media->LastBlock; - } - status = __stream->GetPosition(__stream, &off); - if(EFI_ERROR(status)) { -err: __stdio_seterrno(status); - return 1; - } - status = __stream->GetInfo(__stream, &infGuid, &fsiz, &info); - if(EFI_ERROR(status)) goto err; - __stream->SetPosition(__stream, off); - return info.FileSize == off; -} - -int vsnprintf(char_t *dst, size_t maxlen, const char_t *fmt, __builtin_va_list args) -{ -#define needsescape(a) (a==CL('\"') || a==CL('\\') || a==CL('\a') || a==CL('\b') || a==CL('\033') || a==CL('\f') || \ - a==CL('\r') || a==CL('\n') || a==CL('\t') || a==CL('\v')) - efi_physical_address_t m; - uint8_t *mem; - uint64_t arg; - int64_t iarg; - int len, sign, i, j; - char_t *p, *orig=dst, *end = dst + maxlen - 1, tmpstr[24], pad, n; -#ifdef UEFI_NO_UTF8 - char *c; -#endif - if(dst==NULL || fmt==NULL) - return 0; - - arg = 0; - while(*fmt && dst < end) { - if(*fmt==CL('%')) { - fmt++; - if(*fmt==CL('%')) goto put; - len=0; pad=CL(' '); - if(*fmt==CL('0')) pad=CL('0'); - while(*fmt>=CL('0') && *fmt<=CL('9')) { - len *= 10; - len += *fmt-CL('0'); - fmt++; - } - if(*fmt==CL('l')) fmt++; - if(*fmt==CL('c')) { - arg = __builtin_va_arg(args, uint32_t); -#ifndef UEFI_NO_UTF8 - if(arg<0x80) { *dst++ = arg; } else - if(arg<0x800) { *dst++ = ((arg>>6)&0x1F)|0xC0; *dst++ = (arg&0x3F)|0x80; } else - { *dst++ = ((arg>>12)&0x0F)|0xE0; *dst++ = ((arg>>6)&0x3F)|0x80; *dst++ = (arg&0x3F)|0x80; } -#else - *dst++ = (wchar_t)(arg & 0xffff); -#endif - fmt++; - continue; - } else - if(*fmt==CL('d') || *fmt==CL('i') || *fmt==CL('u')) { - iarg = __builtin_va_arg(args, int64_t); - sign=0; - if(*fmt!=CL('u') && iarg<0) { - arg=-iarg; - sign++; - } else arg=(uint64_t)iarg; - i=23; - tmpstr[i]=0; - do { - tmpstr[--i]=CL('0')+(arg%10); - arg/=10; - } while(arg!=0 && i>0); - if(sign) { - tmpstr[--i]=CL('-'); - } - if(len>0 && len<23) { - while(i && i>23-len) { - tmpstr[--i]=pad; - } - } - p=&tmpstr[i]; - goto copystring; - } else - if(*fmt==CL('p')) { - arg = __builtin_va_arg(args, uint64_t); - len = 16; pad = CL('0'); goto hex; - } else - if(*fmt==CL('x') || *fmt==CL('X')) { - arg = __builtin_va_arg(args, uint64_t); -hex: i=16; - tmpstr[i]=0; - do { - n=arg & 0xf; - /* 0-9 => '0'-'9', 10-15 => 'A'-'F' */ - tmpstr[--i]=n+(n>9?(*fmt==CL('X')?0x37:0x57):0x30); - arg>>=4; - } while(arg!=0 && i>0); - /* padding, only leading zeros */ - if(len>0 && len<=16) { - while(i>16-len) { - tmpstr[--i]=CL('0'); - } - } - p=&tmpstr[i]; - goto copystring; - } else - if(*fmt==CL('s') || *fmt==CL('q')) { - p = __builtin_va_arg(args, char_t*); -copystring: if(p==NULL) { - p=CL("(null)"); - } - while(*p && dst + 2 < end) { - if(*fmt==CL('q') && needsescape(*p)) { - *dst++ = CL('\\'); - switch(*p) { - case CL('\a'): *dst++ = CL('a'); break; - case CL('\b'): *dst++ = CL('b'); break; - case 27: *dst++ = CL('e'); break; /* gcc 10.2 doesn't like CL('\e') in ansi mode */ - case CL('\f'): *dst++ = CL('f'); break; - case CL('\n'): *dst++ = CL('n'); break; - case CL('\r'): *dst++ = CL('r'); break; - case CL('\t'): *dst++ = CL('t'); break; - case CL('\v'): *dst++ = CL('v'); break; - default: *dst++ = *p++; break; - } - } else { - if(*p == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r'); - *dst++ = *p++; - } - } - } else -#ifdef UEFI_NO_UTF8 - if(*fmt==L'S' || *fmt==L'Q') { - c = __builtin_va_arg(args, char*); - if(c==NULL) goto copystring; - while(*p && dst + 2 < end) { - arg = *c; - if((*c & 128) != 0) { - if((*c & 32) == 0 ) { - arg = ((*c & 0x1F)<<6)|(*(c+1) & 0x3F); - c += 1; - } else - if((*c & 16) == 0 ) { - arg = ((*c & 0xF)<<12)|((*(c+1) & 0x3F)<<6)|(*(c+2) & 0x3F); - c += 2; - } else - if((*c & 8) == 0 ) { - arg = ((*c & 0x7)<<18)|((*(c+1) & 0x3F)<<12)|((*(c+2) & 0x3F)<<6)|(*(c+3) & 0x3F); - c += 3; - } else - arg = L'?'; - } - if(!arg) break; - if(*fmt==L'Q' && needsescape(arg)) { - *dst++ = L'\\'; - switch(arg) { - case L'\a': *dst++ = L'a'; break; - case L'\b': *dst++ = L'b'; break; - case 27: *dst++ = L'e'; break; /* gcc 10.2 doesn't like L'\e' in ansi mode */ - case L'\f': *dst++ = L'f'; break; - case L'\n': *dst++ = L'n'; break; - case L'\r': *dst++ = L'r'; break; - case L'\t': *dst++ = L't'; break; - case L'\v': *dst++ = L'v'; break; - default: *dst++ = arg; break; - } - } else { - if(arg == L'\n') *dst++ = L'\r'; - *dst++ = (wchar_t)(arg & 0xffff); - } - } - } else -#endif - if(*fmt==CL('D')) { - m = __builtin_va_arg(args, efi_physical_address_t); - for(j = 0; j < (len < 1 ? 1 : (len > 16 ? 16 : len)); j++) { - for(i = 44; i >= 0; i -= 4) { - n = (m >> i) & 15; *dst++ = n + (n>9?0x37:0x30); - if(dst >= end) goto zro; - } - *dst++ = CL(':'); if(dst >= end) goto zro; - *dst++ = CL(' '); if(dst >= end) goto zro; - mem = (uint8_t*)m; - for(i = 0; i < 16; i++) { - n = (mem[i] >> 4) & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro; - n = mem[i] & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro; - *dst++ = CL(' ');if(dst >= end) goto zro; - } - *dst++ = CL(' '); if(dst >= end) goto zro; - for(i = 0; i < 16; i++) { - *dst++ = (mem[i] < 32 || mem[i] >= 127 ? CL('.') : (char_t)mem[i]); - if(dst >= end) goto zro; - } - *dst++ = CL('\r'); if(dst >= end) goto zro; - *dst++ = CL('\n'); if(dst >= end) goto zro; - m += 16; - } - } - } else { -put: if(*fmt == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r'); - *dst++ = *fmt; - } - fmt++; - } -zro:*dst=0; - return (int)(dst-orig); -#undef needsescape -} - -int vsprintf(char_t *dst, const char_t *fmt, __builtin_va_list args) -{ - return vsnprintf(dst, BUFSIZ, fmt, args); -} - -int sprintf(char_t *dst, const char_t* fmt, ...) -{ - int ret; - __builtin_va_list args; - __builtin_va_start(args, fmt); - ret = vsnprintf(dst, BUFSIZ, fmt, args); - __builtin_va_end(args); - return ret; -} - -int snprintf(char_t *dst, size_t maxlen, const char_t* fmt, ...) -{ - int ret; - __builtin_va_list args; - __builtin_va_start(args, fmt); - ret = vsnprintf(dst, maxlen, fmt, args); - __builtin_va_end(args); - return ret; -} - -int vprintf(const char_t* fmt, __builtin_va_list args) -{ - int ret; - wchar_t dst[BUFSIZ]; -#ifndef UEFI_NO_UTF8 - char_t tmp[BUFSIZ]; - ret = vsnprintf(tmp, BUFSIZ, fmt, args); - mbstowcs(dst, tmp, BUFSIZ - 1); -#else - ret = vsnprintf(dst, BUFSIZ, fmt, args); -#endif - ST->ConOut->OutputString(ST->ConOut, (wchar_t *)&dst); - return ret; -} - -int printf(const char_t* fmt, ...) -{ - int ret; - __builtin_va_list args; - __builtin_va_start(args, fmt); - ret = vprintf(fmt, args); - __builtin_va_end(args); - return ret; -} - -int vfprintf (FILE *__stream, const char_t *__format, __builtin_va_list args) -{ - wchar_t dst[BUFSIZ]; - char_t tmp[BUFSIZ]; - uintn_t ret, i; -#ifndef UEFI_NO_UTF8 - ret = (uintn_t)vsnprintf(tmp, BUFSIZ, __format, args); - ret = mbstowcs(dst, tmp, BUFSIZ - 1); -#else - ret = vsnprintf(dst, BUFSIZ, __format, args); -#endif - if(ret < 1 || !__stream || __stream == stdin) return 0; - for(i = 0; i < __blk_ndevs; i++) - if(__stream == (FILE*)__blk_devs[i].bio) { - errno = EBADF; - return -1; - } - if(__stream == stdout) - ST->ConOut->OutputString(ST->ConOut, (wchar_t*)&dst); - else if(__stream == stderr) - ST->StdErr->OutputString(ST->StdErr, (wchar_t*)&dst); - else if(__ser && __stream == (FILE*)__ser) { -#ifdef UEFI_NO_UTF8 - wcstombs((char*)&tmp, dst, BUFSIZ - 1); -#endif - __ser->Write(__ser, &ret, (void*)&tmp); - } else -#ifndef UEFI_NO_UTF8 - __stream->Write(__stream, &ret, (void*)&tmp); -#else - __stream->Write(__stream, &ret, (void*)&dst); -#endif - return (int)ret; -} - -int fprintf (FILE *__stream, const char_t *__format, ...) -{ - int ret; - __builtin_va_list args; - __builtin_va_start(args, __format); - ret = vfprintf(__stream, __format, args); - __builtin_va_end(args); - return ret; -} - -int getchar_ifany (void) -{ - efi_input_key_t key = { 0 }; - efi_status_t status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); - return EFI_ERROR(status) ? 0 : key.UnicodeChar; -} - -int getchar (void) -{ - uintn_t idx; - BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &idx); - return getchar_ifany(); -} - -int putchar (int __c) -{ - wchar_t tmp[2]; - tmp[0] = (wchar_t)__c; - tmp[1] = 0; - ST->ConOut->OutputString(ST->ConOut, (__c == L'\n' ? (wchar_t*)L"\r\n" : (wchar_t*)&tmp)); - return (int)tmp[0]; -} diff --git a/Bootloader/Source/uefi/stdlib.c b/Bootloader/Source/uefi/stdlib.c deleted file mode 100644 index 81b33df..0000000 --- a/Bootloader/Source/uefi/stdlib.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * stdlib.c - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief Implementing functions which are defined in stdlib.h - * - */ - -#include - -int errno = 0; -static uint64_t __srand_seed = 6364136223846793005ULL; -extern void __stdio_cleanup(void); -#ifndef UEFI_NO_TRACK_ALLOC -static uintptr_t *__stdlib_allocs = NULL; -static uintn_t __stdlib_numallocs = 0; -#endif - -int atoi(const char_t *s) -{ - return (int)atol(s); -} - -int64_t atol(const char_t *s) -{ - int64_t sign = 1; - if(!s || !*s) return 0; - if(*s == CL('-')) { sign = -1; s++; } - if(s[0] == CL('0')) { - if(s[1] == CL('x')) - return strtol(s + 2, NULL, 16) * sign; - if(s[1] >= CL('0') && s[1] <= CL('7')) - return strtol(s, NULL, 8) * sign; - } - return strtol(s, NULL, 10) * sign; -} - -int64_t strtol (const char_t *s, char_t **__endptr, int __base) -{ - int64_t v=0, sign = 1; - if(!s || !*s) return 0; - if(*s == CL('-')) { sign = -1; s++; } - while(!(*s < CL('0') || (__base < 10 && *s >= __base + CL('0')) || (__base >= 10 && ((*s > CL('9') && *s < CL('A')) || - (*s > CL('F') && *s < CL('a')) || *s > CL('f'))))) { - v *= __base; - if(*s >= CL('0') && *s <= (__base < 10 ? __base + CL('0') : CL('9'))) - v += (*s)-CL('0'); - else if(__base == 16 && *s >= CL('a') && *s <= CL('f')) - v += (*s)-CL('a')+10; - else if(__base == 16 && *s >= CL('A') && *s <= CL('F')) - v += (*s)-CL('A')+10; - s++; - } - if(__endptr) *__endptr = (char_t*)s; - return v * sign; -} - -void *malloc (size_t __size) -{ - void *ret = NULL; - efi_status_t status; -#ifndef UEFI_NO_TRACK_ALLOC - uintn_t i; - for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != 0; i += 2); - if(i == __stdlib_numallocs) { - /* no free slots found, (re)allocate the housekeeping array */ - status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (__stdlib_numallocs + 2) * sizeof(uintptr_t), &ret); - if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; } - if(__stdlib_allocs) memcpy(ret, __stdlib_allocs, __stdlib_numallocs * sizeof(uintptr_t)); - __stdlib_allocs = (uintptr_t*)ret; - __stdlib_allocs[i] = __stdlib_allocs[i + 1] = 0; - __stdlib_numallocs += 2; - ret = NULL; - } -#endif - status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); - if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; } -#ifndef UEFI_NO_TRACK_ALLOC - __stdlib_allocs[i] = (uintptr_t)ret; - __stdlib_allocs[i + 1] = (uintptr_t)__size; -#endif - return ret; -} - -void *calloc (size_t __nmemb, size_t __size) -{ - void *ret = malloc(__nmemb * __size); - if(ret) memset(ret, 0, __nmemb * __size); - return ret; -} - -void *realloc (void *__ptr, size_t __size) -{ - void *ret = NULL; - efi_status_t status; -#ifndef UEFI_NO_TRACK_ALLOC - uintn_t i; -#endif - if(!__ptr) return malloc(__size); - if(!__size) { free(__ptr); return NULL; } -#ifndef UEFI_NO_TRACK_ALLOC - /* get the slot which stores the old size for this buffer */ - for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2); - if(i == __stdlib_numallocs) { errno = ENOMEM; return NULL; } - /* allocate a new buffer and copy data from old buffer */ - status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); - if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; } - else { - memcpy(ret, (void*)__stdlib_allocs[i], __stdlib_allocs[i + 1] < __size ? __stdlib_allocs[i + 1] : __size); - if(__size > __stdlib_allocs[i + 1]) memset((uint8_t*)ret + __stdlib_allocs[i + 1], 0, __size - __stdlib_allocs[i + 1]); - /* free old buffer and store new buffer in slot */ - BS->FreePool((void*)__stdlib_allocs[i]); - __stdlib_allocs[i] = (uintptr_t)ret; - __stdlib_allocs[i + 1] = (uintptr_t)__size; - } -#else - status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); - if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; } - /* this means out of bounds read, but fine with POSIX as the end of new buffer supposed to be left uninitialized) */ - memcpy(ret, (void*)__ptr, __size); - BS->FreePool((void*)__ptr); -#endif - return ret; -} - -void free (void *__ptr) -{ - efi_status_t status; -#ifndef UEFI_NO_TRACK_ALLOC - uintn_t i; -#endif - if(!__ptr) { errno = ENOMEM; return; } -#ifndef UEFI_NO_TRACK_ALLOC - /* find and clear the slot */ - for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2); - if(i == __stdlib_numallocs) { errno = ENOMEM; return; } - __stdlib_allocs[i] = 0; - __stdlib_allocs[i + 1] = 0; - /* if there are only empty slots, free the housekeeping array too */ - for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] == 0; i += 2); - if(i == __stdlib_numallocs) { BS->FreePool(__stdlib_allocs); __stdlib_allocs = NULL; __stdlib_numallocs = 0; } -#endif - status = BS->FreePool(__ptr); - if(EFI_ERROR(status)) errno = ENOMEM; -} - -void abort () -{ -#ifndef UEFI_NO_TRACK_ALLOC - if(__stdlib_allocs) - BS->FreePool(__stdlib_allocs); - __stdlib_allocs = NULL; - __stdlib_numallocs = 0; -#endif - __stdio_cleanup(); - BS->Exit(IM, EFI_ABORTED, 0, NULL); -} - -void exit (int __status) -{ -#ifndef UEFI_NO_TRACK_ALLOC - if(__stdlib_allocs) - BS->FreePool(__stdlib_allocs); - __stdlib_allocs = NULL; - __stdlib_numallocs = 0; -#endif - __stdio_cleanup(); - BS->Exit(IM, !__status ? 0 : (__status < 0 ? EFIERR(-__status) : EFIERR(__status)), 0, NULL); -} - -int exit_bs() -{ - efi_status_t status = 0; - efi_memory_descriptor_t *memory_map = NULL; - uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0; -#ifndef UEFI_NO_TRACK_ALLOC - if(__stdlib_allocs) - BS->FreePool(__stdlib_allocs); - __stdlib_allocs = NULL; - __stdlib_numallocs = 0; -#endif - __stdio_cleanup(); - while(cnt--) { - status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL); - if (status!=EFI_BUFFER_TOO_SMALL) break; - status = BS->ExitBootServices(IM, map_key); - if(!EFI_ERROR(status)) return 0; - } - return (int)(status & 0xffff); -} - -void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, __compar_fn_t cmp) -{ - uint64_t s=0, e=nmemb, m; - int ret; - while (s < e) { - m = s + (e-s)/2; - ret = cmp(key, (uint8_t*)base + m*size); - if (ret < 0) e = m; else - if (ret > 0) s = m+1; else - return (void *)((uint8_t*)base + m*size); - } - return NULL; -} - -int mblen(const char *s, size_t n) -{ - const char *e = s+n; - int c = 0; - if(s) { - while(s < e && *s) { - if((*s & 128) != 0) { - if((*s & 32) == 0 ) s++; else - if((*s & 16) == 0 ) s+=2; else - if((*s & 8) == 0 ) s+=3; - } - c++; - s++; - } - } - return c; -} - -int mbtowc (wchar_t * __pwc, const char *s, size_t n) -{ - wchar_t arg; - int ret = 1; - if(!s || !*s) return 0; - arg = (wchar_t)*s; - if((*s & 128) != 0) { - if((*s & 32) == 0 && n > 0) { arg = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); ret = 2; } else - if((*s & 16) == 0 && n > 1) { arg = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); ret = 3; } else - if((*s & 8) == 0 && n > 2) { arg = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); ret = 4; } - else return -1; - } - if(__pwc) *__pwc = arg; - return ret; -} - -int wctomb (char *s, wchar_t u) -{ - int ret = 0; - if(u<0x80) { - *s = u; - ret = 1; - } else if(u<0x800) { - *(s+0)=((u>>6)&0x1F)|0xC0; - *(s+1)=(u&0x3F)|0x80; - ret = 2; - } else { - *(s+0)=((u>>12)&0x0F)|0xE0; - *(s+1)=((u>>6)&0x3F)|0x80; - *(s+2)=(u&0x3F)|0x80; - ret = 3; - } - return ret; -} - -size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n) -{ - int r; - wchar_t *orig = __pwcs; - if(!__s || !*__s) return 0; - while(*__s) { - r = mbtowc(__pwcs, __s, __n - (size_t)(__pwcs - orig)); - if(r < 0) return (size_t)-1; - __pwcs++; - __s += r; - } - *__pwcs = 0; - return (size_t)(__pwcs - orig); -} - -size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n) -{ - int r; - char *orig = __s; - if(!__s || !__pwcs || !*__pwcs) return 0; - while(*__pwcs && ((size_t)(__s - orig + 4) < __n)) { - r = wctomb(__s, *__pwcs); - if(r < 0) return (size_t)-1; - __pwcs++; - __s += r; - } - *__s = 0; - return (size_t)(__s - orig); -} - -void srand(unsigned int __seed) -{ - __srand_seed = __seed - 1; -} - -int rand() -{ - efi_guid_t rngGuid = EFI_RNG_PROTOCOL_GUID; - efi_rng_protocol_t *rng = NULL; - efi_status_t status; - int ret = 0; - - __srand_seed = 6364136223846793005ULL*__srand_seed + 1; - status = BS->LocateProtocol(&rngGuid, NULL, (void**)&rng); - if(!EFI_ERROR(status) && rng) - rng->GetRNG(rng, NULL, (uintn_t)sizeof(int), (uint8_t*)&ret); - ret ^= (int)(__srand_seed>>33); - return ret; -} - -uint8_t *getenv(char_t *name, uintn_t *len) -{ - efi_guid_t globGuid = EFI_GLOBAL_VARIABLE; - uint8_t tmp[EFI_MAXIMUM_VARIABLE_SIZE], *ret; - uint32_t attr; - efi_status_t status; -#ifndef UEFI_NO_UTF8 - wchar_t wcname[256]; - mbstowcs((wchar_t*)&wcname, name, 256); - status = RT->GetVariable((wchar_t*)&wcname, &globGuid, &attr, len, &tmp); -#else - status = RT->GetVariable(name, &globGuid, &attr, len, &tmp); -#endif - if(EFI_ERROR(status) || *len < 1 || !(ret = malloc((*len) + 1))) { - *len = 0; - return NULL; - } - memcpy(ret, tmp, *len); - ret[*len] = 0; - return ret; -} - -int setenv(char_t *name, uintn_t len, uint8_t *data) -{ - efi_guid_t globGuid = EFI_GLOBAL_VARIABLE; - efi_status_t status; -#ifndef UEFI_NO_UTF8 - wchar_t wcname[256]; - mbstowcs((wchar_t*)&wcname, name, 256); - status = RT->SetVariable(wcname, &globGuid, 0, len, data); -#else - status = RT->SetVariable(name, &globGuid, 0, len, data); -#endif - return !EFI_ERROR(status); -} diff --git a/Bootloader/Source/uefi/string.c b/Bootloader/Source/uefi/string.c deleted file mode 100644 index a6d0348..0000000 --- a/Bootloader/Source/uefi/string.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * string.c - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief Implementing functions which are defined in string.h - * - */ - -#include - -void *memcpy(void *dst, const void *src, size_t n) -{ - uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src; - if(src && dst && src != dst && n>0) { - while(n--) *a++ = *b++; - } - return dst; -} - -void *memmove(void *dst, const void *src, size_t n) -{ - uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src; - if(src && dst && src != dst && n>0) { - if(a>b && a0) *a--=*b--; - } else { - while(n--) *a++ = *b++; - } - } - return dst; -} - -void *memset(void *s, int c, size_t n) -{ - uint8_t *p=(uint8_t*)s; - if(s && n>0) { - while(n--) *p++ = (uint8_t)c; - } - return s; -} - -int memcmp(const void *s1, const void *s2, size_t n) -{ - uint8_t *a=(uint8_t*)s1,*b=(uint8_t*)s2; - if(s1 && s2 && s1 != s2 && n>0) { - while(n--) { - if(*a != *b) return *a - *b; - a++; b++; - } - } - return 0; -} - -void *memchr(const void *s, int c, size_t n) -{ - uint8_t *e, *p=(uint8_t*)s; - if(s && n>0) { - for(e=p+n; p0) { - for(e=p+n; p hl) return NULL; - hl -= nl - 1; - while(hl) { - if(!memcmp(c, needle, nl)) return c; - c++; hl--; - } - return NULL; -} - -void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl) -{ - uint8_t *c = (uint8_t*)haystack; - if(!haystack || !needle || !hl || !nl || nl > hl) return NULL; - hl -= nl; - c += hl; - while(hl) { - if(!memcmp(c, needle, nl)) return c; - c--; hl--; - } - return NULL; -} - -char_t *strcpy(char_t *dst, const char_t *src) -{ - char_t *s = dst; - if(src && dst && src != dst) { - while(*src) {*dst++=*src++;} *dst=0; - } - return s; -} - -char_t *strncpy(char_t *dst, const char_t *src, size_t n) -{ - char_t *s = dst; - const char_t *e = src+n; - if(src && dst && src != dst && n>0) { - while(*src && src0) { - dst += strlen(dst); - while(*src && src0) { - while(s1 - -static struct tm __tm; -time_t __mktime_efi(efi_time_t *t); - -/* from musl */ -static uint64_t __year_to_secs(uint64_t year, int *is_leap) -{ - int y, cycles, centuries, leaps, rem; - - if (year-2ULL <= 136) { - y = (int)year; - leaps = (y-68)>>2; - if (!((y-68)&3)) { - leaps--; - if (is_leap) *is_leap = 1; - } else if (is_leap) *is_leap = 0; - return 31536000ULL*(uint64_t)(y-70) + 86400ULL*(uint64_t)leaps; - } - - if (!is_leap) is_leap = &(int){0}; - cycles = (int)((year-100) / 400); - rem = (year-100) % 400; - if (rem < 0) { - cycles--; - rem += 400; - } - if (!rem) { - *is_leap = 1; - centuries = 0; - leaps = 0; - } else { - if (rem >= 200) { - if (rem >= 300) { centuries = 3; rem -= 300; } - else { centuries = 2; rem -= 200; } - } else { - if (rem >= 100) { centuries = 1; rem -= 100; } - else centuries = 0; - } - if (!rem) { - *is_leap = 0; - leaps = 0; - } else { - leaps = rem / 4; - rem %= 4; - *is_leap = !rem; - } - } - - leaps += 97*cycles + 24*centuries - *is_leap; - - return (uint64_t)(year-100) * 31536000ULL + (uint64_t)leaps * 86400ULL + 946684800ULL + 86400ULL; -} - -time_t __mktime_efi(efi_time_t *t) -{ - __tm.tm_year = t->Year + (/* workaround some buggy firmware*/ t->Year > 2000 ? -1900 : 98); - __tm.tm_mon = t->Month - 1; - __tm.tm_mday = t->Day; - __tm.tm_hour = t->Hour; - __tm.tm_min = t->Minute; - __tm.tm_sec = t->Second; - __tm.tm_isdst = t->Daylight; - return mktime(&__tm); -} - -/** - * This isn't POSIX, no arguments. Just returns the current time in struct tm - */ -struct tm *localtime (const time_t *__timer) -{ - efi_time_t t = {0}; - (void)__timer; - ST->RuntimeServices->GetTime(&t, NULL); - __mktime_efi(&t); - return &__tm; -} - -time_t mktime(const struct tm *tm) -{ - static const uint64_t secs_through_month[] = { - 0, 31*86400, 59*86400, 90*86400, - 120*86400, 151*86400, 181*86400, 212*86400, - 243*86400, 273*86400, 304*86400, 334*86400 }; - int is_leap; - uint64_t year = (uint64_t)tm->tm_year, t, adj; - int month = tm->tm_mon; - if (month >= 12 || month < 0) { - adj = (uint64_t)month / 12; - month %= 12; - if (month < 0) { - adj--; - month += 12; - } - year += adj; - } - t = __year_to_secs(year, &is_leap); - t += secs_through_month[month]; - if (is_leap && month >= 2) t += 86400; - t += 86400ULL * (uint64_t)(tm->tm_mday-1); - t += 3600ULL * (uint64_t)tm->tm_hour; - t += 60ULL * (uint64_t)tm->tm_min; - t += (uint64_t)tm->tm_sec; - return (time_t)t; -} - -time_t time(time_t *__timer) -{ - time_t ret; - efi_time_t t = {0}; - ST->RuntimeServices->GetTime(&t, NULL); - ret = __mktime_efi(&t); - if(__timer) *__timer = ret; - return ret; -} - diff --git a/Bootloader/Source/uefi/uefi.h b/Bootloader/Source/uefi/uefi.h index d46ed95..f229ba1 100644 --- a/Bootloader/Source/uefi/uefi.h +++ b/Bootloader/Source/uefi/uefi.h @@ -1,514 +1,56 @@ -/* - * uefi.h - * https://gitlab.com/bztsrc/posix-uefi - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief Main (and only) header file - * - */ +#pragma once -#ifndef _UEFI_H_ -#define _UEFI_H_ - -/*** configuration ***/ -/* #define UEFI_NO_UTF8 */ /* use wchar_t in your application */ -/* #define UEFI_NO_TRACK_ALLOC */ /* do not track allocated buffers' size */ -/*** configuration ends ***/ - -#ifdef __cplusplus -extern "C" { -#endif - -/* get these from the compiler or the efi headers, only define if we have neither */ -#if !defined(_STDINT_H) && !defined(_GCC_STDINT_H) && !defined(_EFI_INCLUDE_) -#define _STDINT_H -typedef char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef int int32_t; -typedef unsigned int uint32_t; -#ifndef __clang__ -typedef long int int64_t; -typedef unsigned long int uint64_t; -typedef unsigned long int uintptr_t; -#else -typedef long long int64_t; -typedef unsigned long long uint64_t; -typedef unsigned long long uintptr_t; -#endif -#endif -extern char c_assert1[sizeof(uint32_t) == 4 ? 1 : -1]; -extern char c_assert2[sizeof(uint64_t) == 8 ? 1 : -1]; -extern char c_assert3[sizeof(uintptr_t) == 8 ? 1 : -1]; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef int int32_t; +typedef long long int64_t; +typedef uint64_t uintptr_t; +typedef int64_t intn_t; +typedef uint64_t uintn_t; +typedef uint8_t boolean_t; +typedef uint64_t efi_status_t; +typedef uint64_t efi_tpl_t; +typedef uint64_t efi_physical_address_t; +typedef uint64_t efi_virtual_address_t; +typedef void* efi_handle_t; +typedef void* efi_event_t; #ifndef NULL #define NULL ((void*)0) #endif -/*** common defines and typedefs ***/ -typedef int64_t intn_t; -typedef uint8_t boolean_t; + #ifndef __cplusplus typedef uint16_t wchar_t; #endif -typedef uint64_t uintn_t; -typedef uint64_t size_t; -typedef uint64_t time_t; -typedef uint64_t mode_t; -typedef uint64_t off_t; -typedef uint64_t blkcnt_t; -typedef uint64_t efi_status_t; -typedef uint64_t efi_tpl_t; -typedef uint64_t efi_lba_t; -typedef uint64_t efi_physical_address_t; -typedef uint64_t efi_virtual_address_t; -typedef void *efi_handle_t; -typedef void *efi_event_t; -#ifndef UEFI_NO_UTF8 -typedef char char_t; -#define CL(a) a -extern char *__argvutf8; -#else -typedef wchar_t char_t; -#define CL(a) L ## a -#endif - -typedef struct { - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; -} efi_guid_t; - -typedef struct { - uint8_t Type; - uint8_t SubType; - uint8_t Length[2]; -} efi_device_path_t; - -typedef struct { - uint32_t Type; - uint32_t Pad; - efi_physical_address_t PhysicalStart; - efi_virtual_address_t VirtualStart; - uint64_t NumberOfPages; - uint64_t Attribute; -} efi_memory_descriptor_t; - -typedef struct { - uint64_t Signature; - uint32_t Revision; - uint32_t HeaderSize; - uint32_t CRC32; - uint32_t Reserved; -} efi_table_header_t; - -/*** definitions only needed when efi.h (either from EDK II or gnu-efi) is NOT included ***/ - -#ifndef EFI_SPECIFICATION_MAJOR_REVISION - -/* efibind.h */ -#ifndef __WCHAR_TYPE__ -# define __WCHAR_TYPE__ short -#endif -#define EFIERR(a) (0x8000000000000000 | (unsigned int)(a)) -#define EFI_ERROR_MASK 0x8000000000000000 -#define EFIERR_OEM(a) (0xc000000000000000 | (unsigned int)(a)) - -#define BAD_POINTER 0xFBFBFBFBFBFBFBFB -#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF - -#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) -#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) -#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((uint64_t)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) #ifndef EFIAPI -# ifdef _MSC_EXTENSIONS -# define EFIAPI __cdecl -# elif defined(HAVE_USE_MS_ABI) -# define EFIAPI __attribute__((ms_abi)) -# else -# define EFIAPI -# endif +#define EFIAPI #endif -/* efistdarg.h */ -typedef __builtin_va_list va_list; -#define va_start(v,l) __builtin_va_start(v,l) -#define va_end(v) __builtin_va_end(v) -#define va_arg(v,l) __builtin_va_arg(v,l) -#define va_copy(d,s) __builtin_va_copy(d,s) +#define EFIERR(value) (0x8000000000000000ULL | (uint32_t)(value)) +#define EFI_ERROR(status) (((intn_t)(status)) < 0) -/* efierr.h */ -#define EFIWARN(a) (a) -#define EFI_ERROR(a) (((intn_t) a) < 0) -#define EFI_SUCCESS 0 -#define EFI_LOAD_ERROR EFIERR(1) -#define EFI_INVALID_PARAMETER EFIERR(2) -#define EFI_UNSUPPORTED EFIERR(3) -#define EFI_BAD_BUFFER_SIZE EFIERR(4) -#define EFI_BUFFER_TOO_SMALL EFIERR(5) -#define EFI_NOT_READY EFIERR(6) -#define EFI_DEVICE_ERROR EFIERR(7) -#define EFI_WRITE_PROTECTED EFIERR(8) -#define EFI_OUT_OF_RESOURCES EFIERR(9) -#define EFI_VOLUME_CORRUPTED EFIERR(10) -#define EFI_VOLUME_FULL EFIERR(11) -#define EFI_NO_MEDIA EFIERR(12) -#define EFI_MEDIA_CHANGED EFIERR(13) -#define EFI_NOT_FOUND EFIERR(14) -#define EFI_ACCESS_DENIED EFIERR(15) -#define EFI_NO_RESPONSE EFIERR(16) -#define EFI_NO_MAPPING EFIERR(17) -#define EFI_TIMEOUT EFIERR(18) -#define EFI_NOT_STARTED EFIERR(19) -#define EFI_ALREADY_STARTED EFIERR(20) -#define EFI_ABORTED EFIERR(21) -#define EFI_ICMP_ERROR EFIERR(22) -#define EFI_TFTP_ERROR EFIERR(23) -#define EFI_PROTOCOL_ERROR EFIERR(24) -#define EFI_INCOMPATIBLE_VERSION EFIERR(25) -#define EFI_SECURITY_VIOLATION EFIERR(26) -#define EFI_CRC_ERROR EFIERR(27) -#define EFI_END_OF_MEDIA EFIERR(28) -#define EFI_END_OF_FILE EFIERR(31) -#define EFI_INVALID_LANGUAGE EFIERR(32) -#define EFI_COMPROMISED_DATA EFIERR(33) +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR EFIERR(1) +#define EFI_UNSUPPORTED EFIERR(3) +#define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_ABORTED EFIERR(21) -#define EFI_WARN_UNKOWN_GLYPH EFIWARN(1) -#define EFI_WARN_UNKNOWN_GLYPH EFIWARN(1) -#define EFI_WARN_DELETE_FAILURE EFIWARN(2) -#define EFI_WARN_WRITE_FAILURE EFIWARN(3) -#define EFI_WARN_BUFFER_TOO_SMALL EFIWARN(4) +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_FILE_MODE_READ 0x0000000000000001ULL -/* efisetjmp.h */ -#ifdef __x86_64__ -typedef struct { - uint64_t Rbx; - uint64_t Rsp; - uint64_t Rbp; - uint64_t Rdi; - uint64_t Rsi; - uint64_t R12; - uint64_t R13; - uint64_t R14; - uint64_t R15; - uint64_t Rip; - uint64_t MxCsr; - uint8_t XmmBuffer[160]; -} __attribute__((aligned(8))) jmp_buf[1]; -#endif -#ifdef __aarch64__ -typedef struct { - uint64_t X19; - uint64_t X20; - uint64_t X21; - uint64_t X22; - uint64_t X23; - uint64_t X24; - uint64_t X25; - uint64_t X26; - uint64_t X27; - uint64_t X28; - uint64_t FP; - uint64_t LR; - uint64_t IP0; - uint64_t reserved; - uint64_t D8; - uint64_t D9; - uint64_t D10; - uint64_t D11; - uint64_t D12; - uint64_t D13; - uint64_t D14; - uint64_t D15; -} __attribute__((aligned(8))) jmp_buf[1]; -#endif -#if defined(__riscv) && __riscv_xlen == 64 -typedef struct { - uint64_t pc; - uint64_t sp; - uint64_t regs[12]; - double fp[12]; -} __attribute__((aligned(8))) jmp_buf[1]; -#endif -extern uintn_t setjmp(jmp_buf env) __attribute__((returns_twice)); -extern void longjmp(jmp_buf env, uintn_t value) __attribute__((noreturn)); +#define EFI_LOADED_IMAGE_PROTOCOL_GUID \ + {0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B}} +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ + {0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +#define EFI_FILE_INFO_GUID \ + {0x09576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ + {0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a}} -/* efidevp.h */ -#define EFI_DEVICE_PATH_PROTOCOL_GUID { 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } -#define EFI_DP_TYPE_MASK 0x7F -#define EFI_DP_TYPE_UNPACKED 0x80 -#define END_DEVICE_PATH_TYPE 0x7f -#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff -#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 -#define END_DEVICE_PATH_LENGTH (sizeof(efi_device_path_t)) -#define DP_IS_END_TYPE(a) -#define DP_IS_END_SUBTYPE(a) ( ((a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) -#define DevicePathType(a) ( ((a)->Type) & EFI_DP_TYPE_MASK ) -#define DevicePathSubType(a) ( (a)->SubType ) -#define DevicePathNodeLength(a) ( ((a)->Length[0]) | ((a)->Length[1] << 8) ) -#define NextDevicePathNode(a) ( (efi_device_path_t *) ( ((uint8_t *) (a)) + DevicePathNodeLength(a))) -#define IsDevicePathEndType(a) ( DevicePathType(a) == END_DEVICE_PATH_TYPE ) -#define IsDevicePathEndSubType(a) ( (a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) -#define IsDevicePathEnd(a) ( IsDevicePathEndType(a) && IsDevicePathEndSubType(a) ) -#define IsDevicePathUnpacked(a) ( (a)->Type & EFI_DP_TYPE_UNPACKED ) -#define SetDevicePathNodeLength(a,l) { \ - (a)->Length[0] = (uint8_t) (l); \ - (a)->Length[1] = (uint8_t) ((l) >> 8); \ - } -#define SetDevicePathEndNode(a) { \ - (a)->Type = END_DEVICE_PATH_TYPE; \ - (a)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; \ - (a)->Length[0] = sizeof(efi_device_path_t); \ - (a)->Length[1] = 0; \ - } - -/* efiapi.h */ -#define EFI_SPECIFICATION_MAJOR_REVISION 1 -#define EFI_SPECIFICATION_MINOR_REVISION 02 - -#define TPL_APPLICATION 4 -#define TPL_CALLBACK 8 -#define TPL_NOTIFY 16 -#define TPL_HIGH_LEVEL 31 -#define EFI_TPL_APPLICATION TPL_APPLICATION -#define EFI_TPL_CALLBACK TPL_CALLBACK -#define EFI_TPL_NOTIFY TPL_NOTIFY -#define EFI_TPL_HIGH_LEVEL TPL_HIGH_LEVEL - -#define NextMemoryDescriptor(Ptr,Size) ((efi_memory_descriptor_t *) (((uint8_t *) Ptr) + Size)) - -#define EFI_PAGE_SIZE 4096 -#define EFI_PAGE_MASK 0xFFF -#define EFI_PAGE_SHIFT 12 - -#define EFI_SIZE_TO_PAGES(a) ( ((a) >> EFI_PAGE_SHIFT) + ((a) & EFI_PAGE_MASK ? 1 : 0) ) - -#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_RUNTIME 0x8000000000000000 -#define EFI_MEMORY_DESCRIPTOR_VERSION 1 - -#define EVT_TIMER 0x80000000 -#define EVT_RUNTIME 0x40000000 -#define EVT_RUNTIME_CONTEXT 0x20000000 - -#define EVT_NOTIFY_WAIT 0x00000100 -#define EVT_NOTIFY_SIGNAL 0x00000200 - -#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 -#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 - -#define EVT_EFI_SIGNAL_MASK 0x000000FF -#define EVT_EFI_SIGNAL_MAX 4 - -#define EFI_EVENT_TIMER EVT_TIMER -#define EFI_EVENT_RUNTIME EVT_RUNTIME -#define EFI_EVENT_RUNTIME_CONTEXT EVT_RUNTIME_CONTEXT -#define EFI_EVENT_NOTIFY_WAIT EVT_NOTIFY_WAIT -#define EFI_EVENT_NOTIFY_SIGNAL EVT_NOTIFY_SIGNAL -#define EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES EVT_SIGNAL_EXIT_BOOT_SERVICES -#define EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE -#define EFI_EVENT_EFI_SIGNAL_MASK EVT_EFI_SIGNAL_MASK -#define EFI_EVENT_EFI_SIGNAL_MAX EVT_EFI_SIGNAL_MAX - -#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_OPTIONAL_PTR 0x00000001 -#define EFI_INTERNAL_FNC 0x00000002 -#define EFI_INTERNAL_PTR 0x00000004 - -#define EFI_GLOBAL_VARIABLE { 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C} } -#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 -#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 -#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 -#define EFI_VARIABLE_APPEND_WRITE 0x00000040 -#define EFI_MAXIMUM_VARIABLE_SIZE 1024 - -#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 -#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 -#define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 - -#define MPS_TABLE_GUID { 0xeb9d2d2f, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } -#define ACPI_TABLE_GUID { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } -#define ACPI_20_TABLE_GUID { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } -#define SMBIOS_TABLE_GUID { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } -#define SMBIOS3_TABLE_GUID { 0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e,0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94} } -#define SAL_SYSTEM_TABLE_GUID { 0xeb9d2d32, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552 -#define EFI_RUNTIME_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) - -#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 -#define EFI_BOOT_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) - -#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 -#define EFI_SYSTEM_TABLE_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) - -/* eficon.h */ -#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID { 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } -#define EFI_BLACK 0x00 -#define EFI_BLUE 0x01 -#define EFI_GREEN 0x02 -#define EFI_CYAN (EFI_BLUE | EFI_GREEN) -#define EFI_RED 0x04 -#define EFI_MAGENTA (EFI_BLUE | EFI_RED) -#define EFI_BROWN (EFI_GREEN | EFI_RED) -#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED) -#define EFI_BRIGHT 0x08 -#define EFI_DARKGRAY (EFI_BRIGHT) -#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT) -#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT) -#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT) -#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT) -#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT) -#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT) -#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT) -#define EFI_TEXT_ATTR(f,b) ((f) | ((b) << 4)) -#define EFI_BACKGROUND_BLACK 0x00 -#define EFI_BACKGROUND_BLUE 0x10 -#define EFI_BACKGROUND_GREEN 0x20 -#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN) -#define EFI_BACKGROUND_RED 0x40 -#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED) -#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) -#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) -#define BOXDRAW_HORIZONTAL 0x2500 -#define BOXDRAW_VERTICAL 0x2502 -#define BOXDRAW_DOWN_RIGHT 0x250c -#define BOXDRAW_DOWN_LEFT 0x2510 -#define BOXDRAW_UP_RIGHT 0x2514 -#define BOXDRAW_UP_LEFT 0x2518 -#define BOXDRAW_VERTICAL_RIGHT 0x251c -#define BOXDRAW_VERTICAL_LEFT 0x2524 -#define BOXDRAW_DOWN_HORIZONTAL 0x252c -#define BOXDRAW_UP_HORIZONTAL 0x2534 -#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c -#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 -#define BOXDRAW_DOUBLE_VERTICAL 0x2551 -#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 -#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 -#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 -#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 -#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 -#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 -#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 -#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 -#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a -#define BOXDRAW_UP_LEFT_DOUBLE 0x255b -#define BOXDRAW_UP_DOUBLE_LEFT 0x255c -#define BOXDRAW_DOUBLE_UP_LEFT 0x255d -#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e -#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f -#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 -#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 -#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 -#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 -#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 -#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 -#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 -#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 -#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 -#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 -#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a -#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b -#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c -#define BLOCKELEMENT_FULL_BLOCK 0x2588 -#define BLOCKELEMENT_LIGHT_SHADE 0x2591 -#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 -#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba -#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc -#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 -#define ARROW_UP 0x2191 -#define ARROW_DOWN 0x2193 - -#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID { 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } -#define CHAR_NULL 0x0000 -#define CHAR_BACKSPACE 0x0008 -#define CHAR_TAB 0x0009 -#define CHAR_LINEFEED 0x000A -#define CHAR_CARRIAGE_RETURN 0x000D -#define SCAN_NULL 0x0000 -#define SCAN_UP 0x0001 -#define SCAN_DOWN 0x0002 -#define SCAN_RIGHT 0x0003 -#define SCAN_LEFT 0x0004 -#define SCAN_HOME 0x0005 -#define SCAN_END 0x0006 -#define SCAN_INSERT 0x0007 -#define SCAN_DELETE 0x0008 -#define SCAN_PAGE_UP 0x0009 -#define SCAN_PAGE_DOWN 0x000A -#define SCAN_F1 0x000B -#define SCAN_F2 0x000C -#define SCAN_F3 0x000D -#define SCAN_F4 0x000E -#define SCAN_F5 0x000F -#define SCAN_F6 0x0010 -#define SCAN_F7 0x0011 -#define SCAN_F8 0x0012 -#define SCAN_F9 0x0013 -#define SCAN_F10 0x0014 -#define SCAN_F11 0x0015 -#define SCAN_F12 0x0016 -#define SCAN_ESC 0x0017 - -/* efigpt.h */ -#define PRIMARY_PART_HEADER_LBA 1 -#define EFI_PTAB_HEADER_ID "EFI PART" -#define EFI_PART_USED_BY_EFI 0x0000000000000001 -#define EFI_PART_REQUIRED_TO_FUNCTION 0x0000000000000002 -#define EFI_PART_USED_BY_OS 0x0000000000000004 -#define EFI_PART_REQUIRED_BY_OS 0x0000000000000008 -#define EFI_PART_BACKUP_REQUIRED 0x0000000000000010 -#define EFI_PART_USER_DATA 0x0000000000000020 -#define EFI_PART_CRITICAL_USER_DATA 0x0000000000000040 -#define EFI_PART_REDUNDANT_PARTITION 0x0000000000000080 -#define EFI_PART_TYPE_UNUSED_GUID { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } -#define EFI_PART_TYPE_EFI_SYSTEM_PART_GUID { 0xc12a7328, 0xf81f, 0x11d2, {0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} } -#define EFI_PART_TYPE_LEGACY_MBR_GUID { 0x024dee41, 0x33e7, 0x11d3, {0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f} } - -/* Protocol GUIDs */ -#ifndef INTERNAL_SHELL_GUID -#define INTERNAL_SHELL_GUID { 0xd65a6b8c, 0x71e5, 0x4df0, {0xa9, 0x09, 0xf0, 0xd2, 0x99, 0x2b, 0x5a, 0xa9} } -#endif +#define FILENAME_MAX 262 typedef enum { AllocateAnyPages, @@ -537,13 +79,6 @@ typedef enum { EfiMaxMemoryType } efi_memory_type_t; -typedef enum { - TimerCancel, - TimerPeriodic, - TimerRelative, - TimerTypeMax -} efi_timer_delay_t; - typedef enum { AllHandles, ByRegisterNotify, @@ -551,896 +86,313 @@ typedef enum { } efi_locate_search_type_t; typedef enum { - EfiResetCold, - EfiResetWarm, - EfiResetShutdown -} efi_reset_type_t; - -#else - -#define efi_allocate_type_t EFI_ALLOCATE_TYPE -#define efi_memory_type_t EFI_MEMORY_TYPE -#define efi_timer_delay_t EFI_TIMER_DELAY -#define efi_locate_search_type_t EFI_LOCATE_SEARCH_TYPE -#define efi_reset_type_t EFI_RESET_TYPE - -#endif - -/*** standard input, output and error streams via ConIn, ConOut and StdErr ***/ -typedef struct { - uint16_t ScanCode; - wchar_t UnicodeChar; -} efi_input_key_t; - -typedef efi_status_t (EFIAPI *efi_input_reset_t)(void *This, boolean_t ExtendedVerification); -typedef efi_status_t (EFIAPI *efi_input_read_key_t)(void *This, efi_input_key_t *Key); + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax +} efi_gop_pixel_format_t; typedef struct { - efi_input_reset_t Reset; - efi_input_read_key_t ReadKeyStroke; - efi_event_t WaitForKey; -} simple_input_interface_t; - -typedef efi_status_t (EFIAPI *efi_text_reset_t)(void *This, boolean_t ExtendedVerification); -typedef efi_status_t (EFIAPI *efi_text_output_string_t)(void *This, wchar_t *String); -typedef efi_status_t (EFIAPI *efi_text_test_string_t)(void *This, wchar_t *String); -typedef efi_status_t (EFIAPI *efi_text_query_mode_t)(void *This, uintn_t ModeNumber, uintn_t *Column, uintn_t *Row); -typedef efi_status_t (EFIAPI *efi_text_set_mode_t)(void *This, uintn_t ModeNumber); -typedef efi_status_t (EFIAPI *efi_text_set_attribute_t)(void *This, uintn_t Attribute); -typedef efi_status_t (EFIAPI *efi_text_clear_screen_t)(void *This); -typedef efi_status_t (EFIAPI *efi_text_set_cursor_t)(void *This, uintn_t Column, uintn_t Row); -typedef efi_status_t (EFIAPI *efi_text_enable_cursor_t)(void *This, boolean_t Enable); + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} efi_guid_t; typedef struct { - int32_t MaxMode; - int32_t Mode; - int32_t Attribute; - int32_t CursorColumn; - int32_t CursorRow; - boolean_t CursorVisible; -} simple_text_output_mode_t; + uint8_t Type; + uint8_t SubType; + uint8_t Length[2]; +} efi_device_path_t; typedef struct { - efi_text_reset_t Reset; - efi_text_output_string_t OutputString; - efi_text_test_string_t TestString; - efi_text_query_mode_t QueryMode; - efi_text_set_mode_t SetMode; - efi_text_set_attribute_t SetAttribute; - efi_text_clear_screen_t ClearScreen; - efi_text_set_cursor_t SetCursorPosition; - efi_text_enable_cursor_t EnableCursor; - simple_text_output_mode_t *Mode; -} simple_text_output_interface_t; + uint32_t Type; + uint32_t Pad; + efi_physical_address_t PhysicalStart; + efi_virtual_address_t VirtualStart; + uint64_t NumberOfPages; + uint64_t Attribute; +} efi_memory_descriptor_t; -/*** Runtime Services ***/ typedef struct { - uint16_t Year; /* 1998 - 2XXX */ - uint8_t Month; /* 1 - 12 */ - uint8_t Day; /* 1 - 31 */ - uint8_t Hour; /* 0 - 23 */ - uint8_t Minute; /* 0 - 59 */ - uint8_t Second; /* 0 - 59 */ - uint8_t Pad1; - uint32_t Nanosecond; /* 0 - 999,999,999 */ - int16_t TimeZone; /* -1440 to 1440 or 2047 */ - uint8_t Daylight; - uint8_t Pad2; + uint64_t Signature; + uint32_t Revision; + uint32_t HeaderSize; + uint32_t CRC32; + uint32_t Reserved; +} efi_table_header_t; + +typedef struct { + uint16_t Year; + uint8_t Month; + uint8_t Day; + uint8_t Hour; + uint8_t Minute; + uint8_t Second; + uint8_t Pad1; + uint32_t Nanosecond; + short TimeZone; + uint8_t Daylight; + uint8_t Pad2; } efi_time_t; typedef struct { - uint32_t Resolution; - uint32_t Accuracy; - boolean_t SetsToZero; -} efi_time_capabilities_t; + uint16_t ScanCode; + wchar_t UnicodeChar; +} efi_input_key_t; typedef struct { - efi_guid_t CapsuleGuid; - uint32_t HeaderSize; - uint32_t Flags; - uint32_t CapsuleImageSize; -} efi_capsule_header_t; + int32_t MaxMode; + int32_t Mode; + int32_t Attribute; + int32_t CursorColumn; + int32_t CursorRow; + boolean_t CursorVisible; +} simple_text_output_mode_t; -#ifndef DataBlock -#define DataBlock ContinuationPointer -#endif -typedef struct { - uint64_t Length; - efi_physical_address_t ContinuationPointer; -} efi_capsule_block_descriptor_t; - -typedef efi_status_t (EFIAPI *efi_get_time_t)(efi_time_t *Time, efi_time_capabilities_t *Capabilities); -typedef efi_status_t (EFIAPI *efi_set_time_t)(efi_time_t *Time); -typedef efi_status_t (EFIAPI *efi_get_wakeup_time_t)(boolean_t *Enable, boolean_t *Pending, efi_time_t *Time); -typedef efi_status_t (EFIAPI *efi_set_wakeup_time_t)(boolean_t Enable, efi_time_t *Time); -typedef efi_status_t (EFIAPI *efi_set_virtual_address_map_t)(uintn_t MemoryMapSize, uintn_t DescriptorSize, - uint32_t DescriptorVersion, efi_memory_descriptor_t *VirtualMap); -typedef efi_status_t (EFIAPI *efi_convert_pointer_t)(uintn_t DebugDisposition, void **Address); -typedef efi_status_t (EFIAPI *efi_get_variable_t)(wchar_t *VariableName, efi_guid_t *VendorGuid, uint32_t *Attributes, - uintn_t *DataSize, void *Data); -typedef efi_status_t (EFIAPI *efi_get_next_variable_name_t)(uintn_t *VariableNameSize, wchar_t *VariableName, - efi_guid_t *VendorGuid); -typedef efi_status_t (EFIAPI *efi_set_variable_t)(wchar_t *VariableName, efi_guid_t *VendorGuid, uint32_t Attributes, - uintn_t DataSize, void *Data); -typedef efi_status_t (EFIAPI *efi_get_next_high_mono_t)(uint64_t *Count); -typedef efi_status_t (EFIAPI *efi_reset_system_t)(efi_reset_type_t ResetType, efi_status_t ResetStatus, uintn_t DataSize, - wchar_t *ResetData); -typedef efi_status_t (EFIAPI *efi_update_capsule_t)(efi_capsule_header_t **CapsuleHeaderArray, uintn_t CapsuleCount, - efi_physical_address_t ScatterGatherList); -typedef efi_status_t (EFIAPI *efi_query_capsule_capabilities_t)(efi_capsule_header_t **CapsuleHeaderArray, uintn_t CapsuleCount, - uint64_t *MaximumCapsuleSize, efi_reset_type_t *ResetType); -typedef efi_status_t (EFIAPI *efi_query_variable_info_t)(uint32_t Attributes, uint64_t *MaximumVariableStorageSize, - uint64_t *RemainingVariableStorageSize, uint64_t *MaximumVariableSize); +typedef efi_status_t (EFIAPI *efi_input_reset_t)(void* this_ptr, boolean_t extended_verification); +typedef efi_status_t (EFIAPI *efi_input_read_key_t)(void* this_ptr, efi_input_key_t* key); +typedef efi_status_t (EFIAPI *efi_text_reset_t)(void* this_ptr, boolean_t extended_verification); +typedef efi_status_t (EFIAPI *efi_text_output_string_t)(void* this_ptr, wchar_t* string); +typedef efi_status_t (EFIAPI *efi_text_test_string_t)(void* this_ptr, wchar_t* string); +typedef efi_status_t (EFIAPI *efi_text_query_mode_t)(void* this_ptr, uintn_t mode_number, uintn_t* column, uintn_t* row); +typedef efi_status_t (EFIAPI *efi_text_set_mode_t)(void* this_ptr, uintn_t mode_number); +typedef efi_status_t (EFIAPI *efi_text_set_attribute_t)(void* this_ptr, uintn_t attribute); +typedef efi_status_t (EFIAPI *efi_text_clear_screen_t)(void* this_ptr); +typedef efi_status_t (EFIAPI *efi_text_set_cursor_t)(void* this_ptr, uintn_t column, uintn_t row); +typedef efi_status_t (EFIAPI *efi_text_enable_cursor_t)(void* this_ptr, boolean_t enable); typedef struct { - efi_table_header_t Hdr; + efi_input_reset_t Reset; + efi_input_read_key_t ReadKeyStroke; + efi_event_t WaitForKey; +} simple_input_interface_t; - efi_get_time_t GetTime; - efi_set_time_t SetTime; - efi_get_wakeup_time_t GetWakeupTime; - efi_set_wakeup_time_t SetWakeupTime; +typedef struct { + efi_text_reset_t Reset; + efi_text_output_string_t OutputString; + efi_text_test_string_t TestString; + efi_text_query_mode_t QueryMode; + efi_text_set_mode_t SetMode; + efi_text_set_attribute_t SetAttribute; + efi_text_clear_screen_t ClearScreen; + efi_text_set_cursor_t SetCursorPosition; + efi_text_enable_cursor_t EnableCursor; + simple_text_output_mode_t* Mode; +} simple_text_output_interface_t; - efi_set_virtual_address_map_t SetVirtualAddressMap; - efi_convert_pointer_t ConvertPointer; - - efi_get_variable_t GetVariable; - efi_get_next_variable_name_t GetNextVariableName; - efi_set_variable_t SetVariable; - - efi_get_next_high_mono_t GetNextHighMonotonicCount; - efi_reset_system_t ResetSystem; - - efi_update_capsule_t UpdateCapsule; - efi_query_capsule_capabilities_t QueryCapsuleCapabilities; - efi_query_variable_info_t QueryVariableInfo; +typedef struct efi_runtime_services_t { + efi_table_header_t Hdr; } efi_runtime_services_t; -extern efi_runtime_services_t *RT; -#define gRT RT -/** Boot Services ***/ typedef struct { - efi_handle_t AgentHandle; - efi_handle_t ControllerHandle; - uint32_t Attributes; - uint32_t OpenCount; + efi_handle_t AgentHandle; + efi_handle_t ControllerHandle; + uint32_t Attributes; + uint32_t OpenCount; } efi_open_protocol_information_entry_t; -typedef efi_tpl_t (EFIAPI *efi_raise_tpl_t)(efi_tpl_t NewTpl); -typedef efi_tpl_t (EFIAPI *efi_restore_tpl_t)(efi_tpl_t OldTpl); -typedef efi_status_t (EFIAPI *efi_allocate_pages_t)(efi_allocate_type_t Type, efi_memory_type_t MemoryType, - uintn_t NoPages, efi_physical_address_t *Memory); -typedef efi_status_t (EFIAPI *efi_free_pages_t)(efi_physical_address_t Memory, uintn_t NoPages); -typedef efi_status_t (EFIAPI *efi_get_memory_map_t)(uintn_t *MemoryMapSize, efi_memory_descriptor_t *MemoryMap, - uintn_t *MapKey, uintn_t *DescriptorSize, uint32_t *DescriptorVersion); -typedef efi_status_t (EFIAPI *efi_allocate_pool_t)(efi_memory_type_t PoolType, uintn_t Size, void **Buffer); -typedef efi_status_t (EFIAPI *efi_free_pool_t)(void *Buffer); -typedef void (EFIAPI *efi_event_notify_t)(efi_event_t Event, void *Context); -typedef efi_status_t (EFIAPI *efi_create_event_t)(uint32_t Type, efi_tpl_t NotifyTpl, efi_event_notify_t NotifyFunction, - void *NextContext, efi_event_t *Event); -typedef efi_status_t (EFIAPI *efi_set_timer_t)(efi_event_t Event, efi_timer_delay_t Type, uint64_t TriggerTime); -typedef efi_status_t (EFIAPI *efi_wait_for_event_t)(uintn_t NumberOfEvents, efi_event_t *Event, uintn_t *Index); -typedef efi_status_t (EFIAPI *efi_signal_event_t)(efi_event_t Event); -typedef efi_status_t (EFIAPI *efi_close_event_t)(efi_event_t Event); -typedef efi_status_t (EFIAPI *efi_check_event_t)(efi_event_t Event); -typedef efi_status_t (EFIAPI *efi_handle_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, void **Interface); -typedef efi_status_t (EFIAPI *efi_register_protocol_notify_t)(efi_guid_t *Protocol, efi_event_t Event, void **Registration); -typedef efi_status_t (EFIAPI *efi_locate_handle_t)(efi_locate_search_type_t SearchType, efi_guid_t *Protocol, - void *SearchKey, uintn_t *BufferSize, efi_handle_t *Buffer); -typedef efi_status_t (EFIAPI *efi_locate_device_path_t)(efi_guid_t *Protocol, efi_device_path_t **DevicePath, - efi_handle_t *Device); -typedef efi_status_t (EFIAPI *efi_install_configuration_table_t)(efi_guid_t *Guid, void *Table); -typedef efi_status_t (EFIAPI *efi_image_load_t)(boolean_t BootPolicy, efi_handle_t ParentImageHandle, efi_device_path_t *FilePath, - void *SourceBuffer, uintn_t SourceSize, efi_handle_t *ImageHandle); -typedef efi_status_t (EFIAPI *efi_image_start_t)(efi_handle_t ImageHandle, uintn_t *ExitDataSize, wchar_t **ExitData); -typedef efi_status_t (EFIAPI *efi_exit_t)(efi_handle_t ImageHandle, efi_status_t ExitStatus, uintn_t ExitDataSize, - wchar_t *ExitData); -typedef efi_status_t (EFIAPI *efi_exit_boot_services_t)(efi_handle_t ImageHandle, uintn_t MapKey); -typedef efi_status_t (EFIAPI *efi_get_next_monotonic_t)(uint64_t *Count); -typedef efi_status_t (EFIAPI *efi_stall_t)(uintn_t Microseconds); -typedef efi_status_t (EFIAPI *efi_set_watchdog_timer_t)(uintn_t Timeout, uint64_t WatchdogCode, uintn_t DataSize, - wchar_t *WatchdogData); -typedef efi_status_t (EFIAPI *efi_connect_controller_t)(efi_handle_t ControllerHandle, efi_handle_t *DriverImageHandle, - efi_device_path_t *RemainingDevicePath, boolean_t Recursive); -typedef efi_status_t (EFIAPI *efi_disconnect_controller_t)(efi_handle_t ControllerHandle, efi_handle_t DriverImageHandle, - efi_handle_t ChildHandle); -typedef efi_status_t (EFIAPI *efi_open_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, void **Interface, - efi_handle_t AgentHandle, efi_handle_t ControllerHandle, uint32_t Attributes); -typedef efi_status_t (EFIAPI *efi_close_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, efi_handle_t AgentHandle, - efi_handle_t ControllerHandle); -typedef efi_status_t (EFIAPI *efi_open_protocol_information_t)(efi_handle_t Handle, efi_guid_t *Protocol, - efi_open_protocol_information_entry_t**EntryBuffer, uintn_t *EntryCount); -typedef efi_status_t (EFIAPI *efi_protocols_per_handle_t)(efi_handle_t Handle, efi_guid_t ***ProtocolBuffer, - uintn_t *ProtocolBufferCount); -typedef efi_status_t (EFIAPI *efi_locate_handle_buffer_t)(efi_locate_search_type_t SearchType, efi_guid_t *Protocol, - void *SearchKey, uintn_t *NoHandles, efi_handle_t **Handles); -typedef efi_status_t (EFIAPI *efi_locate_protocol_t)(efi_guid_t *Protocol, void *Registration, void **Interface); -typedef efi_status_t (EFIAPI *efi_calculate_crc32_t)(void *Data, uintn_t DataSize, uint32_t *Crc32); +typedef efi_tpl_t (EFIAPI *efi_raise_tpl_t)(efi_tpl_t new_tpl); +typedef efi_tpl_t (EFIAPI *efi_restore_tpl_t)(efi_tpl_t old_tpl); +typedef efi_status_t (EFIAPI *efi_allocate_pages_t)(efi_allocate_type_t type, efi_memory_type_t memory_type, uintn_t pages, efi_physical_address_t* memory); +typedef efi_status_t (EFIAPI *efi_free_pages_t)(efi_physical_address_t memory, uintn_t pages); +typedef efi_status_t (EFIAPI *efi_get_memory_map_t)(uintn_t* memory_map_size, efi_memory_descriptor_t* memory_map, uintn_t* map_key, uintn_t* descriptor_size, uint32_t* descriptor_version); +typedef efi_status_t (EFIAPI *efi_allocate_pool_t)(efi_memory_type_t pool_type, uintn_t size, void** buffer); +typedef efi_status_t (EFIAPI *efi_free_pool_t)(void* buffer); +typedef void (EFIAPI *efi_event_notify_t)(efi_event_t event, void* context); +typedef efi_status_t (EFIAPI *efi_create_event_t)(uint32_t type, efi_tpl_t notify_tpl, efi_event_notify_t notify_function, void* context, efi_event_t* event); +typedef efi_status_t (EFIAPI *efi_set_timer_t)(efi_event_t event, uint32_t type, uint64_t trigger_time); +typedef efi_status_t (EFIAPI *efi_wait_for_event_t)(uintn_t number_of_events, efi_event_t* event, uintn_t* index); +typedef efi_status_t (EFIAPI *efi_signal_event_t)(efi_event_t event); +typedef efi_status_t (EFIAPI *efi_close_event_t)(efi_event_t event); +typedef efi_status_t (EFIAPI *efi_check_event_t)(efi_event_t event); +typedef efi_status_t (EFIAPI *efi_handle_protocol_t)(efi_handle_t handle, efi_guid_t* protocol, void** interface); +typedef efi_status_t (EFIAPI *efi_register_protocol_notify_t)(efi_guid_t* protocol, efi_event_t event, void** registration); +typedef efi_status_t (EFIAPI *efi_locate_handle_t)(efi_locate_search_type_t search_type, efi_guid_t* protocol, void* search_key, uintn_t* buffer_size, efi_handle_t* buffer); +typedef efi_status_t (EFIAPI *efi_locate_device_path_t)(efi_guid_t* protocol, efi_device_path_t** device_path, efi_handle_t* device); +typedef efi_status_t (EFIAPI *efi_install_configuration_table_t)(efi_guid_t* guid, void* table); +typedef efi_status_t (EFIAPI *efi_image_load_t)(boolean_t boot_policy, efi_handle_t parent_image_handle, efi_device_path_t* file_path, void* source_buffer, uintn_t source_size, efi_handle_t* image_handle); +typedef efi_status_t (EFIAPI *efi_image_start_t)(efi_handle_t image_handle, uintn_t* exit_data_size, wchar_t** exit_data); +typedef efi_status_t (EFIAPI *efi_exit_t)(efi_handle_t image_handle, efi_status_t exit_status, uintn_t exit_data_size, wchar_t* exit_data); +typedef efi_status_t (EFIAPI *efi_exit_boot_services_t)(efi_handle_t image_handle, uintn_t map_key); +typedef efi_status_t (EFIAPI *efi_get_next_monotonic_t)(uint64_t* count); +typedef efi_status_t (EFIAPI *efi_stall_t)(uintn_t microseconds); +typedef efi_status_t (EFIAPI *efi_set_watchdog_timer_t)(uintn_t timeout, uint64_t watchdog_code, uintn_t data_size, wchar_t* watchdog_data); +typedef efi_status_t (EFIAPI *efi_connect_controller_t)(efi_handle_t controller_handle, efi_handle_t* driver_image_handle, efi_device_path_t* remaining_device_path, boolean_t recursive); +typedef efi_status_t (EFIAPI *efi_disconnect_controller_t)(efi_handle_t controller_handle, efi_handle_t driver_image_handle, efi_handle_t child_handle); +typedef efi_status_t (EFIAPI *efi_open_protocol_t)(efi_handle_t handle, efi_guid_t* protocol, void** interface, efi_handle_t agent_handle, efi_handle_t controller_handle, uint32_t attributes); +typedef efi_status_t (EFIAPI *efi_close_protocol_t)(efi_handle_t handle, efi_guid_t* protocol, efi_handle_t agent_handle, efi_handle_t controller_handle); +typedef efi_status_t (EFIAPI *efi_open_protocol_information_t)(efi_handle_t handle, efi_guid_t* protocol, efi_open_protocol_information_entry_t** entry_buffer, uintn_t* entry_count); +typedef efi_status_t (EFIAPI *efi_protocols_per_handle_t)(efi_handle_t handle, efi_guid_t*** protocol_buffer, uintn_t* protocol_buffer_count); +typedef efi_status_t (EFIAPI *efi_locate_handle_buffer_t)(efi_locate_search_type_t search_type, efi_guid_t* protocol, void* search_key, uintn_t* handle_count, efi_handle_t** handles); +typedef efi_status_t (EFIAPI *efi_locate_protocol_t)(efi_guid_t* protocol, void* registration, void** interface); +typedef efi_status_t (EFIAPI *efi_calculate_crc32_t)(void* data, uintn_t data_size, uint32_t* crc32); typedef struct { - efi_table_header_t Hdr; - - efi_raise_tpl_t RaiseTPL; - efi_restore_tpl_t RestoreTPL; - - efi_allocate_pages_t AllocatePages; - efi_free_pages_t FreePages; - efi_get_memory_map_t GetMemoryMap; - efi_allocate_pool_t AllocatePool; - efi_free_pool_t FreePool; - - efi_create_event_t CreateEvent; - efi_set_timer_t SetTimer; - efi_wait_for_event_t WaitForEvent; - efi_signal_event_t SignalEvent; - efi_close_event_t CloseEvent; - efi_check_event_t CheckEvent; - - void* InstallProtocolInterface; /* not defined yet */ - void* ReinstallProtocolInterface; - void* UninstallProtocolInterface; - efi_handle_protocol_t HandleProtocol; - efi_handle_protocol_t PCHandleProtocol; + efi_table_header_t Hdr; + efi_raise_tpl_t RaiseTPL; + efi_restore_tpl_t RestoreTPL; + efi_allocate_pages_t AllocatePages; + efi_free_pages_t FreePages; + efi_get_memory_map_t GetMemoryMap; + efi_allocate_pool_t AllocatePool; + efi_free_pool_t FreePool; + efi_create_event_t CreateEvent; + efi_set_timer_t SetTimer; + efi_wait_for_event_t WaitForEvent; + efi_signal_event_t SignalEvent; + efi_close_event_t CloseEvent; + efi_check_event_t CheckEvent; + void* InstallProtocolInterface; + void* ReinstallProtocolInterface; + void* UninstallProtocolInterface; + efi_handle_protocol_t HandleProtocol; + efi_handle_protocol_t PCHandleProtocol; efi_register_protocol_notify_t RegisterProtocolNotify; - efi_locate_handle_t LocateHandle; - efi_locate_device_path_t LocateDevicePath; + efi_locate_handle_t LocateHandle; + efi_locate_device_path_t LocateDevicePath; efi_install_configuration_table_t InstallConfigurationTable; - - efi_image_load_t LoadImage; - efi_image_start_t StartImage; - efi_exit_t Exit; - void* UnloadImage; /* not defined in gnu-efi either */ - efi_exit_boot_services_t ExitBootServices; - - efi_get_next_monotonic_t GetNextHighMonotonicCount; - efi_stall_t Stall; - efi_set_watchdog_timer_t SetWatchdogTimer; - - efi_connect_controller_t ConnectController; + efi_image_load_t LoadImage; + efi_image_start_t StartImage; + efi_exit_t Exit; + void* UnloadImage; + efi_exit_boot_services_t ExitBootServices; + efi_get_next_monotonic_t GetNextHighMonotonicCount; + efi_stall_t Stall; + efi_set_watchdog_timer_t SetWatchdogTimer; + efi_connect_controller_t ConnectController; efi_disconnect_controller_t DisconnectController; - - efi_open_protocol_t OpenProtocol; - efi_close_protocol_t CloseProtocol; + efi_open_protocol_t OpenProtocol; + efi_close_protocol_t CloseProtocol; efi_open_protocol_information_t OpenProtocolInformation; - - efi_protocols_per_handle_t ProtocolsPerHandle; - efi_locate_handle_buffer_t LocateHandleBuffer; - efi_locate_protocol_t LocateProtocol; - void* InstallMultipleProtocolInterfaces; - void* UninstallMultipleProtocolInterfaces; - - efi_calculate_crc32_t CalculateCrc32; + efi_protocols_per_handle_t ProtocolsPerHandle; + efi_locate_handle_buffer_t LocateHandleBuffer; + efi_locate_protocol_t LocateProtocol; + void* InstallMultipleProtocolInterfaces; + void* UninstallMultipleProtocolInterfaces; + efi_calculate_crc32_t CalculateCrc32; } efi_boot_services_t; -extern efi_boot_services_t *BS; -#define gBS BS - -/*** Loaded Image Protocol ***/ -#ifndef EFI_LOADED_IMAGE_PROTOCOL_GUID -#define EFI_LOADED_IMAGE_PROTOCOL_GUID { 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } -#define LOADED_IMAGE_PROTOCOL EFI_LOADED_IMAGE_PROTOCOL_GUID - -#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000 -#define EFI_IMAGE_INFORMATION_REVISION EFI_LOADED_IMAGE_PROTOCOL_REVISION -#endif typedef struct { - uint32_t Revision; - efi_handle_t ParentHandle; - void *SystemTable; - efi_handle_t DeviceHandle; - efi_device_path_t *FilePath; - void *Reserved; - uint32_t LoadOptionsSize; - void *LoadOptions; - void *ImageBase; - uint64_t ImageSize; - efi_memory_type_t ImageCodeType; - efi_memory_type_t ImageDataType; + uint32_t Revision; + efi_handle_t ParentHandle; + void* SystemTable; + efi_handle_t DeviceHandle; + efi_device_path_t* FilePath; + void* Reserved; + uint32_t LoadOptionsSize; + void* LoadOptions; + void* ImageBase; + uint64_t ImageSize; + efi_memory_type_t ImageCodeType; + efi_memory_type_t ImageDataType; } efi_loaded_image_protocol_t; -extern efi_loaded_image_protocol_t *LIP; -extern efi_handle_t IM; -/*** System Table ***/ typedef struct { - efi_guid_t VendorGuid; - void *VendorTable; + efi_guid_t VendorGuid; + void* VendorTable; } efi_configuration_table_t; typedef struct { - efi_table_header_t Hdr; - - wchar_t *FirmwareVendor; - uint32_t FirmwareRevision; - - efi_handle_t ConsoleInHandle; - simple_input_interface_t *ConIn; - - efi_handle_t ConsoleOutHandle; - simple_text_output_interface_t *ConOut; - - efi_handle_t ConsoleErrorHandle; - simple_text_output_interface_t *StdErr; - - efi_runtime_services_t *RuntimeServices; - efi_boot_services_t *BootServices; - - uintn_t NumberOfTableEntries; - efi_configuration_table_t *ConfigurationTable; + efi_table_header_t Hdr; + wchar_t* FirmwareVendor; + uint32_t FirmwareRevision; + efi_handle_t ConsoleInHandle; + simple_input_interface_t* ConIn; + efi_handle_t ConsoleOutHandle; + simple_text_output_interface_t* ConOut; + efi_handle_t ConsoleErrorHandle; + simple_text_output_interface_t* StdErr; + efi_runtime_services_t* RuntimeServices; + efi_boot_services_t* BootServices; + uintn_t NumberOfTableEntries; + efi_configuration_table_t* ConfigurationTable; } efi_system_table_t; -extern efi_system_table_t *ST; -#define gST ST - -/*** Simple File System Protocol ***/ -#ifndef EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID -#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID { 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000 -#define EFI_FILE_IO_INTERFACE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION - -#define EFI_FILE_MODE_READ 0x0000000000000001 -#define EFI_FILE_MODE_WRITE 0x0000000000000002 -#define EFI_FILE_MODE_CREATE 0x8000000000000000 - -#define EFI_FILE_READ_ONLY 0x0000000000000001 -#define EFI_FILE_HIDDEN 0x0000000000000002 -#define EFI_FILE_SYSTEM 0x0000000000000004 -#define EFI_FILE_RESERVED 0x0000000000000008 -#define EFI_FILE_DIRECTORY 0x0000000000000010 -#define EFI_FILE_ARCHIVE 0x0000000000000020 -#define EFI_FILE_VALID_ATTR 0x0000000000000037 - -#define EFI_FILE_PROTOCOL_REVISION 0x00010000 -#define EFI_FILE_HANDLE_REVISION EFI_FILE_PROTOCOL_REVISION -#endif - -#ifndef EFI_FILE_INFO_GUID -#define EFI_FILE_INFO_GUID { 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } -#endif - -#ifndef FILENAME_MAX -#define FILENAME_MAX 262 /* from FAT spec */ -#endif - -typedef struct { - uint64_t Size; - uint64_t FileSize; - uint64_t PhysicalSize; - efi_time_t CreateTime; - efi_time_t LastAccessTime; - efi_time_t ModificationTime; - uint64_t Attribute; - wchar_t FileName[FILENAME_MAX]; -} efi_file_info_t; typedef struct efi_file_handle_s efi_file_handle_t; -typedef efi_status_t (EFIAPI *efi_volume_open_t)(void *This, efi_file_handle_t **Root); +typedef efi_status_t (EFIAPI *efi_volume_open_t)(void* this_ptr, efi_file_handle_t** root); typedef struct { - uint64_t Revision; - efi_volume_open_t OpenVolume; + uint64_t Revision; + efi_volume_open_t OpenVolume; } efi_simple_file_system_protocol_t; -typedef efi_status_t (EFIAPI *efi_file_open_t)(efi_file_handle_t *File, efi_file_handle_t **NewHandle, wchar_t *FileName, - uint64_t OpenMode, uint64_t Attributes); -typedef efi_status_t (EFIAPI *efi_file_close_t)(efi_file_handle_t *File); -typedef efi_status_t (EFIAPI *efi_file_delete_t)(efi_file_handle_t *File); -typedef efi_status_t (EFIAPI *efi_file_read_t)(efi_file_handle_t *File, uintn_t *BufferSize, void *Buffer); -typedef efi_status_t (EFIAPI *efi_file_write_t)(efi_file_handle_t *File, uintn_t *BufferSize, void *Buffer); -typedef efi_status_t (EFIAPI *efi_file_get_pos_t)(efi_file_handle_t *File, uint64_t *Position); -typedef efi_status_t (EFIAPI *efi_file_set_pos_t)(efi_file_handle_t *File, uint64_t Position); -typedef efi_status_t (EFIAPI *efi_file_get_info_t)(efi_file_handle_t *File, efi_guid_t *InformationType, uintn_t *BufferSize, - void *Buffer); -typedef efi_status_t (EFIAPI *efi_file_set_info_t)(efi_file_handle_t *File, efi_guid_t *InformationType, uintn_t BufferSize, - void *Buffer); -typedef efi_status_t (EFIAPI *efi_file_flush_t)(efi_file_handle_t *File); +typedef struct { + uint64_t Size; + uint64_t FileSize; + uint64_t PhysicalSize; + efi_time_t CreateTime; + efi_time_t LastAccessTime; + efi_time_t ModificationTime; + uint64_t Attribute; + wchar_t FileName[FILENAME_MAX]; +} efi_file_info_t; + +typedef efi_status_t (EFIAPI *efi_file_open_t)(efi_file_handle_t* file, efi_file_handle_t** new_handle, wchar_t* file_name, uint64_t open_mode, uint64_t attributes); +typedef efi_status_t (EFIAPI *efi_file_close_t)(efi_file_handle_t* file); +typedef efi_status_t (EFIAPI *efi_file_delete_t)(efi_file_handle_t* file); +typedef efi_status_t (EFIAPI *efi_file_read_t)(efi_file_handle_t* file, uintn_t* buffer_size, void* buffer); +typedef efi_status_t (EFIAPI *efi_file_write_t)(efi_file_handle_t* file, uintn_t* buffer_size, void* buffer); +typedef efi_status_t (EFIAPI *efi_file_get_pos_t)(efi_file_handle_t* file, uint64_t* position); +typedef efi_status_t (EFIAPI *efi_file_set_pos_t)(efi_file_handle_t* file, uint64_t position); +typedef efi_status_t (EFIAPI *efi_file_get_info_t)(efi_file_handle_t* file, efi_guid_t* information_type, uintn_t* buffer_size, void* buffer); +typedef efi_status_t (EFIAPI *efi_file_set_info_t)(efi_file_handle_t* file, efi_guid_t* information_type, uintn_t buffer_size, void* buffer); +typedef efi_status_t (EFIAPI *efi_file_flush_t)(efi_file_handle_t* file); struct efi_file_handle_s { - uint64_t Revision; - efi_file_open_t Open; - efi_file_close_t Close; - efi_file_delete_t Delete; - efi_file_read_t Read; - efi_file_write_t Write; - efi_file_get_pos_t GetPosition; - efi_file_set_pos_t SetPosition; - efi_file_get_info_t GetInfo; - efi_file_set_info_t SetInfo; - efi_file_flush_t Flush; + uint64_t Revision; + efi_file_open_t Open; + efi_file_close_t Close; + efi_file_delete_t Delete; + efi_file_read_t Read; + efi_file_write_t Write; + efi_file_get_pos_t GetPosition; + efi_file_set_pos_t SetPosition; + efi_file_get_info_t GetInfo; + efi_file_set_info_t SetInfo; + efi_file_flush_t Flush; }; -/*** Shell Parameter Protocols ***/ -#ifndef EFI_SHELL_PARAMETERS_PROTOCOL_GUID -#define EFI_SHELL_PARAMETERS_PROTOCOL_GUID { 0x752f3136, 0x4e16, 0x4fdc, {0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca} } -#endif - typedef struct { - wchar_t **Argv; - uintn_t Argc; - efi_handle_t StdIn; - efi_handle_t StdOut; - efi_handle_t StdErr; -} efi_shell_parameters_protocol_t; - -#ifndef SHELL_INTERFACE_PROTOCOL_GUID -#define SHELL_INTERFACE_PROTOCOL_GUID { 0x47c7b223, 0xc42a, 0x11d2, {0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } -#endif - -typedef struct { - efi_handle_t ImageHandle; - void* *Info; - wchar_t **Argv; - uintn_t Argc; - wchar_t **RedirArgv; - uintn_t RedirArgc; - efi_handle_t StdIn; - efi_handle_t StdOut; - efi_handle_t StdErr; -} efi_shell_interface_protocol_t; - -/*** Random Number Generator ***/ -#ifndef EFI_RNG_PROTOCOL_GUID -#define EFI_RNG_PROTOCOL_GUID { 0x3152bca5, 0xeade, 0x433d, {0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44} } -#endif - -typedef efi_status_t (EFIAPI *efi_rng_get_info_t)(void *This, uintn_t *RNGAlgorithmListSize, efi_guid_t *RNGAlgorithmList); -typedef efi_status_t (EFIAPI *efi_rng_get_rng_t)(void *This, efi_guid_t *RNGAlgorithm, uintn_t RNGValueLength, uint8_t *RNGValue); - -typedef struct { - efi_rng_get_info_t GetInfo; - efi_rng_get_rng_t GetRNG; -} efi_rng_protocol_t; - -/*** Serial IO Protocol ***/ -#ifndef EFI_SERIAL_IO_PROTOCOL_GUID -#define EFI_SERIAL_IO_PROTOCOL_GUID { 0xBB25CF6F, 0xF1D4, 0x11D2, {0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD} } - -#define SERIAL_IO_INTERFACE_REVISION 0x00010000 -#define EFI_SERIAL_CLEAR_TO_SEND 0x0010 -#define EFI_SERIAL_DATA_SET_READY 0x0020 -#define EFI_SERIAL_RING_INDICATE 0x0040 -#define EFI_SERIAL_CARRIER_DETECT 0x0080 -#define EFI_SERIAL_REQUEST_TO_SEND 0x0002 -#define EFI_SERIAL_DATA_TERMINAL_READY 0x0001 -#define EFI_SERIAL_INPUT_BUFFER_EMPTY 0x0100 -#define EFI_SERIAL_OUTPUT_BUFFER_EMPTY 0x0200 -#define EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE 0x1000 -#define EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE 0x2000 -#define EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE 0x4000 - -typedef enum { - DefaultParity, - NoParity, - EvenParity, - OddParity, - MarkParity, - SpaceParity -} efi_parity_type_t; - -typedef enum { - DefaultStopBits, - OneStopBit, - OneFiveStopBits, - TwoStopBits -} efi_stop_bits_type_t; - -#else - -#define efi_parity_type_t EFI_PARITY_TYPE -#define efi_stop_bits_type_t EFI_STOP_BITS_TYPE - -#endif - -typedef struct { - uint32_t ControlMask; - uint32_t Timeout; - uint64_t BaudRate; - uint32_t ReceiveFifoDepth; - uint32_t DataBits; - uint32_t Parity; - uint32_t StopBits; -} efi_serial_io_mode_t; - -typedef efi_status_t (EFIAPI *efi_serial_reset_t)(void *This); -typedef efi_status_t (EFIAPI *efi_serial_set_attributes_t)(void *This, uint64_t BaudRate, uint32_t ReceiveFifoDepth, - uint32_t Timeout, efi_parity_type_t Parity, uint8_t DataBits, efi_stop_bits_type_t StopBits); -typedef efi_status_t (EFIAPI *efi_serial_set_control_bits_t)(void *This, uint32_t Control); -typedef efi_status_t (EFIAPI *efi_serial_get_control_bits_t)(void *This, uint32_t *Control); -typedef efi_status_t (EFIAPI *efi_serial_write_t)(void *This, uintn_t *BufferSize, void *Buffer); -typedef efi_status_t (EFIAPI *efi_serial_read_t)(void *This, uintn_t *BufferSize, void *Buffer); - -typedef struct { - uint32_t Revision; - efi_serial_reset_t Reset; - efi_serial_set_attributes_t SetAttributes; - efi_serial_set_control_bits_t SetControl; - efi_serial_get_control_bits_t GetControl; - efi_serial_write_t Write; - efi_serial_read_t Read; - efi_serial_io_mode_t *Mode; -} efi_serial_io_protocol_t; - -/*** Block IO Protocol ***/ -#ifndef EFI_BLOCK_IO_PROTOCOL_GUID -#define EFI_BLOCK_IO_PROTOCOL_GUID { 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -#define EFI_BLOCK_IO_PROTOCOL_REVISION 0x00010000 -#define EFI_BLOCK_IO_INTERFACE_REVISION EFI_BLOCK_IO_PROTOCOL_REVISION - -#endif - -typedef struct { - uint32_t MediaId; - boolean_t RemovableMedia; - boolean_t MediaPresent; - boolean_t LogicalPartition; - boolean_t ReadOnly; - boolean_t WriteCaching; - uint32_t BlockSize; - uint32_t IoAlign; - efi_lba_t LastBlock; -} efi_block_io_media_t; - -typedef efi_status_t (EFIAPI *efi_block_reset_t)(void *This, boolean_t ExtendedVerification); -typedef efi_status_t (EFIAPI *efi_block_read_t)(void *This, uint32_t MediaId, efi_lba_t LBA, uintn_t BufferSize, void *Buffer); -typedef efi_status_t (EFIAPI *efi_block_write_t)(void *This, uint32_t MediaId, efi_lba_t LBA, uintn_t BufferSize, void *Buffer); -typedef efi_status_t (EFIAPI *efi_block_flush_t)(void *This); - -typedef struct { - uint64_t Revision; - efi_block_io_media_t *Media; - efi_block_reset_t Reset; - efi_block_read_t ReadBlocks; - efi_block_write_t WriteBlocks; - efi_block_flush_t FlushBlocks; -} efi_block_io_t; - -typedef struct { - off_t offset; - efi_block_io_t *bio; -} block_file_t; - -/*** Graphics Output Protocol (not used, but could be useful to have) ***/ -#ifndef EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID -#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID { 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } } - -typedef enum { - PixelRedGreenBlueReserved8BitPerColor, - PixelBlueGreenRedReserved8BitPerColor, - PixelBitMask, - PixelBltOnly, - PixelFormatMax -} efi_gop_pixel_format_t; - -typedef enum { - EfiBltVideoFill, - EfiBltVideoToBltBuffer, - EfiBltBufferToVideo, - EfiBltVideoToVideo, - EfiGraphicsOutputBltOperationMax -} efi_gop_blt_operation_t; - -#else - -#define efi_gop_pixel_format_t EFI_GRAPHICS_PIXEL_FORMAT -#define efi_gop_blt_operation_t EFI_GRAPHICS_OUTPUT_BLT_OPERATION - -#endif - -typedef struct { - uint32_t RedMask; - uint32_t GreenMask; - uint32_t BlueMask; - uint32_t ReservedMask; + uint32_t RedMask; + uint32_t GreenMask; + uint32_t BlueMask; + uint32_t ReservedMask; } efi_gop_pixel_bitmask_t; typedef struct { - uint32_t Version; - uint32_t HorizontalResolution; - uint32_t VerticalResolution; - efi_gop_pixel_format_t PixelFormat; + uint32_t Version; + uint32_t HorizontalResolution; + uint32_t VerticalResolution; + efi_gop_pixel_format_t PixelFormat; efi_gop_pixel_bitmask_t PixelInformation; - uint32_t PixelsPerScanLine; + uint32_t PixelsPerScanLine; } efi_gop_mode_info_t; typedef struct { - uint32_t MaxMode; - uint32_t Mode; - efi_gop_mode_info_t *Information; - uintn_t SizeOfInfo; - efi_physical_address_t FrameBufferBase; - uintn_t FrameBufferSize; + uint32_t MaxMode; + uint32_t Mode; + efi_gop_mode_info_t* Information; + uintn_t SizeOfInfo; + efi_physical_address_t FrameBufferBase; + uintn_t FrameBufferSize; } efi_gop_mode_t; -typedef efi_status_t (EFIAPI *efi_gop_query_mode_t)(void *This, uint32_t ModeNumber, uintn_t *SizeOfInfo, - efi_gop_mode_info_t **Info); -typedef efi_status_t (EFIAPI *efi_gop_set_mode_t)(void *This, uint32_t ModeNumber); -typedef efi_status_t (EFIAPI *efi_gop_blt_t)(void *This, uint32_t *BltBuffer, efi_gop_blt_operation_t BltOperation, - uintn_t SourceX, uintn_t SourceY, uintn_t DestinationX, uintn_t DestionationY, uintn_t Width, uintn_t Height, uintn_t Delta); +typedef efi_status_t (EFIAPI *efi_gop_query_mode_t)(void* this_ptr, uint32_t mode_number, uintn_t* size_of_info, efi_gop_mode_info_t** info); +typedef efi_status_t (EFIAPI *efi_gop_set_mode_t)(void* this_ptr, uint32_t mode_number); +typedef efi_status_t (EFIAPI *efi_gop_blt_t)(void* this_ptr, uint32_t* blt_buffer, uint32_t blt_operation, uintn_t source_x, uintn_t source_y, uintn_t destination_x, uintn_t destination_y, uintn_t width, uintn_t height, uintn_t delta); typedef struct { - efi_gop_query_mode_t QueryMode; - efi_gop_set_mode_t SetMode; - efi_gop_blt_t Blt; - efi_gop_mode_t *Mode; + efi_gop_query_mode_t QueryMode; + efi_gop_set_mode_t SetMode; + efi_gop_blt_t Blt; + efi_gop_mode_t* Mode; } efi_gop_t; -/*** EDID Protocol (not used, but could be useful to have) ***/ -#ifndef EFI_EDID_ACTIVE_GUID -#define EFI_EDID_ACTIVE_GUID { 0xbd8c1056, 0x9f36, 0x44ec, { 0x92, 0xa8, 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86 } } -#define EFI_EDID_DISCOVERED_GUID { 0x1c0c34f6, 0xd380, 0x41fa, { 0xa0, 0x49, 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa } } -#endif +extern efi_handle_t IM; +extern efi_system_table_t* ST; +extern efi_boot_services_t* BS; +extern efi_runtime_services_t* RT; -typedef struct { - uint32_t SizeOfEdid; - uint8_t *Edid; -} efi_edid_t; - -/*** Simple Pointer Protocol (not used, but could be useful to have) ***/ -#ifndef EFI_SIMPLE_POINTER_PROTOCOL_GUID -#define EFI_SIMPLE_POINTER_PROTOCOL_GUID { 0x31878c87, 0xb75, 0x11d5, { 0x9a, 0x4f, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } -#endif - -typedef struct { - int32_t RelativeMovementX; - int32_t RelativeMovementY; - int32_t RelativeMovementZ; - boolean_t LeftButton; - boolean_t RightButton; -} efi_simple_pointer_state_t; - -typedef struct { - uint64_t ResolutionX; - uint64_t ResolutionY; - uint64_t ResolutionZ; - boolean_t LeftButton; - boolean_t RightButton; -} efi_simple_pointer_mode_t; - -typedef efi_status_t (EFIAPI *efi_simple_pointer_reset_t) (void *This, boolean_t ExtendedVerification); -typedef efi_status_t (EFIAPI *efi_simple_pointer_get_state_t) (void *This, efi_simple_pointer_state_t *State); - -typedef struct { - efi_simple_pointer_reset_t Reset; - efi_simple_pointer_get_state_t GetState; - efi_event_t WaitForInput; - efi_simple_pointer_mode_t *Mode; -} efi_simple_pointer_protocol_t; - -/*** Option ROM Protocol (not used, but could be useful to have) ***/ -#ifndef EFI_PCI_OPTION_ROM_TABLE_GUID -#define EFI_PCI_OPTION_ROM_TABLE_GUID { 0x7462660f, 0x1cbd, 0x48da, {0xad, 0x11, 0x91, 0x71, 0x79, 0x13, 0x83, 0x1c} } -#endif - -typedef struct { - efi_physical_address_t RomAddress; - efi_memory_type_t MemoryType; - uint32_t RomLength; - uint32_t Seg; - uint8_t Bus; - uint8_t Dev; - uint8_t Func; - boolean_t ExecutedLegacyBiosImage; - boolean_t DontLoadEfiRom; -} efi_pci_option_rom_descriptor_t; - -typedef struct { - uint64_t PciOptionRomCount; - efi_pci_option_rom_descriptor_t *PciOptionRomDescriptors; -} efi_pci_option_rom_table_t; - -/*** GPT partitioning table (not used, but could be useful to have) ***/ -typedef struct { - efi_table_header_t Header; - efi_lba_t MyLBA; - efi_lba_t AlternateLBA; - efi_lba_t FirstUsableLBA; - efi_lba_t LastUsableLBA; - efi_guid_t DiskGUID; - efi_lba_t PartitionEntryLBA; - uint32_t NumberOfPartitionEntries; - uint32_t SizeOfPartitionEntry; - uint32_t PartitionEntryArrayCRC32; -} efi_partition_table_header_t; - -typedef struct { - efi_guid_t PartitionTypeGUID; - efi_guid_t UniquePartitionGUID; - efi_lba_t StartingLBA; - efi_lba_t EndingLBA; - uint64_t Attributes; - wchar_t PartitionName[36]; -} efi_partition_entry_t; - -/*** POSIX definitions ***/ -#define abs(x) ((x)<0?-(x):(x)) -#define min(x,y) ((x)<(y)?(x):(y)) -#define max(x,y) ((x)>(y)?(x):(y)) - -/* dirent.h */ -#define IFTODT(mode) (((mode) & 0170000) >> 12) -#define DTTOIF(dirtype) ((dirtype) << 12) -#define DT_DIR 4 -#define DT_REG 8 -struct dirent { - unsigned short int d_reclen; - unsigned char d_type; - char_t d_name[FILENAME_MAX]; -}; -typedef struct efi_file_handle_s DIR; -extern DIR *opendir (const char_t *__name); -extern struct dirent *readdir (DIR *__dirp); -extern void rewinddir (DIR *__dirp); -extern int closedir (DIR *__dirp); - -/* errno.h */ -extern int errno; -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Argument list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ - -/* stdlib.h */ -#define RAND_MAX 2147483647 -typedef int (*__compar_fn_t) (const void *, const void *); -extern int atoi (const char_t *__nptr); -extern int64_t atol (const char_t *__nptr); -extern int64_t strtol (const char_t *__nptr, char_t **__endptr, int __base); -extern void *malloc (size_t __size); -extern void *calloc (size_t __nmemb, size_t __size); -extern void *realloc (void *__ptr, size_t __size); -extern void free (void *__ptr); -extern void abort (void); -extern void exit (int __status); -/* exit Boot Services function. Returns 0 on success. */ -extern int exit_bs(void); -extern void *bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size, __compar_fn_t __compar); -extern void qsort (void *__base, size_t __nmemb, size_t __size, __compar_fn_t __compar); -extern int mblen (const char *__s, size_t __n); -extern int mbtowc (wchar_t * __pwc, const char * __s, size_t __n); -extern int wctomb (char *__s, wchar_t __wchar); -extern size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n); -extern size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n); -extern void srand(unsigned int __seed); -extern int rand(void); -extern uint8_t *getenv(char_t *name, uintn_t *len); -extern int setenv(char_t *name, uintn_t len, uint8_t *data); - -/* stdio.h */ -#ifndef BUFSIZ -#define BUFSIZ 8192 -#endif -#define SEEK_SET 0 /* Seek from beginning of file. */ -#define SEEK_CUR 1 /* Seek from current position. */ -#define SEEK_END 2 /* Seek from end of file. */ -#define stdin (FILE*)ST->ConsoleInHandle -#define stdout (FILE*)ST->ConsoleOutHandle -#define stderr (FILE*)ST->ConsoleErrorHandle -typedef struct efi_file_handle_s FILE; -extern int fclose (FILE *__stream); -extern int fflush (FILE *__stream); -extern int remove (const char_t *__filename); -extern FILE *fopen (const char_t *__filename, const char_t *__modes); -extern size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream); -extern size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__s); -extern int fseek (FILE *__stream, long int __off, int __whence); -extern long int ftell (FILE *__stream); -extern int feof (FILE *__stream); -extern int fprintf (FILE *__stream, const char_t *__format, ...); -extern int printf (const char_t *__format, ...); -extern int sprintf (char_t *__s, const char_t *__format, ...); -extern int vfprintf (FILE *__s, const char_t *__format, __builtin_va_list __arg); -extern int vprintf (const char_t *__format, __builtin_va_list __arg); -extern int vsprintf (char_t *__s, const char_t *__format, __builtin_va_list __arg); -extern int snprintf (char_t *__s, size_t __maxlen, const char_t *__format, ...); -extern int vsnprintf (char_t *__s, size_t __maxlen, const char_t *__format, __builtin_va_list __arg); -extern int getchar (void); -/* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */ -extern int getchar_ifany (void); -extern int putchar (int __c); - -/* string.h */ -extern void *memcpy(void *__dest, const void *__src, size_t __n); -extern void *memmove(void *__dest, const void *__src, size_t __n); -extern void *memset(void *__s, int __c, size_t __n); -extern int memcmp(const void *__s1, const void *__s2, size_t __n); -extern void *memchr(const void *__s, int __c, size_t __n); -extern void *memrchr(const void *__s, int __c, size_t __n); -void *memmem(const void *haystack, size_t hl, const void *needle, size_t nl); -void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl); -extern char_t *strcpy (char_t *__dest, const char_t *__src); -extern char_t *strncpy (char_t *__dest, const char_t *__src, size_t __n); -extern char_t *strcat (char_t *__dest, const char_t *__src); -extern char_t *strncat (char_t *__dest, const char_t *__src, size_t __n); -extern int strcmp (const char_t *__s1, const char_t *__s2); -extern int strncmp (const char_t *__s1, const char_t *__s2, size_t __n); -extern char_t *strdup (const char_t *__s); -extern char_t *strchr (const char_t *__s, int __c); -extern char_t *strrchr (const char_t *__s, int __c); -extern char_t *strstr (const char_t *__haystack, const char_t *__needle); -extern char_t *strtok (char_t *__s, const char_t *__delim); -extern char_t *strtok_r (char_t *__s, const char_t *__delim, char_t **__save_ptr); -extern size_t strlen (const char_t *__s); - -/* sys/stat.h */ -#define S_IREAD 0400 /* Read by owner. */ -#define S_IWRITE 0200 /* Write by owner. */ -#define S_IFMT 0170000 /* These bits determine file type. */ -#define S_IFIFO 0010000 /* FIFO. */ -#define S_IFCHR 0020000 /* Character device. */ -#define S_IFDIR 0040000 /* Directory. */ -#define S_IFBLK 0060000 /* Block device. */ -#define S_IFREG 0100000 /* Regular file. */ -#define S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask)) -#define S_ISCHR(mode) S_ISTYPE((mode), S_IFCHR) -#define S_ISDIR(mode) S_ISTYPE((mode), S_IFDIR) -#define S_ISBLK(mode) S_ISTYPE((mode), S_IFBLK) -#define S_ISREG(mode) S_ISTYPE((mode), S_IFREG) -#define S_ISFIFO(mode) S_ISTYPE((mode), S_IFIFO) -struct stat { - mode_t st_mode; - off_t st_size; - blkcnt_t st_blocks; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; -}; -extern int stat (const char_t *__file, struct stat *__buf); -extern int fstat (FILE *__f, struct stat *__buf); -extern int mkdir (const char_t *__path, mode_t __mode); - -/* time.h */ -struct tm { - int tm_sec; /* Seconds. [0-60] (1 leap second) */ - int tm_min; /* Minutes. [0-59] */ - int tm_hour; /* Hours. [0-23] */ - int tm_mday; /* Day. [1-31] */ - int tm_mon; /* Month. [0-11] */ - int tm_year; /* Year - 1900. */ - int tm_wday; /* Day of week. [0-6] (not set) */ - int tm_yday; /* Days in year.[0-365] (not set) */ - int tm_isdst; /* DST. [-1/0/1]*/ -}; -extern struct tm *localtime (const time_t *__timer); -extern time_t mktime(const struct tm *__tm); -extern time_t time(time_t *__timer); - -/* unistd.h */ -extern unsigned int sleep (unsigned int __seconds); -extern int usleep (unsigned long int __useconds); -extern int unlink (const wchar_t *__filename); -extern int rmdir (const wchar_t *__filename); - -#ifdef __cplusplus -} -#endif - -#endif /* _UEFI_H_ */ +#define gBS BS diff --git a/Bootloader/Source/uefi/unistd.c b/Bootloader/Source/uefi/unistd.c deleted file mode 100644 index b8dccdd..0000000 --- a/Bootloader/Source/uefi/unistd.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * unistd.c - * - * Copyright (C) 2021 bzt (bztsrc@gitlab) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This file is part of the POSIX-UEFI package. - * @brief Implementing functions which are defined in unistd.h - * - */ - -#include - -int __remove(const wchar_t *__filename, int isdir); - -int usleep (unsigned long int __useconds) -{ - BS->Stall(__useconds); - return 0; -} - -unsigned int sleep (unsigned int __seconds) -{ - /* Issue 56: some real firmware is buggy and Stall doesn't work for large delays, so use a timer instead */ - uint64_t usec = (uint64_t)__seconds * 1000000UL; - uintn_t index = 0; - efi_event_t timer_event; - efi_status_t status = status = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer_event); - if(!EFI_ERROR(status)) { - BS->SetTimer(timer_event, TimerRelative, usec * 10UL); - BS->WaitForEvent(1, &timer_event, &index); - BS->CloseEvent(timer_event); - } else - BS->Stall(usec); - return 0; -} - -int unlink (const wchar_t *__filename) -{ - return __remove(__filename, 0); -} - -int rmdir (const wchar_t *__filename) -{ - return __remove(__filename, 1); -} -- 2.52.0 From 7aa49b37f5a2b43d0da511da620208c91fd8619e Mon Sep 17 00:00:00 2001 From: karina Date: Tue, 21 Apr 2026 06:37:34 +0400 Subject: [PATCH 05/49] chore: compile_commands.json now is at {{TEMP_DIR}}/Kernel instead of Kernel sources --- Kernel/CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 80567d6..c44dd52 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -137,6 +137,14 @@ foreach(_src IN LISTS SWIFT_SOURCES) math(EXPR _idx "${_idx} + 1") endforeach() -file(GENERATE OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/compile_commands.json" +if(DEFINED ENV{TEMP_DIR}) + set(COMPDB_OUTPUT_DIR "$ENV{TEMP_DIR}/Kernel") +elseif(DEFINED ENV{BUILD_DIR}) + set(COMPDB_OUTPUT_DIR "$ENV{BUILD_DIR}/temp/Kernel") +else() + set(COMPDB_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") +endif() + +file(GENERATE OUTPUT "${COMPDB_OUTPUT_DIR}/compile_commands.json" CONTENT "[\n${COMPDB_ENTRIES}]\n" ) \ No newline at end of file -- 2.52.0 From 97538aa09867272cb9bb787911bdfe93a185c26f Mon Sep 17 00:00:00 2001 From: karina Date: Wed, 22 Apr 2026 09:32:01 +0400 Subject: [PATCH 06/49] wip: vectors, panics and lsp fix --- .gitignore | 1 + .sourcekit-lsp/config.json | 8 +++ Kernel/CMakeLists.txt | 52 +++++++++++--- Kernel/Source/Arch/ExceptionContext.swift | 74 ++++++++++++++++++++ Kernel/Source/Arch/dtb.swift | 2 + Kernel/Source/Arch/vectors.S | 83 +++++++++++++++++++++++ Kernel/Source/OS/panic.swift | 6 ++ Kernel/Source/Support/BridgingHeader.h | 4 ++ Kernel/Source/kernel.swift | 8 +++ Kernel/justfile | 3 +- justfile | 4 ++ 11 files changed, 234 insertions(+), 11 deletions(-) create mode 100644 .sourcekit-lsp/config.json create mode 100644 Kernel/Source/Arch/ExceptionContext.swift create mode 100644 Kernel/Source/Arch/vectors.S create mode 100644 Kernel/Source/OS/panic.swift diff --git a/.gitignore b/.gitignore index 377b8fa..ddf013f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .vscode .DS_Store compile_commands.json +ide-swift-toolchain.txt .cache \ No newline at end of file diff --git a/.sourcekit-lsp/config.json b/.sourcekit-lsp/config.json new file mode 100644 index 0000000..96d4543 --- /dev/null +++ b/.sourcekit-lsp/config.json @@ -0,0 +1,8 @@ +{ + "defaultWorkspaceType": "compilationDatabase", + "compilationDatabase": { + "searchPaths": [".", "Kernel"] + }, + "backgroundIndexing": true, + "backgroundPreparationMode": "enabled" +} diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index c44dd52..2fc76c2 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -2,6 +2,12 @@ cmake_minimum_required(VERSION 3.20) project(ksOSKernel LANGUAGES ASM C) set(KERNEL_MODULE_NAME "Kernel") +# Where to emit compile_commands.json for SourceKit-LSP. Empty: Kernel/ +# (ancestor of SWIFT_SOURCES). Override: -DKERNEL_COMPILE_COMMANDS_DIR=/path +# or env KERNEL_COMPILE_COMMANDS_DIR. +set(KERNEL_COMPILE_COMMANDS_DIR "" CACHE PATH + "Directory for Swift compile_commands.json (SourceKit-LSP)") + # --- Locate Swift toolchain with Embedded Swift stdlib --- # Priority: cmake var > env var > auto-detect if(NOT SWIFT_TOOLCHAIN AND DEFINED ENV{SWIFT_TOOLCHAIN}) @@ -52,6 +58,18 @@ endif() message(STATUS "Swift: ${SWIFTC}") message(STATUS "Swift resource dir: ${SWIFT_RESOURCE_DIR}") +# Hint for SourceKit: VSCode must use this toolchain (same as compile_commands), +# not Xcode's default; otherwise: "Loading the standard library failed" with Embedded. +get_filename_component(_SWIFT_IDE_PATH "${SWIFTC}" DIRECTORY) +set(_ide_hint +"# If SourceKit reports \"Loading the standard library failed\", set the Swift +# extension's swift.path to the directory on the line below and restart +# \"Swift: Restart SourceKit LSP\". (Embedded Swift — must match this toolchain, not Xcode.) +# Regenerated on each CMake configure. +") +string(APPEND _ide_hint "${_SWIFT_IDE_PATH}\n") +file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/../ide-swift-toolchain.txt" "${_ide_hint}") + # --- Build --- add_compile_options(-ffreestanding -nostdlib -O0 -g) @@ -64,9 +82,11 @@ add_link_options( ) set(SWIFT_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/Source/kernel.swift - ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/dtb.swift - ${CMAKE_CURRENT_SOURCE_DIR}/Source/IO/uart.swift + ${CMAKE_CURRENT_SOURCE_DIR}/Source/Kernel.swift + ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/DTB.swift + ${CMAKE_CURRENT_SOURCE_DIR}/Source/IO/UART.swift + ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/ExceptionContext.swift + ${CMAKE_CURRENT_SOURCE_DIR}/Source/OS/panic.swift # idfk why but sourcekit-lsp dont see Panic.swift but see panic.swift perfectly ) set(SWIFT_OBJ ${CMAKE_CURRENT_BINARY_DIR}/kernel_swift.o) @@ -94,7 +114,7 @@ set_source_files_properties(${SWIFT_OBJ} PROPERTIES GENERATED TRUE ) -add_executable(kernel.elf Source/Arch/entry.S Source/Support/stubs.c ${SWIFT_OBJ}) +add_executable(kernel.elf Source/Arch/entry.S Source/Support/stubs.c Source/Arch/vectors.S ${SWIFT_OBJ}) add_custom_command(TARGET kernel.elf POST_BUILD COMMAND ${LLVM_OBJCOPY} -O binary kernel.elf kernel.bin @@ -109,8 +129,10 @@ set(SWIFT_ARGS "\"-enable-experimental-feature\"" "\"Embedded\"" "\"-module-name\"" "\"${KERNEL_MODULE_NAME}\"" "\"-parse-as-library\"" + "\"-wmo\"" "\"-import-bridging-header\"" "\"${_BRIDGING_HEADER}\"" "\"-Xcc\"" "\"-I${CMAKE_CURRENT_SOURCE_DIR}/../Common\"" + "\"-Xcc\"" "\"-fno-stack-protector\"" "\"-resource-dir\"" "\"${SWIFT_RESOURCE_DIR}\"" ) foreach(_src IN LISTS SWIFT_SOURCES) @@ -137,14 +159,24 @@ foreach(_src IN LISTS SWIFT_SOURCES) math(EXPR _idx "${_idx} + 1") endforeach() -if(DEFINED ENV{TEMP_DIR}) - set(COMPDB_OUTPUT_DIR "$ENV{TEMP_DIR}/Kernel") -elseif(DEFINED ENV{BUILD_DIR}) - set(COMPDB_OUTPUT_DIR "$ENV{BUILD_DIR}/temp/Kernel") +# Precedence: CMake -D > env > Kernel/ (ancestor of all SWIFT_SOURCES). +if(NOT KERNEL_COMPILE_COMMANDS_DIR STREQUAL "") + set(COMPDB_OUTPUT_DIR "${KERNEL_COMPILE_COMMANDS_DIR}") +elseif(DEFINED ENV{KERNEL_COMPILE_COMMANDS_DIR} AND NOT "$ENV{KERNEL_COMPILE_COMMANDS_DIR}" STREQUAL "") + set(COMPDB_OUTPUT_DIR "$ENV{KERNEL_COMPILE_COMMANDS_DIR}") else() - set(COMPDB_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + set(COMPDB_OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") endif() +# Same JSON twice: (1) optional Kernel/ or KERNEL_COMPILE_COMMANDS_DIR, (2) repo +# root. SourceKit/Cursor/VSCode Swift extension resolve compile_commands at the +# workspace root first; a DB only under Kernel/ often yields no language service +# and broken cross-file resolution (WMO) even though the build works. +set(KERNEL_COMPDB_CONTENT "[\n${COMPDB_ENTRIES}]\n") file(GENERATE OUTPUT "${COMPDB_OUTPUT_DIR}/compile_commands.json" - CONTENT "[\n${COMPDB_ENTRIES}]\n" + CONTENT "${KERNEL_COMPDB_CONTENT}" +) +set(_REPO_COMPDB "${CMAKE_CURRENT_SOURCE_DIR}/../compile_commands.json") +file(GENERATE OUTPUT "${_REPO_COMPDB}" + CONTENT "${KERNEL_COMPDB_CONTENT}" ) \ No newline at end of file diff --git a/Kernel/Source/Arch/ExceptionContext.swift b/Kernel/Source/Arch/ExceptionContext.swift new file mode 100644 index 0000000..2949d7a --- /dev/null +++ b/Kernel/Source/Arch/ExceptionContext.swift @@ -0,0 +1,74 @@ +@frozen +public struct ExceptionContext { + public var x0: UInt64 + public var x1: UInt64 + public var x2: UInt64 + public var x3: UInt64 + public var x4: UInt64 + public var x5: UInt64 + public var x6: UInt64 + public var x7: UInt64 + public var x8: UInt64 + public var x9: UInt64 + public var x10: UInt64 + public var x11: UInt64 + public var x12: UInt64 + public var x13: UInt64 + public var x14: UInt64 + public var x15: UInt64 + public var x16: UInt64 + public var x17: UInt64 + public var x18: UInt64 + public var x19: UInt64 + public var x20: UInt64 + public var x21: UInt64 + public var x22: UInt64 + public var x23: UInt64 + public var x24: UInt64 + public var x25: UInt64 + public var x26: UInt64 + public var x27: UInt64 + public var x28: UInt64 + public var x29: UInt64 // fp + public var x30: UInt64 // lr + public var elr_el1: UInt64 // pc + public var spsr_el1: UInt64 // cpu status + public var esr_el1: UInt64 // error reason +} + +@frozen +public enum ExceptionType: UInt64 { + // curr el with sp0 (EL1t) + // usually dont happen cuz we switch to sp_el1, but just in case + case syncEL1t = 0 + case irqEL1t = 1 + case fiqEL1t = 2 + case seErrorEL1t = 3 + + // curr el with sp1 (EL1h) + // exception in kernel space + case syncEL1h = 4 + case irqEL1h = 5 + case fiqEL1h = 6 + case seErrorEL1h = 7 + + // lower EL 64-bit from userspace + case syncEL0_64 = 8 + case irqEL0_64 = 9 + case fiqEL0_64 = 10 + case seErrorEL0_64 = 11 + + // lower EL 32-bit from userspace + case syncEL0_32 = 12 + case irqEL0_32 = 13 + case fiqEL0_32 = 14 + case seErrorEL0_32 = 15 +} + +@_cdecl("swift_trap_handler") +public func trapHandler(context: UnsafeMutableRawPointer, rawType: UInt64) { + let context = context.assumingMemoryBound(to: ExceptionContext.self) + let type = ExceptionType(rawValue: rawType)! + + panic(context: context.pointee) +} \ No newline at end of file diff --git a/Kernel/Source/Arch/dtb.swift b/Kernel/Source/Arch/dtb.swift index 04f8b8b..15f7dda 100644 --- a/Kernel/Source/Arch/dtb.swift +++ b/Kernel/Source/Arch/dtb.swift @@ -69,6 +69,8 @@ func parseDTB(at pointer: UnsafeRawPointer) { structBase = structBase.advanced(by: 8) // skip header structBase = structBase.advanced(by: alignUp(dataLength, to: 4)) // skip data for now + + // TODO: finish it :D case .endNode: continue case .nop: diff --git a/Kernel/Source/Arch/vectors.S b/Kernel/Source/Arch/vectors.S new file mode 100644 index 0000000..aab9215 --- /dev/null +++ b/Kernel/Source/Arch/vectors.S @@ -0,0 +1,83 @@ +.macro ventry type + .align 7 + sub sp, sp, #272 // save 272 bytes of stack + stp x0, x1, [sp, #0] // move stack + mov x1, #\type // move type to x1 + b common_trap_entry +.endm + +.section .text.vectors +.align 11 +.global vectors +vector_table: + // EL1t (curr EL with SP0) + ventry 0 // Sync + ventry 1 // IRQ + ventry 2 // FIQ + ventry 3 // SError + + // EL1h (curr EL with SP1) + ventry 4 // Sync + ventry 5 // IRQ + ventry 6 // FIQ + ventry 7 // SError + + // EL0 (lower EL 64-bit from userspace) + ventry 8 // Sync + ventry 9 // IRQ + ventry 10 // FIQ + ventry 11 // SError + + // EL0 (lower EL 32-bit from userspace) + ventry 12; ventry 13; ventry 14; ventry 15 + +common_trap_entry: + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + + mrs x21, elr_el1 + mrs x22, spsr_el1 + mrs x23, esr_el1 + + stp x30, x21, [sp, #16 * 15] + stp x22, x23, [sp, #16 * 16] + + mov x0, sp + bl swift_trap_handler + + ldp x22, x23, [sp, #16 * 16] + msr spsr_el1, x22 + + ldp x30, x21, [sp, #16 * 15] + msr elr_el1, x21 + + ldp x28, x29, [sp, #16 * 14] + ldp x26, x27, [sp, #16 * 13] + ldp x24, x25, [sp, #16 * 12] + ldp x22, x23, [sp, #16 * 11] + ldp x20, x21, [sp, #16 * 10] + ldp x18, x19, [sp, #16 * 9] + ldp x16, x17, [sp, #16 * 8] + ldp x14, x15, [sp, #16 * 7] + ldp x12, x13, [sp, #16 * 6] + ldp x10, x11, [sp, #16 * 5] + ldp x8, x9, [sp, #16 * 4] + ldp x6, x7, [sp, #16 * 3] + ldp x4, x5, [sp, #16 * 2] + ldp x2, x3, [sp, #16 * 1] + ldp x0, x1, [sp, #0] + + add sp, sp, #272 + eret \ No newline at end of file diff --git a/Kernel/Source/OS/panic.swift b/Kernel/Source/OS/panic.swift new file mode 100644 index 0000000..c8f2205 --- /dev/null +++ b/Kernel/Source/OS/panic.swift @@ -0,0 +1,6 @@ +// idfk why but sourcekit-lsp dont see Panic.swift but see panic.swift perfectly + +public func panic(context: ExceptionContext) { + kprint("kernel panic stub meow") + _wfi() +} \ No newline at end of file diff --git a/Kernel/Source/Support/BridgingHeader.h b/Kernel/Source/Support/BridgingHeader.h index 9208982..a041a31 100644 --- a/Kernel/Source/Support/BridgingHeader.h +++ b/Kernel/Source/Support/BridgingHeader.h @@ -7,4 +7,8 @@ static inline void mmio_write32(uintptr_t addr, uint32_t val) { static inline uint32_t mmio_read32(uintptr_t addr) { return *(volatile uint32_t *)addr; +} + +static inline void _wfi(void) { + __asm__ volatile("wfi"); } \ No newline at end of file diff --git a/Kernel/Source/kernel.swift b/Kernel/Source/kernel.swift index a438c9e..0f68ce9 100644 --- a/Kernel/Source/kernel.swift +++ b/Kernel/Source/kernel.swift @@ -1,4 +1,12 @@ +@inline(never) +func getDenominator() -> Int { + return 0 +} + @_cdecl("kmain") public func kernelMain(_ bootInfo: UnsafeMutablePointer) { kprint("Test nya") + let a: Int = 10 + let b = getDenominator() + let c = a / b } diff --git a/Kernel/justfile b/Kernel/justfile index 417ef27..2d9764b 100644 --- a/Kernel/justfile +++ b/Kernel/justfile @@ -10,4 +10,5 @@ build: @echo "✅ Kernel ready at: {{BUILD_DIR}}/Kernel/ksOSKernel.bin" clean: - rm -rf {{TEMP_DIR}}/Kernel \ No newline at end of file + rm -rf {{TEMP_DIR}}/Kernel + rm -f compile_commands.json \ No newline at end of file diff --git a/justfile b/justfile index 0566df1..d843608 100644 --- a/justfile +++ b/justfile @@ -86,4 +86,8 @@ _prep: just run @clean: + just Bootloader clean + just Kernel clean rm -rf {{BUILD_DIR}} + rm -f compile_commands.json + rm -f ide-swift-toolchain.txt \ No newline at end of file -- 2.52.0 From bfa84040b8a7b80823e5ae94db924c484c0c2ada Mon Sep 17 00:00:00 2001 From: karina Date: Wed, 22 Apr 2026 23:12:06 +0400 Subject: [PATCH 07/49] wip: bare bones for C in kernel --- .gitignore | 1 + Kernel/CMakeLists.txt | 199 ++++------------------ Kernel/Source/Arch/ExceptionContext.swift | 74 -------- Kernel/Source/Arch/dtb.swift | 83 --------- Kernel/Source/Arch/entry.S | 6 +- Kernel/Source/Arch/vectors.S | 83 --------- Kernel/Source/IO/uart.swift | 20 --- Kernel/Source/KernelMain.c | 3 + Kernel/Source/OS/panic.swift | 6 - Kernel/Source/Support/BridgingHeader.h | 14 -- Kernel/Source/Support/stubs.c | 42 ----- Kernel/Source/kernel.swift | 12 -- Kernel/cmake/aarch64-bare.cmake | 10 ++ 13 files changed, 46 insertions(+), 507 deletions(-) delete mode 100644 Kernel/Source/Arch/ExceptionContext.swift delete mode 100644 Kernel/Source/Arch/dtb.swift delete mode 100644 Kernel/Source/Arch/vectors.S delete mode 100644 Kernel/Source/IO/uart.swift create mode 100644 Kernel/Source/KernelMain.c delete mode 100644 Kernel/Source/OS/panic.swift delete mode 100644 Kernel/Source/Support/BridgingHeader.h delete mode 100644 Kernel/Source/Support/stubs.c delete mode 100644 Kernel/Source/kernel.swift diff --git a/.gitignore b/.gitignore index ddf013f..04b9ca0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .build +build .vscode .DS_Store compile_commands.json diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 2fc76c2..d25b339 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,182 +1,43 @@ cmake_minimum_required(VERSION 3.20) project(ksOSKernel LANGUAGES ASM C) -set(KERNEL_MODULE_NAME "Kernel") -# Where to emit compile_commands.json for SourceKit-LSP. Empty: Kernel/ -# (ancestor of SWIFT_SOURCES). Override: -DKERNEL_COMPILE_COMMANDS_DIR=/path -# or env KERNEL_COMPILE_COMMANDS_DIR. -set(KERNEL_COMPILE_COMMANDS_DIR "" CACHE PATH - "Directory for Swift compile_commands.json (SourceKit-LSP)") +file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/Source/KernelMain.c + ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/entry.S + ${CMAKE_CURRENT_SOURCE_DIR}/Source/**/*.c +) -# --- Locate Swift toolchain with Embedded Swift stdlib --- -# Priority: cmake var > env var > auto-detect -if(NOT SWIFT_TOOLCHAIN AND DEFINED ENV{SWIFT_TOOLCHAIN}) - set(SWIFT_TOOLCHAIN "$ENV{SWIFT_TOOLCHAIN}") -endif() +add_executable(Kernel ${KERNEL_SOURCES}) +target_include_directories(Kernel PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/Include/ + ${CMAKE_CURRENT_SOURCE_DIR}/../Common +) -if(SWIFT_TOOLCHAIN) - set(SWIFTC "${SWIFT_TOOLCHAIN}/usr/bin/swiftc") - set(SWIFT_RESOURCE_DIR "${SWIFT_TOOLCHAIN}/usr/lib/swift") -elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") - # Scan for a swift.org toolchain that ships the embedded stdlib. - # APPLE is false here (target is Generic), so we check the HOST OS. - file(GLOB _tc_candidates - "$ENV{HOME}/Library/Developer/Toolchains/*.xctoolchain" - "/Library/Developer/Toolchains/*.xctoolchain" - ) - foreach(_tc ${_tc_candidates}) - if(EXISTS "${_tc}/usr/lib/swift/embedded") - set(SWIFTC "${_tc}/usr/bin/swiftc") - set(SWIFT_RESOURCE_DIR "${_tc}/usr/lib/swift") - break() - endif() - endforeach() -else() - # Linux: find swiftc in PATH - find_program(_SWIFTC_EXE swiftc) - if(_SWIFTC_EXE) - get_filename_component(_SWIFTC_BIN "${_SWIFTC_EXE}" DIRECTORY) - get_filename_component(_SWIFTC_USR "${_SWIFTC_BIN}" DIRECTORY) - - if(EXISTS "${_SWIFTC_USR}/lib/swift/embedded") - set(SWIFTC "${_SWIFTC_EXE}") - set(SWIFT_RESOURCE_DIR "${_SWIFTC_USR}/lib/swift") - elseif(EXISTS "${_SWIFTC_USR}/lib/swift/lib/swift/embedded") - set(SWIFTC "${_SWIFTC_EXE}") - set(SWIFT_RESOURCE_DIR "${_SWIFTC_USR}/lib/swift/lib/swift") - endif() - endif() -endif() +target_compile_options(Kernel PRIVATE + $<$: + -ffreestanding + -fno-stack-protector + -fno-builtin + -Wall -Wextra + -g + -mgeneral-regs-only + > +) -if(NOT SWIFTC OR NOT EXISTS "${SWIFT_RESOURCE_DIR}/embedded") - message(FATAL_ERROR - "Swift toolchain with Embedded Swift not found.\n" - "Install a swift.org toolchain and pass -DSWIFT_TOOLCHAIN= " - "or set the SWIFT_TOOLCHAIN env var.") -endif() - -message(STATUS "Swift: ${SWIFTC}") -message(STATUS "Swift resource dir: ${SWIFT_RESOURCE_DIR}") - -# Hint for SourceKit: VSCode must use this toolchain (same as compile_commands), -# not Xcode's default; otherwise: "Loading the standard library failed" with Embedded. -get_filename_component(_SWIFT_IDE_PATH "${SWIFTC}" DIRECTORY) -set(_ide_hint -"# If SourceKit reports \"Loading the standard library failed\", set the Swift -# extension's swift.path to the directory on the line below and restart -# \"Swift: Restart SourceKit LSP\". (Embedded Swift — must match this toolchain, not Xcode.) -# Regenerated on each CMake configure. -") -string(APPEND _ide_hint "${_SWIFT_IDE_PATH}\n") -file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/../ide-swift-toolchain.txt" "${_ide_hint}") - -# --- Build --- -add_compile_options(-ffreestanding -nostdlib -O0 -g) - -set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld) -add_link_options( - -fuse-ld=lld +target_link_options(Kernel PRIVATE -nostdlib -static - -Wl,-T,${LINKER_SCRIPT} + -no-pie + -T "${CMAKE_CURRENT_SOURCE_DIR}/linker.ld" + -z max-page-size=0x1000 ) -set(SWIFT_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/Source/Kernel.swift - ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/DTB.swift - ${CMAKE_CURRENT_SOURCE_DIR}/Source/IO/UART.swift - ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/ExceptionContext.swift - ${CMAKE_CURRENT_SOURCE_DIR}/Source/OS/panic.swift # idfk why but sourcekit-lsp dont see Panic.swift but see panic.swift perfectly -) -set(SWIFT_OBJ ${CMAKE_CURRENT_BINARY_DIR}/kernel_swift.o) - -add_custom_command( - OUTPUT ${SWIFT_OBJ} - COMMAND ${SWIFTC} - -target aarch64-none-none-elf - -enable-experimental-feature Embedded - -parse-as-library - -wmo - -O - -Xcc -fno-stack-protector - -Xcc -I${CMAKE_CURRENT_SOURCE_DIR}/../Common - -import-bridging-header ${CMAKE_CURRENT_SOURCE_DIR}/Source/Support/BridgingHeader.h - -resource-dir ${SWIFT_RESOURCE_DIR} - -c ${SWIFT_SOURCES} - -o ${SWIFT_OBJ} - COMMAND ${LLVM_OBJCOPY} --remove-section=.swift_modhash ${SWIFT_OBJ} - DEPENDS ${SWIFT_SOURCES} - COMMENT "Compiling Swift kernel" +set_target_properties(Kernel PROPERTIES + OUTPUT_NAME "Kernel.elf" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) -set_source_files_properties(${SWIFT_OBJ} PROPERTIES - EXTERNAL_OBJECT TRUE - GENERATED TRUE -) - -add_executable(kernel.elf Source/Arch/entry.S Source/Support/stubs.c Source/Arch/vectors.S ${SWIFT_OBJ}) - -add_custom_command(TARGET kernel.elf POST_BUILD - COMMAND ${LLVM_OBJCOPY} -O binary kernel.elf kernel.bin -) - -# --- SourceKit-LSP: generate compile_commands.json for Swift (Dynamic) --- -set(_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/Source/Support/BridgingHeader.h") - -set(SWIFT_ARGS - "\"${SWIFTC}\"" - "\"-target\"" "\"aarch64-none-none-elf\"" - "\"-enable-experimental-feature\"" "\"Embedded\"" - "\"-module-name\"" "\"${KERNEL_MODULE_NAME}\"" - "\"-parse-as-library\"" - "\"-wmo\"" - "\"-import-bridging-header\"" "\"${_BRIDGING_HEADER}\"" - "\"-Xcc\"" "\"-I${CMAKE_CURRENT_SOURCE_DIR}/../Common\"" - "\"-Xcc\"" "\"-fno-stack-protector\"" - "\"-resource-dir\"" "\"${SWIFT_RESOURCE_DIR}\"" -) -foreach(_src IN LISTS SWIFT_SOURCES) - list(APPEND SWIFT_ARGS "\"${_src}\"") -endforeach() - -string(JOIN ", " SWIFT_ARGS_JSON ${SWIFT_ARGS}) - -set(COMPDB_ENTRIES "") -list(LENGTH SWIFT_SOURCES _src_count) -math(EXPR _last_idx "${_src_count} - 1") -set(_idx 0) - -foreach(_src IN LISTS SWIFT_SOURCES) - set(_entry " {\n \"file\": \"${_src}\",\n \"directory\": \"${CMAKE_CURRENT_BINARY_DIR}\",\n \"arguments\": [${SWIFT_ARGS_JSON}]\n }") - - if(_idx LESS _last_idx) - string(APPEND _entry ",\n") - else() - string(APPEND _entry "\n") - endif() - - string(APPEND COMPDB_ENTRIES "${_entry}") - math(EXPR _idx "${_idx} + 1") -endforeach() - -# Precedence: CMake -D > env > Kernel/ (ancestor of all SWIFT_SOURCES). -if(NOT KERNEL_COMPILE_COMMANDS_DIR STREQUAL "") - set(COMPDB_OUTPUT_DIR "${KERNEL_COMPILE_COMMANDS_DIR}") -elseif(DEFINED ENV{KERNEL_COMPILE_COMMANDS_DIR} AND NOT "$ENV{KERNEL_COMPILE_COMMANDS_DIR}" STREQUAL "") - set(COMPDB_OUTPUT_DIR "$ENV{KERNEL_COMPILE_COMMANDS_DIR}") -else() - set(COMPDB_OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") -endif() - -# Same JSON twice: (1) optional Kernel/ or KERNEL_COMPILE_COMMANDS_DIR, (2) repo -# root. SourceKit/Cursor/VSCode Swift extension resolve compile_commands at the -# workspace root first; a DB only under Kernel/ often yields no language service -# and broken cross-file resolution (WMO) even though the build works. -set(KERNEL_COMPDB_CONTENT "[\n${COMPDB_ENTRIES}]\n") -file(GENERATE OUTPUT "${COMPDB_OUTPUT_DIR}/compile_commands.json" - CONTENT "${KERNEL_COMPDB_CONTENT}" -) -set(_REPO_COMPDB "${CMAKE_CURRENT_SOURCE_DIR}/../compile_commands.json") -file(GENERATE OUTPUT "${_REPO_COMPDB}" - CONTENT "${KERNEL_COMPDB_CONTENT}" +add_custom_command(TARGET Kernel POST_BUILD + COMMAND ${LLVM_OBJCOPY} -O binary ${CMAKE_BINARY_DIR}/Kernel.elf ${CMAKE_BINARY_DIR}/Kernel.bin + COMMENT "Generating ksOSKernel.bin from Kernel.elf" ) \ No newline at end of file diff --git a/Kernel/Source/Arch/ExceptionContext.swift b/Kernel/Source/Arch/ExceptionContext.swift deleted file mode 100644 index 2949d7a..0000000 --- a/Kernel/Source/Arch/ExceptionContext.swift +++ /dev/null @@ -1,74 +0,0 @@ -@frozen -public struct ExceptionContext { - public var x0: UInt64 - public var x1: UInt64 - public var x2: UInt64 - public var x3: UInt64 - public var x4: UInt64 - public var x5: UInt64 - public var x6: UInt64 - public var x7: UInt64 - public var x8: UInt64 - public var x9: UInt64 - public var x10: UInt64 - public var x11: UInt64 - public var x12: UInt64 - public var x13: UInt64 - public var x14: UInt64 - public var x15: UInt64 - public var x16: UInt64 - public var x17: UInt64 - public var x18: UInt64 - public var x19: UInt64 - public var x20: UInt64 - public var x21: UInt64 - public var x22: UInt64 - public var x23: UInt64 - public var x24: UInt64 - public var x25: UInt64 - public var x26: UInt64 - public var x27: UInt64 - public var x28: UInt64 - public var x29: UInt64 // fp - public var x30: UInt64 // lr - public var elr_el1: UInt64 // pc - public var spsr_el1: UInt64 // cpu status - public var esr_el1: UInt64 // error reason -} - -@frozen -public enum ExceptionType: UInt64 { - // curr el with sp0 (EL1t) - // usually dont happen cuz we switch to sp_el1, but just in case - case syncEL1t = 0 - case irqEL1t = 1 - case fiqEL1t = 2 - case seErrorEL1t = 3 - - // curr el with sp1 (EL1h) - // exception in kernel space - case syncEL1h = 4 - case irqEL1h = 5 - case fiqEL1h = 6 - case seErrorEL1h = 7 - - // lower EL 64-bit from userspace - case syncEL0_64 = 8 - case irqEL0_64 = 9 - case fiqEL0_64 = 10 - case seErrorEL0_64 = 11 - - // lower EL 32-bit from userspace - case syncEL0_32 = 12 - case irqEL0_32 = 13 - case fiqEL0_32 = 14 - case seErrorEL0_32 = 15 -} - -@_cdecl("swift_trap_handler") -public func trapHandler(context: UnsafeMutableRawPointer, rawType: UInt64) { - let context = context.assumingMemoryBound(to: ExceptionContext.self) - let type = ExceptionType(rawValue: rawType)! - - panic(context: context.pointee) -} \ No newline at end of file diff --git a/Kernel/Source/Arch/dtb.swift b/Kernel/Source/Arch/dtb.swift deleted file mode 100644 index 15f7dda..0000000 --- a/Kernel/Source/Arch/dtb.swift +++ /dev/null @@ -1,83 +0,0 @@ -struct FDTHeader { - let magic: UInt32 // 0xd00dfeed - let totalsize: UInt32 - let off_dt_struct: UInt32 - let off_dt_strings: UInt32 - let off_mem_rsvmap: UInt32 - let version: UInt32 - let last_comp_version: UInt32 - let boot_cpuid_phys: UInt32 - let size_dt_strings: UInt32 - let size_dt_struct: UInt32 -} - -struct FDTProperty { - let len: UInt32 - let nameoff: UInt32 -} - -enum FDTToken: UInt32 { - case beginNode = 0x1 - case endNode = 0x2 - case prop = 0x3 - case nop = 0x4 - case end = 0x9 -} - -extension UInt32 { - var fromBe: UInt32 { - return self.byteSwapped - } -} - -func alignUp(_ value: Int, to: Int) -> Int { - return (value + to - 1) & ~(to - 1) -} - -let kFDTHeaderMagic = 0xd00dfeed - -func parseDTB(at pointer: UnsafeRawPointer) { - let header = pointer.bindMemory(to: FDTHeader.self, capacity: 1).pointee - guard header.magic.byteSwapped == kFDTHeaderMagic else { - return - } - - let structOffset = Int(header.off_dt_struct.byteSwapped) - let stringOffset = Int(header.off_dt_strings.byteSwapped) - - var structBase = pointer.advanced(by: structOffset) - let stringsBase = pointer.advanced(by: stringOffset) - - var finished = false - while !finished { - let rawToken = structBase.load(as: UInt32.self).byteSwapped - structBase = structBase.advanced(by: 4) - - if let token = FDTToken(rawValue: rawToken) { - switch token { - case .beginNode: - let namePointer = structBase.assumingMemoryBound(to: UInt8.self) - let name = String(cString: namePointer) - let nameLength = name.utf8.count + 1 - structBase = structBase.advanced(by: alignUp(nameLength, to: 4)) - case .prop: - let propertyHeader = structBase.load(as: FDTProperty.self) - let dataLength = Int(propertyHeader.len.byteSwapped) - let nameOffset = Int(propertyHeader.nameoff.byteSwapped) - - let namePointer = stringsBase.advanced(by: nameOffset).assumingMemoryBound(to: UInt8.self) - - structBase = structBase.advanced(by: 8) // skip header - structBase = structBase.advanced(by: alignUp(dataLength, to: 4)) // skip data for now - - // TODO: finish it :D - case .endNode: - continue - case .nop: - continue - case .end: - finished = true - } - } - } -} \ No newline at end of file diff --git a/Kernel/Source/Arch/entry.S b/Kernel/Source/Arch/entry.S index 2638f10..59853a5 100644 --- a/Kernel/Source/Arch/entry.S +++ b/Kernel/Source/Arch/entry.S @@ -1,7 +1,5 @@ .section .text.boot, "ax" .global _start - _start: - bl kmain -.hang: - b .hang \ No newline at end of file + bl KernelMain + b . \ No newline at end of file diff --git a/Kernel/Source/Arch/vectors.S b/Kernel/Source/Arch/vectors.S deleted file mode 100644 index aab9215..0000000 --- a/Kernel/Source/Arch/vectors.S +++ /dev/null @@ -1,83 +0,0 @@ -.macro ventry type - .align 7 - sub sp, sp, #272 // save 272 bytes of stack - stp x0, x1, [sp, #0] // move stack - mov x1, #\type // move type to x1 - b common_trap_entry -.endm - -.section .text.vectors -.align 11 -.global vectors -vector_table: - // EL1t (curr EL with SP0) - ventry 0 // Sync - ventry 1 // IRQ - ventry 2 // FIQ - ventry 3 // SError - - // EL1h (curr EL with SP1) - ventry 4 // Sync - ventry 5 // IRQ - ventry 6 // FIQ - ventry 7 // SError - - // EL0 (lower EL 64-bit from userspace) - ventry 8 // Sync - ventry 9 // IRQ - ventry 10 // FIQ - ventry 11 // SError - - // EL0 (lower EL 32-bit from userspace) - ventry 12; ventry 13; ventry 14; ventry 15 - -common_trap_entry: - stp x2, x3, [sp, #16 * 1] - stp x4, x5, [sp, #16 * 2] - stp x6, x7, [sp, #16 * 3] - stp x8, x9, [sp, #16 * 4] - stp x10, x11, [sp, #16 * 5] - stp x12, x13, [sp, #16 * 6] - stp x14, x15, [sp, #16 * 7] - stp x16, x17, [sp, #16 * 8] - stp x18, x19, [sp, #16 * 9] - stp x20, x21, [sp, #16 * 10] - stp x22, x23, [sp, #16 * 11] - stp x24, x25, [sp, #16 * 12] - stp x26, x27, [sp, #16 * 13] - stp x28, x29, [sp, #16 * 14] - - mrs x21, elr_el1 - mrs x22, spsr_el1 - mrs x23, esr_el1 - - stp x30, x21, [sp, #16 * 15] - stp x22, x23, [sp, #16 * 16] - - mov x0, sp - bl swift_trap_handler - - ldp x22, x23, [sp, #16 * 16] - msr spsr_el1, x22 - - ldp x30, x21, [sp, #16 * 15] - msr elr_el1, x21 - - ldp x28, x29, [sp, #16 * 14] - ldp x26, x27, [sp, #16 * 13] - ldp x24, x25, [sp, #16 * 12] - ldp x22, x23, [sp, #16 * 11] - ldp x20, x21, [sp, #16 * 10] - ldp x18, x19, [sp, #16 * 9] - ldp x16, x17, [sp, #16 * 8] - ldp x14, x15, [sp, #16 * 7] - ldp x12, x13, [sp, #16 * 6] - ldp x10, x11, [sp, #16 * 5] - ldp x8, x9, [sp, #16 * 4] - ldp x6, x7, [sp, #16 * 3] - ldp x4, x5, [sp, #16 * 2] - ldp x2, x3, [sp, #16 * 1] - ldp x0, x1, [sp, #0] - - add sp, sp, #272 - eret \ No newline at end of file diff --git a/Kernel/Source/IO/uart.swift b/Kernel/Source/IO/uart.swift deleted file mode 100644 index 3d9107f..0000000 --- a/Kernel/Source/IO/uart.swift +++ /dev/null @@ -1,20 +0,0 @@ -let kUARTBaseAddress: UInt = 0x09000000 // TODO: Make it dynamic by parsion DTB - -@_cdecl("putchar") -@discardableResult -public func _serialPutchar(_ char: Int32) -> Int32 { - let uartFR: UInt = kUARTBaseAddress + 0x18// TXFF -- TRansmit FIFO Full for PL011 is 5 bit of FR reg (0x18) - - while (mmio_read32(uartFR) & (1 << 5)) != 0 { - // i love pizza btw - } - - mmio_write32(UInt(kUARTBaseAddress), UInt32(char)) - return char -} - -public func kprint(_ message: StaticString) { - for i in 0.. - -static inline void mmio_write32(uintptr_t addr, uint32_t val) { - *(volatile uint32_t *)addr = val; -} - -static inline uint32_t mmio_read32(uintptr_t addr) { - return *(volatile uint32_t *)addr; -} - -static inline void _wfi(void) { - __asm__ volatile("wfi"); -} \ No newline at end of file diff --git a/Kernel/Source/Support/stubs.c b/Kernel/Source/Support/stubs.c deleted file mode 100644 index ca96b13..0000000 --- a/Kernel/Source/Support/stubs.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -void* memmove(void* dest, const void* src, unsigned long n) { - unsigned char* d = (unsigned char*)dest; - const unsigned char* s = (const unsigned char*)src; - if (d < s) { - while (n--) *d++ = *s++; - } else { - d += n; s += n; - while (n--) *--d = *--s; - } - return dest; -} - -void* memcpy(void* dest, const void* src, unsigned long n) { - return memmove(dest, src, n); -} - -void* memset(void* dest, int c, unsigned long n) { - unsigned char* d = (unsigned char*)dest; - while (n--) *d++ = (unsigned char)c; - return dest; -} - -// Stack protection -long __stack_chk_guard = (long)0xDEADBEEFCAFEBABEULL; -void __stack_chk_fail(void) { while (1); } - -// Swift runtime allocator stubs — should never be called in embedded mode -int posix_memalign(void** ptr, unsigned long align, unsigned long size) { - (void)ptr; (void)align; (void)size; - while (1); -} - -void free(void* ptr) { (void)ptr; } - -// Swift stdlib uses arc4random_buf for Hasher seed — stub with zeroes in bare-metal -void arc4random_buf(void* buf, unsigned long nbytes) { - unsigned char* b = (unsigned char*)buf; - while (nbytes--) *b++ = 0; -} diff --git a/Kernel/Source/kernel.swift b/Kernel/Source/kernel.swift deleted file mode 100644 index 0f68ce9..0000000 --- a/Kernel/Source/kernel.swift +++ /dev/null @@ -1,12 +0,0 @@ -@inline(never) -func getDenominator() -> Int { - return 0 -} - -@_cdecl("kmain") -public func kernelMain(_ bootInfo: UnsafeMutablePointer) { - kprint("Test nya") - let a: Int = 10 - let b = getDenominator() - let c = a / b -} diff --git a/Kernel/cmake/aarch64-bare.cmake b/Kernel/cmake/aarch64-bare.cmake index 3b90c1b..4974c8d 100644 --- a/Kernel/cmake/aarch64-bare.cmake +++ b/Kernel/cmake/aarch64-bare.cmake @@ -26,3 +26,13 @@ set(LLVM_OBJCOPY "${LLVM_BIN}/llvm-objcopy") set(TARGET_TRIPLE aarch64-none-elf) set(CMAKE_C_COMPILER_TARGET ${TARGET_TRIPLE}) set(CMAKE_ASM_COMPILER_TARGET ${TARGET_TRIPLE}) + +if(APPLE) + find_program(TERMOS_LD_LLD NAMES ld.lld HINTS /usr/local/bin /opt/homebrew/bin REQUIRED) + find_program(LLVM_OBJCOPY NAMES llvm-objcopy objcopy + HINTS /usr/local/opt/llvm/bin /opt/homebrew/opt/llvm/bin /usr/local/bin /opt/homebrew/bin + REQUIRED) + set(CMAKE_C_LINK_FLAGS "") + set(CMAKE_C_LINK_EXECUTABLE + "${TERMOS_LD_LLD} -o ") +endif() -- 2.52.0 From cf142ba78e17e60e819eff516bf6944ab75e9bf3 Mon Sep 17 00:00:00 2001 From: karina Date: Thu, 23 Apr 2026 06:49:40 +0400 Subject: [PATCH 08/49] fix: clangd --- Kernel/.clangd | 2 ++ Kernel/CMakeLists.txt | 1 + Kernel/Include/types.h | 18 +++++++++++++++ Kernel/Source/KernelMain.c | 4 +++- Kernel/cmake/aarch64-bare.cmake | 39 +++++++++++++++++++++++---------- Kernel/justfile | 2 +- 6 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 Kernel/.clangd create mode 100644 Kernel/Include/types.h diff --git a/Kernel/.clangd b/Kernel/.clangd new file mode 100644 index 0000000..9992ca2 --- /dev/null +++ b/Kernel/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + CompilationDatabase: ../.build/temp/Kernel diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index d25b339..6c42a05 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.20) project(ksOSKernel LANGUAGES ASM C) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Source/KernelMain.c diff --git a/Kernel/Include/types.h b/Kernel/Include/types.h new file mode 100644 index 0000000..3c0ad3e --- /dev/null +++ b/Kernel/Include/types.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKarinyash + +#pragma once + +typedef unsigned char UInt8; +typedef unsigned short UInt16; +typedef unsigned int UInt32; +typedef unsigned long long UInt64; + +typedef signed char Int8; +typedef signed short Int16; +typedef signed int Int32; +typedef signed long long Int64; + +typedef UInt64 Size; + + diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 7e4f917..22c22be 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,3 +1,5 @@ +#include "types.h" + void KernelMain(void) { - + volatile UInt64 meow = 0x12345; } \ No newline at end of file diff --git a/Kernel/cmake/aarch64-bare.cmake b/Kernel/cmake/aarch64-bare.cmake index 4974c8d..461e28a 100644 --- a/Kernel/cmake/aarch64-bare.cmake +++ b/Kernel/cmake/aarch64-bare.cmake @@ -3,25 +3,35 @@ set(CMAKE_SYSTEM_PROCESSOR aarch64) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) if(NOT LLVM_BIN) - if(APPLE) + find_program(_CLANG + NAMES clang + HINTS + /opt/homebrew/opt/llvm/bin + /usr/local/opt/llvm/bin + ) + + if(NOT _CLANG AND APPLE) execute_process( COMMAND brew --prefix llvm OUTPUT_VARIABLE LLVM_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE BREW_PREFIX_RESULT ) - set(LLVM_BIN "${LLVM_PREFIX}/bin") - else() - find_program(_CLANG clang) - if(NOT _CLANG) - message(FATAL_ERROR "clang not found.") + if(BREW_PREFIX_RESULT EQUAL 0 AND EXISTS "${LLVM_PREFIX}/bin/clang") + set(_CLANG "${LLVM_PREFIX}/bin/clang") endif() - get_filename_component(LLVM_BIN "${_CLANG}" DIRECTORY) endif() + + if(NOT _CLANG) + message(FATAL_ERROR "clang not found. Set LLVM_BIN or add clang to PATH.") + endif() + + get_filename_component(LLVM_BIN "${_CLANG}" DIRECTORY) endif() set(CMAKE_C_COMPILER "${LLVM_BIN}/clang") set(CMAKE_ASM_COMPILER "${LLVM_BIN}/clang") -set(LLVM_OBJCOPY "${LLVM_BIN}/llvm-objcopy") set(TARGET_TRIPLE aarch64-none-elf) set(CMAKE_C_COMPILER_TARGET ${TARGET_TRIPLE}) @@ -29,10 +39,17 @@ set(CMAKE_ASM_COMPILER_TARGET ${TARGET_TRIPLE}) if(APPLE) find_program(TERMOS_LD_LLD NAMES ld.lld HINTS /usr/local/bin /opt/homebrew/bin REQUIRED) - find_program(LLVM_OBJCOPY NAMES llvm-objcopy objcopy - HINTS /usr/local/opt/llvm/bin /opt/homebrew/opt/llvm/bin /usr/local/bin /opt/homebrew/bin - REQUIRED) set(CMAKE_C_LINK_FLAGS "") set(CMAKE_C_LINK_EXECUTABLE "${TERMOS_LD_LLD} -o ") endif() + +find_program(LLVM_OBJCOPY NAMES llvm-objcopy objcopy + HINTS + "${LLVM_BIN}" + /usr/local/opt/llvm/bin + /opt/homebrew/opt/llvm/bin + /usr/local/bin + /opt/homebrew/bin + REQUIRED +) diff --git a/Kernel/justfile b/Kernel/justfile index 2d9764b..d621268 100644 --- a/Kernel/justfile +++ b/Kernel/justfile @@ -6,7 +6,7 @@ build: cmake --build {{TEMP_DIR}}/Kernel - cp {{TEMP_DIR}}/Kernel/kernel.bin {{BUILD_DIR}}/Kernel/ksOSKernel.bin + cp {{TEMP_DIR}}/Kernel/Kernel.bin {{BUILD_DIR}}/Kernel/ksOSKernel.bin @echo "✅ Kernel ready at: {{BUILD_DIR}}/Kernel/ksOSKernel.bin" clean: -- 2.52.0 From 502413b9ab0e9c07fd516e8ab1ce661675459a5b Mon Sep 17 00:00:00 2001 From: karina Date: Thu, 23 Apr 2026 21:25:15 +0400 Subject: [PATCH 09/49] feat(kernel): add PL011 UART console and arch I/O helpers - Add IOSerial: PL011 (0x0900_0000) TX with FIFO-full polling, yield while waiting - Add Arch/IO.h (32-bit MMIO with DSB) and Arch/CPU.h (yield, WFI) - Extend types.h (e.g. ASCII, Address, Int/UInt aliases) - Wire KernelMain to IOSerialPutString for early boot output - Drop .sourcekit-lsp config; note IO glob in CMake (commented) --- .sourcekit-lsp/config.json | 8 -------- Kernel/CMakeLists.txt | 1 + Kernel/Include/Arch/CPU.h | 9 +++++++++ Kernel/Include/Arch/IO.h | 14 ++++++++++++++ Kernel/Include/IO/IOSerial.h | 9 +++++++++ Kernel/Include/types.h | 8 +++++++- Kernel/Source/IO/IOSerial.c | 25 +++++++++++++++++++++++++ Kernel/Source/KernelMain.c | 5 +++-- 8 files changed, 68 insertions(+), 11 deletions(-) delete mode 100644 .sourcekit-lsp/config.json create mode 100644 Kernel/Include/Arch/CPU.h create mode 100644 Kernel/Include/Arch/IO.h create mode 100644 Kernel/Include/IO/IOSerial.h create mode 100644 Kernel/Source/IO/IOSerial.c diff --git a/.sourcekit-lsp/config.json b/.sourcekit-lsp/config.json deleted file mode 100644 index 96d4543..0000000 --- a/.sourcekit-lsp/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "defaultWorkspaceType": "compilationDatabase", - "compilationDatabase": { - "searchPaths": [".", "Kernel"] - }, - "backgroundIndexing": true, - "backgroundPreparationMode": "enabled" -} diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 6c42a05..91025ab 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Source/KernelMain.c ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/entry.S +# ${CMAKE_CURRENT_SOURCE_DIR}/Source/IO/*.c ${CMAKE_CURRENT_SOURCE_DIR}/Source/**/*.c ) diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h new file mode 100644 index 0000000..ce9532a --- /dev/null +++ b/Kernel/Include/Arch/CPU.h @@ -0,0 +1,9 @@ +#pragma once + +static inline void CPUYield() { + __asm__ volatile ("yield" ::: "memory"); +} + +static inline void CPUWaitForInterrupt() { + __asm__ volatile ("wfi" ::: "memory"); +} \ No newline at end of file diff --git a/Kernel/Include/Arch/IO.h b/Kernel/Include/Arch/IO.h new file mode 100644 index 0000000..6b378d1 --- /dev/null +++ b/Kernel/Include/Arch/IO.h @@ -0,0 +1,14 @@ +#pragma once +#include + +static inline void IOAddressWrite32(UInt64 address, UInt32 value) { + __asm__ volatile ("dsb sy" ::: "memory"); // wait till all previous writes are finished physically + *(volatile UInt32*)address = value; + __asm__ volatile ("dsb sy" ::: "memory"); // wait till my write is finished physically +} + +static inline UInt32 IOAddressRead32(UInt64 address) { + UInt32 value = *(volatile UInt32*)address; + __asm__ volatile ("dsb ld" ::: "memory"); // wait till my read is finished physically + return value; +} \ No newline at end of file diff --git a/Kernel/Include/IO/IOSerial.h b/Kernel/Include/IO/IOSerial.h new file mode 100644 index 0000000..f2d7787 --- /dev/null +++ b/Kernel/Include/IO/IOSerial.h @@ -0,0 +1,9 @@ +#pragma once +#include + +enum { + kUARTBaseAddress = 0x09000000, // TODO: make it dynamic by parsing DTB +}; + +Int32 IOSerialPutCharacter(ASCII character); +Int32 IOSerialPutString(const ASCII* string); \ No newline at end of file diff --git a/Kernel/Include/types.h b/Kernel/Include/types.h index 3c0ad3e..442cefc 100644 --- a/Kernel/Include/types.h +++ b/Kernel/Include/types.h @@ -7,12 +7,18 @@ typedef unsigned char UInt8; typedef unsigned short UInt16; typedef unsigned int UInt32; typedef unsigned long long UInt64; +typedef unsigned long long UInt; + +typedef UInt Address; +typedef UInt8* BytePointer; +typedef UInt8* MemoryPointer; typedef signed char Int8; typedef signed short Int16; typedef signed int Int32; typedef signed long long Int64; +typedef int Int; typedef UInt64 Size; - +typedef char ASCII; diff --git a/Kernel/Source/IO/IOSerial.c b/Kernel/Source/IO/IOSerial.c new file mode 100644 index 0000000..e2cf1f2 --- /dev/null +++ b/Kernel/Source/IO/IOSerial.c @@ -0,0 +1,25 @@ +#include +#include +#include + +Int32 IOSerialPutCharacter(ASCII character) { + // TXFF -- TRansmit FIFO Full for PL011 is 5 bit of FR reg (0x18) + UInt64 uartFR = kUARTBaseAddress + 0x18; + + while ((IOAddressRead32(uartFR) & (1 << 5)) != 0) { + CPUYield(); + } + + IOAddressWrite32(kUARTBaseAddress, character); + return character; +} + +Int32 IOSerialPutString(const ASCII* string) { + Int i = 0; + while (string[i] != '\0') { + IOSerialPutCharacter(string[i]); + i++; + } + + return i; +} \ No newline at end of file diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 22c22be..10592dd 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,5 +1,6 @@ -#include "types.h" +#include +#include void KernelMain(void) { - volatile UInt64 meow = 0x12345; + IOSerialPutString("Meow nya!!\n"); } \ No newline at end of file -- 2.52.0 From 93bce5a46d33462ff223c31a1f97f38d5d3e5c94 Mon Sep 17 00:00:00 2001 From: karina Date: Thu, 23 Apr 2026 22:03:18 +0400 Subject: [PATCH 10/49] feat(kernel): add vectors.S and Exceptions.h/c as a stub for future exceptions handling --- Kernel/CMakeLists.txt | 2 +- Kernel/Include/Arch/Exceptions.h | 67 ++++++++++++++++++++++++ Kernel/Source/Arch/Exceptions.c | 10 ++++ Kernel/Source/Arch/entry.S | 1 + Kernel/Source/Arch/vectors.S | 90 ++++++++++++++++++++++++++++++++ Kernel/Source/KernelMain.c | 2 + 6 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 Kernel/Include/Arch/Exceptions.h create mode 100644 Kernel/Source/Arch/Exceptions.c create mode 100644 Kernel/Source/Arch/vectors.S diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 91025ab..be84ad4 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Source/KernelMain.c ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/entry.S -# ${CMAKE_CURRENT_SOURCE_DIR}/Source/IO/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/vectors.S ${CMAKE_CURRENT_SOURCE_DIR}/Source/**/*.c ) diff --git a/Kernel/Include/Arch/Exceptions.h b/Kernel/Include/Arch/Exceptions.h new file mode 100644 index 0000000..df48045 --- /dev/null +++ b/Kernel/Include/Arch/Exceptions.h @@ -0,0 +1,67 @@ +#pragma once +#include + +typedef struct ExceptionsContext { + UInt64 x0; + UInt64 x1; + UInt64 x2; + UInt64 x3; + UInt64 x4; + UInt64 x5; + UInt64 x6; + UInt64 x7; + UInt64 x8; + UInt64 x9; + UInt64 x10; + UInt64 x11; + UInt64 x12; + UInt64 x13; + UInt64 x14; + UInt64 x15; + UInt64 x16; + UInt64 x17; + UInt64 x18; + UInt64 x19; + UInt64 x20; + UInt64 x21; + UInt64 x22; + UInt64 x23; + UInt64 x24; + UInt64 x25; + UInt64 x26; + UInt64 x27; + UInt64 x28; + UInt64 x29; // fp + UInt64 x30; // lr + UInt64 elr_el1; // pc + UInt64 spsr_el1; // cpu status + UInt64 esr_el1; // error reason +} ExceptionsContext; + +typedef enum ExceptionsType { + // curr el with sp0 (EL1t) + // usually dont happen cuz we switch to sp_el1, but just in case + ExceptionsSyncEl1t, + ExceptionsIRQEl1t, + ExceptionsFIQEl1t, + ExceptionsSErrorEl1t, + + // curr el with sp1 (EL1h) + // exception in kernel space + ExceptionsSyncEl1h, + ExceptionsIRQEl1h, + ExceptionsFIQEl1h, + ExceptionsSErrorEl1h, + + // lower EL 64-bit from userspace + ExceptionsSyncEl064, + ExceptionsIRQEl064, + ExceptionsFIQEl064, + ExceptionsSErrorEl064, + + // lower EL 32-bit from userspace + ExceptionsSyncEl032, + ExceptionsIRQEl032, + ExceptionsFIQEl032, + ExceptionsSErrorEl032, +} ExceptionsType; \ No newline at end of file diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c new file mode 100644 index 0000000..952d356 --- /dev/null +++ b/Kernel/Source/Arch/Exceptions.c @@ -0,0 +1,10 @@ +#include +#include +#include + +void ExceptionsHandler(ExceptionsContext* context, ExceptionsType type) { + IOSerialPutString("Exception occurred"); + while (1) { + CPUWaitForInterrupt(); + } +} \ No newline at end of file diff --git a/Kernel/Source/Arch/entry.S b/Kernel/Source/Arch/entry.S index 59853a5..af21614 100644 --- a/Kernel/Source/Arch/entry.S +++ b/Kernel/Source/Arch/entry.S @@ -1,5 +1,6 @@ .section .text.boot, "ax" .global _start _start: + bl ExceptionsVectorsInit bl KernelMain b . \ No newline at end of file diff --git a/Kernel/Source/Arch/vectors.S b/Kernel/Source/Arch/vectors.S new file mode 100644 index 0000000..05e183e --- /dev/null +++ b/Kernel/Source/Arch/vectors.S @@ -0,0 +1,90 @@ +.macro ventry type + .align 7 + sub sp, sp, #272 // save 272 bytes of stack + stp x0, x1, [sp, #0] // move stack + mov x1, #\type // move type to x1 + b ExceptionsTrapEntry +.endm + +.section .text.vectors +.align 11 +.global vectors +ExceptionsVectorsTable: + // EL1t (curr EL with SP0) + ventry 0 // Sync + ventry 1 // IRQ + ventry 2 // FIQ + ventry 3 // SError + + // EL1h (curr EL with SP1) + ventry 4 // Sync + ventry 5 // IRQ + ventry 6 // FIQ + ventry 7 // SError + + // EL0 (lower EL 64-bit from userspace) + ventry 8 // Sync + ventry 9 // IRQ + ventry 10 // FIQ + ventry 11 // SError + + // EL0 (lower EL 32-bit from userspace) + ventry 12; ventry 13; ventry 14; ventry 15 + +ExceptionsTrapEntry: + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + + mrs x21, elr_el1 + mrs x22, spsr_el1 + mrs x23, esr_el1 + + stp x30, x21, [sp, #16 * 15] + stp x22, x23, [sp, #16 * 16] + + mov x0, sp + bl ExceptionsHandler + + ldp x22, x23, [sp, #16 * 16] + msr spsr_el1, x22 + + ldp x30, x21, [sp, #16 * 15] + msr elr_el1, x21 + + ldp x28, x29, [sp, #16 * 14] + ldp x26, x27, [sp, #16 * 13] + ldp x24, x25, [sp, #16 * 12] + ldp x22, x23, [sp, #16 * 11] + ldp x20, x21, [sp, #16 * 10] + ldp x18, x19, [sp, #16 * 9] + ldp x16, x17, [sp, #16 * 8] + ldp x14, x15, [sp, #16 * 7] + ldp x12, x13, [sp, #16 * 6] + ldp x10, x11, [sp, #16 * 5] + ldp x8, x9, [sp, #16 * 4] + ldp x6, x7, [sp, #16 * 3] + ldp x4, x5, [sp, #16 * 2] + ldp x2, x3, [sp, #16 * 1] + ldp x0, x1, [sp, #0] + + add sp, sp, #272 + eret + +.global ExceptionsVectorsInit +ExceptionsVectorsInit: + adr x0, ExceptionsVectorsTable + msr vbar_el1, x0 + isb + ret \ No newline at end of file diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 10592dd..ddd4caf 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -3,4 +3,6 @@ void KernelMain(void) { IOSerialPutString("Meow nya!!\n"); + __asm__ volatile ("brk #0"); + IOSerialPutString("How\r\n"); } \ No newline at end of file -- 2.52.0 From f469da7e0b874dbb121ecf0135e6e92d72a27932 Mon Sep 17 00:00:00 2001 From: karina Date: Thu, 23 Apr 2026 22:17:56 +0400 Subject: [PATCH 11/49] refactor(kernel): minor refactor. Changed naming convention --- Kernel/Include/Arch/IO.h | 4 ++-- Kernel/Include/IO/{IOSerial.h => Serial.h} | 0 Kernel/Source/Arch/Exceptions.c | 2 +- Kernel/Source/IO/{IOSerial.c => Serial.c} | 2 +- Kernel/Source/KernelMain.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename Kernel/Include/IO/{IOSerial.h => Serial.h} (100%) rename Kernel/Source/IO/{IOSerial.c => Serial.c} (95%) diff --git a/Kernel/Include/Arch/IO.h b/Kernel/Include/Arch/IO.h index 6b378d1..91f494b 100644 --- a/Kernel/Include/Arch/IO.h +++ b/Kernel/Include/Arch/IO.h @@ -1,13 +1,13 @@ #pragma once #include -static inline void IOAddressWrite32(UInt64 address, UInt32 value) { +static inline void IOAddressWrite32(Address address, UInt32 value) { __asm__ volatile ("dsb sy" ::: "memory"); // wait till all previous writes are finished physically *(volatile UInt32*)address = value; __asm__ volatile ("dsb sy" ::: "memory"); // wait till my write is finished physically } -static inline UInt32 IOAddressRead32(UInt64 address) { +static inline UInt32 IOAddressRead32(Address address) { UInt32 value = *(volatile UInt32*)address; __asm__ volatile ("dsb ld" ::: "memory"); // wait till my read is finished physically return value; diff --git a/Kernel/Include/IO/IOSerial.h b/Kernel/Include/IO/Serial.h similarity index 100% rename from Kernel/Include/IO/IOSerial.h rename to Kernel/Include/IO/Serial.h diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c index 952d356..200e529 100644 --- a/Kernel/Source/Arch/Exceptions.c +++ b/Kernel/Source/Arch/Exceptions.c @@ -1,6 +1,6 @@ #include #include -#include +#include void ExceptionsHandler(ExceptionsContext* context, ExceptionsType type) { IOSerialPutString("Exception occurred"); diff --git a/Kernel/Source/IO/IOSerial.c b/Kernel/Source/IO/Serial.c similarity index 95% rename from Kernel/Source/IO/IOSerial.c rename to Kernel/Source/IO/Serial.c index e2cf1f2..2a92d13 100644 --- a/Kernel/Source/IO/IOSerial.c +++ b/Kernel/Source/IO/Serial.c @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index ddd4caf..131de92 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,5 +1,5 @@ #include -#include +#include void KernelMain(void) { IOSerialPutString("Meow nya!!\n"); -- 2.52.0 From 373ee00d045e4c9413f778063c81fc122a00d072 Mon Sep 17 00:00:00 2001 From: karina Date: Thu, 23 Apr 2026 23:14:24 +0400 Subject: [PATCH 12/49] feat: add kernel exception panic --- Kernel/Include/Arch/CPU.h | 11 ++++++++- Kernel/Include/OS/Panic.h | 6 +++++ Kernel/Source/Arch/Exceptions.c | 8 +++--- Kernel/Source/KernelMain.c | 2 -- Kernel/Source/OS/Panic.c | 43 +++++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 Kernel/Include/OS/Panic.h create mode 100644 Kernel/Source/OS/Panic.c diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index ce9532a..ae6aafa 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -1,4 +1,5 @@ #pragma once +#include static inline void CPUYield() { __asm__ volatile ("yield" ::: "memory"); @@ -6,4 +7,12 @@ static inline void CPUYield() { static inline void CPUWaitForInterrupt() { __asm__ volatile ("wfi" ::: "memory"); -} \ No newline at end of file +} + +static inline void CPUDisableInterrupts() { + __asm__ volatile ("msr daifset, #3" ::: "memory"); +} + +static inline void CPUEnableInterrupts() { + __asm__ volatile ("msr daifclr, #3" ::: "memory"); +} diff --git a/Kernel/Include/OS/Panic.h b/Kernel/Include/OS/Panic.h new file mode 100644 index 0000000..c8d69d5 --- /dev/null +++ b/Kernel/Include/OS/Panic.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +__attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame); \ No newline at end of file diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c index 200e529..532bbb2 100644 --- a/Kernel/Source/Arch/Exceptions.c +++ b/Kernel/Source/Arch/Exceptions.c @@ -1,10 +1,8 @@ #include #include #include +#include -void ExceptionsHandler(ExceptionsContext* context, ExceptionsType type) { - IOSerialPutString("Exception occurred"); - while (1) { - CPUWaitForInterrupt(); - } +void ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) { + OSPanicException(frame); } \ No newline at end of file diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 131de92..7cc4f2d 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -3,6 +3,4 @@ void KernelMain(void) { IOSerialPutString("Meow nya!!\n"); - __asm__ volatile ("brk #0"); - IOSerialPutString("How\r\n"); } \ No newline at end of file diff --git a/Kernel/Source/OS/Panic.c b/Kernel/Source/OS/Panic.c new file mode 100644 index 0000000..769d159 --- /dev/null +++ b/Kernel/Source/OS/Panic.c @@ -0,0 +1,43 @@ +#include +#include +#include + +static const ASCII* GetExceptionClassString(UInt32 class) { + switch (class) { + case 0x00: return "Unknown reason"; + case 0x01: return "Trapped WFI | WFE instruction"; + case 0x07: return "Trapped SIMD | FP instruction"; + case 0x11: return "SVC from EL1"; + case 0x15: return "SVC from EL0"; + case 0x20: return "Instruction abort (LoEL)"; // User Execute Fault + case 0x21: return "Instruction abort (CurrEL)"; // Kernel Execute Fault + case 0x22: return "PC Alignment Fault"; // Jumped to a misaligned address + case 0x24: return "Data abort (LoEL)"; // User Memory Fault + case 0x25: return "Data abort (CurrEL)"; // Kernel Memory Fault + case 0x26: return "SP Alignment Fault"; // SP must be 16-byte aligned + case 0x3C: return "Breakpoint"; + default: return "Reserved"; + } +} + + +__attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { + UInt32 esr = frame->esr_el1; + UInt32 class = (esr >> 26) & 0x3F; // Exception class (Bits 31:26) + UInt32 length = (esr >> 25) & 0x1; // Instruction length (Bit 25) + UInt32 syndrome = esr & 0x1FFFFFF; // Syndrome (Bits 24:0) + + // i cant show any info since i have no formatter yet :( + IOSerialPutString("\n-------------------\n"); + IOSerialPutString("Kernel Panic! :(\n"); + IOSerialPutString("-------------------\n"); + IOSerialPutString("CPU Exception: "); + IOSerialPutString(GetExceptionClassString(class)); + IOSerialPutString("\n-------------------\n"); + IOSerialPutString("System halted.\n"); + + while (1) { + CPUDisableInterrupts(); + CPUWaitForInterrupt(); + } +} \ No newline at end of file -- 2.52.0 From 78dcfdd662c83fdca72dd835c23ba9d3d7d7d4b5 Mon Sep 17 00:00:00 2001 From: karina Date: Fri, 24 Apr 2026 16:29:46 +0400 Subject: [PATCH 13/49] feat: formatter and oslog() --- Kernel/Include/Lib/String.h | 18 ++++ Kernel/Include/Lib/VAArgs.h | 8 ++ Kernel/Include/OS/Log.h | 8 ++ Kernel/Source/IO/Serial.c | 4 +- Kernel/Source/KernelMain.c | 4 +- Kernel/Source/Lib/String.c | 179 ++++++++++++++++++++++++++++++++++++ Kernel/Source/OS/Log.c | 15 +++ 7 files changed, 231 insertions(+), 5 deletions(-) create mode 100644 Kernel/Include/Lib/String.h create mode 100644 Kernel/Include/Lib/VAArgs.h create mode 100644 Kernel/Include/OS/Log.h create mode 100644 Kernel/Source/Lib/String.c create mode 100644 Kernel/Source/OS/Log.c diff --git a/Kernel/Include/Lib/String.h b/Kernel/Include/Lib/String.h new file mode 100644 index 0000000..201334f --- /dev/null +++ b/Kernel/Include/Lib/String.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +void* StringSet(BytePointer destination, ASCII value, Size count); +void* MemoryCopy(void* destination, const void* source, Size count); + +Int32 StringCompare(const ASCII* firstString, const ASCII* secondString); +Int32 StringCompareWithLimit(const ASCII* firstString, const ASCII* secondString, Size limit); + +ASCII* StringCopy(ASCII* destination, const ASCII* source); +ASCII* StringCopyWithLimit(ASCII* destination, const ASCII* source, Size limit); + +Size StringGetLength(const ASCII* string); +const ASCII* StringFindLastOccurrenceOfCharacter(const ASCII* string, ASCII separator); + +Int32 StringFormatVariadic(ASCII* string, Size size, const ASCII* format, va_list args); +Int32 StringFormat(ASCII* destination, UInt64 size, const ASCII* format, ...); \ No newline at end of file diff --git a/Kernel/Include/Lib/VAArgs.h b/Kernel/Include/Lib/VAArgs.h new file mode 100644 index 0000000..da688ef --- /dev/null +++ b/Kernel/Include/Lib/VAArgs.h @@ -0,0 +1,8 @@ +#pragma once + +typedef __builtin_va_list va_list; + +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) \ No newline at end of file diff --git a/Kernel/Include/OS/Log.h b/Kernel/Include/OS/Log.h new file mode 100644 index 0000000..5b9d1d2 --- /dev/null +++ b/Kernel/Include/OS/Log.h @@ -0,0 +1,8 @@ +#pragma once +#include + +enum { + kOSLogBufferSize = 1024, +}; + +void OSLog(const ASCII* format, ...); \ No newline at end of file diff --git a/Kernel/Source/IO/Serial.c b/Kernel/Source/IO/Serial.c index 2a92d13..68f7ef9 100644 --- a/Kernel/Source/IO/Serial.c +++ b/Kernel/Source/IO/Serial.c @@ -4,7 +4,7 @@ Int32 IOSerialPutCharacter(ASCII character) { // TXFF -- TRansmit FIFO Full for PL011 is 5 bit of FR reg (0x18) - UInt64 uartFR = kUARTBaseAddress + 0x18; + UInt64 uartFR = kUARTBaseAddress + 0x18; while ((IOAddressRead32(uartFR) & (1 << 5)) != 0) { CPUYield(); @@ -22,4 +22,4 @@ Int32 IOSerialPutString(const ASCII* string) { } return i; -} \ No newline at end of file +} diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 7cc4f2d..d21d0c3 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,6 +1,4 @@ -#include -#include +#include void KernelMain(void) { - IOSerialPutString("Meow nya!!\n"); } \ No newline at end of file diff --git a/Kernel/Source/Lib/String.c b/Kernel/Source/Lib/String.c new file mode 100644 index 0000000..5a23995 --- /dev/null +++ b/Kernel/Source/Lib/String.c @@ -0,0 +1,179 @@ +#include +#include + +static void BufferAdd(ASCII* buffer, Size bufferSize, Size* written, ASCII character) { + if (*written + 1 < bufferSize) { + buffer[*written] = character; + } + (*written)++; +} + +void* StringSet(BytePointer destination, ASCII value, Size count) { + BytePointer savedDestination = destination; + while (count--) { + *destination++ = (UInt8) value; + } + return savedDestination; +} + +void* MemoryCopy(void* destination, const void* source, Size count) { + BytePointer destinationBuffer = (BytePointer) destination; + const UInt8* sourceBuffer = (const UInt8*) source; + + while (count >= 8) { + *(UInt64*) destinationBuffer = *(const UInt64*) sourceBuffer; + destinationBuffer += 8; + sourceBuffer += 8; + count -= 8; + } + + while (count > 0) { + *destinationBuffer++ = *sourceBuffer++; + count--; + } + + return destination; +} + +Int32 StringCompare(const ASCII* firstString, const ASCII* secondString) { + while (*firstString && (*firstString == *secondString)) { + firstString++; + secondString++; + } + return *(const UInt8*) firstString - *(const UInt8*) secondString; +} + +Int32 StringCompareWithLimit(const ASCII* firstString, const ASCII* secondString, Size limit) { + while (limit > 0) { + if (*firstString != *secondString) return *(const UInt8*) firstString - *(const UInt8*) secondString; + if (*firstString == '\0') return 0; + firstString++; + secondString++; + limit--; + } + + return 0; +} + +ASCII* StringCopy(ASCII* destination, const ASCII* source) { + ASCII* saved = destination; + while (*source) *destination++ = *source++; + *destination = 0; + return saved; +} + +ASCII* StringCopyWithLimit(ASCII* destination, const ASCII* source, Size limit) { + ASCII* saved = destination; + while (*source && limit > 0) { + *destination++ = *source++; + limit--; + } + while (limit > 0) { + *destination++ = 0; + limit--; + } + return saved; +} + +Size StringGetLength(const ASCII* string) { + Size result = 0; + for (result = 0; string[result]; result++); + return result; +} + +const ASCII* StringFindLastOccurrenceOfCharacter(const ASCII* string, ASCII separator) { + const ASCII* lastSeparator = 0; + do { + if (*string == separator) lastSeparator = string; + } while (*string++); + + return lastSeparator; +} + +Int32 StringFormatVariadic(ASCII* string, Size size, const ASCII* format, va_list args) { + Size written = 0; + for (Size i = 0; format[i] != '\0'; i++) { + if (format[i] == '%') { + i++; + if (format[i] == '\0') break; + switch (format[i]) { + case 's': { + const ASCII* vaArgString = va_arg(args, const ASCII*); + if (!vaArgString) vaArgString = "(null)"; + while (*vaArgString) BufferAdd(string, size, &written, *vaArgString++); + break; + } + case 'c': { + ASCII character = (ASCII)va_arg(args, Int); + BufferAdd(string, size, &written, character); + break; + } + case 'd': { + Int64 number = va_arg(args, Int); + if (number < 0) { + BufferAdd(string, size, &written, '-'); + number = -number; + } + + UInt64 unsignedNumber = (UInt64)number; + ASCII tempBuffer[32]; + Size position = 0; + + if (unsignedNumber == 0) tempBuffer[position++] = '0'; + while (unsignedNumber > 0) { + tempBuffer[position++] = (ASCII)((unsignedNumber % 10) + '0'); + unsignedNumber /= 10; + } + + while (position > 0) BufferAdd(string, size, &written, tempBuffer[--position]); + break; + } + case 'x': + case 'X': { + UInt64 unsignedNumber = va_arg(args, UInt64); + UInt8 padding = (format[i] == 'X') ? 16 : 0; + + ASCII tempBuffer[32]; + Size position = 0; + static const ASCII kHexDigits[] = "0123456789ABCDEF"; + + if (unsignedNumber == 0 && padding == 0) tempBuffer[position++] = '0'; + while (unsignedNumber > 0) { + tempBuffer[position++] = kHexDigits[unsignedNumber % 16]; + unsignedNumber /= 16; + } + + while (position < (Size)padding) tempBuffer[position++] = '0'; + while (position > 0) BufferAdd(string, size, &written, tempBuffer[--position]); + break; + } + case '%': { + BufferAdd(string, size, &written, '%'); + break; + } + default: { + BufferAdd(string, size, &written, '%'); + BufferAdd(string, size, &written, format[i]); + break; + } + } + } else { + BufferAdd(string, size, &written, format[i]); + } + } + + if (size > 0) { + if (written < size) string[written] = '\0'; + else string[size - 1] = '\0'; + } + + return (Int32)written; +} + +Int32 StringFormat(ASCII* destination, UInt64 size, const ASCII* format, ...) { + va_list args; + va_start(args, format); + Int32 returnValue = StringFormatVariadic(destination, size, format, args); + va_end(args); + return returnValue; +} \ No newline at end of file diff --git a/Kernel/Source/OS/Log.c b/Kernel/Source/OS/Log.c new file mode 100644 index 0000000..d69be46 --- /dev/null +++ b/Kernel/Source/OS/Log.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +void OSLog(const ASCII* format, ...) { + ASCII buffer[kOSLogBufferSize]; + + va_list args; + va_start(args, format); + StringFormatVariadic(buffer, kOSLogBufferSize, format, args); + va_end(args); + + IOSerialPutString(buffer); +} \ No newline at end of file -- 2.52.0 From 560bdc8b1d6f810babad8f875bdf4bdb969f443a Mon Sep 17 00:00:00 2001 From: karina Date: Fri, 24 Apr 2026 18:14:04 +0400 Subject: [PATCH 14/49] feat: error parse in panic --- Kernel/Include/Arch/CPU.h | 6 ++++ Kernel/Include/types.h | 1 + Kernel/Source/KernelMain.c | 1 + Kernel/Source/OS/Panic.c | 70 +++++++++++++++++++++++++++++++++----- 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index ae6aafa..d142bc9 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -16,3 +16,9 @@ static inline void CPUDisableInterrupts() { static inline void CPUEnableInterrupts() { __asm__ volatile ("msr daifclr, #3" ::: "memory"); } + +static inline UInt64 CPUGetFAR() { + UInt64 far; + __asm__ volatile ("mrs %0, far_el1" : "=r" (far)); + return far; +} \ No newline at end of file diff --git a/Kernel/Include/types.h b/Kernel/Include/types.h index 442cefc..3e4261f 100644 --- a/Kernel/Include/types.h +++ b/Kernel/Include/types.h @@ -22,3 +22,4 @@ typedef int Int; typedef UInt64 Size; typedef char ASCII; +typedef _Bool Boolean; diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index d21d0c3..3976a24 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,4 +1,5 @@ #include void KernelMain(void) { + OSLog("Hi meow! ;3\n"); } \ No newline at end of file diff --git a/Kernel/Source/OS/Panic.c b/Kernel/Source/OS/Panic.c index 769d159..13883ac 100644 --- a/Kernel/Source/OS/Panic.c +++ b/Kernel/Source/OS/Panic.c @@ -1,5 +1,5 @@ #include -#include +#include #include static const ASCII* GetExceptionClassString(UInt32 class) { @@ -20,6 +20,10 @@ static const ASCII* GetExceptionClassString(UInt32 class) { } } +static void PrintSeparator() { + OSLog("--------------------------------\n"); +} + __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { UInt32 esr = frame->esr_el1; @@ -27,14 +31,62 @@ __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { UInt32 length = (esr >> 25) & 0x1; // Instruction length (Bit 25) UInt32 syndrome = esr & 0x1FFFFFF; // Syndrome (Bits 24:0) - // i cant show any info since i have no formatter yet :( - IOSerialPutString("\n-------------------\n"); - IOSerialPutString("Kernel Panic! :(\n"); - IOSerialPutString("-------------------\n"); - IOSerialPutString("CPU Exception: "); - IOSerialPutString(GetExceptionClassString(class)); - IOSerialPutString("\n-------------------\n"); - IOSerialPutString("System halted.\n"); + PrintSeparator(); + OSLog("Kernel Panic! :(\n"); + PrintSeparator(); + OSLog("CPU Exception: %s (%d)\n", GetExceptionClassString(class), class); + OSLog("ESR_EL1 (Syndrome): 0x%x (%d)\n", esr, syndrome); + OSLog("Instruction pointer: 0x%x (%s)\n", frame->elr_el1, length ? "32-bit" : "64-bit"); + OSLog("CPU status: 0x%x\n", frame->spsr_el1); + + if (class == 0x25 || class == 0x24 || class == 0x20 || class == 0x21 ) { + PrintSeparator(); + OSLog("Memory abort helper:\n"); + PrintSeparator(); + + UInt64 far = CPUGetFAR(); + OSLog("Faulting address: 0x%x\n", far); + + UInt32 wnr = (syndrome >> 6) & 0x1; + if (class == 0x24 || class == 0x25) { + OSLog("[W] Caused by %s\n", wnr ? "WRITE" : "READ"); + } else { + OSLog("[T] Tried to execute code from NX/Invalid memory\n"); + } + + + UInt32 dfsc = syndrome & 0x3F; + switch (dfsc & 0b111100) { + case 0b000000: OSLog("[P] Reason: Address size fault (Bad pointer format)\n"); break; + case 0b000100: OSLog("[P] Reason: Translation fault\n"); break; + case 0b001100: OSLog("[P] Reason: Permission fault (Page protection violation)\n"); break; + case 0b010000: OSLog("[P] Reason: Synchronous external abort\n"); break; + case 0b100000: OSLog("[P] Reason: Alignment fault\n"); break; + default: OSLog("[P] Reason: Unknown fault code (0x%X)\n", dfsc); break; + } + } + PrintSeparator(); + OSLog("Registers:\n"); + PrintSeparator(); + OSLog("x0 = 0x%X; x1 = 0x%X\n", frame->x0, frame->x1); + OSLog("x2 = 0x%X; x3 = 0x%X\n", frame->x2, frame->x3); + OSLog("x4 = 0x%X; x5 = 0x%X\n", frame->x4, frame->x5); + OSLog("x6 = 0x%X; x7 = 0x%X\n", frame->x6, frame->x7); + OSLog("x8 = 0x%X; x9 = 0x%X\n", frame->x8, frame->x9); + OSLog("x10 = 0x%X; x11 = 0x%X\n", frame->x10, frame->x11); + OSLog("x12 = 0x%X; x13 = 0x%X\n", frame->x12, frame->x13); + OSLog("x14 = 0x%X; x15 = 0x%X\n", frame->x14, frame->x15); + OSLog("x16 = 0x%X; x17 = 0x%X\n", frame->x16, frame->x17); + OSLog("x18 = 0x%X; x19 = 0x%X\n", frame->x18, frame->x19); + OSLog("x20 = 0x%X; x21 = 0x%X\n", frame->x20, frame->x21); + OSLog("x22 = 0x%X; x23 = 0x%X\n", frame->x22, frame->x23); + OSLog("x24 = 0x%X; x25 = 0x%X\n", frame->x24, frame->x25); + OSLog("x26 = 0x%X; x27 = 0x%X\n", frame->x26, frame->x27); + OSLog("\t\tx28 = 0x%X\n", frame->x28); + OSLog("FP = 0x%X; LR = 0x%X\n", frame->x29, frame->x30); + PrintSeparator(); + + OSLog("System halted.\n"); while (1) { CPUDisableInterrupts(); -- 2.52.0 From 730d88f9b057ded5088df017e5e40031bcbf2035 Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 25 Apr 2026 06:05:46 +0400 Subject: [PATCH 15/49] fix: preserve bootinfo pointer in kernel _start --- Kernel/Source/Arch/entry.S | 4 ++++ Kernel/Source/KernelMain.c | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Kernel/Source/Arch/entry.S b/Kernel/Source/Arch/entry.S index af21614..af8fadc 100644 --- a/Kernel/Source/Arch/entry.S +++ b/Kernel/Source/Arch/entry.S @@ -1,6 +1,10 @@ .section .text.boot, "ax" .global _start _start: + sub sp, sp, #16 + str x0, [sp] bl ExceptionsVectorsInit + ldr x0, [sp] + add sp, sp, #16 bl KernelMain b . \ No newline at end of file diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 3976a24..b36806a 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,5 +1,7 @@ #include +#include "../Common/bootinfo.h" -void KernelMain(void) { - OSLog("Hi meow! ;3\n"); +void KernelMain(Bootinfo* bootinfo) { + OSLog("DTB located at 0x%x\n", bootinfo->dtb); + OSLog("Kernel located at 0x%x\n", bootinfo->kernelInfo.kernelAddress); } \ No newline at end of file -- 2.52.0 From b606fa23d03637dcd0ba3b0ff6054def7a177814 Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 25 Apr 2026 06:55:41 +0400 Subject: [PATCH 16/49] feat: OSPanic(message) --- Kernel/Include/OS/Panic.h | 3 ++- Kernel/Source/OS/Panic.c | 40 +++++++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Kernel/Include/OS/Panic.h b/Kernel/Include/OS/Panic.h index c8d69d5..2eb3722 100644 --- a/Kernel/Include/OS/Panic.h +++ b/Kernel/Include/OS/Panic.h @@ -3,4 +3,5 @@ #include #include -__attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame); \ No newline at end of file +__attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame); +__attribute__((noreturn)) void OSPanic(const ASCII* message); \ No newline at end of file diff --git a/Kernel/Source/OS/Panic.c b/Kernel/Source/OS/Panic.c index 13883ac..8891ca8 100644 --- a/Kernel/Source/OS/Panic.c +++ b/Kernel/Source/OS/Panic.c @@ -20,10 +20,36 @@ static const ASCII* GetExceptionClassString(UInt32 class) { } } +__attribute__((noreturn)) static void Halt() { + while (1) { + CPUDisableInterrupts(); + CPUWaitForInterrupt(); + } +} + static void PrintSeparator() { OSLog("--------------------------------\n"); } +static void DrawPanicHeader() { + OSLog("\n\n"); + PrintSeparator(); + OSLog("\tKernel Panic! :(\n"); + PrintSeparator(); +} + +static void DrawPanicFooter() { + PrintSeparator(); + OSLog("\tSystem halted.\n"); + PrintSeparator(); +} + +__attribute__((noreturn)) void OSPanic(const ASCII* message) { + DrawPanicHeader(); + OSLog("\tReason: %s\n", message); + DrawPanicFooter(); + Halt(); +} __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { UInt32 esr = frame->esr_el1; @@ -31,9 +57,8 @@ __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { UInt32 length = (esr >> 25) & 0x1; // Instruction length (Bit 25) UInt32 syndrome = esr & 0x1FFFFFF; // Syndrome (Bits 24:0) - PrintSeparator(); - OSLog("Kernel Panic! :(\n"); - PrintSeparator(); + DrawPanicHeader(); + OSLog("CPU Exception: %s (%d)\n", GetExceptionClassString(class), class); OSLog("ESR_EL1 (Syndrome): 0x%x (%d)\n", esr, syndrome); OSLog("Instruction pointer: 0x%x (%s)\n", frame->elr_el1, length ? "32-bit" : "64-bit"); @@ -84,12 +109,7 @@ __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { OSLog("x26 = 0x%X; x27 = 0x%X\n", frame->x26, frame->x27); OSLog("\t\tx28 = 0x%X\n", frame->x28); OSLog("FP = 0x%X; LR = 0x%X\n", frame->x29, frame->x30); - PrintSeparator(); - OSLog("System halted.\n"); - - while (1) { - CPUDisableInterrupts(); - CPUWaitForInterrupt(); - } + DrawPanicFooter(); + Halt(); } \ No newline at end of file -- 2.52.0 From e49af76aefcda9170e9b1f8c654729a35a0552ed Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 25 Apr 2026 09:56:17 +0400 Subject: [PATCH 17/49] ref: renamed types.h to Types.h for match naming convention; also added Align.h and Bytes.h with helpers --- Kernel/Include/Arch/CPU.h | 2 +- Kernel/Include/Arch/DTB.h | 35 ++++++++++++++++++++++++++++++++ Kernel/Include/Arch/Exceptions.h | 2 +- Kernel/Include/Arch/IO.h | 2 +- Kernel/Include/IO/Serial.h | 2 +- Kernel/Include/Lib/Align.h | 19 +++++++++++++++++ Kernel/Include/Lib/Bytes.h | 10 +++++++++ Kernel/Include/Lib/String.h | 2 +- Kernel/Include/OS/Log.h | 2 +- Kernel/Include/OS/Panic.h | 2 +- Kernel/Include/types.h | 7 +++++++ 11 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 Kernel/Include/Arch/DTB.h create mode 100644 Kernel/Include/Lib/Align.h create mode 100644 Kernel/Include/Lib/Bytes.h diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index d142bc9..83e2710 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -1,5 +1,5 @@ #pragma once -#include +#include static inline void CPUYield() { __asm__ volatile ("yield" ::: "memory"); diff --git a/Kernel/Include/Arch/DTB.h b/Kernel/Include/Arch/DTB.h new file mode 100644 index 0000000..c73efa9 --- /dev/null +++ b/Kernel/Include/Arch/DTB.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +typedef struct FDTHeader { + UInt32 magic; // 0xd00dfeed + UInt32 totalSize; + UInt32 offDtStruct; + UInt32 offDtStrings; + UInt32 offMemRsvMap; + UInt32 version; + UInt32 lastCompVersion; + UInt32 bootCpuidPhys; + UInt32 sizeDtStrings; + UInt32 sizeDtStruct; +} FDTHeader; + +typedef struct FDTProperty { + UInt32 length; + UInt32 nameOffset; +} FDTProperty; + +typedef enum FDTToken { + FDTTokenBeginNode = 0x1, + FDTTokenEndNode = 0x2, + FDTTokenProperty = 0x3, + FDTTokenNOP = 0x4, + FDTTokenEnd = 0x9, +} FDTToken; + +enum { + kFDTHeaderMagic = 0xd00dfeed, +}; + +void DTBParse(Pointer dtb); \ No newline at end of file diff --git a/Kernel/Include/Arch/Exceptions.h b/Kernel/Include/Arch/Exceptions.h index df48045..fe069c1 100644 --- a/Kernel/Include/Arch/Exceptions.h +++ b/Kernel/Include/Arch/Exceptions.h @@ -1,5 +1,5 @@ #pragma once -#include +#include typedef struct ExceptionsContext { UInt64 x0; diff --git a/Kernel/Include/Arch/IO.h b/Kernel/Include/Arch/IO.h index 91f494b..980f76a 100644 --- a/Kernel/Include/Arch/IO.h +++ b/Kernel/Include/Arch/IO.h @@ -1,5 +1,5 @@ #pragma once -#include +#include static inline void IOAddressWrite32(Address address, UInt32 value) { __asm__ volatile ("dsb sy" ::: "memory"); // wait till all previous writes are finished physically diff --git a/Kernel/Include/IO/Serial.h b/Kernel/Include/IO/Serial.h index f2d7787..f87d102 100644 --- a/Kernel/Include/IO/Serial.h +++ b/Kernel/Include/IO/Serial.h @@ -1,5 +1,5 @@ #pragma once -#include +#include enum { kUARTBaseAddress = 0x09000000, // TODO: make it dynamic by parsing DTB diff --git a/Kernel/Include/Lib/Align.h b/Kernel/Include/Lib/Align.h new file mode 100644 index 0000000..7d86a1b --- /dev/null +++ b/Kernel/Include/Lib/Align.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +static inline UInt64 AlignUp64(UInt64 value, UInt64 alignment) { + return (value + alignment - 1) & ~(alignment - 1); +} + +static inline UInt64 AlignDown64(UInt64 value, UInt64 alignment) { + return value & ~(alignment - 1); +} + +static inline UInt32 AlignUp32(UInt32 value, UInt32 alignment) { + return (value + alignment - 1) & ~(alignment - 1); +} + +static inline UInt32 AlignDown32(UInt32 value, UInt32 alignment) { + return value & ~(alignment - 1); +} diff --git a/Kernel/Include/Lib/Bytes.h b/Kernel/Include/Lib/Bytes.h new file mode 100644 index 0000000..852c199 --- /dev/null +++ b/Kernel/Include/Lib/Bytes.h @@ -0,0 +1,10 @@ +#pragma once +#include + +static inline UInt32 BytesSwap32(UInt32 value) { + return __builtin_bswap32(value); +} + +static inline UInt64 BytesSwap64(UInt64 value) { + return __builtin_bswap64(value); +} diff --git a/Kernel/Include/Lib/String.h b/Kernel/Include/Lib/String.h index 201334f..89572df 100644 --- a/Kernel/Include/Lib/String.h +++ b/Kernel/Include/Lib/String.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include void* StringSet(BytePointer destination, ASCII value, Size count); diff --git a/Kernel/Include/OS/Log.h b/Kernel/Include/OS/Log.h index 5b9d1d2..a19fcd6 100644 --- a/Kernel/Include/OS/Log.h +++ b/Kernel/Include/OS/Log.h @@ -1,5 +1,5 @@ #pragma once -#include +#include enum { kOSLogBufferSize = 1024, diff --git a/Kernel/Include/OS/Panic.h b/Kernel/Include/OS/Panic.h index 2eb3722..cb31981 100644 --- a/Kernel/Include/OS/Panic.h +++ b/Kernel/Include/OS/Panic.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame); diff --git a/Kernel/Include/types.h b/Kernel/Include/types.h index 3e4261f..8f9a059 100644 --- a/Kernel/Include/types.h +++ b/Kernel/Include/types.h @@ -3,12 +3,19 @@ #pragma once +#if defined(NDEBUG) || defined(__OPTIMIZE__) + #define IS_RELEASE 1 +#else + #define IS_RELEASE 0 +#endif + typedef unsigned char UInt8; typedef unsigned short UInt16; typedef unsigned int UInt32; typedef unsigned long long UInt64; typedef unsigned long long UInt; +typedef void* Pointer; typedef UInt Address; typedef UInt8* BytePointer; typedef UInt8* MemoryPointer; -- 2.52.0 From 14912b8067858288f6a598e166ce83f03a127498 Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 25 Apr 2026 10:01:31 +0400 Subject: [PATCH 18/49] build: switched to ninja --- Bootloader/justfile | 3 ++- Kernel/CMakeLists.txt | 1 + Kernel/justfile | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Bootloader/justfile b/Bootloader/justfile index f960253..ab8a73c 100644 --- a/Bootloader/justfile +++ b/Bootloader/justfile @@ -3,7 +3,8 @@ TEMP_DIR := env_var_or_default("TEMP_DIR", BUILD_DIR + "/temp") build: cmake -B {{TEMP_DIR}}/Bootloader -S . \ -DCMAKE_TOOLCHAIN_FILE=cmake/aarch64-uefi.cmake \ - -DCMAKE_BUILD_TYPE=Release + -DCMAKE_BUILD_TYPE=Release \ + -G Ninja cmake --build {{TEMP_DIR}}/Bootloader diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index be84ad4..caec459 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -17,6 +17,7 @@ target_include_directories(Kernel PRIVATE target_compile_options(Kernel PRIVATE $<$: + -std=c23 -ffreestanding -fno-stack-protector -fno-builtin diff --git a/Kernel/justfile b/Kernel/justfile index d621268..f82044a 100644 --- a/Kernel/justfile +++ b/Kernel/justfile @@ -2,7 +2,8 @@ BUILD_DIR := env_var_or_default("BUILD_DIR", justfile_directory() + "/.build") TEMP_DIR := env_var_or_default("TEMP_DIR", BUILD_DIR + "/temp") build: cmake -B {{TEMP_DIR}}/Kernel -S . \ - -DCMAKE_TOOLCHAIN_FILE=cmake/aarch64-bare.cmake + -DCMAKE_TOOLCHAIN_FILE=cmake/aarch64-bare.cmake \ + -G Ninja cmake --build {{TEMP_DIR}}/Kernel -- 2.52.0 From 716dc37da17bfd536f8cf8d6065863180b0ee3d4 Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 25 Apr 2026 11:22:50 +0400 Subject: [PATCH 19/49] fix: rename types.h to Types.h to fix clang warnings --- Kernel/Include/{types.h => Types.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Kernel/Include/{types.h => Types.h} (100%) diff --git a/Kernel/Include/types.h b/Kernel/Include/Types.h similarity index 100% rename from Kernel/Include/types.h rename to Kernel/Include/Types.h -- 2.52.0 From 77db85ccc5c968db15ab0bfa2fb6dafb11a498cc Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 25 Apr 2026 16:01:43 +0400 Subject: [PATCH 20/49] build: added drun and dcrun (debugging) --- justfile | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/justfile b/justfile index d843608..a32eec2 100644 --- a/justfile +++ b/justfile @@ -80,11 +80,31 @@ _prep: -serial stdio \ -monitor telnet:127.0.0.1:5555,server,nowait +@drun: _image + @echo "🚀 Debugging (accel: {{ACCEL_INFO}})..." + qemu-system-aarch64 {{ACCEL}} \ + -machine virt,acpi=off \ + -cpu {{CPU}} \ + -m 512M \ + -device ramfb \ + {{DISPLAY_FLAGS}} \ + -drive if=pflash,format=raw,readonly=on,file={{OVMF_ARM}} \ + -drive file={{IMG_FILE}},format=raw,if=none,id=hd0 \ + -device virtio-blk-device,drive=hd0 \ + -serial stdio \ + -monitor telnet:127.0.0.1:5555,server,nowait + -s -S + @crun: @echo "🧹 Cleaning and running.." just clean just run +@dcrun: + @echo "🧹 Cleaning and debugging.." + just clean + just drun + @clean: just Bootloader clean just Kernel clean -- 2.52.0 From 1463402c6c291d6666ee86ea2d7c292e8647c360 Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 25 Apr 2026 16:09:32 +0400 Subject: [PATCH 21/49] fix: added missing backslash in justfile --- justfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/justfile b/justfile index a32eec2..91ee8d5 100644 --- a/justfile +++ b/justfile @@ -92,7 +92,7 @@ _prep: -drive file={{IMG_FILE}},format=raw,if=none,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -serial stdio \ - -monitor telnet:127.0.0.1:5555,server,nowait + -monitor telnet:127.0.0.1:5555,server,nowait \ -s -S @crun: @@ -110,4 +110,4 @@ _prep: just Kernel clean rm -rf {{BUILD_DIR}} rm -f compile_commands.json - rm -f ide-swift-toolchain.txt \ No newline at end of file + rm -f ide-swift-toolchain.txt -- 2.52.0 From 6698c4ab3f33b22ac32137e78e8b2e829b7c2bce Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 09:32:07 +0400 Subject: [PATCH 22/49] feat: kernel is now elf --- Bootloader/CMakeLists.txt | 4 +- Bootloader/Source/main.c | 98 +++++++++++++++---- Bootloader/Source/modules/elf/elf.h | 32 ++++++ .../Source/{ => modules}/uefi/efi_entry.c | 0 Bootloader/Source/{ => modules}/uefi/uefi.h | 2 + Kernel/CMakeLists.txt | 9 +- Kernel/justfile | 4 +- Kernel/linker.ld | 23 +++-- justfile | 7 +- 9 files changed, 137 insertions(+), 42 deletions(-) create mode 100644 Bootloader/Source/modules/elf/elf.h rename Bootloader/Source/{ => modules}/uefi/efi_entry.c (100%) rename Bootloader/Source/{ => modules}/uefi/uefi.h (99%) diff --git a/Bootloader/CMakeLists.txt b/Bootloader/CMakeLists.txt index d8ee154..2a6c1f0 100644 --- a/Bootloader/CMakeLists.txt +++ b/Bootloader/CMakeLists.txt @@ -9,13 +9,13 @@ set(UEFI_COMPILE_OPTIONS ) add_executable(BOOTAA64 - Source/uefi/efi_entry.c + Source/modules/uefi/efi_entry.c Source/main.c ) target_compile_options(BOOTAA64 PRIVATE ${UEFI_COMPILE_OPTIONS}) target_include_directories(BOOTAA64 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Source - ${CMAKE_CURRENT_SOURCE_DIR}/Source/uefi + ${CMAKE_CURRENT_SOURCE_DIR}/Source/modules/uefi ) target_link_options(BOOTAA64 PRIVATE diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index 05a954f..edfa06f 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -1,10 +1,11 @@ -#include "uefi/uefi.h" +#include "modules/uefi/uefi.h" +#include "modules/elf/elf.h" #include "../../Common/bootinfo.h" #define PAGE_SIZE 0x1000 #define WSTR(str) ((wchar_t*)L##str) -static wchar_t* kernel_path = WSTR("ksOSKernel.bin"); +static wchar_t* kernel_path = WSTR("ksOSKernel.elf"); static efi_guid_t dtb_guid = { 0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0} }; @@ -13,6 +14,14 @@ static void print(const wchar_t* msg) { ST->ConOut->OutputString(ST->ConOut, (wchar_t*)msg); } +void* memset(void* destination, int value, uint64_t count) { + uint8_t* ptr = (uint8_t*)destination; + while (count--) { + *ptr++ = (uint8_t)value; + } + return destination; +} + static efi_status_t die(void) { while (1) { __asm__ volatile("wfi"); @@ -83,33 +92,73 @@ static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** fi return file->GetInfo(file, &file_info_guid, &file_info_size, *file_info); } -static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size) { +static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size, efi_file_handle_t** out_handle) { efi_file_handle_t* kernel_file = NULL; - efi_file_info_t* kernel_info = NULL; efi_status_t status = root->Open(root, &kernel_file, kernel_path, EFI_FILE_MODE_READ, 0); - if (EFI_ERROR(status)) { - return status; - } + if (EFI_ERROR(status)) return status; + efi_file_info_t* kernel_info = NULL; status = read_file_info(kernel_file, &kernel_info); - if (EFI_ERROR(status)) { - return status; - } + if (EFI_ERROR(status)) return status; *kernel_size = kernel_info->FileSize; - - uintn_t bytes_to_read = (uintn_t)*kernel_size; uintn_t kernel_pages = (*kernel_size + PAGE_SIZE - 1) / PAGE_SIZE; - *kernel_addr = 0; status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel_pages, kernel_addr); - if (EFI_ERROR(status)) { - return status; + if (EFI_ERROR(status)) return status; + + uintn_t bytes_to_read = (uintn_t)*kernel_size; + status = kernel_file->Read(kernel_file, &bytes_to_read, (void*)*kernel_addr); + if (EFI_ERROR(status)) return status; + + *out_handle = kernel_file; + return EFI_SUCCESS; +} + +static efi_status_t parse_elf_headers(efi_physical_address_t kernel_addr) { + Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr; + + if (elf_header->e_ident[0] != 0x7f || elf_header->e_ident[1] != 'E' || + elf_header->e_ident[2] != 'L' || elf_header->e_ident[3] != 'F') { + return fail(WSTR("Invalid ELF header\r\n")); + } + if (elf_header->e_machine != 0xB7) { // AArch64 + return fail(WSTR("Invalid ELF machine\r\n")); } - status = kernel_file->Read(kernel_file, &bytes_to_read, (void*)*kernel_addr); - if (EFI_ERROR(status) || bytes_to_read != (uintn_t)*kernel_size) { - return EFI_LOAD_ERROR; + return EFI_SUCCESS; +} + +static efi_status_t load_elf_segments(efi_physical_address_t kernel_addr, efi_file_handle_t* kernel_file) { + Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr; + + for (int i = 0; i < elf_header->e_phnum; i++) { + Elf64_Phdr* phdr = (Elf64_Phdr*)(kernel_addr + elf_header->e_phoff + i * elf_header->e_phentsize); + + if (phdr->p_type != PT_LOAD) continue; + if (phdr->p_vaddr < 0x40000000) { + print(WSTR("Skipping low/weird segment\r\n")); + continue; + } + + uintn_t pages = (phdr->p_memsz + 0xFFF) / 0x1000; + efi_physical_address_t segment_addr = phdr->p_vaddr; + + efi_status_t status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment_addr); + if (EFI_ERROR(status)) { + if (status == EFI_NOT_FOUND) print(WSTR(" (Range not in RAM) ")); + if (status == EFI_OUT_OF_RESOURCES) print(WSTR(" (Occupied) ")); + return fail(WSTR("Address conflict!\r\n")); + } + + memset((void*)segment_addr, 0, phdr->p_memsz); + kernel_file->SetPosition(kernel_file, phdr->p_offset); + + uintn_t size_to_read = phdr->p_filesz; + status = kernel_file->Read(kernel_file, &size_to_read, (void*)segment_addr); + if (EFI_ERROR(status) || size_to_read != phdr->p_filesz) { + return fail(WSTR("File read error\r\n")); + } } return EFI_SUCCESS; @@ -175,11 +224,20 @@ efi_status_t bootloader_main(void) { efi_physical_address_t kernel_addr = 0; uint64_t kernel_size = 0; - status = load_kernel(root, &kernel_addr, &kernel_size); + efi_file_handle_t* kernel_file = NULL; + status = load_kernel(root, &kernel_addr, &kernel_size, &kernel_file); if (EFI_ERROR(status)) { return fail(WSTR("Failed to load ksOSKernel.bin\r\n")); } + Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr; + + status = parse_elf_headers(kernel_addr); + if (EFI_ERROR(status)) return status; + + status = load_elf_segments(kernel_addr, kernel_file); + if (EFI_ERROR(status)) return status; + Bootinfo* boot_info = NULL; status = gBS->AllocatePool(EfiLoaderData, sizeof(Bootinfo), (void**)&boot_info); if (EFI_ERROR(status) || boot_info == NULL) { @@ -203,7 +261,7 @@ efi_status_t bootloader_main(void) { } typedef void (*kernel_entry_t)(Bootinfo*); - kernel_entry_t kernel_main = (kernel_entry_t)kernel_addr; + kernel_entry_t kernel_main = (kernel_entry_t)elf_header->e_entry; kernel_main(boot_info); return EFI_SUCCESS; diff --git a/Bootloader/Source/modules/elf/elf.h b/Bootloader/Source/modules/elf/elf.h new file mode 100644 index 0000000..2722c79 --- /dev/null +++ b/Bootloader/Source/modules/elf/elf.h @@ -0,0 +1,32 @@ +#pragma once +#include "../../modules/uefi/uefi.h" // IWYU pragma: keep + +typedef struct { + uint8_t e_ident[16]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} Elf64_Ehdr; + +typedef struct { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +} Elf64_Phdr; + +#define PT_LOAD 1 \ No newline at end of file diff --git a/Bootloader/Source/uefi/efi_entry.c b/Bootloader/Source/modules/uefi/efi_entry.c similarity index 100% rename from Bootloader/Source/uefi/efi_entry.c rename to Bootloader/Source/modules/uefi/efi_entry.c diff --git a/Bootloader/Source/uefi/uefi.h b/Bootloader/Source/modules/uefi/uefi.h similarity index 99% rename from Bootloader/Source/uefi/uefi.h rename to Bootloader/Source/modules/uefi/uefi.h index f229ba1..8bbf190 100644 --- a/Bootloader/Source/uefi/uefi.h +++ b/Bootloader/Source/modules/uefi/uefi.h @@ -36,6 +36,8 @@ typedef uint16_t wchar_t; #define EFI_LOAD_ERROR EFIERR(1) #define EFI_UNSUPPORTED EFIERR(3) #define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_OUT_OF_RESOURCES EFIERR(9) +#define EFI_NOT_FOUND EFIERR(14) #define EFI_ABORTED EFIERR(21) #define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index caec459..4e24457 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -33,14 +33,11 @@ target_link_options(Kernel PRIVATE -no-pie -T "${CMAKE_CURRENT_SOURCE_DIR}/linker.ld" -z max-page-size=0x1000 + --image-base=0x40100000 + --no-dynamic-linker ) set_target_properties(Kernel PROPERTIES - OUTPUT_NAME "Kernel.elf" + OUTPUT_NAME "ksOSKernel.elf" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) - -add_custom_command(TARGET Kernel POST_BUILD - COMMAND ${LLVM_OBJCOPY} -O binary ${CMAKE_BINARY_DIR}/Kernel.elf ${CMAKE_BINARY_DIR}/Kernel.bin - COMMENT "Generating ksOSKernel.bin from Kernel.elf" -) \ No newline at end of file diff --git a/Kernel/justfile b/Kernel/justfile index f82044a..ae01553 100644 --- a/Kernel/justfile +++ b/Kernel/justfile @@ -7,8 +7,8 @@ build: cmake --build {{TEMP_DIR}}/Kernel - cp {{TEMP_DIR}}/Kernel/Kernel.bin {{BUILD_DIR}}/Kernel/ksOSKernel.bin - @echo "✅ Kernel ready at: {{BUILD_DIR}}/Kernel/ksOSKernel.bin" + cp {{TEMP_DIR}}/Kernel/ksOSKernel.elf {{BUILD_DIR}}/Kernel/ksOSKernel.elf + @echo "✅ Kernel ready at: {{BUILD_DIR}}/Kernel/ksOSKernel.elf" clean: rm -rf {{TEMP_DIR}}/Kernel diff --git a/Kernel/linker.ld b/Kernel/linker.ld index 22e97ea..b793125 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -1,15 +1,20 @@ -ENTRY(_start) +PHDRS +{ + text PT_LOAD FLAGS(5); /* Read | Execute */ + data PT_LOAD FLAGS(6); /* Read | Write */ +} -SECTIONS { - . = 0; +SECTIONS +{ + . = 0x40100000; .text : { *(.text.boot) *(.text*) - } + } :text - .rodata : { *(.rodata*) } - .data : { *(.data*) } - .bss : { *(.bss*) *(COMMON) } - -} + .rodata : { *(.rodata*) } :text + + .data : { *(.data*) } :data + .bss : { *(.bss*) *(COMMON) } :data +} \ No newline at end of file diff --git a/justfile b/justfile index 91ee8d5..749656d 100644 --- a/justfile +++ b/justfile @@ -28,6 +28,7 @@ DISPLAY_FLAGS := if OS_NAME == "macos" { } ACCEL_INFO := if ACCEL == "" { "none (TCG)" } else { ACCEL } +RAM := "2G" export BUILD_DIR := justfile_directory() + "/.build" export TEMP_DIR := BUILD_DIR + "/temp" @@ -64,14 +65,14 @@ _prep: @mkfs.fat -F 32 {{IMG_FILE}} > /dev/null @mmd -i {{IMG_FILE}} ::/EFI ::/EFI/BOOT @mcopy -i {{IMG_FILE}} {{BOOT_BIN}} ::/EFI/BOOT/BOOTAA64.EFI - @mcopy -i {{IMG_FILE}} {{BUILD_DIR}}/Kernel/ksOSKernel.bin ::/ksOSKernel.bin + @mcopy -i {{IMG_FILE}} {{BUILD_DIR}}/Kernel/ksOSKernel.elf ::/ksOSKernel.elf @run: _image @echo "🚀 Launching (accel: {{ACCEL_INFO}})..." qemu-system-aarch64 {{ACCEL}} \ -machine virt,acpi=off \ -cpu {{CPU}} \ - -m 512M \ + -m {{RAM}} \ -device ramfb \ {{DISPLAY_FLAGS}} \ -drive if=pflash,format=raw,readonly=on,file={{OVMF_ARM}} \ @@ -85,7 +86,7 @@ _prep: qemu-system-aarch64 {{ACCEL}} \ -machine virt,acpi=off \ -cpu {{CPU}} \ - -m 512M \ + -m {{RAM}} \ -device ramfb \ {{DISPLAY_FLAGS}} \ -drive if=pflash,format=raw,readonly=on,file={{OVMF_ARM}} \ -- 2.52.0 From 7d68e78cb24bb4a5b3d584eab6cfcb79852f1787 Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 25 Apr 2026 14:21:32 +0400 Subject: [PATCH 23/49] wip: dtb: --- Kernel/.clangd | 1 + Kernel/Include/Types.h | 2 ++ Kernel/Source/Arch/DTB.c | 63 ++++++++++++++++++++++++++++++++++++++ Kernel/Source/KernelMain.c | 7 +++-- 4 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 Kernel/Source/Arch/DTB.c diff --git a/Kernel/.clangd b/Kernel/.clangd index 9992ca2..fb73a7a 100644 --- a/Kernel/.clangd +++ b/Kernel/.clangd @@ -1,2 +1,3 @@ CompileFlags: CompilationDatabase: ../.build/temp/Kernel + Add: [-std=c23] \ No newline at end of file diff --git a/Kernel/Include/Types.h b/Kernel/Include/Types.h index 8f9a059..16ab7bf 100644 --- a/Kernel/Include/Types.h +++ b/Kernel/Include/Types.h @@ -17,6 +17,7 @@ typedef unsigned long long UInt; typedef void* Pointer; typedef UInt Address; +typedef UInt32 Address32; typedef UInt8* BytePointer; typedef UInt8* MemoryPointer; @@ -30,3 +31,4 @@ typedef UInt64 Size; typedef char ASCII; typedef _Bool Boolean; +#define loop while (1) \ No newline at end of file diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c new file mode 100644 index 0000000..ef41555 --- /dev/null +++ b/Kernel/Source/Arch/DTB.c @@ -0,0 +1,63 @@ +#include "Types.h" +#include +#include +#include +#include +#include +#include + +void DTBParse(Pointer dtb) { + FDTHeader* header = (FDTHeader*)dtb; + if (BytesSwap32(header->magic) != kFDTHeaderMagic) { + OSPanic("Invalid DTB magic"); + } + + UInt32 offStruct = BytesSwap32(header->offDtStruct); + UInt32 offStrings = BytesSwap32(header->offDtStrings); + + BytePointer structs = (BytePointer)dtb + offStruct; + ASCII* strings = (ASCII*)dtb + offStrings; + + Int depth = 0; + + while (true) { + UInt32 token = BytesSwap32(*(UInt32*)structs); + structs += 4; + + switch (token) { + case FDTTokenBeginNode: { + ASCII* name = (ASCII*)structs; + + OSLog("Node [%d]: %s\n", depth, name[0] ? name : "ROOT"); + + UInt32 nameLength = StringGetLength(name); + structs += (nameLength + 1); + structs = (BytePointer)AlignUp32((Address)structs, 4); + + depth++; + break; + } + case FDTTokenProperty: { + UInt32 propertyLength = BytesSwap32(*(UInt32*)structs); + UInt32 nameOffset = BytesSwap32(*(UInt32*)(structs + 4)); + structs += 8; + + ASCII* propertyName = strings + nameOffset; + BytePointer propertyData = structs; + OSLog("Property %s (len %d)\n", propertyName, propertyLength); + + structs += propertyLength; + structs = (BytePointer)AlignUp32((Address)structs, 4); + + break; + } + + case FDTTokenEndNode: depth--; break; + case FDTTokenNOP: continue; + case FDTTokenEnd: return; + default: + OSPanic("Invalid DTB token"); + } + } + +} \ No newline at end of file diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index b36806a..07cb91c 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,7 +1,8 @@ -#include #include "../Common/bootinfo.h" +#include +#include void KernelMain(Bootinfo* bootinfo) { - OSLog("DTB located at 0x%x\n", bootinfo->dtb); - OSLog("Kernel located at 0x%x\n", bootinfo->kernelInfo.kernelAddress); + OSLog("Kernel started.\n"); + DTBParse(bootinfo->dtb); } \ No newline at end of file -- 2.52.0 From f15a146608a627cddcc14aba2f57f539610f24aa Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 08:50:57 +0400 Subject: [PATCH 24/49] wip: dtb; --- Kernel/Source/Arch/DTB.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index ef41555..978262e 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -1,4 +1,3 @@ -#include "Types.h" #include #include #include -- 2.52.0 From 32931021d2f912779d6caeb8cf37e38a15e6fd5b Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 10:48:54 +0400 Subject: [PATCH 25/49] feat: parsing dtb --- Kernel/Include/Lib/Bytes.h | 4 ++++ Kernel/Include/Lib/String.h | 4 +++- Kernel/Source/Arch/DTB.c | 25 +++++++++++++------------ Kernel/Source/Arch/Exceptions.c | 2 +- Kernel/Source/Lib/String.c | 4 ++++ 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Kernel/Include/Lib/Bytes.h b/Kernel/Include/Lib/Bytes.h index 852c199..ecb90c1 100644 --- a/Kernel/Include/Lib/Bytes.h +++ b/Kernel/Include/Lib/Bytes.h @@ -8,3 +8,7 @@ static inline UInt32 BytesSwap32(UInt32 value) { static inline UInt64 BytesSwap64(UInt64 value) { return __builtin_bswap64(value); } + +static inline UInt64 Merge32To64(UInt32 low, UInt32 high) { + return ((UInt64)high << 32) | low; +} diff --git a/Kernel/Include/Lib/String.h b/Kernel/Include/Lib/String.h index 89572df..1db07ac 100644 --- a/Kernel/Include/Lib/String.h +++ b/Kernel/Include/Lib/String.h @@ -15,4 +15,6 @@ Size StringGetLength(const ASCII* string); const ASCII* StringFindLastOccurrenceOfCharacter(const ASCII* string, ASCII separator); Int32 StringFormatVariadic(ASCII* string, Size size, const ASCII* format, va_list args); -Int32 StringFormat(ASCII* destination, UInt64 size, const ASCII* format, ...); \ No newline at end of file +Int32 StringFormat(ASCII* destination, UInt64 size, const ASCII* format, ...); + +Boolean StringStartsWith(const ASCII* string, const ASCII* prefix); \ No newline at end of file diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index 978262e..9cd89ee 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -16,8 +16,7 @@ void DTBParse(Pointer dtb) { BytePointer structs = (BytePointer)dtb + offStruct; ASCII* strings = (ASCII*)dtb + offStrings; - - Int depth = 0; + ASCII* currentNode = ""; while (true) { UInt32 token = BytesSwap32(*(UInt32*)structs); @@ -25,15 +24,12 @@ void DTBParse(Pointer dtb) { switch (token) { case FDTTokenBeginNode: { - ASCII* name = (ASCII*)structs; + currentNode = (ASCII*)structs; - OSLog("Node [%d]: %s\n", depth, name[0] ? name : "ROOT"); - - UInt32 nameLength = StringGetLength(name); + UInt32 nameLength = StringGetLength(currentNode); structs += (nameLength + 1); - structs = (BytePointer)AlignUp32((Address)structs, 4); + structs = (BytePointer)AlignUp64((Address)structs, 4); - depth++; break; } case FDTTokenProperty: { @@ -42,16 +38,21 @@ void DTBParse(Pointer dtb) { structs += 8; ASCII* propertyName = strings + nameOffset; - BytePointer propertyData = structs; - OSLog("Property %s (len %d)\n", propertyName, propertyLength); + if (StringCompare(propertyName, "reg") == 0 && StringStartsWith(currentNode, "memory")) { + UInt32* cells = (UInt32*)structs; + + UInt64 base = Merge32To64(BytesSwap32(cells[0]), BytesSwap32(cells[1])); + UInt64 size = Merge32To64(BytesSwap32(cells[2]), BytesSwap32(cells[3])); + OSLog("Memory: base=0x%x, size=0x%x\n", base, size); + } structs += propertyLength; - structs = (BytePointer)AlignUp32((Address)structs, 4); + structs = (BytePointer)AlignUp64((Address)structs, 4); break; } - case FDTTokenEndNode: depth--; break; + case FDTTokenEndNode: break; case FDTTokenNOP: continue; case FDTTokenEnd: return; default: diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c index 532bbb2..b3aa22d 100644 --- a/Kernel/Source/Arch/Exceptions.c +++ b/Kernel/Source/Arch/Exceptions.c @@ -3,6 +3,6 @@ #include #include -void ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) { +void ExceptionsHandler(ExceptionsContext* frame, [[maybe_unused]]ExceptionsType type) { OSPanicException(frame); } \ No newline at end of file diff --git a/Kernel/Source/Lib/String.c b/Kernel/Source/Lib/String.c index 5a23995..ccd5bda 100644 --- a/Kernel/Source/Lib/String.c +++ b/Kernel/Source/Lib/String.c @@ -176,4 +176,8 @@ Int32 StringFormat(ASCII* destination, UInt64 size, const ASCII* format, ...) { Int32 returnValue = StringFormatVariadic(destination, size, format, args); va_end(args); return returnValue; +} + +Boolean StringStartsWith(const ASCII* string, const ASCII* prefix) { + return StringCompareWithLimit(string, prefix, StringGetLength(prefix)) == 0; } \ No newline at end of file -- 2.52.0 From d0948b9f2b9abcea46ff67a8ae5d8979870d6ba8 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 10:57:01 +0400 Subject: [PATCH 26/49] feat: checking bootinfo magic at the start of the kernel --- Kernel/Source/KernelMain.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 07cb91c..3611ac3 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,8 +1,13 @@ #include "../Common/bootinfo.h" #include #include +#include void KernelMain(Bootinfo* bootinfo) { OSLog("Kernel started.\n"); + if (bootinfo->magic != BOOTINFO_MAGIC) { + OSPanic("Invalid bootinfo magic"); + } + DTBParse(bootinfo->dtb); } \ No newline at end of file -- 2.52.0 From 32bb6a933e55821da4ea3cd192d4aea11d4b1994 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 11:09:56 +0400 Subject: [PATCH 27/49] build: removed drun, dcrun, crun and combined it as flags to run --- justfile | 57 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/justfile b/justfile index 749656d..45f5896 100644 --- a/justfile +++ b/justfile @@ -67,44 +67,47 @@ _prep: @mcopy -i {{IMG_FILE}} {{BOOT_BIN}} ::/EFI/BOOT/BOOTAA64.EFI @mcopy -i {{IMG_FILE}} {{BUILD_DIR}}/Kernel/ksOSKernel.elf ::/ksOSKernel.elf -@run: _image - @echo "🚀 Launching (accel: {{ACCEL_INFO}})..." - qemu-system-aarch64 {{ACCEL}} \ - -machine virt,acpi=off \ - -cpu {{CPU}} \ - -m {{RAM}} \ - -device ramfb \ - {{DISPLAY_FLAGS}} \ - -drive if=pflash,format=raw,readonly=on,file={{OVMF_ARM}} \ - -drive file={{IMG_FILE}},format=raw,if=none,id=hd0 \ - -device virtio-blk-device,drive=hd0 \ - -serial stdio \ - -monitor telnet:127.0.0.1:5555,server,nowait -@drun: _image - @echo "🚀 Debugging (accel: {{ACCEL_INFO}})..." +run *FLAGS: + #!/usr/bin/env bash + set -e + + FLAGS=" {{FLAGS}} " + + if [[ "$FLAGS" == *" -clean "* ]]; then + echo "🧹 Cleaning..." + just clean + fi + + just _image + + DEBUG_ARGS="" + DISPLAY_ARGS="{{DISPLAY_FLAGS}}" + STATE_MSG="Launching" + + if [[ "$FLAGS" == *" -debug "* ]]; then + DEBUG_ARGS="-s -S" + STATE_MSG="Debugging" + fi + + if [[ "$FLAGS" == *" -nographic "* ]]; then + DISPLAY_ARGS="-nographic" + fi + + echo "🚀 $STATE_MSG (accel: {{ACCEL_INFO}})..." + qemu-system-aarch64 {{ACCEL}} \ -machine virt,acpi=off \ -cpu {{CPU}} \ -m {{RAM}} \ -device ramfb \ - {{DISPLAY_FLAGS}} \ + $DISPLAY_ARGS \ -drive if=pflash,format=raw,readonly=on,file={{OVMF_ARM}} \ -drive file={{IMG_FILE}},format=raw,if=none,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -serial stdio \ -monitor telnet:127.0.0.1:5555,server,nowait \ - -s -S - -@crun: - @echo "🧹 Cleaning and running.." - just clean - just run - -@dcrun: - @echo "🧹 Cleaning and debugging.." - just clean - just drun + $DEBUG_ARGS @clean: just Bootloader clean -- 2.52.0 From 785a61b451597ff0169f2b560b8dcbb0e8db0b2c Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 13:32:44 +0400 Subject: [PATCH 28/49] feat: DTB now populates VMBootMemoryMap structure. --- Kernel/Include/Arch/DTB.h | 3 ++- Kernel/Include/Lib/Stubs.h | 4 +++ Kernel/Include/VM/PMM.h | 19 ++++++++++++++ Kernel/Source/Arch/DTB.c | 53 ++++++++++++++++++++++++++++++-------- Kernel/Source/KernelMain.c | 8 ++++-- Kernel/Source/Lib/Stubs.c | 6 +++++ Kernel/Source/VM/PMM.c | 22 ++++++++++++++++ Kernel/linker.ld | 8 ++++++ 8 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 Kernel/Include/Lib/Stubs.h create mode 100644 Kernel/Include/VM/PMM.h create mode 100644 Kernel/Source/Lib/Stubs.c create mode 100644 Kernel/Source/VM/PMM.c diff --git a/Kernel/Include/Arch/DTB.h b/Kernel/Include/Arch/DTB.h index c73efa9..215b4d7 100644 --- a/Kernel/Include/Arch/DTB.h +++ b/Kernel/Include/Arch/DTB.h @@ -1,6 +1,7 @@ #pragma once #include +#include typedef struct FDTHeader { UInt32 magic; // 0xd00dfeed @@ -32,4 +33,4 @@ enum { kFDTHeaderMagic = 0xd00dfeed, }; -void DTBParse(Pointer dtb); \ No newline at end of file +void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap); \ No newline at end of file diff --git a/Kernel/Include/Lib/Stubs.h b/Kernel/Include/Lib/Stubs.h new file mode 100644 index 0000000..313fa92 --- /dev/null +++ b/Kernel/Include/Lib/Stubs.h @@ -0,0 +1,4 @@ +#pragma once +#include + +void* memset(void* destination, int value, Size count); \ No newline at end of file diff --git a/Kernel/Include/VM/PMM.h b/Kernel/Include/VM/PMM.h new file mode 100644 index 0000000..6beddd3 --- /dev/null +++ b/Kernel/Include/VM/PMM.h @@ -0,0 +1,19 @@ +#pragma once +#include + +enum { + kVMPageSize = 4096, + kVMBlocksPerByte = 8, + kVMMaxReservedRegions = 128, +}; + +typedef struct { + UInt64 base; + Size size; +} VMMemoryRegion; + +typedef struct { + VMMemoryRegion totalRAM; + VMMemoryRegion reserved[kVMMaxReservedRegions]; + UInt32 reservedCount; +} VMBootMemoryMap; \ No newline at end of file diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index 9cd89ee..69c4f7e 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -4,8 +4,9 @@ #include #include #include +#include -void DTBParse(Pointer dtb) { +void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { FDTHeader* header = (FDTHeader*)dtb; if (BytesSwap32(header->magic) != kFDTHeaderMagic) { OSPanic("Invalid DTB magic"); @@ -16,7 +17,11 @@ void DTBParse(Pointer dtb) { BytePointer structs = (BytePointer)dtb + offStruct; ASCII* strings = (ASCII*)dtb + offStrings; + ASCII* currentNode = ""; + UInt32 currentDepth = 0; + UInt32 reservedMemoryDepth = 0; + bool inReservedMemory = false; while (true) { UInt32 token = BytesSwap32(*(UInt32*)structs); @@ -24,35 +29,61 @@ void DTBParse(Pointer dtb) { switch (token) { case FDTTokenBeginNode: { + currentDepth++; currentNode = (ASCII*)structs; + if (StringStartsWith(currentNode, "reserved-memory")) { + inReservedMemory = true; + reservedMemoryDepth = currentDepth; + } + UInt32 nameLength = StringGetLength(currentNode); structs += (nameLength + 1); structs = (BytePointer)AlignUp64((Address)structs, 4); - break; } case FDTTokenProperty: { UInt32 propertyLength = BytesSwap32(*(UInt32*)structs); UInt32 nameOffset = BytesSwap32(*(UInt32*)(structs + 4)); structs += 8; - ASCII* propertyName = strings + nameOffset; - if (StringCompare(propertyName, "reg") == 0 && StringStartsWith(currentNode, "memory")) { - UInt32* cells = (UInt32*)structs; - - UInt64 base = Merge32To64(BytesSwap32(cells[0]), BytesSwap32(cells[1])); - UInt64 size = Merge32To64(BytesSwap32(cells[2]), BytesSwap32(cells[3])); - OSLog("Memory: base=0x%x, size=0x%x\n", base, size); + if (StringCompare(propertyName, "reg") == 0) { + if (StringStartsWith(currentNode, "memory")) { + UInt32* cells = (UInt32*)structs; + UInt64 base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); + UInt64 size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); + OSLog("Main Memory: base=0x%x, size=0x%x\n", base, size); + bootMap->totalRAM.base = base; + bootMap->totalRAM.size = size; + } + else if (inReservedMemory && currentDepth > reservedMemoryDepth) { + UInt32* cells = (UInt32*)structs; + UInt64 base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); + UInt64 size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); + + UInt32 index = bootMap->reservedCount; + bootMap->reserved[index].base = base; + bootMap->reserved[index].size = size; + bootMap->reservedCount++; + + OSLog("Reserved Region (%s): base=0x%x, size=0x%x\n", currentNode, base, size); + } } + structs += propertyLength; structs = (BytePointer)AlignUp64((Address)structs, 4); - break; } - case FDTTokenEndNode: break; + case FDTTokenEndNode: { + if (inReservedMemory && currentDepth == reservedMemoryDepth) { + inReservedMemory = false; + } + currentDepth--; + break; + } + case FDTTokenNOP: continue; case FDTTokenEnd: return; default: diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 3611ac3..a0fb291 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,4 +1,5 @@ #include "../Common/bootinfo.h" +#include #include #include #include @@ -8,6 +9,9 @@ void KernelMain(Bootinfo* bootinfo) { if (bootinfo->magic != BOOTINFO_MAGIC) { OSPanic("Invalid bootinfo magic"); } - - DTBParse(bootinfo->dtb); + + VMBootMemoryMap bootMap = {0}; + bootMap.reservedCount = 0; + DTBParse(bootinfo->dtb, &bootMap); + OSLog("Meow...\n"); } \ No newline at end of file diff --git a/Kernel/Source/Lib/Stubs.c b/Kernel/Source/Lib/Stubs.c new file mode 100644 index 0000000..8a5544f --- /dev/null +++ b/Kernel/Source/Lib/Stubs.c @@ -0,0 +1,6 @@ +#include +#include + +void* memset(void* destination, int value, Size count) { + return StringSet(destination, value, count); +} \ No newline at end of file diff --git a/Kernel/Source/VM/PMM.c b/Kernel/Source/VM/PMM.c new file mode 100644 index 0000000..280983a --- /dev/null +++ b/Kernel/Source/VM/PMM.c @@ -0,0 +1,22 @@ +#include + +static inline Size BitmapGetByteIndex(Address address) { + return (address / kVMPageSize) / kVMBlocksPerByte; +} + +static inline UInt8 BitmapGetBitOffset(Address address) { + return (UInt8)((address / kVMPageSize) % kVMBlocksPerByte); +} + +static inline Boolean BitmapTest(const MemoryPointer bitmap, Address address) { + return (bitmap[BitmapGetByteIndex(address)] & (1U << BitmapGetBitOffset(address))) != 0; +} + +static inline void BitmapSet(MemoryPointer bitmap, Address address) { + bitmap[BitmapGetByteIndex(address)] |= (1U << BitmapGetBitOffset(address)); +} + +static inline void BitmapUnset(MemoryPointer bitmap, Address address) { + bitmap[BitmapGetByteIndex(address)] &= ~(1U << BitmapGetBitOffset(address)); +} + diff --git a/Kernel/linker.ld b/Kernel/linker.ld index b793125..4e8729e 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -7,14 +7,22 @@ PHDRS SECTIONS { . = 0x40100000; + _kernelStart = .; .text : { *(.text.boot) *(.text*) } :text + . = ALIGN(8); .rodata : { *(.rodata*) } :text + . = ALIGN(4096); .data : { *(.data*) } :data + + . = ALIGN(8); .bss : { *(.bss*) *(COMMON) } :data + + . = ALIGN(4096); + _kernelEnd = .; } \ No newline at end of file -- 2.52.0 From 55335013a940a4c39baf34d1c42ea47d0072b2da Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 15:12:04 +0400 Subject: [PATCH 29/49] feat: completely functional PMM --- Kernel/Include/VM/PMM.h | 6 +++- Kernel/Source/Arch/DTB.c | 18 ++++++----- Kernel/Source/KernelMain.c | 2 +- Kernel/Source/VM/PMM.c | 61 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 9 deletions(-) diff --git a/Kernel/Include/VM/PMM.h b/Kernel/Include/VM/PMM.h index 6beddd3..6704e4c 100644 --- a/Kernel/Include/VM/PMM.h +++ b/Kernel/Include/VM/PMM.h @@ -16,4 +16,8 @@ typedef struct { VMMemoryRegion totalRAM; VMMemoryRegion reserved[kVMMaxReservedRegions]; UInt32 reservedCount; -} VMBootMemoryMap; \ No newline at end of file +} VMBootMemoryMap; + +void PMMInitialize(VMBootMemoryMap* bootMap); +Pointer PMMAllocatePage(); +void PMMFreePage(Address address); \ No newline at end of file diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index 69c4f7e..6808a68 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -1,3 +1,4 @@ +#include "Types.h" #include #include #include @@ -12,6 +13,11 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { OSPanic("Invalid DTB magic"); } + UInt32 index = bootMap->reservedCount; + bootMap->reserved[index].base = (Address)dtb; + bootMap->reserved[index].size = BytesSwap32(header->totalSize); + bootMap->reservedCount++; + UInt32 offStruct = BytesSwap32(header->offDtStruct); UInt32 offStrings = BytesSwap32(header->offDtStrings); @@ -51,23 +57,21 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { if (StringCompare(propertyName, "reg") == 0) { if (StringStartsWith(currentNode, "memory")) { UInt32* cells = (UInt32*)structs; - UInt64 base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); - UInt64 size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); - OSLog("Main Memory: base=0x%x, size=0x%x\n", base, size); + Address base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); + Size size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); + bootMap->totalRAM.base = base; bootMap->totalRAM.size = size; } else if (inReservedMemory && currentDepth > reservedMemoryDepth) { UInt32* cells = (UInt32*)structs; - UInt64 base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); - UInt64 size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); + Address base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); + Size size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); UInt32 index = bootMap->reservedCount; bootMap->reserved[index].base = base; bootMap->reserved[index].size = size; bootMap->reservedCount++; - - OSLog("Reserved Region (%s): base=0x%x, size=0x%x\n", currentNode, base, size); } } diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index a0fb291..efe5aa1 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -13,5 +13,5 @@ void KernelMain(Bootinfo* bootinfo) { VMBootMemoryMap bootMap = {0}; bootMap.reservedCount = 0; DTBParse(bootinfo->dtb, &bootMap); - OSLog("Meow...\n"); + PMMInitialize(&bootMap); } \ No newline at end of file diff --git a/Kernel/Source/VM/PMM.c b/Kernel/Source/VM/PMM.c index 280983a..e15d06e 100644 --- a/Kernel/Source/VM/PMM.c +++ b/Kernel/Source/VM/PMM.c @@ -1,4 +1,8 @@ #include +#include + +extern char _kernelStart[]; +extern char _kernelEnd[]; static inline Size BitmapGetByteIndex(Address address) { return (address / kVMPageSize) / kVMBlocksPerByte; @@ -20,3 +24,60 @@ static inline void BitmapUnset(MemoryPointer bitmap, Address address) { bitmap[BitmapGetByteIndex(address)] &= ~(1U << BitmapGetBitOffset(address)); } +static MemoryPointer sPMMBitmap; +static Size sPMMBitmapSize; +static Size sPMMTotalPages; + +void PMMInitialize(VMBootMemoryMap* bootMap) { + UInt32 vIndex = bootMap->reservedCount; + bootMap->reserved[vIndex].base = 0x0; + bootMap->reserved[vIndex].size = bootMap->totalRAM.base; + bootMap->reservedCount++; + + UInt32 kIndex = bootMap->reservedCount; + bootMap->reserved[kIndex].base = (Address)_kernelStart; + bootMap->reserved[kIndex].size = (Address)_kernelEnd - (Address)_kernelStart; + bootMap->reservedCount++; + + sPMMTotalPages = bootMap->totalRAM.size / kVMPageSize; + sPMMBitmapSize = sPMMTotalPages / kVMBlocksPerByte; + sPMMBitmap = (MemoryPointer)_kernelEnd; + + StringSet(sPMMBitmap, 0, sPMMBitmapSize); + + UInt32 bIndex = bootMap->reservedCount; + bootMap->reserved[bIndex].base = (Address)sPMMBitmap; + bootMap->reserved[bIndex].size = sPMMBitmapSize; + bootMap->reservedCount++; + + for (Size i = 0; i < bootMap->reservedCount; i++) { + Address regionBase = bootMap->reserved[i].base; + Size regionSize = bootMap->reserved[i].size; + + Size pagesToReserve = (regionSize + kVMPageSize - 1) / kVMPageSize; + + for (Size p = 0; p < pagesToReserve; p++) { + Address pageAdress = regionBase + (p * kVMPageSize); + BitmapSet(sPMMBitmap, pageAdress); + } + } +} + +Pointer PMMAllocatePage() { + for (Size i = 0; i < sPMMBitmapSize; i++) { + if (sPMMBitmap[i] == 0xFF) continue; + for (Size bit = 0; bit < kVMBlocksPerByte; bit++) { + if ((sPMMBitmap[i] & (1 << bit)) == 0) { + Address address = (i * kVMBlocksPerByte + bit) * kVMPageSize; + BitmapSet(sPMMBitmap, address); + return (Pointer)address; + } + } + } + + return nullptr; +} + +void PMMFreePage(Address address) { + BitmapUnset(sPMMBitmap, address); +} \ No newline at end of file -- 2.52.0 From b56b55e4b36b9b8f991b6dba087d37efcabf6ccd Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 21:47:41 +0400 Subject: [PATCH 30/49] feat(arm64): higher-half kernel, early MMU in boot, and VMM --- Bootloader/Source/main.c | 24 +++-- Kernel/Include/Arch/CPU.h | 50 ++++++++++ Kernel/Include/Lib/String.h | 4 +- Kernel/Include/VM/PMM.h | 5 +- Kernel/Include/VM/VMM.h | 49 ++++++++++ Kernel/Source/Arch/DTB.c | 6 +- Kernel/Source/Arch/entry.S | 121 +++++++++++++++++++++++- Kernel/Source/KernelMain.c | 8 +- Kernel/Source/Lib/String.c | 10 +- Kernel/Source/Lib/Stubs.c | 13 ++- Kernel/Source/OS/Panic.c | 2 +- Kernel/Source/VM/PMM.c | 41 ++++---- Kernel/Source/VM/VMM.c | 183 ++++++++++++++++++++++++++++++++++++ Kernel/linker.ld | 24 ++++- 14 files changed, 485 insertions(+), 55 deletions(-) create mode 100644 Kernel/Include/VM/VMM.h create mode 100644 Kernel/Source/VM/VMM.c diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index edfa06f..1193ffd 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -129,20 +129,18 @@ static efi_status_t parse_elf_headers(efi_physical_address_t kernel_addr) { return EFI_SUCCESS; } -static efi_status_t load_elf_segments(efi_physical_address_t kernel_addr, efi_file_handle_t* kernel_file) { +static efi_status_t load_elf_segments(efi_physical_address_t kernel_addr, efi_file_handle_t* kernel_file, efi_physical_address_t* out_phys_entry) { Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr; + *out_phys_entry = 0; for (int i = 0; i < elf_header->e_phnum; i++) { Elf64_Phdr* phdr = (Elf64_Phdr*)(kernel_addr + elf_header->e_phoff + i * elf_header->e_phentsize); if (phdr->p_type != PT_LOAD) continue; - if (phdr->p_vaddr < 0x40000000) { - print(WSTR("Skipping low/weird segment\r\n")); - continue; - } uintn_t pages = (phdr->p_memsz + 0xFFF) / 0x1000; - efi_physical_address_t segment_addr = phdr->p_vaddr; + + efi_physical_address_t segment_addr = phdr->p_paddr; efi_status_t status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment_addr); if (EFI_ERROR(status)) { @@ -159,6 +157,15 @@ static efi_status_t load_elf_segments(efi_physical_address_t kernel_addr, efi_fi if (EFI_ERROR(status) || size_to_read != phdr->p_filesz) { return fail(WSTR("File read error\r\n")); } + + if (elf_header->e_entry >= phdr->p_vaddr && elf_header->e_entry < phdr->p_vaddr + phdr->p_memsz) { + uint64_t entry_offset = elf_header->e_entry - phdr->p_vaddr; + *out_phys_entry = segment_addr + entry_offset; + } + } + + if (*out_phys_entry == 0) { + return fail(WSTR("Entry point not found in PT_LOAD segments\r\n")); } return EFI_SUCCESS; @@ -235,7 +242,8 @@ efi_status_t bootloader_main(void) { status = parse_elf_headers(kernel_addr); if (EFI_ERROR(status)) return status; - status = load_elf_segments(kernel_addr, kernel_file); + efi_physical_address_t phys_entry = 0; + status = load_elf_segments(kernel_addr, kernel_file, &phys_entry); if (EFI_ERROR(status)) return status; Bootinfo* boot_info = NULL; @@ -261,7 +269,7 @@ efi_status_t bootloader_main(void) { } typedef void (*kernel_entry_t)(Bootinfo*); - kernel_entry_t kernel_main = (kernel_entry_t)elf_header->e_entry; + kernel_entry_t kernel_main = (kernel_entry_t)phys_entry; kernel_main(boot_info); return EFI_SUCCESS; diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index 83e2710..3d43452 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -21,4 +21,54 @@ static inline UInt64 CPUGetFAR() { UInt64 far; __asm__ volatile ("mrs %0, far_el1" : "=r" (far)); return far; +} + +static inline void CPUInvalidateTLB(Address virt) { + __asm__ volatile( + "dsb ishst\n" + "tlbi vaae1is, %0\n" + "dsb ish\n" + "isb\n" + :: "r" (virt >> 12) : "memory" + ); +} + +static inline void CPUEnableMMU(Address l0PhysicalAddress) { + // MAIR_EL1 (Memory Attribute Indirection Register) + // kPTENormalMem is index 0 and kPTEDeviceMem is index 1 + // 0xFF = Normal, 0x00 = Device + UInt64 mair = (0xFFULL << 0) | (0x00ULL << 8); + + // TCR_EL1 (Translation Control Register) + // configures the mmu for 4kb pages and 48bit virtual addresses + // t0sz/t1sz = 16 (64-48 = 16) + // tg0/tg1 = 4kb granule + UInt64 tcr = (16ULL << 0) | // T0SZ (userspace size) + (16ULL << 16) | // T1SZ (kernelspace size) + (0ULL << 14) | // TG0 (User 4KB) + (2ULL << 30) | // TG1 (Kernel 4KB) + (3ULL << 28) | // SH1 (Inner Shareable) + (3ULL << 12) | // SH0 (Inner Shareable) + (5ULL << 32); // IPS + + __asm__ volatile ( + "msr mair_el1, %0\n" + "msr tcr_el1, %1\n" + "msr ttbr0_el1, %2\n" // set userspace root + "msr ttbr1_el1, %2\n" // set kernelspace root + "isb\n" // Instruction Synchronization Barrier + :: "r"(mair), "r"(tcr), "r"(l0PhysicalAddress) : "memory" + ); + + // turn on the MMU in SCTLR_EL1 (System Control Register) + // Bit 0 = M (MMU Enable), Bit 2 = C (Data Cache Enable), Bit 12 = I (Instruction Cache Enable) + UInt64 sctlr; + UInt64 sctlr_flags = 0x1005; // set bits 0 (M), 2 (C), and 12 (I) + __asm__ volatile ( + "mrs %0, sctlr_el1\n" + "orr %0, %0, %1\n" + "msr sctlr_el1, %0\n" + "isb\n" + : "=r"(sctlr) : "r"(sctlr_flags) : "memory" + ); } \ No newline at end of file diff --git a/Kernel/Include/Lib/String.h b/Kernel/Include/Lib/String.h index 1db07ac..4203842 100644 --- a/Kernel/Include/Lib/String.h +++ b/Kernel/Include/Lib/String.h @@ -2,8 +2,8 @@ #include #include -void* StringSet(BytePointer destination, ASCII value, Size count); -void* MemoryCopy(void* destination, const void* source, Size count); +Pointer MemorySet(Pointer destination, ASCII value, Size count); +Pointer MemoryCopy(Pointer destination, const Pointer source, Size count); Int32 StringCompare(const ASCII* firstString, const ASCII* secondString); Int32 StringCompareWithLimit(const ASCII* firstString, const ASCII* secondString, Size limit); diff --git a/Kernel/Include/VM/PMM.h b/Kernel/Include/VM/PMM.h index 6704e4c..33c3384 100644 --- a/Kernel/Include/VM/PMM.h +++ b/Kernel/Include/VM/PMM.h @@ -1,5 +1,6 @@ #pragma once #include +#include "../Common/bootinfo.h" enum { kVMPageSize = 4096, @@ -12,12 +13,14 @@ typedef struct { Size size; } VMMemoryRegion; + typedef struct { VMMemoryRegion totalRAM; VMMemoryRegion reserved[kVMMaxReservedRegions]; UInt32 reservedCount; + VMMemoryRegion UART; } VMBootMemoryMap; -void PMMInitialize(VMBootMemoryMap* bootMap); +void PMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info); Pointer PMMAllocatePage(); void PMMFreePage(Address address); \ No newline at end of file diff --git a/Kernel/Include/VM/VMM.h b/Kernel/Include/VM/VMM.h new file mode 100644 index 0000000..83c7615 --- /dev/null +++ b/Kernel/Include/VM/VMM.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include "../Common/bootinfo.h" + +enum VMPTEFlags { + kPTEValid = (1ULL << 0), // 1 = Present (Will page fault if 0) + kPTETable = (1ULL << 1), // 1 = Valid for L0/L1/L2 Directory + kPTEPage = (1ULL << 1), // 1 = Valid for L3 Page (Same bit) + + kPTENormalMem = (0ULL << 2), // Cached, Normal RAM + kPTEDeviceMem = (1ULL << 2), // Uncached, MMIO Device + + kPTEAccessRW = (0ULL << 6), // Read/Write + kPTEAccessRO = (1ULL << 6), // Read-Only + kPTEUser = (1ULL << 7), // 1 = EL0, 0 = EL1 + + kPTEInnerShare = (3ULL << 8), // Inner Shareable (SMP safe) + kPTEAccessFlag = (1ULL << 10), // CPU access tracking (MUST be 1 to avoid faults) + kPTEPrivNX = (1ULL << 53), // PXN: Privileged Execute Never + kPTEUserNX = (1ULL << 54) // UXN: Unprivileged Execute Never +}; + +enum { + kVMKernelVMA = 0xFFFFFFFF80000000, + kHHDMOffset = 0xFFFF888000000000, + kVMFbVirtBase = 0xFFFFFFFFFC000000, +}; + + +static inline Address VMKernelVirtToPhys(Address virt) { + return virt - kVMKernelVMA; +} + +static inline Address VMPhysToHHDM(Address phys) { + return phys + kHHDMOffset; +} + +static inline Address VMHHDMToPhys(Address virt) { + return virt - kHHDMOffset; +} + +extern Address* gVMKernelL0Table; +extern Address gVMKernelL0Physical; + +Address* VMMMapPage(Address* l0Table, Address phys, Address virt, UInt64 flags); +void VMMUnmapPage(Address* l0Table, Address virt); +Pointer VMMGetOrAllocatePage(Address* l0Table, Address virt, UInt64 flags); +void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info); diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index 6808a68..238fa97 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -1,4 +1,3 @@ -#include "Types.h" #include #include #include @@ -73,6 +72,11 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { bootMap->reserved[index].size = size; bootMap->reservedCount++; } + else if (StringStartsWith(currentNode, "pl011")) { + UInt32* cells = (UInt32*)structs; + bootMap->UART.base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); + bootMap->UART.size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); + } } structs += propertyLength; diff --git a/Kernel/Source/Arch/entry.S b/Kernel/Source/Arch/entry.S index af8fadc..77d9009 100644 --- a/Kernel/Source/Arch/entry.S +++ b/Kernel/Source/Arch/entry.S @@ -1,10 +1,121 @@ .section .text.boot, "ax" .global _start + _start: - sub sp, sp, #16 - str x0, [sp] + // disable interrupts + msr daifset, #3 + // save phys addr of Bootinfo* in x0 to x20 + mov x20, x0 + + // get phys addr of tables + adrp x0, early_ttbr0_l0 + adrp x1, early_ttbr1_l0 + + // memzero that tables (4 tables = 16 KB) + mov x2, #16384 + mov x3, x0 +1: str xzr, [x3], #8 + subs x2, x2, #8 + b.ne 1b + + // set up ttbr0 (identity map of 512 gb) + adrp x0, early_ttbr0_l0 + adrp x1, early_ttbr1_l0 + + // early_ttbr0_l0[0] -> early_ttbr0_l1 (Valid + Table = 0x3) + ldr x2, =0x3 + orr x3, x1, x2 + str x3, [x0, #0] + + // fill l1 table with 512 entrie + // flags 0x701 = valid + block + accessflag + innershareable + normalram + mov x2, xzr + mov x3, #512 + ldr x4, =0x701 + mov x6, #(1 << 30) +2: orr x5, x2, x4 + str x5, [x1], #8 // early_ttbr0_l1[i] = base | flags + add x2, x2, x6 + subs x3, x3, #1 + b.ne 2b + + // set up ttbr1 (HH: 0xFFFFFFFF80000000) + adrp x0, early_ttbr1_l0 + adrp x1, early_ttbr1_l1 + + // early_ttbr1_l0[511] -> early_ttbr1_l1 (Valid + Table = 0x3) + ldr x2, =0x3 + orr x3, x1, x2 + mov x4, #(511 * 8) + str x3, [x0, x4] + + // determine where is kernel rn + adr x2, _start // curr pc in absoule addr + lsr x2, x2, #30 // leave only number of gig + lsl x2, x2, #30 // return it in absoule addr + + // map that at 510 (0xFFFFFFFF80000000) + ldr x3, =0x701 // flags + orr x2, x2, x3 + mov x4, #(510 * 8) + str x2, [x1, x4] // early_ttbr1_l1[510] = base | flags + + // enable MMU (MAIR, TCR, SCTLR) + // see Kernel/Include/Arch/CPU.h for explanaition + ldr x2, =((0xFF << 0) | (0x00 << 8)) + msr mair_el1, x2 + + ldr x2, =((16 << 0) | (16 << 16) | (0 << 14) | (2 << 30) | (3 << 28) | (3 << 12) | (5 << 32)) + msr tcr_el1, x2 + + adrp x0, early_ttbr0_l0 + adrp x1, early_ttbr1_l0 + msr ttbr0_el1, x0 + msr ttbr1_el1, x1 + dsb ish + isb + + mrs x2, sctlr_el1 + ldr x3, =0x1005 + orr x2, x2, x3 + msr sctlr_el1, x2 + isb + + ldr x2, =higher_half_jump + br x2 + +higher_half_jump: + ldr x3, =_boot_stack_top + mov sp, x3 + + // clean .bss + ldr x1, =__bss_start + ldr x2, =__bss_end + cbz x1, 4f + cmp x1, x2 + b.eq 4f +3: str xzr, [x1], #8 + cmp x1, x2 + b.lt 3b +4: bl ExceptionsVectorsInit - ldr x0, [sp] - add sp, sp, #16 + + mov x0, x20 // return phys of Bootinfo* in x20 + bl KernelMain - b . \ No newline at end of file + +halt: + wfi + b halt + +.section .data +.align 12 +early_ttbr0_l0: .fill 4096, 1, 0 +early_ttbr0_l1: .fill 4096, 1, 0 +early_ttbr1_l0: .fill 4096, 1, 0 +early_ttbr1_l1: .fill 4096, 1, 0 + +.section .bss +.align 16 + .skip 16384 +_boot_stack_top: \ No newline at end of file diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index efe5aa1..1605bce 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,6 +1,7 @@ #include "../Common/bootinfo.h" -#include #include +#include +#include #include #include @@ -13,5 +14,8 @@ void KernelMain(Bootinfo* bootinfo) { VMBootMemoryMap bootMap = {0}; bootMap.reservedCount = 0; DTBParse(bootinfo->dtb, &bootMap); - PMMInitialize(&bootMap); + PMMInitialize(&bootMap, bootinfo); + VMMInitialize(&bootMap, bootinfo); + + OSLog("Kernel initialized.\n"); } \ No newline at end of file diff --git a/Kernel/Source/Lib/String.c b/Kernel/Source/Lib/String.c index ccd5bda..4e99f7c 100644 --- a/Kernel/Source/Lib/String.c +++ b/Kernel/Source/Lib/String.c @@ -8,15 +8,15 @@ static void BufferAdd(ASCII* buffer, Size bufferSize, Size* written, ASCII chara (*written)++; } -void* StringSet(BytePointer destination, ASCII value, Size count) { - BytePointer savedDestination = destination; +Pointer MemorySet(Pointer destination, ASCII value, Size count) { + BytePointer savedDestination = (BytePointer) destination; while (count--) { - *destination++ = (UInt8) value; + *savedDestination++ = (UInt8) value; } - return savedDestination; + return destination; } -void* MemoryCopy(void* destination, const void* source, Size count) { +Pointer MemoryCopy(Pointer destination, const Pointer source, Size count) { BytePointer destinationBuffer = (BytePointer) destination; const UInt8* sourceBuffer = (const UInt8*) source; diff --git a/Kernel/Source/Lib/Stubs.c b/Kernel/Source/Lib/Stubs.c index 8a5544f..6a223be 100644 --- a/Kernel/Source/Lib/Stubs.c +++ b/Kernel/Source/Lib/Stubs.c @@ -2,5 +2,14 @@ #include void* memset(void* destination, int value, Size count) { - return StringSet(destination, value, count); -} \ No newline at end of file + return MemorySet(destination, value, count); +} + +// A little bit of Monica in my life +// A little bit of Erica by my side +// A little bit of Rita's all I need +// A little bit of Tina's what I see +// A little bit of Sandra in the sun +// A little bit of Mary all night long +// A little bit of Jessica, here I am +// A little bit of you makes me your man \ No newline at end of file diff --git a/Kernel/Source/OS/Panic.c b/Kernel/Source/OS/Panic.c index 8891ca8..56ed5d2 100644 --- a/Kernel/Source/OS/Panic.c +++ b/Kernel/Source/OS/Panic.c @@ -21,7 +21,7 @@ static const ASCII* GetExceptionClassString(UInt32 class) { } __attribute__((noreturn)) static void Halt() { - while (1) { + loop { CPUDisableInterrupts(); CPUWaitForInterrupt(); } diff --git a/Kernel/Source/VM/PMM.c b/Kernel/Source/VM/PMM.c index e15d06e..ba176c9 100644 --- a/Kernel/Source/VM/PMM.c +++ b/Kernel/Source/VM/PMM.c @@ -1,19 +1,21 @@ #include #include +#include "../Common/bootinfo.h" extern char _kernelStart[]; extern char _kernelEnd[]; +static Address sPMMRamBase = 0; +static MemoryPointer sPMMBitmap; +static Size sPMMBitmapSize; +static Size sPMMTotalPages; + static inline Size BitmapGetByteIndex(Address address) { - return (address / kVMPageSize) / kVMBlocksPerByte; + return ((address - sPMMRamBase) / kVMPageSize) / kVMBlocksPerByte; } static inline UInt8 BitmapGetBitOffset(Address address) { - return (UInt8)((address / kVMPageSize) % kVMBlocksPerByte); -} - -static inline Boolean BitmapTest(const MemoryPointer bitmap, Address address) { - return (bitmap[BitmapGetByteIndex(address)] & (1U << BitmapGetBitOffset(address))) != 0; + return (UInt8)(((address - sPMMRamBase) / kVMPageSize) % kVMBlocksPerByte); } static inline void BitmapSet(MemoryPointer bitmap, Address address) { @@ -24,27 +26,18 @@ static inline void BitmapUnset(MemoryPointer bitmap, Address address) { bitmap[BitmapGetByteIndex(address)] &= ~(1U << BitmapGetBitOffset(address)); } -static MemoryPointer sPMMBitmap; -static Size sPMMBitmapSize; -static Size sPMMTotalPages; +void PMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { + sPMMRamBase = bootMap->totalRAM.base; + sPMMTotalPages = bootMap->totalRAM.size / kVMPageSize; + sPMMBitmapSize = sPMMTotalPages / kVMBlocksPerByte; + sPMMBitmap = (MemoryPointer)_kernelEnd; + MemorySet(sPMMBitmap, 0, sPMMBitmapSize); -void PMMInitialize(VMBootMemoryMap* bootMap) { - UInt32 vIndex = bootMap->reservedCount; - bootMap->reserved[vIndex].base = 0x0; - bootMap->reserved[vIndex].size = bootMap->totalRAM.base; - bootMap->reservedCount++; - UInt32 kIndex = bootMap->reservedCount; bootMap->reserved[kIndex].base = (Address)_kernelStart; bootMap->reserved[kIndex].size = (Address)_kernelEnd - (Address)_kernelStart; bootMap->reservedCount++; - sPMMTotalPages = bootMap->totalRAM.size / kVMPageSize; - sPMMBitmapSize = sPMMTotalPages / kVMBlocksPerByte; - sPMMBitmap = (MemoryPointer)_kernelEnd; - - StringSet(sPMMBitmap, 0, sPMMBitmapSize); - UInt32 bIndex = bootMap->reservedCount; bootMap->reserved[bIndex].base = (Address)sPMMBitmap; bootMap->reserved[bIndex].size = sPMMBitmapSize; @@ -58,7 +51,9 @@ void PMMInitialize(VMBootMemoryMap* bootMap) { for (Size p = 0; p < pagesToReserve; p++) { Address pageAdress = regionBase + (p * kVMPageSize); - BitmapSet(sPMMBitmap, pageAdress); + if (pageAdress >= sPMMRamBase && pageAdress < (sPMMRamBase + bootMap->totalRAM.size)) { + BitmapSet(sPMMBitmap, pageAdress); + } } } } @@ -68,7 +63,7 @@ Pointer PMMAllocatePage() { if (sPMMBitmap[i] == 0xFF) continue; for (Size bit = 0; bit < kVMBlocksPerByte; bit++) { if ((sPMMBitmap[i] & (1 << bit)) == 0) { - Address address = (i * kVMBlocksPerByte + bit) * kVMPageSize; + Address address = sPMMRamBase + (i * kVMBlocksPerByte + bit) * kVMPageSize; BitmapSet(sPMMBitmap, address); return (Pointer)address; } diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c new file mode 100644 index 0000000..f0911a9 --- /dev/null +++ b/Kernel/Source/VM/VMM.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include +#include +#include "../Common/bootinfo.h" + +static const UInt64 kPTEAddressMask = 0x0000FFFFFFFFF000ULL; +static inline Address GetPTEAddress(UInt64 entry) { return entry & kPTEAddressMask; } +static inline UInt64 GetPTEFlags(UInt64 entry) { return entry & ~kPTEAddressMask; } +static inline UInt16 GetL0Index(Address virt) { return (virt >> 39) & 0x1FF; } +static inline UInt16 GetL1Index(Address virt) { return (virt >> 30) & 0x1FF; } +static inline UInt16 GetL2Index(Address virt) { return (virt >> 21) & 0x1FF; } +static inline UInt16 GetL3Index(Address virt) { return (virt >> 12) & 0x1FF; } + +static Boolean isInitialized = false; + +Address* gVMKernelL0Table = nullptr; +Address gVMKernelL0Physical = 0; + +static Address* GetVirtualTable(Address phys) { + if (isInitialized) return (Address*)VMPhysToHHDM(phys); + return (Address*)phys; +} + +static inline Address* GetOrAllocateTable(Address* parentTable, Size index, UInt64 flags, UInt64 directoryFlags) { + if (!(parentTable[index] & kPTEValid)) { + Pointer newTable = PMMAllocatePage(); + if (!newTable) return nullptr; + + Address* newTableVirt = GetVirtualTable((Address)newTable); + MemorySet(newTableVirt, 0, kVMPageSize); + + parentTable[index] = (Address)newTable | directoryFlags; + return newTableVirt; + } + + parentTable[index] |= (flags & kPTEUser); + + Address physAddress = GetPTEAddress(parentTable[index]); + return GetVirtualTable(physAddress); +} + +static Address GetMappedPhysicalAddress(Address* l0Table, Address virt) { + // A little bit of Monica in my life + UInt16 l0Index = GetL0Index(virt); + // A little bit of Erica by my side + UInt16 l1Index = GetL1Index(virt); + // A little bit of Rita's all I need + UInt16 l2Index = GetL2Index(virt); + // A little bit of Tina's what I see + UInt16 l3Index = GetL3Index(virt); + + // A little bit of Sandra in the sun + Address* l0Virt = l0Table; + if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table); + if (!(l0Virt[l0Index] & kPTEValid)) return 0; + + // A little bit of Mary all night long... + Address* l1Virt = GetVirtualTable(GetPTEAddress(l0Virt[l0Index])); + if (!(l1Virt[l1Index] & kPTEValid)) return 0; + + // A little bit of Jessica, here I am! + Address* l2Virt = GetVirtualTable(GetPTEAddress(l1Virt[l1Index])); + if (!(l2Virt[l2Index] & kPTEValid)) return 0; + + // A little bit of you makes me your man + Address* l3Virt = GetVirtualTable(GetPTEAddress(l2Virt[l2Index])); + if (!(l3Virt[l3Index] & kPTEValid)) return 0; + + return GetPTEAddress(l3Virt[l3Index]); +} + +Address* VMMMapPage(Address* l0Table, Address phys, Address virt, UInt64 flags) { + UInt16 l0Index = GetL0Index(virt); + UInt16 l1Index = GetL1Index(virt); + UInt16 l2Index = GetL2Index(virt); + UInt16 l3Index = GetL3Index(virt); + + Address* l0Virt = l0Table; + if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table); + + UInt64 directoryFlags = kPTEValid | kPTETable | (flags & kPTEUser); + + Address* l1Virt = GetOrAllocateTable(l0Virt, l0Index, flags, directoryFlags); + if (!l1Virt) return nullptr; + + Address* l2Virt = GetOrAllocateTable(l1Virt, l1Index, flags, directoryFlags); + if (!l2Virt) return nullptr; + + Address* l3Virt = GetOrAllocateTable(l2Virt, l2Index, flags, directoryFlags); + if (!l3Virt) return nullptr; + + l3Virt[l3Index] = phys | flags | kPTEPage | kPTEAccessFlag | kPTEValid; + CPUInvalidateTLB(virt); + return l3Virt; +} + +void VMMUnmapPage(Address* l0Table, Address virt) { + UInt16 l0Index = GetL0Index(virt); + UInt16 l1Index = GetL1Index(virt); + UInt16 l2Index = GetL2Index(virt); + UInt16 l3Index = GetL3Index(virt); + + Address* l0Virt = l0Table; + if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table); + if (!(l0Virt[l0Index] & kPTEValid)) return; + + Address* l1Virt = GetVirtualTable(GetPTEAddress(l0Virt[l0Index])); + if (!(l1Virt[l1Index] & kPTEValid)) return; + + Address* l2Virt = GetVirtualTable(GetPTEAddress(l1Virt[l1Index])); + if (!(l2Virt[l2Index] & kPTEValid)) return; + + Address* l3Virt = GetVirtualTable(GetPTEAddress(l2Virt[l2Index])); + l3Virt[l3Index] = 0; + + CPUInvalidateTLB(virt); +} + +Pointer VMMGetOrAllocatePage(Address* l0Table, Address virt, UInt64 flags) { + Address existingPhys = GetMappedPhysicalAddress(l0Table, virt); + if (existingPhys) return (Pointer)GetVirtualTable(existingPhys); + + Pointer newPhys = PMMAllocatePage(); + if (!newPhys) return nullptr; // OOM + + Address* mappedVirt = VMMMapPage(l0Table, (Address) newPhys, virt, flags); + if (!mappedVirt) return nullptr; + + Pointer finalVirtAddress = (Pointer)GetVirtualTable((Address)newPhys); + MemorySet(finalVirtAddress, 0, kVMPageSize); + + return finalVirtAddress; +} + +void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { + gVMKernelL0Physical = (Address)PMMAllocatePage(); + gVMKernelL0Table = (Address*)gVMKernelL0Physical; + if (!gVMKernelL0Physical) OSPanic("Failed to allocate kernel L0 table"); + + Size totalRAM = bootMap->totalRAM.size; + Size ramEnd = bootMap->totalRAM.base + totalRAM; + for (Address phys = bootMap->totalRAM.base; phys < ramEnd; phys += kVMPageSize) { + VMMMapPage( + gVMKernelL0Table, + phys, VMPhysToHHDM(phys), + kPTENormalMem | kPTEAccessRW | kPTEPrivNX | kPTEUserNX + ); + } + + Address kernelPhysStart = (Address)info->kernelInfo.kernelAddress; + Size kernelSize = info->kernelInfo.kernelSize; + for (Address offset = 0; offset < kernelSize; offset += kVMPageSize) { + Address phys = kernelPhysStart + offset; + Address virt = kVMKernelVMA + offset; + VMMMapPage(gVMKernelL0Table, phys, virt, kPTENormalMem | kPTEAccessRW); + } + + Address fbPhys = (Address)info->framebuffer.base; + Size fbSize = info->framebuffer.baseSize; + for (Address offset = 0; offset < fbSize; offset += kVMPageSize) { + VMMMapPage( + gVMKernelL0Table, fbPhys + offset, + kVMFbVirtBase + offset, + kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX + ); + } + + Address UARTPhys = bootMap->UART.base; + VMMMapPage( + gVMKernelL0Table, UARTPhys, VMPhysToHHDM(UARTPhys), + kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX + ); + + for (Address offset = 0; offset < kernelSize; offset += kVMPageSize) { + VMMMapPage(gVMKernelL0Table, kernelPhysStart + offset, kernelPhysStart + offset, kPTENormalMem | kPTEAccessRW); + } + + info->framebuffer.base = (BIUInt32*)kVMFbVirtBase;; + CPUEnableMMU(gVMKernelL0Physical); + isInitialized = true; +} \ No newline at end of file diff --git a/Kernel/linker.ld b/Kernel/linker.ld index 4e8729e..35a10ce 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -1,3 +1,8 @@ +ENTRY(_start) + +KERNEL_PA = 0x40100000; +KERNEL_VA = 0xFFFFFFFF80100000; + PHDRS { text PT_LOAD FLAGS(5); /* Read | Execute */ @@ -6,22 +11,31 @@ PHDRS SECTIONS { - . = 0x40100000; + . = KERNEL_VA; _kernelStart = .; - .text : { + .text : AT(ADDR(.text) - KERNEL_VA + KERNEL_PA) { *(.text.boot) *(.text*) } :text . = ALIGN(8); - .rodata : { *(.rodata*) } :text + .rodata : AT(ADDR(.rodata) - KERNEL_VA + KERNEL_PA) { + *(.rodata*) + } :text . = ALIGN(4096); - .data : { *(.data*) } :data + .data : AT(ADDR(.data) - KERNEL_VA + KERNEL_PA) { + *(.data*) + } :data . = ALIGN(8); - .bss : { *(.bss*) *(COMMON) } :data + .bss : AT(ADDR(.bss) - KERNEL_VA + KERNEL_PA) { + __bss_start = .; + *(.bss*) + *(COMMON) + __bss_end = .; + } :data . = ALIGN(4096); _kernelEnd = .; -- 2.52.0 From 5d010f7fb28830ad54efe596c36835514eb5174f Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 23:41:57 +0400 Subject: [PATCH 31/49] fix(vmm): make MMU bring-up and kernel mappings reliable --- Kernel/Include/Arch/CPU.h | 1 + Kernel/Include/VM/Heap.h | 24 +++++++++ Kernel/Include/VM/PMM.h | 2 +- Kernel/Include/VM/VMM.h | 2 +- Kernel/Source/KernelMain.c | 4 +- Kernel/Source/VM/Heap.c | 101 +++++++++++++++++++++++++++++++++++++ Kernel/Source/VM/PMM.c | 8 ++- Kernel/Source/VM/VMM.c | 38 +++++++++++--- 8 files changed, 167 insertions(+), 13 deletions(-) create mode 100644 Kernel/Include/VM/Heap.h create mode 100644 Kernel/Source/VM/Heap.c diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index 3d43452..df5c60c 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -56,6 +56,7 @@ static inline void CPUEnableMMU(Address l0PhysicalAddress) { "msr tcr_el1, %1\n" "msr ttbr0_el1, %2\n" // set userspace root "msr ttbr1_el1, %2\n" // set kernelspace root + "tlbi vmalle1is\n" "isb\n" // Instruction Synchronization Barrier :: "r"(mair), "r"(tcr), "r"(l0PhysicalAddress) : "memory" ); diff --git a/Kernel/Include/VM/Heap.h b/Kernel/Include/VM/Heap.h new file mode 100644 index 0000000..c76a94d --- /dev/null +++ b/Kernel/Include/VM/Heap.h @@ -0,0 +1,24 @@ +#pragma once +#include + +enum { + kHeapSizePages = 1024, + kHeapBlockHeaderMagic = 0x43555445, // CUTE + kKernelHeapStart = 0xFFFFFFFFC0000000 +}; + +static inline Address VMPhysToHeap(Address phys) { return phys + kKernelHeapStart; } +static inline Address VMHeapToPhys(Address heap) { return heap - kKernelHeapStart; } + +typedef struct __attribute__((aligned(16))) VMHeapBlockHeader { + UInt64 magic; + struct VMHeapBlockHeader* next; + struct VMHeapBlockHeader* previous; + UInt64 size; + bool isFree; +} VMHeapBlockHeader; + +void HeapInitialize(); +Pointer HeapAllocate(Size size); +void HeapFree(Pointer pointer); +Pointer HeapResize(Pointer pointer, Size newSize); \ No newline at end of file diff --git a/Kernel/Include/VM/PMM.h b/Kernel/Include/VM/PMM.h index 33c3384..1ee4399 100644 --- a/Kernel/Include/VM/PMM.h +++ b/Kernel/Include/VM/PMM.h @@ -21,6 +21,6 @@ typedef struct { VMMemoryRegion UART; } VMBootMemoryMap; -void PMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info); +void PMMInitialize(VMBootMemoryMap* bootMap); Pointer PMMAllocatePage(); void PMMFreePage(Address address); \ No newline at end of file diff --git a/Kernel/Include/VM/VMM.h b/Kernel/Include/VM/VMM.h index 83c7615..1b6d0b9 100644 --- a/Kernel/Include/VM/VMM.h +++ b/Kernel/Include/VM/VMM.h @@ -29,7 +29,7 @@ enum { static inline Address VMKernelVirtToPhys(Address virt) { - return virt - kVMKernelVMA; + return virt - 0xFFFFFFFF80100000 + 0x40100000; // TODO: hardcode is awful } static inline Address VMPhysToHHDM(Address phys) { diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 1605bce..fc0ba27 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -14,8 +15,9 @@ void KernelMain(Bootinfo* bootinfo) { VMBootMemoryMap bootMap = {0}; bootMap.reservedCount = 0; DTBParse(bootinfo->dtb, &bootMap); - PMMInitialize(&bootMap, bootinfo); + PMMInitialize(&bootMap); VMMInitialize(&bootMap, bootinfo); + HeapInitialize(); OSLog("Kernel initialized.\n"); } \ No newline at end of file diff --git a/Kernel/Source/VM/Heap.c b/Kernel/Source/VM/Heap.c new file mode 100644 index 0000000..a230b16 --- /dev/null +++ b/Kernel/Source/VM/Heap.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include + +static VMHeapBlockHeader* sVMHeapListHead = nullptr; + +static void CombineForward(VMHeapBlockHeader* current) { + if (!current->next || !current->next->isFree) return; + current->size += sizeof(VMHeapBlockHeader) + current->next->size; + current->next = current->next->next; + if (current->next) current->next->previous = current; // what the fuck +} + +void HeapInitialize() { + Address heapStart = kKernelHeapStart; + + for (UInt64 i = 0; i < kHeapSizePages; i++) { + Address physical = (Address)PMMAllocatePage(); + if (!physical) OSPanic("OOM during heap init"); + + Address virtual = heapStart + (i * kVMPageSize); + VMMMapPage(gVMKernelL0Table, physical, virtual, kPTENormalMem | kPTEAccessRW | kPTEPrivNX | kPTEUserNX); + } + + sVMHeapListHead = (VMHeapBlockHeader*)heapStart; + sVMHeapListHead->magic = kHeapBlockHeaderMagic; + sVMHeapListHead->size = (kHeapSizePages * kVMPageSize) - sizeof(VMHeapBlockHeader); + sVMHeapListHead->isFree = true; + sVMHeapListHead->next = nullptr; + sVMHeapListHead->previous = nullptr; +} + +Pointer HeapAllocate(Size size) { + if (size == 0) return nullptr; + Size alignedSize = (size + 15) & ~15; + + VMHeapBlockHeader* current = sVMHeapListHead; + while (current) { + if (current->isFree && current->size >= alignedSize) { + if (current->size > alignedSize + sizeof(VMHeapBlockHeader) + 16) { + VMHeapBlockHeader* new_block = (VMHeapBlockHeader*)((Address)current + sizeof(VMHeapBlockHeader) + alignedSize); + new_block->size = current->size - alignedSize - sizeof(VMHeapBlockHeader); + new_block->isFree = true; + new_block->next = current->next; + new_block->previous = current; + new_block->magic = kHeapBlockHeaderMagic; + + if (current->next) current->next->previous = new_block; + current->next = new_block; + current->size = alignedSize; + } + current->isFree = false; + return (Pointer)((Address)current + sizeof(VMHeapBlockHeader)); + } + current = current->next; + } + + return nullptr; +} + +void HeapFree(Pointer pointer) { + if (!pointer) return; + + VMHeapBlockHeader* current = (VMHeapBlockHeader*)((Address)pointer - sizeof(VMHeapBlockHeader)); + if (current->magic != kHeapBlockHeaderMagic) return; + + current->isFree = true; + if (current->next && current->next->isFree) CombineForward(current); + if (current->previous && current->previous->isFree) CombineForward(current->previous); +} + +Pointer HeapResize(Pointer pointer, Size newSize) { + if (!pointer) return HeapAllocate(newSize); + if (newSize == 0) { + HeapFree(pointer); + return nullptr; + } + + Size alignedSize = (newSize + 15) & ~15; + + VMHeapBlockHeader* current = (VMHeapBlockHeader*)((Address)pointer - sizeof(VMHeapBlockHeader)); + if (current->size >= alignedSize) { + return pointer; + } + + if (current->next && current->next->isFree && + (current->size + sizeof(VMHeapBlockHeader) + current->next->size) >= alignedSize) { + CombineForward(current); + return pointer; + } + + Pointer newPointer = HeapAllocate(newSize); + if (newPointer) { + MemoryCopy(newPointer, pointer, current->size); + HeapFree(pointer); + } + + return newPointer; +} \ No newline at end of file diff --git a/Kernel/Source/VM/PMM.c b/Kernel/Source/VM/PMM.c index ba176c9..e346d48 100644 --- a/Kernel/Source/VM/PMM.c +++ b/Kernel/Source/VM/PMM.c @@ -1,6 +1,5 @@ #include #include -#include "../Common/bootinfo.h" extern char _kernelStart[]; extern char _kernelEnd[]; @@ -26,13 +25,18 @@ static inline void BitmapUnset(MemoryPointer bitmap, Address address) { bitmap[BitmapGetByteIndex(address)] &= ~(1U << BitmapGetBitOffset(address)); } -void PMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { +void PMMInitialize(VMBootMemoryMap* bootMap) { sPMMRamBase = bootMap->totalRAM.base; sPMMTotalPages = bootMap->totalRAM.size / kVMPageSize; sPMMBitmapSize = sPMMTotalPages / kVMBlocksPerByte; sPMMBitmap = (MemoryPointer)_kernelEnd; MemorySet(sPMMBitmap, 0, sPMMBitmapSize); + UInt32 safeIndex = bootMap->reservedCount; + bootMap->reserved[safeIndex].base = sPMMRamBase; + bootMap->reserved[safeIndex].size = 16 * 1024 * 1024; // 16 Mb + bootMap->reservedCount++; + UInt32 kIndex = bootMap->reservedCount; bootMap->reserved[kIndex].base = (Address)_kernelStart; bootMap->reserved[kIndex].size = (Address)_kernelEnd - (Address)_kernelStart; diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c index f0911a9..f279528 100644 --- a/Kernel/Source/VM/VMM.c +++ b/Kernel/Source/VM/VMM.c @@ -4,6 +4,7 @@ #include #include #include "../Common/bootinfo.h" +#include "OS/Log.h" static const UInt64 kPTEAddressMask = 0x0000FFFFFFFFF000ULL; static inline Address GetPTEAddress(UInt64 entry) { return entry & kPTEAddressMask; } @@ -18,6 +19,9 @@ static Boolean isInitialized = false; Address* gVMKernelL0Table = nullptr; Address gVMKernelL0Physical = 0; +extern char _kernelStart[]; +extern char _kernelEnd[]; + static Address* GetVirtualTable(Address phys) { if (isInitialized) return (Address*)VMPhysToHHDM(phys); return (Address*)phys; @@ -92,7 +96,7 @@ Address* VMMMapPage(Address* l0Table, Address phys, Address virt, UInt64 flags) if (!l3Virt) return nullptr; l3Virt[l3Index] = phys | flags | kPTEPage | kPTEAccessFlag | kPTEValid; - CPUInvalidateTLB(virt); + if (isInitialized) CPUInvalidateTLB(virt); return l3Virt; } @@ -138,7 +142,9 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { gVMKernelL0Physical = (Address)PMMAllocatePage(); gVMKernelL0Table = (Address*)gVMKernelL0Physical; if (!gVMKernelL0Physical) OSPanic("Failed to allocate kernel L0 table"); + MemorySet(gVMKernelL0Table, 0, kVMPageSize); + OSLog("Mapping RAM.. Can take a while\n"); Size totalRAM = bootMap->totalRAM.size; Size ramEnd = bootMap->totalRAM.base + totalRAM; for (Address phys = bootMap->totalRAM.base; phys < ramEnd; phys += kVMPageSize) { @@ -148,14 +154,25 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { kPTENormalMem | kPTEAccessRW | kPTEPrivNX | kPTEUserNX ); } + OSLog("RAM mapped\n"); + + Size pmmBitmapSize = (bootMap->totalRAM.size / kVMPageSize) / 8; + Size kernelSize = ((Address)_kernelEnd - (Address)_kernelStart) + pmmBitmapSize; + kernelSize = (kernelSize + kVMPageSize - 1) & ~(kVMPageSize - 1); + + Address kernelPhysStart = 0x40100000; // TODO: hardcode is awful - Address kernelPhysStart = (Address)info->kernelInfo.kernelAddress; - Size kernelSize = info->kernelInfo.kernelSize; for (Address offset = 0; offset < kernelSize; offset += kVMPageSize) { Address phys = kernelPhysStart + offset; - Address virt = kVMKernelVMA + offset; + Address virt = (Address)_kernelStart + offset; VMMMapPage(gVMKernelL0Table, phys, virt, kPTENormalMem | kPTEAccessRW); } + OSLog("Kernel mapped to HHDM\n"); + + for (Address offset = 0; offset < kernelSize; offset += kVMPageSize) { + VMMMapPage(gVMKernelL0Table, kernelPhysStart + offset, kernelPhysStart + offset, kPTENormalMem | kPTEAccessRW); + } + OSLog("Kernel Identity mapped\n"); Address fbPhys = (Address)info->framebuffer.base; Size fbSize = info->framebuffer.baseSize; @@ -166,18 +183,23 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX ); } + OSLog("Framebuffer mapped\n"); Address UARTPhys = bootMap->UART.base; + if (!UARTPhys) UARTPhys = 0x09000000; + VMMMapPage( gVMKernelL0Table, UARTPhys, VMPhysToHHDM(UARTPhys), kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX ); + VMMMapPage( + gVMKernelL0Table, UARTPhys, UARTPhys, + kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX + ); + OSLog("UART mapped\n"); - for (Address offset = 0; offset < kernelSize; offset += kVMPageSize) { - VMMMapPage(gVMKernelL0Table, kernelPhysStart + offset, kernelPhysStart + offset, kPTENormalMem | kPTEAccessRW); - } - info->framebuffer.base = (BIUInt32*)kVMFbVirtBase;; + OSLog("Enabling MMU...\n"); CPUEnableMMU(gVMKernelL0Physical); isInitialized = true; } \ No newline at end of file -- 2.52.0 From 7935a6132e3a6b735a64614188f606171604b083 Mon Sep 17 00:00:00 2001 From: karina Date: Mon, 27 Apr 2026 07:02:56 +0400 Subject: [PATCH 32/49] ref: cleaned code a bit --- Kernel/Source/Lib/Stubs.c | 11 +---------- Kernel/Source/VM/VMM.c | 3 +-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/Kernel/Source/Lib/Stubs.c b/Kernel/Source/Lib/Stubs.c index 6a223be..4133542 100644 --- a/Kernel/Source/Lib/Stubs.c +++ b/Kernel/Source/Lib/Stubs.c @@ -3,13 +3,4 @@ void* memset(void* destination, int value, Size count) { return MemorySet(destination, value, count); -} - -// A little bit of Monica in my life -// A little bit of Erica by my side -// A little bit of Rita's all I need -// A little bit of Tina's what I see -// A little bit of Sandra in the sun -// A little bit of Mary all night long -// A little bit of Jessica, here I am -// A little bit of you makes me your man \ No newline at end of file +} \ No newline at end of file diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c index f279528..7e4cec2 100644 --- a/Kernel/Source/VM/VMM.c +++ b/Kernel/Source/VM/VMM.c @@ -3,12 +3,11 @@ #include #include #include +#include #include "../Common/bootinfo.h" -#include "OS/Log.h" static const UInt64 kPTEAddressMask = 0x0000FFFFFFFFF000ULL; static inline Address GetPTEAddress(UInt64 entry) { return entry & kPTEAddressMask; } -static inline UInt64 GetPTEFlags(UInt64 entry) { return entry & ~kPTEAddressMask; } static inline UInt16 GetL0Index(Address virt) { return (virt >> 39) & 0x1FF; } static inline UInt16 GetL1Index(Address virt) { return (virt >> 30) & 0x1FF; } static inline UInt16 GetL2Index(Address virt) { return (virt >> 21) & 0x1FF; } -- 2.52.0 From 7fcb50587e268efad83a6a8d2dd06d39864badb2 Mon Sep 17 00:00:00 2001 From: karina Date: Wed, 29 Apr 2026 08:46:13 +0400 Subject: [PATCH 33/49] feat: GICv2 and timer fix: TimerReset in GIC.c now uses kTimerFrequency --- Kernel/Include/Arch/CPU.h | 2 +- Kernel/Include/Arch/GIC.h | 28 ++++++++++++++ Kernel/Include/Arch/Timer.h | 8 ++++ Kernel/Include/VM/PMM.h | 6 +++ Kernel/Source/Arch/DTB.c | 9 +++++ Kernel/Source/Arch/Exceptions.c | 7 +++- Kernel/Source/Arch/GIC.c | 65 +++++++++++++++++++++++++++++++++ Kernel/Source/Arch/Timer.c | 14 +++++++ Kernel/Source/KernelMain.c | 13 ++++++- Kernel/Source/VM/VMM.c | 34 ++++++++++++++++- 10 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 Kernel/Include/Arch/GIC.h create mode 100644 Kernel/Include/Arch/Timer.h create mode 100644 Kernel/Source/Arch/GIC.c create mode 100644 Kernel/Source/Arch/Timer.c diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index df5c60c..ad69c8a 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -72,4 +72,4 @@ static inline void CPUEnableMMU(Address l0PhysicalAddress) { "isb\n" : "=r"(sctlr) : "r"(sctlr_flags) : "memory" ); -} \ No newline at end of file +} diff --git a/Kernel/Include/Arch/GIC.h b/Kernel/Include/Arch/GIC.h new file mode 100644 index 0000000..0978e16 --- /dev/null +++ b/Kernel/Include/Arch/GIC.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include + +enum { + kGICDBaseAddress = 0x08000000, + kGICCBaseAddress = kGICDBaseAddress + 0x10000, + + // GIC Distributor (GICD), offsets from GICD base + kGICDCTLR = 0x000, // control + kGICDTYPER = 0x004, // controller type + kGICDISENABLER = 0x100, // interrupt set-enable + kGICDICENABLER = 0x180, // interrupt clear-enable + kGICDICPENDR = 0x280, // interrupt clear-pending + kGICDIPRIORITYR = 0x400, // interrupt priority + kGICDITARGETSR = 0x800, // interrupt processor targets + + // GIC CPU interface (GICC), offsets from CPU interface base + kGICCCTLR = 0x000, // CPU interface control + kGICCPMR = 0x004, // priority mask + kGICCIAR = 0x00C, // interrupt acknowledge + kGICCEOIR = 0x010, // end of interrupt +}; + +void GICInitialize(Pointer gicdVirtBase, Pointer giccVirtBase); +void GICEnableInterrupt(UInt32 irqID); +void GICDispatch(ExceptionsType type); diff --git a/Kernel/Include/Arch/Timer.h b/Kernel/Include/Arch/Timer.h new file mode 100644 index 0000000..eb93df6 --- /dev/null +++ b/Kernel/Include/Arch/Timer.h @@ -0,0 +1,8 @@ +#pragma once +#include + +static const UInt64 kTimerFrequency = 1000; // 1ms +static const UInt8 kTimerIRQ = 30; + +void TimerInitialize(); +void TimerReset(UInt64 interval); \ No newline at end of file diff --git a/Kernel/Include/VM/PMM.h b/Kernel/Include/VM/PMM.h index 1ee4399..cd45223 100644 --- a/Kernel/Include/VM/PMM.h +++ b/Kernel/Include/VM/PMM.h @@ -13,12 +13,18 @@ typedef struct { Size size; } VMMemoryRegion; +typedef struct { + VMMemoryRegion GICD; + VMMemoryRegion GICC; +} GICRegion; + typedef struct { VMMemoryRegion totalRAM; VMMemoryRegion reserved[kVMMaxReservedRegions]; UInt32 reservedCount; VMMemoryRegion UART; + GICRegion GIC; } VMBootMemoryMap; void PMMInitialize(VMBootMemoryMap* bootMap); diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index 238fa97..9d638a2 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -77,6 +77,15 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { bootMap->UART.base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); bootMap->UART.size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); } + else if (StringStartsWith(currentNode, "intc")) { + UInt32* cells = (UInt32*)structs; + + bootMap->GIC.GICD.base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); + bootMap->GIC.GICD.size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); + + bootMap->GIC.GICC.base = Merge32To64(BytesSwap32(cells[5]), BytesSwap32(cells[4])); + bootMap->GIC.GICC.size = Merge32To64(BytesSwap32(cells[7]), BytesSwap32(cells[6])); + } } structs += propertyLength; diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c index b3aa22d..a2b93fd 100644 --- a/Kernel/Source/Arch/Exceptions.c +++ b/Kernel/Source/Arch/Exceptions.c @@ -1,8 +1,11 @@ #include #include +#include #include #include -void ExceptionsHandler(ExceptionsContext* frame, [[maybe_unused]]ExceptionsType type) { +void ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) { + if (type == ExceptionsIRQEl1h || type == ExceptionsIRQEl064) return GICDispatch(type); OSPanicException(frame); -} \ No newline at end of file +} + diff --git a/Kernel/Source/Arch/GIC.c b/Kernel/Source/Arch/GIC.c new file mode 100644 index 0000000..732f096 --- /dev/null +++ b/Kernel/Source/Arch/GIC.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +static volatile UInt32* GICD = nullptr; +static volatile UInt32* GICC = nullptr; + +void GICInitialize(Pointer gicdVirtBase, Pointer giccVirtBase) { + GICD = (volatile UInt32*)gicdVirtBase; + GICC = (volatile UInt32*)giccVirtBase; + + GICD[kGICDCTLR / 4] = 0; // disable Distributor (gicd) + UInt32 typer = GICD[kGICDTYPER / 4]; // how many interrupts are supported + UInt32 maxIRQS = 32 * ((typer & 0x1F) + 1); // total number of interrupts + OSLog("GIC: maxIRQS: %d\n", maxIRQS); + + for (UInt32 i = 0; i < maxIRQS / 32; i++) { + GICD[kGICDICENABLER / 4 + i] = 0xFFFFFFFF; // clear enable + GICD[kGICDICPENDR / 4 + i] = 0xFFFFFFFF; // clear pending + } + + for (UInt32 i = 0; i < maxIRQS / 4; i++) { + GICD[kGICDIPRIORITYR / 4 + i] = 0xA0A0A0A0; // set priority 0xA0 for all interrupts + } + + for (UInt32 i = 8; i < maxIRQS / 4; i++) { + GICD[kGICDITARGETSR / 4 + i] = 0x01010101; // set interrupts id >= 32 for CPU 0 + } + + GICD[kGICDCTLR / 4] = 1; // enable Distributor (gicd) + + GICC[kGICCCTLR / 4] = 0; // disable cpu interface + GICC[kGICCPMR / 4] = 0xFF; // set lowest priority (accept all interrupts) + GICC[kGICCCTLR / 4] = 1; // enable CPU interface (gicc) + + OSLog("GICv2 initialized.\n"); +} + +void GICEnableInterrupt(UInt32 irqID) { + UInt32 regOffset = irqID / 32; + UInt32 bitMask = 1 << (irqID % 32); + + GICD[kGICDISENABLER / 4 + regOffset] = bitMask; +} + +UInt32 GICCReadIAR(void) { + return GICC[kGICCIAR / 4]; +} + +void GICCWriteEOIR(UInt32 irqID) { + GICC[kGICCEOIR / 4] = irqID; +} + +void GICDispatch(ExceptionsType type) { + if (type != ExceptionsIRQEl1h && type != ExceptionsIRQEl064) return; + UInt32 irqID = GICCReadIAR() & 0x3FF; + if (irqID == 1023) return; // spurious interrupt + + if (irqID == 30) { + TimerReset(kTimerFrequency); + } + + GICCWriteEOIR(irqID); +} diff --git a/Kernel/Source/Arch/Timer.c b/Kernel/Source/Arch/Timer.c new file mode 100644 index 0000000..4967695 --- /dev/null +++ b/Kernel/Source/Arch/Timer.c @@ -0,0 +1,14 @@ +#include +#include + +void TimerInitialize() { + GICEnableInterrupt(kTimerIRQ); + TimerReset(kTimerFrequency); +} + +void TimerReset(UInt64 interval) { + UInt64 frequency; + __asm__ volatile ("mrs %0, cntfrq_el0" : "=r"(frequency)); + __asm__ volatile ("msr cntp_tval_el0, %0" :: "r"(frequency /interval)); + __asm__ volatile ("msr cntp_ctl_el0, %0" :: "r" (1)); +} diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index fc0ba27..60c6007 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,5 +1,8 @@ #include "../Common/bootinfo.h" #include +#include +#include +#include #include #include #include @@ -15,9 +18,17 @@ void KernelMain(Bootinfo* bootinfo) { VMBootMemoryMap bootMap = {0}; bootMap.reservedCount = 0; DTBParse(bootinfo->dtb, &bootMap); + PMMInitialize(&bootMap); VMMInitialize(&bootMap, bootinfo); HeapInitialize(); + GICInitialize( + (Pointer)VMPhysToHHDM(bootMap.GIC.GICD.base), + (Pointer)VMPhysToHHDM(bootMap.GIC.GICC.base) + ); + TimerInitialize(); + CPUEnableInterrupts(); + OSLog("Kernel initialized.\n"); -} \ No newline at end of file +} diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c index 7e4cec2..ccbf659 100644 --- a/Kernel/Source/VM/VMM.c +++ b/Kernel/Source/VM/VMM.c @@ -197,7 +197,39 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { ); OSLog("UART mapped\n"); - info->framebuffer.base = (BIUInt32*)kVMFbVirtBase;; + Address gicdPhys = bootMap->GIC.GICD.base; + Size gicdSize = bootMap->GIC.GICD.size; + if (!gicdPhys) { + gicdPhys = 0x08000000; // QEMU fallback + gicdSize = 0x10000; + } + + for (Address offset = 0; offset < gicdSize; offset += kVMPageSize) { + VMMMapPage( + gVMKernelL0Table, gicdPhys + offset, + VMPhysToHHDM(gicdPhys + offset), + kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX + ); + } + OSLog("GICD mapped\n"); + + Address giccPhys = bootMap->GIC.GICC.base; + Size giccSize = bootMap->GIC.GICC.size; + if (!giccPhys) { + giccPhys = 0x08001000; // QEMU fallback + giccSize = 0x10000; + } + + for (Address offset = 0; offset < giccSize; offset += kVMPageSize) { + VMMMapPage( + gVMKernelL0Table, giccPhys + offset, + VMPhysToHHDM(giccPhys + offset), + kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX + ); + } + OSLog("GICC mapped\n"); + + info->framebuffer.base = (BIUInt32*)kVMFbVirtBase; OSLog("Enabling MMU...\n"); CPUEnableMMU(gVMKernelL0Physical); isInitialized = true; -- 2.52.0 From 8d675abae95e5583a7dc335ce6f49800b5529e9e Mon Sep 17 00:00:00 2001 From: karina Date: Wed, 29 Apr 2026 08:56:34 +0400 Subject: [PATCH 34/49] fix: changed phyisical timer to virtual timer --- Kernel/Include/Arch/Timer.h | 2 +- Kernel/Source/Arch/GIC.c | 4 +++- Kernel/Source/Arch/Timer.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Kernel/Include/Arch/Timer.h b/Kernel/Include/Arch/Timer.h index eb93df6..3fbe2e4 100644 --- a/Kernel/Include/Arch/Timer.h +++ b/Kernel/Include/Arch/Timer.h @@ -2,7 +2,7 @@ #include static const UInt64 kTimerFrequency = 1000; // 1ms -static const UInt8 kTimerIRQ = 30; +static const UInt8 kTimerIRQ = 27; void TimerInitialize(); void TimerReset(UInt64 interval); \ No newline at end of file diff --git a/Kernel/Source/Arch/GIC.c b/Kernel/Source/Arch/GIC.c index 732f096..c98326b 100644 --- a/Kernel/Source/Arch/GIC.c +++ b/Kernel/Source/Arch/GIC.c @@ -53,11 +53,13 @@ void GICCWriteEOIR(UInt32 irqID) { } void GICDispatch(ExceptionsType type) { + OSLog("GICDispatch: %d\n", type); if (type != ExceptionsIRQEl1h && type != ExceptionsIRQEl064) return; UInt32 irqID = GICCReadIAR() & 0x3FF; if (irqID == 1023) return; // spurious interrupt - if (irqID == 30) { + if (irqID == kTimerIRQ) { + OSLog("Timer IRQ\n"); TimerReset(kTimerFrequency); } diff --git a/Kernel/Source/Arch/Timer.c b/Kernel/Source/Arch/Timer.c index 4967695..7d875f3 100644 --- a/Kernel/Source/Arch/Timer.c +++ b/Kernel/Source/Arch/Timer.c @@ -9,6 +9,6 @@ void TimerInitialize() { void TimerReset(UInt64 interval) { UInt64 frequency; __asm__ volatile ("mrs %0, cntfrq_el0" : "=r"(frequency)); - __asm__ volatile ("msr cntp_tval_el0, %0" :: "r"(frequency /interval)); - __asm__ volatile ("msr cntp_ctl_el0, %0" :: "r" (1)); + __asm__ volatile ("msr cntv_tval_el0, %0" :: "r"(frequency /interval)); + __asm__ volatile ("msr cntv_ctl_el0, %0" :: "r" (1)); } -- 2.52.0 From f3e60da11d117401cdcd1229b7d7752c0a872996 Mon Sep 17 00:00:00 2001 From: karina Date: Wed, 29 Apr 2026 08:59:05 +0400 Subject: [PATCH 35/49] ref: cleaned debug logs --- Kernel/Source/Arch/GIC.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Kernel/Source/Arch/GIC.c b/Kernel/Source/Arch/GIC.c index c98326b..9cf1a48 100644 --- a/Kernel/Source/Arch/GIC.c +++ b/Kernel/Source/Arch/GIC.c @@ -53,13 +53,11 @@ void GICCWriteEOIR(UInt32 irqID) { } void GICDispatch(ExceptionsType type) { - OSLog("GICDispatch: %d\n", type); if (type != ExceptionsIRQEl1h && type != ExceptionsIRQEl064) return; UInt32 irqID = GICCReadIAR() & 0x3FF; if (irqID == 1023) return; // spurious interrupt if (irqID == kTimerIRQ) { - OSLog("Timer IRQ\n"); TimerReset(kTimerFrequency); } -- 2.52.0 From 3f51d93a4e1cf060662ae883de9f1e4124f42daf Mon Sep 17 00:00:00 2001 From: karina Date: Wed, 29 Apr 2026 09:35:22 +0400 Subject: [PATCH 36/49] fix(timer): fixed warning about implict casting int to UInt64 --- Kernel/Source/Arch/Timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kernel/Source/Arch/Timer.c b/Kernel/Source/Arch/Timer.c index 7d875f3..5553a60 100644 --- a/Kernel/Source/Arch/Timer.c +++ b/Kernel/Source/Arch/Timer.c @@ -10,5 +10,5 @@ void TimerReset(UInt64 interval) { UInt64 frequency; __asm__ volatile ("mrs %0, cntfrq_el0" : "=r"(frequency)); __asm__ volatile ("msr cntv_tval_el0, %0" :: "r"(frequency /interval)); - __asm__ volatile ("msr cntv_ctl_el0, %0" :: "r" (1)); + __asm__ volatile ("msr cntv_ctl_el0, %0" :: "r"((UInt64)1)); } -- 2.52.0 From e06abbcb23df5aba1b57f34a9751818cad84e480 Mon Sep 17 00:00:00 2001 From: karina Date: Wed, 29 Apr 2026 17:00:11 +0400 Subject: [PATCH 37/49] feat(scheduler): working scheduler --- Kernel/Include/Arch/CPU.h | 13 ++++ Kernel/Include/Arch/Exceptions.h | 2 + Kernel/Include/Arch/GIC.h | 2 +- Kernel/Include/Arch/Timer.h | 5 +- Kernel/Include/OS/Scheduler.h | 42 +++++++++++ Kernel/Source/Arch/Exceptions.c | 4 +- Kernel/Source/Arch/GIC.c | 12 ++-- Kernel/Source/Arch/Timer.c | 14 ++++ Kernel/Source/Arch/vectors.S | 9 ++- Kernel/Source/KernelMain.c | 4 ++ Kernel/Source/OS/Panic.c | 14 ++-- Kernel/Source/OS/Scheduler.c | 116 +++++++++++++++++++++++++++++++ 12 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 Kernel/Include/OS/Scheduler.h create mode 100644 Kernel/Source/OS/Scheduler.c diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index ad69c8a..db026f2 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -73,3 +73,16 @@ static inline void CPUEnableMMU(Address l0PhysicalAddress) { : "=r"(sctlr) : "r"(sctlr_flags) : "memory" ); } + +static inline void CPUSwitchAddressSpace(Address l0Physical) { + __asm__ volatile( + "dsb ishst\n" // wait till all previous writes are finished physically + "msr ttbr0_el1, %0\n" // Update TTBR0_EL1 (userspace) + "tlbi vmalle1is\n" // Reset TLB cache + "dsb ish\n" // wait for tlb cache to reset + "isb\n" // Clear instruction pipeline + :: "r" (l0Physical) : "memory" + ); +} + +#define CPUException(number) __asm__ volatile ("svc %0" :: "i" (number) : "memory") \ No newline at end of file diff --git a/Kernel/Include/Arch/Exceptions.h b/Kernel/Include/Arch/Exceptions.h index fe069c1..1a68681 100644 --- a/Kernel/Include/Arch/Exceptions.h +++ b/Kernel/Include/Arch/Exceptions.h @@ -36,6 +36,8 @@ typedef struct ExceptionsContext { UInt64 elr_el1; // pc UInt64 spsr_el1; // cpu status UInt64 esr_el1; // error reason + UInt64 sp_el0; // user's stack + UInt64 padding; // align to 16 bytes } ExceptionsContext; typedef enum ExceptionsType { diff --git a/Kernel/Include/Arch/GIC.h b/Kernel/Include/Arch/GIC.h index 0978e16..1f06c56 100644 --- a/Kernel/Include/Arch/GIC.h +++ b/Kernel/Include/Arch/GIC.h @@ -25,4 +25,4 @@ enum { void GICInitialize(Pointer gicdVirtBase, Pointer giccVirtBase); void GICEnableInterrupt(UInt32 irqID); -void GICDispatch(ExceptionsType type); +Address GICDispatch(ExceptionsContext* frame, ExceptionsType type); \ No newline at end of file diff --git a/Kernel/Include/Arch/Timer.h b/Kernel/Include/Arch/Timer.h index 3fbe2e4..4951a05 100644 --- a/Kernel/Include/Arch/Timer.h +++ b/Kernel/Include/Arch/Timer.h @@ -1,8 +1,11 @@ #pragma once #include +#include static const UInt64 kTimerFrequency = 1000; // 1ms static const UInt8 kTimerIRQ = 27; void TimerInitialize(); -void TimerReset(UInt64 interval); \ No newline at end of file +void TimerReset(UInt64 interval); +Address TimerHandler(ExceptionsContext* frame); +UInt64 TimerGetCounter(); \ No newline at end of file diff --git a/Kernel/Include/OS/Scheduler.h b/Kernel/Include/OS/Scheduler.h new file mode 100644 index 0000000..2dc4d5f --- /dev/null +++ b/Kernel/Include/OS/Scheduler.h @@ -0,0 +1,42 @@ +#pragma once +#include + +typedef enum OSTaskState { + OSTaskStateDead, + OSTaskStateRunning, + OSTaskStateReady, + OSTaskStateBlocked, + OSTaskStateSleeping, +} OSTaskState; + +typedef struct OSProcess { + UInt64 id; + OSTaskState state; + Address* l0Table; + Address heapStart; + Address heapCurrent; + struct OSProcess* parent; + ASCII name[32]; +} OSProcess; + +typedef struct OSTask { + Address stackPointer; + struct OSTask* next; + UInt32 id; + UInt32 sleepTicks; + OSTaskState state; + Address kernelStackTop; + Pointer kernelStackBase; + OSProcess* process; + Int32 waitingForProcessId; +} OSTask; + +enum { + kOSSchedulerTaskStackSize = 16 * 1024, + kOSSchedulerExceptionNumber = 0xF0F0 +}; + +void SchedulerInitialize(); +OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Address fixedUserStackAddress); +Address SchedulerNext(Address stackPointer); +void SchedulerYield(UInt64 ticks); \ No newline at end of file diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c index a2b93fd..20692ad 100644 --- a/Kernel/Source/Arch/Exceptions.c +++ b/Kernel/Source/Arch/Exceptions.c @@ -4,8 +4,8 @@ #include #include -void ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) { - if (type == ExceptionsIRQEl1h || type == ExceptionsIRQEl064) return GICDispatch(type); +Address ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) { + if (type == ExceptionsIRQEl1h || type == ExceptionsIRQEl064) return GICDispatch(frame, type); OSPanicException(frame); } diff --git a/Kernel/Source/Arch/GIC.c b/Kernel/Source/Arch/GIC.c index 9cf1a48..d751cea 100644 --- a/Kernel/Source/Arch/GIC.c +++ b/Kernel/Source/Arch/GIC.c @@ -52,14 +52,18 @@ void GICCWriteEOIR(UInt32 irqID) { GICC[kGICCEOIR / 4] = irqID; } -void GICDispatch(ExceptionsType type) { - if (type != ExceptionsIRQEl1h && type != ExceptionsIRQEl064) return; +Address GICDispatch(ExceptionsContext* frame, ExceptionsType type) { + if (type != ExceptionsIRQEl1h && type != ExceptionsIRQEl064) return (Address)frame; UInt32 irqID = GICCReadIAR() & 0x3FF; - if (irqID == 1023) return; // spurious interrupt + if (irqID == 1023) return (Address)frame; // spurious interrupt + + + Address newStackPointer = (Address)frame; if (irqID == kTimerIRQ) { - TimerReset(kTimerFrequency); + newStackPointer = TimerHandler(frame); } GICCWriteEOIR(irqID); + return newStackPointer; } diff --git a/Kernel/Source/Arch/Timer.c b/Kernel/Source/Arch/Timer.c index 5553a60..62b2e74 100644 --- a/Kernel/Source/Arch/Timer.c +++ b/Kernel/Source/Arch/Timer.c @@ -1,5 +1,9 @@ #include #include +#include +#include + +static volatile UInt64 sTimerCounter = 0; void TimerInitialize() { GICEnableInterrupt(kTimerIRQ); @@ -12,3 +16,13 @@ void TimerReset(UInt64 interval) { __asm__ volatile ("msr cntv_tval_el0, %0" :: "r"(frequency /interval)); __asm__ volatile ("msr cntv_ctl_el0, %0" :: "r"((UInt64)1)); } + +Address TimerHandler(ExceptionsContext* frame) { + sTimerCounter++; + TimerReset(kTimerFrequency); + return SchedulerNext((Address)frame); +} + +UInt64 TimerGetCounter() { + return sTimerCounter; +} diff --git a/Kernel/Source/Arch/vectors.S b/Kernel/Source/Arch/vectors.S index 05e183e..59db0d4 100644 --- a/Kernel/Source/Arch/vectors.S +++ b/Kernel/Source/Arch/vectors.S @@ -1,6 +1,6 @@ .macro ventry type .align 7 - sub sp, sp, #272 // save 272 bytes of stack + sub sp, sp, #288 // save 288 bytes of stack stp x0, x1, [sp, #0] // move stack mov x1, #\type // move type to x1 b ExceptionsTrapEntry @@ -50,12 +50,17 @@ ExceptionsTrapEntry: mrs x21, elr_el1 mrs x22, spsr_el1 mrs x23, esr_el1 + mrs x24, sp_el0 stp x30, x21, [sp, #16 * 15] stp x22, x23, [sp, #16 * 16] mov x0, sp bl ExceptionsHandler + mov sp, x0 + + ldp x24, xzr, [sp, #16 * 17] + msr sp_el0, x24 ldp x22, x23, [sp, #16 * 16] msr spsr_el1, x22 @@ -79,7 +84,7 @@ ExceptionsTrapEntry: ldp x2, x3, [sp, #16 * 1] ldp x0, x1, [sp, #0] - add sp, sp, #272 + add sp, sp, #288 eret .global ExceptionsVectorsInit diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 60c6007..e72433e 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -8,6 +8,7 @@ #include #include #include +#include void KernelMain(Bootinfo* bootinfo) { OSLog("Kernel started.\n"); @@ -16,6 +17,7 @@ void KernelMain(Bootinfo* bootinfo) { } VMBootMemoryMap bootMap = {0}; + bootMap.reservedCount = 0; DTBParse(bootinfo->dtb, &bootMap); @@ -30,5 +32,7 @@ void KernelMain(Bootinfo* bootinfo) { TimerInitialize(); CPUEnableInterrupts(); + SchedulerInitialize(); + OSLog("Kernel initialized.\n"); } diff --git a/Kernel/Source/OS/Panic.c b/Kernel/Source/OS/Panic.c index 56ed5d2..4d962da 100644 --- a/Kernel/Source/OS/Panic.c +++ b/Kernel/Source/OS/Panic.c @@ -93,11 +93,11 @@ __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { PrintSeparator(); OSLog("Registers:\n"); PrintSeparator(); - OSLog("x0 = 0x%X; x1 = 0x%X\n", frame->x0, frame->x1); - OSLog("x2 = 0x%X; x3 = 0x%X\n", frame->x2, frame->x3); - OSLog("x4 = 0x%X; x5 = 0x%X\n", frame->x4, frame->x5); - OSLog("x6 = 0x%X; x7 = 0x%X\n", frame->x6, frame->x7); - OSLog("x8 = 0x%X; x9 = 0x%X\n", frame->x8, frame->x9); + OSLog("x0 = 0x%X; x1 = 0x%X\n", frame->x0, frame->x1); + OSLog("x2 = 0x%X; x3 = 0x%X\n", frame->x2, frame->x3); + OSLog("x4 = 0x%X; x5 = 0x%X\n", frame->x4, frame->x5); + OSLog("x6 = 0x%X; x7 = 0x%X\n", frame->x6, frame->x7); + OSLog("x8 = 0x%X; x9 = 0x%X\n", frame->x8, frame->x9); OSLog("x10 = 0x%X; x11 = 0x%X\n", frame->x10, frame->x11); OSLog("x12 = 0x%X; x13 = 0x%X\n", frame->x12, frame->x13); OSLog("x14 = 0x%X; x15 = 0x%X\n", frame->x14, frame->x15); @@ -107,8 +107,8 @@ __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { OSLog("x22 = 0x%X; x23 = 0x%X\n", frame->x22, frame->x23); OSLog("x24 = 0x%X; x25 = 0x%X\n", frame->x24, frame->x25); OSLog("x26 = 0x%X; x27 = 0x%X\n", frame->x26, frame->x27); - OSLog("\t\tx28 = 0x%X\n", frame->x28); - OSLog("FP = 0x%X; LR = 0x%X\n", frame->x29, frame->x30); + OSLog("\t x28 = 0x%X\n", frame->x28); + OSLog("FP = 0x%X; LR = 0x%X\n", frame->x29, frame->x30); DrawPanicFooter(); Halt(); diff --git a/Kernel/Source/OS/Scheduler.c b/Kernel/Source/OS/Scheduler.c new file mode 100644 index 0000000..a818f13 --- /dev/null +++ b/Kernel/Source/OS/Scheduler.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +OSTask* gOSSchedulerCurrentTask = nullptr; +UInt32 gOSSchedulerNextProcessID = 1; + +static OSProcess sOSSchedulerKernelProcess; + +void SchedulerInitialize() { + sOSSchedulerKernelProcess.id = 0; + sOSSchedulerKernelProcess.state = OSTaskStateRunning; + sOSSchedulerKernelProcess.l0Table = gVMKernelL0Table; + StringCopy(sOSSchedulerKernelProcess.name, "kernel"); + + OSTask* kernelTask = (OSTask*)HeapAllocate(sizeof(OSTask)); + if (!kernelTask) OSPanic("Failed to allocate kernel task"); + + MemorySet(kernelTask, 0, sizeof(OSTask)); + kernelTask->id = 0; + kernelTask->process = &sOSSchedulerKernelProcess; + kernelTask->sleepTicks = 0; + kernelTask->next = kernelTask; + kernelTask->state = OSTaskStateRunning; + kernelTask->waitingForProcessId = -1; + + gOSSchedulerCurrentTask = kernelTask; +} + +OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Address fixedUserStackAddress) { + OSTask* task = (OSTask*)HeapAllocate(sizeof(OSTask)); + Pointer stackBase = nullptr; + if (!task) goto cleanup; + + if (!owner) owner = &sOSSchedulerKernelProcess; + Size stackSize = kOSSchedulerTaskStackSize; + stackBase = HeapAllocate(stackSize); + if (!stackBase) goto cleanup; + + Address stackPointer = (Address)stackBase + stackSize; + stackPointer -= sizeof(ExceptionsContext); + stackPointer = AlignDown64(stackPointer, 16); + ExceptionsContext* context = (ExceptionsContext*)stackPointer; + MemorySet(context, 0, sizeof(ExceptionsContext)); + context->elr_el1 = (Address)entryPoint; + + if (isUser) { + context->spsr_el1 = 0x00000000; // El0t (M[3:0] = 0b0000) allow interrupts + context->sp_el0 = fixedUserStackAddress; + } else { + context->spsr_el1 = 0x00000005; // El1h (M[3:0] = 0b0101) allow interrupts + } + + task->stackPointer = stackPointer; + task->process = owner; + task->id = owner->id; + task->sleepTicks = 0; + task->kernelStackBase = stackBase; + task->kernelStackTop = (Address)stackBase + stackSize; + task->state = OSTaskStateRunning; + task->waitingForProcessId = -1; + + task->next = gOSSchedulerCurrentTask->next; + gOSSchedulerCurrentTask->next = task; + + return task; +cleanup: + if (task) HeapFree(task); + if (stackBase) HeapFree(stackBase); + return nullptr; +} + +Address SchedulerNext(Address stackPointer) { + if (!gOSSchedulerCurrentTask) return stackPointer; + + gOSSchedulerCurrentTask->stackPointer = stackPointer; + OSTask* taskIterator = gOSSchedulerCurrentTask->next; + + do { + if (taskIterator->sleepTicks > 0) taskIterator->sleepTicks--; + taskIterator = taskIterator->next; + } while (taskIterator != gOSSchedulerCurrentTask->next); + + if (gOSSchedulerCurrentTask->sleepTicks > 0) gOSSchedulerCurrentTask->sleepTicks--; + + OSTask* nextTask = gOSSchedulerCurrentTask->next; + loop { + if (nextTask->state == OSTaskStateSleeping && nextTask->sleepTicks == 0) nextTask->state = OSTaskStateRunning; + if (nextTask->state == OSTaskStateRunning) break; + nextTask = nextTask->next; + + if (nextTask == gOSSchedulerCurrentTask) { + if (gOSSchedulerCurrentTask->state == OSTaskStateRunning) break; + OSPanic("No running tasks"); + } + } + + if (nextTask->process->l0Table != gOSSchedulerCurrentTask->process->l0Table) { + Address physicalL0Table = VMHHDMToPhys((Address)nextTask->process->l0Table); + CPUSwitchAddressSpace(physicalL0Table); + } + gOSSchedulerCurrentTask = nextTask; + + return gOSSchedulerCurrentTask->stackPointer; +} + +void SchedulerYield(UInt64 ticks) { + gOSSchedulerCurrentTask->sleepTicks = ticks; + gOSSchedulerCurrentTask->state = OSTaskStateSleeping; + CPUException(kOSSchedulerExceptionNumber); +} \ No newline at end of file -- 2.52.0 From b519e69fbd164bd36d140bd8bd912b264e13e3fa Mon Sep 17 00:00:00 2001 From: karina Date: Thu, 30 Apr 2026 13:09:59 +0400 Subject: [PATCH 38/49] feat(panic): funMessages in panic feat(rand): also implemented rand --- Kernel/Include/Lib/Rand.h | 18 ++++++++++++++++++ Kernel/Source/KernelMain.c | 1 - Kernel/Source/OS/Panic.c | 22 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 Kernel/Include/Lib/Rand.h diff --git a/Kernel/Include/Lib/Rand.h b/Kernel/Include/Lib/Rand.h new file mode 100644 index 0000000..93b11af --- /dev/null +++ b/Kernel/Include/Lib/Rand.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +enum { + kRandSeed = 0x9E3779B97F4A7C15ULL, + kRandMultiplier = 0xBF58476D1CE4E5B9ULL, + kRandIncrement = 0x94D049BB133111EBULL, +}; + +static inline UInt64 Rand() { + static _Atomic UInt64 sequence = 0; + + UInt64 z = (TimerGetCounter() + kRandSeed + (++sequence)); + z = (z ^ (z >> 30)) * kRandMultiplier; + z = (z ^ (z >> 27)) * kRandIncrement; + return z ^ (z >> 31); +} diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index e72433e..a94658e 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -31,7 +31,6 @@ void KernelMain(Bootinfo* bootinfo) { ); TimerInitialize(); CPUEnableInterrupts(); - SchedulerInitialize(); OSLog("Kernel initialized.\n"); diff --git a/Kernel/Source/OS/Panic.c b/Kernel/Source/OS/Panic.c index 4d962da..51140a7 100644 --- a/Kernel/Source/OS/Panic.c +++ b/Kernel/Source/OS/Panic.c @@ -1,6 +1,7 @@ #include #include #include +#include static const ASCII* GetExceptionClassString(UInt32 class) { switch (class) { @@ -20,6 +21,24 @@ static const ASCII* GetExceptionClassString(UInt32 class) { } } +static const ASCII* sFunMessages[] = { + "Execution finished abnormally with code: 0x_x", + "Ah shit, here we go again", + "It's definitely your fault.", + "No more Roblox!", + "Call your mom 4 help!", + "2bad4u", + "Touch grass", + "Skill issue", + "You should just go outside actually", + "Perfect opportunity to take a shower", + "404 not found", + "Windows is locked! Password:___ Time left: 5:45:41", + "\"NAM PIZDA\": hackers dropped our registry", + "That's all, folks!", + "rip", +}; + __attribute__((noreturn)) static void Halt() { loop { CPUDisableInterrupts(); @@ -36,6 +55,9 @@ static void DrawPanicHeader() { PrintSeparator(); OSLog("\tKernel Panic! :(\n"); PrintSeparator(); + UInt64 funMessagesCount = sizeof(sFunMessages) / sizeof(sFunMessages[0]); + OSLog("\t%s\n", sFunMessages[Rand() % funMessagesCount]); + PrintSeparator(); } static void DrawPanicFooter() { -- 2.52.0 From 272b9c899824353b4c61d633d00dd7541b9c40ce Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 2 May 2026 22:43:32 +0400 Subject: [PATCH 39/49] chore: general cleanup in code (removed unused includes and cosmetic stuff --- Kernel/Include/Arch/GIC.h | 1 - Kernel/Include/Arch/Timer.h | 6 ++++-- Kernel/Include/VM/Heap.h | 2 +- Kernel/Include/VM/PMM.h | 1 - Kernel/Include/VM/VMM.h | 3 ++- Kernel/Source/Arch/DTB.c | 1 - Kernel/Source/Arch/Exceptions.c | 2 -- Kernel/Source/VM/Heap.c | 2 +- Kernel/Source/VM/PMM.c | 6 +++--- Kernel/Source/VM/VMM.c | 2 +- 10 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Kernel/Include/Arch/GIC.h b/Kernel/Include/Arch/GIC.h index 1f06c56..a89b26f 100644 --- a/Kernel/Include/Arch/GIC.h +++ b/Kernel/Include/Arch/GIC.h @@ -1,6 +1,5 @@ #pragma once #include -#include #include enum { diff --git a/Kernel/Include/Arch/Timer.h b/Kernel/Include/Arch/Timer.h index 4951a05..f9fb0e4 100644 --- a/Kernel/Include/Arch/Timer.h +++ b/Kernel/Include/Arch/Timer.h @@ -2,8 +2,10 @@ #include #include -static const UInt64 kTimerFrequency = 1000; // 1ms -static const UInt8 kTimerIRQ = 27; +enum { + kTimerFrequency = 1000, // 1ms + kTimerIRQ = 27, +}; void TimerInitialize(); void TimerReset(UInt64 interval); diff --git a/Kernel/Include/VM/Heap.h b/Kernel/Include/VM/Heap.h index c76a94d..da04352 100644 --- a/Kernel/Include/VM/Heap.h +++ b/Kernel/Include/VM/Heap.h @@ -15,7 +15,7 @@ typedef struct __attribute__((aligned(16))) VMHeapBlockHeader { struct VMHeapBlockHeader* next; struct VMHeapBlockHeader* previous; UInt64 size; - bool isFree; + Boolean isFree; } VMHeapBlockHeader; void HeapInitialize(); diff --git a/Kernel/Include/VM/PMM.h b/Kernel/Include/VM/PMM.h index cd45223..e7eb1e4 100644 --- a/Kernel/Include/VM/PMM.h +++ b/Kernel/Include/VM/PMM.h @@ -1,6 +1,5 @@ #pragma once #include -#include "../Common/bootinfo.h" enum { kVMPageSize = 4096, diff --git a/Kernel/Include/VM/VMM.h b/Kernel/Include/VM/VMM.h index 1b6d0b9..568763d 100644 --- a/Kernel/Include/VM/VMM.h +++ b/Kernel/Include/VM/VMM.h @@ -25,11 +25,12 @@ enum { kVMKernelVMA = 0xFFFFFFFF80000000, kHHDMOffset = 0xFFFF888000000000, kVMFbVirtBase = 0xFFFFFFFFFC000000, + kKernelPhysBase = 0x40100000, }; static inline Address VMKernelVirtToPhys(Address virt) { - return virt - 0xFFFFFFFF80100000 + 0x40100000; // TODO: hardcode is awful + return virt - 0xFFFFFFFF80100000 + kKernelPhysBase; } static inline Address VMPhysToHHDM(Address phys) { diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index 9d638a2..c57cfeb 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c index 20692ad..70f3a1e 100644 --- a/Kernel/Source/Arch/Exceptions.c +++ b/Kernel/Source/Arch/Exceptions.c @@ -1,7 +1,5 @@ #include -#include #include -#include #include Address ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) { diff --git a/Kernel/Source/VM/Heap.c b/Kernel/Source/VM/Heap.c index a230b16..6735e55 100644 --- a/Kernel/Source/VM/Heap.c +++ b/Kernel/Source/VM/Heap.c @@ -10,7 +10,7 @@ static void CombineForward(VMHeapBlockHeader* current) { if (!current->next || !current->next->isFree) return; current->size += sizeof(VMHeapBlockHeader) + current->next->size; current->next = current->next->next; - if (current->next) current->next->previous = current; // what the fuck + if (current->next) current->next->previous = current; } void HeapInitialize() { diff --git a/Kernel/Source/VM/PMM.c b/Kernel/Source/VM/PMM.c index e346d48..723d3c0 100644 --- a/Kernel/Source/VM/PMM.c +++ b/Kernel/Source/VM/PMM.c @@ -54,9 +54,9 @@ void PMMInitialize(VMBootMemoryMap* bootMap) { Size pagesToReserve = (regionSize + kVMPageSize - 1) / kVMPageSize; for (Size p = 0; p < pagesToReserve; p++) { - Address pageAdress = regionBase + (p * kVMPageSize); - if (pageAdress >= sPMMRamBase && pageAdress < (sPMMRamBase + bootMap->totalRAM.size)) { - BitmapSet(sPMMBitmap, pageAdress); + Address pageAddress = regionBase + (p * kVMPageSize); + if (pageAddress >= sPMMRamBase && pageAddress < (sPMMRamBase + bootMap->totalRAM.size)) { + BitmapSet(sPMMBitmap, pageAddress); } } } diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c index ccbf659..1d7bc05 100644 --- a/Kernel/Source/VM/VMM.c +++ b/Kernel/Source/VM/VMM.c @@ -159,7 +159,7 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { Size kernelSize = ((Address)_kernelEnd - (Address)_kernelStart) + pmmBitmapSize; kernelSize = (kernelSize + kVMPageSize - 1) & ~(kVMPageSize - 1); - Address kernelPhysStart = 0x40100000; // TODO: hardcode is awful + Address kernelPhysStart = kKernelPhysBase; for (Address offset = 0; offset < kernelSize; offset += kVMPageSize) { Address phys = kernelPhysStart + offset; -- 2.52.0 From 5673c44a99a2c17e3796d91fef9b1d72a07789d6 Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 2 May 2026 23:01:40 +0400 Subject: [PATCH 40/49] fix: scheduler L0 table confusion, PMM bitmap rounding, dead task handling --- Kernel/Source/Arch/DTB.c | 2 +- Kernel/Source/OS/Scheduler.c | 7 ++++++- Kernel/Source/VM/PMM.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index c57cfeb..961a1f6 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -25,7 +25,7 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { ASCII* currentNode = ""; UInt32 currentDepth = 0; UInt32 reservedMemoryDepth = 0; - bool inReservedMemory = false; + Boolean inReservedMemory = false; while (true) { UInt32 token = BytesSwap32(*(UInt32*)structs); diff --git a/Kernel/Source/OS/Scheduler.c b/Kernel/Source/OS/Scheduler.c index a818f13..3310c91 100644 --- a/Kernel/Source/OS/Scheduler.c +++ b/Kernel/Source/OS/Scheduler.c @@ -15,7 +15,7 @@ static OSProcess sOSSchedulerKernelProcess; void SchedulerInitialize() { sOSSchedulerKernelProcess.id = 0; sOSSchedulerKernelProcess.state = OSTaskStateRunning; - sOSSchedulerKernelProcess.l0Table = gVMKernelL0Table; + sOSSchedulerKernelProcess.l0Table = (Address*)VMPhysToHHDM((Address)gVMKernelL0Table); StringCopy(sOSSchedulerKernelProcess.name, "kernel"); OSTask* kernelTask = (OSTask*)HeapAllocate(sizeof(OSTask)); @@ -90,6 +90,11 @@ Address SchedulerNext(Address stackPointer) { OSTask* nextTask = gOSSchedulerCurrentTask->next; loop { + if (nextTask->state == OSTaskStateDead) { + nextTask = nextTask->next; + if (nextTask == gOSSchedulerCurrentTask) OSPanic("No running tasks"); + continue; + } if (nextTask->state == OSTaskStateSleeping && nextTask->sleepTicks == 0) nextTask->state = OSTaskStateRunning; if (nextTask->state == OSTaskStateRunning) break; nextTask = nextTask->next; diff --git a/Kernel/Source/VM/PMM.c b/Kernel/Source/VM/PMM.c index 723d3c0..d1095db 100644 --- a/Kernel/Source/VM/PMM.c +++ b/Kernel/Source/VM/PMM.c @@ -28,7 +28,7 @@ static inline void BitmapUnset(MemoryPointer bitmap, Address address) { void PMMInitialize(VMBootMemoryMap* bootMap) { sPMMRamBase = bootMap->totalRAM.base; sPMMTotalPages = bootMap->totalRAM.size / kVMPageSize; - sPMMBitmapSize = sPMMTotalPages / kVMBlocksPerByte; + sPMMBitmapSize = (sPMMTotalPages + kVMBlocksPerByte - 1) / kVMBlocksPerByte; sPMMBitmap = (MemoryPointer)_kernelEnd; MemorySet(sPMMBitmap, 0, sPMMBitmapSize); -- 2.52.0 From 7ff9f4ad4c9fd828e030c379de5fa6540396f2c6 Mon Sep 17 00:00:00 2001 From: karina Date: Sat, 2 May 2026 23:17:09 +0400 Subject: [PATCH 41/49] fix: use rounded bitmap size in VMM kernel mapping calculation --- Kernel/Source/VM/VMM.c | 53 +++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c index 1d7bc05..d0af705 100644 --- a/Kernel/Source/VM/VMM.c +++ b/Kernel/Source/VM/VMM.c @@ -8,9 +8,9 @@ static const UInt64 kPTEAddressMask = 0x0000FFFFFFFFF000ULL; static inline Address GetPTEAddress(UInt64 entry) { return entry & kPTEAddressMask; } -static inline UInt16 GetL0Index(Address virt) { return (virt >> 39) & 0x1FF; } -static inline UInt16 GetL1Index(Address virt) { return (virt >> 30) & 0x1FF; } -static inline UInt16 GetL2Index(Address virt) { return (virt >> 21) & 0x1FF; } +static inline UInt16 GetL0Index(Address virt) { return (virt >> 39) & 0x1FF; } +static inline UInt16 GetL1Index(Address virt) { return (virt >> 30) & 0x1FF; } +static inline UInt16 GetL2Index(Address virt) { return (virt >> 21) & 0x1FF; } static inline UInt16 GetL3Index(Address virt) { return (virt >> 12) & 0x1FF; } static Boolean isInitialized = false; @@ -33,13 +33,13 @@ static inline Address* GetOrAllocateTable(Address* parentTable, Size index, UInt Address* newTableVirt = GetVirtualTable((Address)newTable); MemorySet(newTableVirt, 0, kVMPageSize); - + parentTable[index] = (Address)newTable | directoryFlags; return newTableVirt; } parentTable[index] |= (flags & kPTEUser); - + Address physAddress = GetPTEAddress(parentTable[index]); return GetVirtualTable(physAddress); } @@ -58,11 +58,11 @@ static Address GetMappedPhysicalAddress(Address* l0Table, Address virt) { Address* l0Virt = l0Table; if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table); if (!(l0Virt[l0Index] & kPTEValid)) return 0; - + // A little bit of Mary all night long... Address* l1Virt = GetVirtualTable(GetPTEAddress(l0Virt[l0Index])); if (!(l1Virt[l1Index] & kPTEValid)) return 0; - + // A little bit of Jessica, here I am! Address* l2Virt = GetVirtualTable(GetPTEAddress(l1Virt[l1Index])); if (!(l2Virt[l2Index] & kPTEValid)) return 0; @@ -70,7 +70,7 @@ static Address GetMappedPhysicalAddress(Address* l0Table, Address virt) { // A little bit of you makes me your man Address* l3Virt = GetVirtualTable(GetPTEAddress(l2Virt[l2Index])); if (!(l3Virt[l3Index] & kPTEValid)) return 0; - + return GetPTEAddress(l3Virt[l3Index]); } @@ -84,7 +84,7 @@ Address* VMMMapPage(Address* l0Table, Address phys, Address virt, UInt64 flags) if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table); UInt64 directoryFlags = kPTEValid | kPTETable | (flags & kPTEUser); - + Address* l1Virt = GetOrAllocateTable(l0Virt, l0Index, flags, directoryFlags); if (!l1Virt) return nullptr; @@ -108,7 +108,7 @@ void VMMUnmapPage(Address* l0Table, Address virt) { Address* l0Virt = l0Table; if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table); if (!(l0Virt[l0Index] & kPTEValid)) return; - + Address* l1Virt = GetVirtualTable(GetPTEAddress(l0Virt[l0Index])); if (!(l1Virt[l1Index] & kPTEValid)) return; @@ -149,15 +149,16 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { for (Address phys = bootMap->totalRAM.base; phys < ramEnd; phys += kVMPageSize) { VMMMapPage( gVMKernelL0Table, - phys, VMPhysToHHDM(phys), + phys, VMPhysToHHDM(phys), kPTENormalMem | kPTEAccessRW | kPTEPrivNX | kPTEUserNX ); } OSLog("RAM mapped\n"); - Size pmmBitmapSize = (bootMap->totalRAM.size / kVMPageSize) / 8; + Size totalPages = bootMap->totalRAM.size / kVMPageSize; + Size pmmBitmapSize = (totalPages + kVMBlocksPerByte - 1) / kVMBlocksPerByte; Size kernelSize = ((Address)_kernelEnd - (Address)_kernelStart) + pmmBitmapSize; - kernelSize = (kernelSize + kVMPageSize - 1) & ~(kVMPageSize - 1); + kernelSize = (kernelSize + kVMPageSize - 1) & ~(kVMPageSize - 1); Address kernelPhysStart = kKernelPhysBase; @@ -177,8 +178,8 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { Size fbSize = info->framebuffer.baseSize; for (Address offset = 0; offset < fbSize; offset += kVMPageSize) { VMMMapPage( - gVMKernelL0Table, fbPhys + offset, - kVMFbVirtBase + offset, + gVMKernelL0Table, fbPhys + offset, + kVMFbVirtBase + offset, kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX ); } @@ -188,26 +189,26 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { if (!UARTPhys) UARTPhys = 0x09000000; VMMMapPage( - gVMKernelL0Table, UARTPhys, VMPhysToHHDM(UARTPhys), + gVMKernelL0Table, UARTPhys, VMPhysToHHDM(UARTPhys), kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX ); VMMMapPage( - gVMKernelL0Table, UARTPhys, UARTPhys, + gVMKernelL0Table, UARTPhys, UARTPhys, kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX ); OSLog("UART mapped\n"); Address gicdPhys = bootMap->GIC.GICD.base; Size gicdSize = bootMap->GIC.GICD.size; - if (!gicdPhys) { + if (!gicdPhys) { gicdPhys = 0x08000000; // QEMU fallback gicdSize = 0x10000; } - + for (Address offset = 0; offset < gicdSize; offset += kVMPageSize) { VMMMapPage( - gVMKernelL0Table, gicdPhys + offset, - VMPhysToHHDM(gicdPhys + offset), + gVMKernelL0Table, gicdPhys + offset, + VMPhysToHHDM(gicdPhys + offset), kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX ); } @@ -215,15 +216,15 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { Address giccPhys = bootMap->GIC.GICC.base; Size giccSize = bootMap->GIC.GICC.size; - if (!giccPhys) { + if (!giccPhys) { giccPhys = 0x08001000; // QEMU fallback giccSize = 0x10000; } - + for (Address offset = 0; offset < giccSize; offset += kVMPageSize) { VMMMapPage( - gVMKernelL0Table, giccPhys + offset, - VMPhysToHHDM(giccPhys + offset), + gVMKernelL0Table, giccPhys + offset, + VMPhysToHHDM(giccPhys + offset), kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX ); } @@ -233,4 +234,4 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) { OSLog("Enabling MMU...\n"); CPUEnableMMU(gVMKernelL0Physical); isInitialized = true; -} \ No newline at end of file +} -- 2.52.0 From 6dd68f81626ad4f14a90d2190eff857b0f15a48b Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 00:32:30 +0400 Subject: [PATCH 42/49] fix: plug memory map leak, save sp_el0, dynamic UART, kill `loop` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bootloader: reallocate memory map buffer when ExitBootServices fails, so GetMemoryMap doesn't scribble past the old allocation on retry. - vectors.S: actually store sp_el0 into the exception frame. Previously it was read into x24 and then… vanished. EL0 tasks would wake up with a corrupted stack pointer. Not great. - Serial: split hardcoded 0x09000000 into a fallback default; add SerialUpdate() so the DTB-parsed UART address actually gets used. - DTB: add bounds check on reserved[] with PMM's 3 extra slots accounted for, so malformed/overstuffed DTBs don't silently corrupt memory. - PMM.h: bump kVMMaxReservedRegions 128→256, define kPMMReservedRegionCount. - Types.h: remove `#define loop while(1)`. while(true) is fine. - Rename IOSerial* → Serial* — the IO prefix was redundant, Serial.c already lives under IO/. --- Bootloader/Source/main.c | 6 ++++++ Kernel/Include/IO/Serial.h | 7 ++++--- Kernel/Include/Types.h | 3 +-- Kernel/Include/VM/PMM.h | 5 +++-- Kernel/Source/Arch/DTB.c | 11 +++++++---- Kernel/Source/Arch/vectors.S | 5 +++-- Kernel/Source/IO/Serial.c | 16 +++++++++++----- Kernel/Source/KernelMain.c | 4 +++- Kernel/Source/OS/Log.c | 6 +++--- Kernel/Source/OS/Panic.c | 4 ++-- Kernel/Source/OS/Scheduler.c | 8 ++++---- 11 files changed, 47 insertions(+), 28 deletions(-) diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index 1193ffd..2a6df3d 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -192,6 +192,7 @@ static efi_status_t populate_memory_map(Bootinfo* boot_info) { while (1) { status = gBS->GetMemoryMap(&map_size, map, &map_key, &descriptor_size, &descriptor_version); if (EFI_ERROR(status)) { + gBS->FreePool(map); return status; } @@ -206,7 +207,12 @@ static efi_status_t populate_memory_map(Bootinfo* boot_info) { return EFI_SUCCESS; } + gBS->FreePool(map); map_size += 2 * descriptor_size; + status = gBS->AllocatePool(EfiLoaderData, map_size, (void**)&map); + if (EFI_ERROR(status)) { + return status; + } } } diff --git a/Kernel/Include/IO/Serial.h b/Kernel/Include/IO/Serial.h index f87d102..25dc8d0 100644 --- a/Kernel/Include/IO/Serial.h +++ b/Kernel/Include/IO/Serial.h @@ -2,8 +2,9 @@ #include enum { - kUARTBaseAddress = 0x09000000, // TODO: make it dynamic by parsing DTB + kUARTBaseAddress = 0x09000000, }; -Int32 IOSerialPutCharacter(ASCII character); -Int32 IOSerialPutString(const ASCII* string); \ No newline at end of file +void SerialUpdate(UInt64 address); +Int32 SerialPutCharacter(ASCII character); +Int32 SerialPutString(const ASCII* string); diff --git a/Kernel/Include/Types.h b/Kernel/Include/Types.h index 16ab7bf..96dba99 100644 --- a/Kernel/Include/Types.h +++ b/Kernel/Include/Types.h @@ -12,7 +12,7 @@ typedef unsigned char UInt8; typedef unsigned short UInt16; typedef unsigned int UInt32; -typedef unsigned long long UInt64; +typedef unsigned long long UInt64; typedef unsigned long long UInt; typedef void* Pointer; @@ -31,4 +31,3 @@ typedef UInt64 Size; typedef char ASCII; typedef _Bool Boolean; -#define loop while (1) \ No newline at end of file diff --git a/Kernel/Include/VM/PMM.h b/Kernel/Include/VM/PMM.h index e7eb1e4..da2c560 100644 --- a/Kernel/Include/VM/PMM.h +++ b/Kernel/Include/VM/PMM.h @@ -4,7 +4,8 @@ enum { kVMPageSize = 4096, kVMBlocksPerByte = 8, - kVMMaxReservedRegions = 128, + kVMMaxReservedRegions = 256, + kPMMReservedRegionCount = 3, }; typedef struct { @@ -28,4 +29,4 @@ typedef struct { void PMMInitialize(VMBootMemoryMap* bootMap); Pointer PMMAllocatePage(); -void PMMFreePage(Address address); \ No newline at end of file +void PMMFreePage(Address address); diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index 961a1f6..1a02290 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -24,10 +24,13 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { ASCII* currentNode = ""; UInt32 currentDepth = 0; - UInt32 reservedMemoryDepth = 0; + UInt32 reservedMemoryDepth = 0; Boolean inReservedMemory = false; while (true) { + if (bootMap->reservedCount + kPMMReservedRegionCount >= kVMMaxReservedRegions) { + OSPanic("Too many reserved memory regions!"); // should never occur but jic + } UInt32 token = BytesSwap32(*(UInt32*)structs); structs += 4; @@ -81,7 +84,7 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { bootMap->GIC.GICD.base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0])); bootMap->GIC.GICD.size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2])); - + bootMap->GIC.GICC.base = Merge32To64(BytesSwap32(cells[5]), BytesSwap32(cells[4])); bootMap->GIC.GICC.size = Merge32To64(BytesSwap32(cells[7]), BytesSwap32(cells[6])); } @@ -99,7 +102,7 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { currentDepth--; break; } - + case FDTTokenNOP: continue; case FDTTokenEnd: return; default: @@ -107,4 +110,4 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) { } } -} \ No newline at end of file +} diff --git a/Kernel/Source/Arch/vectors.S b/Kernel/Source/Arch/vectors.S index 59db0d4..617f180 100644 --- a/Kernel/Source/Arch/vectors.S +++ b/Kernel/Source/Arch/vectors.S @@ -1,7 +1,7 @@ .macro ventry type .align 7 sub sp, sp, #288 // save 288 bytes of stack - stp x0, x1, [sp, #0] // move stack + stp x0, x1, [sp, #0] // move stack mov x1, #\type // move type to x1 b ExceptionsTrapEntry .endm @@ -54,6 +54,7 @@ ExceptionsTrapEntry: stp x30, x21, [sp, #16 * 15] stp x22, x23, [sp, #16 * 16] + stp x24, xzr, [sp, #16 * 17] mov x0, sp bl ExceptionsHandler @@ -92,4 +93,4 @@ ExceptionsVectorsInit: adr x0, ExceptionsVectorsTable msr vbar_el1, x0 isb - ret \ No newline at end of file + ret diff --git a/Kernel/Source/IO/Serial.c b/Kernel/Source/IO/Serial.c index 68f7ef9..3775c9a 100644 --- a/Kernel/Source/IO/Serial.c +++ b/Kernel/Source/IO/Serial.c @@ -2,22 +2,28 @@ #include #include -Int32 IOSerialPutCharacter(ASCII character) { +static UInt64 sUARTAddress = kUARTBaseAddress; + +void SerialUpdate(UInt64 address) { + sUARTAddress = address; +} + +Int32 SerialPutCharacter(ASCII character) { // TXFF -- TRansmit FIFO Full for PL011 is 5 bit of FR reg (0x18) - UInt64 uartFR = kUARTBaseAddress + 0x18; + UInt64 uartFR = sUARTAddress + 0x18; while ((IOAddressRead32(uartFR) & (1 << 5)) != 0) { CPUYield(); } - IOAddressWrite32(kUARTBaseAddress, character); + IOAddressWrite32(sUARTAddress, character); return character; } -Int32 IOSerialPutString(const ASCII* string) { +Int32 SerialPutString(const ASCII* string) { Int i = 0; while (string[i] != '\0') { - IOSerialPutCharacter(string[i]); + SerialPutCharacter(string[i]); i++; } diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index a94658e..ae6a2d7 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -17,9 +18,10 @@ void KernelMain(Bootinfo* bootinfo) { } VMBootMemoryMap bootMap = {0}; - + bootMap.reservedCount = 0; DTBParse(bootinfo->dtb, &bootMap); + SerialUpdate(bootMap.UART.base); PMMInitialize(&bootMap); VMMInitialize(&bootMap, bootinfo); diff --git a/Kernel/Source/OS/Log.c b/Kernel/Source/OS/Log.c index d69be46..668381e 100644 --- a/Kernel/Source/OS/Log.c +++ b/Kernel/Source/OS/Log.c @@ -5,11 +5,11 @@ void OSLog(const ASCII* format, ...) { ASCII buffer[kOSLogBufferSize]; - + va_list args; va_start(args, format); StringFormatVariadic(buffer, kOSLogBufferSize, format, args); va_end(args); - IOSerialPutString(buffer); -} \ No newline at end of file + SerialPutString(buffer); +} diff --git a/Kernel/Source/OS/Panic.c b/Kernel/Source/OS/Panic.c index 51140a7..ab9138e 100644 --- a/Kernel/Source/OS/Panic.c +++ b/Kernel/Source/OS/Panic.c @@ -40,7 +40,7 @@ static const ASCII* sFunMessages[] = { }; __attribute__((noreturn)) static void Halt() { - loop { + while (true) { CPUDisableInterrupts(); CPUWaitForInterrupt(); } @@ -134,4 +134,4 @@ __attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame) { DrawPanicFooter(); Halt(); -} \ No newline at end of file +} diff --git a/Kernel/Source/OS/Scheduler.c b/Kernel/Source/OS/Scheduler.c index 3310c91..d2d21a0 100644 --- a/Kernel/Source/OS/Scheduler.c +++ b/Kernel/Source/OS/Scheduler.c @@ -85,11 +85,11 @@ Address SchedulerNext(Address stackPointer) { if (taskIterator->sleepTicks > 0) taskIterator->sleepTicks--; taskIterator = taskIterator->next; } while (taskIterator != gOSSchedulerCurrentTask->next); - + if (gOSSchedulerCurrentTask->sleepTicks > 0) gOSSchedulerCurrentTask->sleepTicks--; OSTask* nextTask = gOSSchedulerCurrentTask->next; - loop { + while (true) { if (nextTask->state == OSTaskStateDead) { nextTask = nextTask->next; if (nextTask == gOSSchedulerCurrentTask) OSPanic("No running tasks"); @@ -110,7 +110,7 @@ Address SchedulerNext(Address stackPointer) { CPUSwitchAddressSpace(physicalL0Table); } gOSSchedulerCurrentTask = nextTask; - + return gOSSchedulerCurrentTask->stackPointer; } @@ -118,4 +118,4 @@ void SchedulerYield(UInt64 ticks) { gOSSchedulerCurrentTask->sleepTicks = ticks; gOSSchedulerCurrentTask->state = OSTaskStateSleeping; CPUException(kOSSchedulerExceptionNumber); -} \ No newline at end of file +} -- 2.52.0 From a3dc3054b846a67b1ccdb7aecb2e4f1bf5d94020 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 00:43:31 +0400 Subject: [PATCH 43/49] build: added -Wno-incompatible-library-redeclaration to kernel cmakelists to disable warning --- Kernel/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 4e24457..3ac5557 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20) project(ksOSKernel LANGUAGES ASM C) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS +file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Source/KernelMain.c ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/entry.S ${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/vectors.S @@ -10,24 +10,25 @@ file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS ) add_executable(Kernel ${KERNEL_SOURCES}) -target_include_directories(Kernel PRIVATE +target_include_directories(Kernel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Include/ ${CMAKE_CURRENT_SOURCE_DIR}/../Common ) -target_compile_options(Kernel PRIVATE +target_compile_options(Kernel PRIVATE $<$: -std=c23 -ffreestanding -fno-stack-protector -fno-builtin -Wall -Wextra + -Wno-incompatible-library-redeclaration -g -mgeneral-regs-only > ) -target_link_options(Kernel PRIVATE +target_link_options(Kernel PRIVATE -nostdlib -static -no-pie -- 2.52.0 From 359eaeb4053fd5c5ac0fd43e255d650b6dcf8072 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 10:11:43 +0400 Subject: [PATCH 44/49] fix(VMM): use correct APTable encoding for table descriptors fix(VMM): use correct APTable encoding for table descriptors fix(vmm): changed flags to match ARMv8 --- Bootloader/CMakeLists.txt | 2 +- Bootloader/Source/main.c | 6 +++--- Kernel/Include/VM/VMM.h | 27 ++++++++++++++++++--------- Kernel/Source/VM/VMM.c | 14 ++++++++++++-- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/Bootloader/CMakeLists.txt b/Bootloader/CMakeLists.txt index 2a6c1f0..b54cb4a 100644 --- a/Bootloader/CMakeLists.txt +++ b/Bootloader/CMakeLists.txt @@ -30,4 +30,4 @@ set_target_properties(BOOTAA64 PROPERTIES SUFFIX ".EFI" OUTPUT_NAME "BOOTAA64" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/efi_bin" -) \ No newline at end of file +) diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index 2a6df3d..d08f24b 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -139,8 +139,8 @@ static efi_status_t load_elf_segments(efi_physical_address_t kernel_addr, efi_fi if (phdr->p_type != PT_LOAD) continue; uintn_t pages = (phdr->p_memsz + 0xFFF) / 0x1000; - - efi_physical_address_t segment_addr = phdr->p_paddr; + + efi_physical_address_t segment_addr = phdr->p_paddr; efi_status_t status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment_addr); if (EFI_ERROR(status)) { @@ -279,4 +279,4 @@ efi_status_t bootloader_main(void) { kernel_main(boot_info); return EFI_SUCCESS; -} \ No newline at end of file +} diff --git a/Kernel/Include/VM/VMM.h b/Kernel/Include/VM/VMM.h index 568763d..90301f6 100644 --- a/Kernel/Include/VM/VMM.h +++ b/Kernel/Include/VM/VMM.h @@ -4,19 +4,28 @@ #include "../Common/bootinfo.h" enum VMPTEFlags { - kPTEValid = (1ULL << 0), // 1 = Present (Will page fault if 0) - kPTETable = (1ULL << 1), // 1 = Valid for L0/L1/L2 Directory - kPTEPage = (1ULL << 1), // 1 = Valid for L3 Page (Same bit) + // Descriptor type (bits [1:0]) + kPTEValid = (1ULL << 0), // 1 = Valid (fault if 0) + kPTETable = (1ULL << 1), // For L0/L1/L2: table descriptor (bits[1:0]=11) + kPTEPage = (1ULL << 1), // For L3: page descriptor (same bit, bits[1:0]=11) - kPTENormalMem = (0ULL << 2), // Cached, Normal RAM - kPTEDeviceMem = (1ULL << 2), // Uncached, MMIO Device + // MAIR attribute index (bits [4:2]) + kPTENormalMem = (0ULL << 2), // AttrIndx 0 → MAIR[7:0] = 0xFF (Normal, WB Cacheable) + kPTEDeviceMem = (1ULL << 2), // AttrIndx 1 → MAIR[15:8] = 0x00 (Device-nGnRnE) - kPTEAccessRW = (0ULL << 6), // Read/Write - kPTEAccessRO = (1ULL << 6), // Read-Only - kPTEUser = (1ULL << 7), // 1 = EL0, 0 = EL1 + // Leaf entry AP[2:1] (bits [7:6]): + // AP[1] (bit 6): 0 = EL0 blocked, 1 = EL0 allowed + // AP[2] (bit 7): 0 = Read/Write, 1 = Read-only + kPTEUser = (1ULL << 6), // AP[1]=1: allow EL0 access + kPTEAccessRW = (0ULL << 7), // AP[2]=0: writable for permitted levels + kPTEAccessRO = (1ULL << 7), // AP[2]=1: read-only for all levels + + // Table descriptor APTable[1:0] (bits [62:61]): + // 00 = no restriction, 01 = block EL0, 10 = reserved, 11 = read-only for all + kPTETableNoEL0 = (1ULL << 61), // APTable[0]=1: prevent EL0 table walk kPTEInnerShare = (3ULL << 8), // Inner Shareable (SMP safe) - kPTEAccessFlag = (1ULL << 10), // CPU access tracking (MUST be 1 to avoid faults) + kPTEAccessFlag = (1ULL << 10), // Access Flag (MUST be 1 to avoid faults) kPTEPrivNX = (1ULL << 53), // PXN: Privileged Execute Never kPTEUserNX = (1ULL << 54) // UXN: Unprivileged Execute Never }; diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c index d0af705..0756043 100644 --- a/Kernel/Source/VM/VMM.c +++ b/Kernel/Source/VM/VMM.c @@ -38,7 +38,11 @@ static inline Address* GetOrAllocateTable(Address* parentTable, Size index, UInt return newTableVirt; } - parentTable[index] |= (flags & kPTEUser); + // if user access requested, clear APTable bit to allow EL0 table walk. + // otherwise leave APTable as-is (kernel-only tables keep kPTETableNoEL0). + if (flags & kPTEUser) { + parentTable[index] &= ~kPTETableNoEL0; + } Address physAddress = GetPTEAddress(parentTable[index]); return GetVirtualTable(physAddress); @@ -83,7 +87,13 @@ Address* VMMMapPage(Address* l0Table, Address phys, Address virt, UInt64 flags) Address* l0Virt = l0Table; if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table); - UInt64 directoryFlags = kPTEValid | kPTETable | (flags & kPTEUser); + // build directory flags for table descriptors + // APTable=01 (kPTETableNoEL0) blocks EL0 entirely - used for kernel-only subtrees. + // APTable=00 allows EL0 access by leaf page permissions - used for user mappings. + UInt64 directoryFlags = kPTEValid | kPTETable; + if (!(flags & kPTEUser)) { + directoryFlags |= kPTETableNoEL0; + } Address* l1Virt = GetOrAllocateTable(l0Virt, l0Index, flags, directoryFlags); if (!l1Virt) return nullptr; -- 2.52.0 From c428097ec6edf730df12e9f85eb260e6c0282390 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 12:26:46 +0400 Subject: [PATCH 45/49] fix(serial): VMPhysToHHDM --- Kernel/Source/KernelMain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index ae6a2d7..14eac88 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -21,10 +21,9 @@ void KernelMain(Bootinfo* bootinfo) { bootMap.reservedCount = 0; DTBParse(bootinfo->dtb, &bootMap); - SerialUpdate(bootMap.UART.base); - PMMInitialize(&bootMap); VMMInitialize(&bootMap, bootinfo); + SerialUpdate(VMPhysToHHDM(bootMap.UART.base)); HeapInitialize(); GICInitialize( @@ -34,6 +33,7 @@ void KernelMain(Bootinfo* bootinfo) { TimerInitialize(); CPUEnableInterrupts(); SchedulerInitialize(); + SchedulerYield(0); OSLog("Kernel initialized.\n"); } -- 2.52.0 From 684c7216fe710a5e996e18f38d122f76238d09fe Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 12:26:58 +0400 Subject: [PATCH 46/49] chore: update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 04b9ca0..1eac00a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ build .DS_Store compile_commands.json ide-swift-toolchain.txt -.cache \ No newline at end of file +.cache +.zed -- 2.52.0 From 5ef70cc72d7338db14452773ccc903da1df6ec90 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 12:27:47 +0400 Subject: [PATCH 47/49] feat: CPUCleanAndInvalidateCode for future EL0 support --- Kernel/Include/Arch/CPU.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index db026f2..eebc81d 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -33,6 +33,29 @@ static inline void CPUInvalidateTLB(Address virt) { ); } +static inline void CPUCleanAndInvalidateCode(Pointer codeVirt, Size size) { + // Read cache line sizes from CTR_EL0 + UInt64 ctr; + __asm__ volatile ("mrs %0, ctr_el0" : "=r" (ctr)); + UInt64 dcacheLineSize = 4ULL << ((ctr >> 16) & 0xF); + UInt64 icacheLineSize = 4ULL << (ctr & 0xF); + + Address addr = (Address)codeVirt; + Address end = addr + size; + + // Clean D-cache to PoU (Point of Unification) + for (Address va = addr; va < end; va += dcacheLineSize) { + __asm__ volatile ("dc cvau, %0" :: "r" (va) : "memory"); + } + __asm__ volatile ("dsb ish" ::: "memory"); + + // Invalidate I-cache to PoU + for (Address va = addr; va < end; va += icacheLineSize) { + __asm__ volatile ("ic ivau, %0" :: "r" (va) : "memory"); + } + __asm__ volatile ("dsb ish\nisb" ::: "memory"); +} + static inline void CPUEnableMMU(Address l0PhysicalAddress) { // MAIR_EL1 (Memory Attribute Indirection Register) // kPTENormalMem is index 0 and kPTEDeviceMem is index 1 -- 2.52.0 From 038219772e3b4d13e9642f9d0db00ee7f144af43 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 12:28:30 +0400 Subject: [PATCH 48/49] fix(scheduler): yield fixed and dont panic --- Kernel/Source/Arch/Exceptions.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c index 70f3a1e..1c4228f 100644 --- a/Kernel/Source/Arch/Exceptions.c +++ b/Kernel/Source/Arch/Exceptions.c @@ -1,9 +1,20 @@ #include #include #include +#include Address ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) { if (type == ExceptionsIRQEl1h || type == ExceptionsIRQEl064) return GICDispatch(frame, type); + if (type == ExceptionsSyncEl1h || type == ExceptionsSyncEl064) { + UInt32 esr = frame->esr_el1; + UInt32 class = (esr >> 26) & 0x3F; + UInt32 syndrome = esr & 0x1FFFFFF; + + if (class == 0x11 || class == 0x15) { + if (syndrome == kOSSchedulerExceptionNumber) { + return SchedulerNext((Address)frame); + } + } + } OSPanicException(frame); } - -- 2.52.0 From 2c7396353c3b07946848361f50cdf33a511f66e4 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 13:05:55 +0400 Subject: [PATCH 49/49] Readme and license --- Assets/ksOS.png | Bin 0 -> 3695 bytes Bootloader/CMakeLists.txt | 3 + Bootloader/Source/main.c | 3 + Bootloader/Source/modules/elf/elf.h | 3 + Bootloader/Source/modules/uefi/efi_entry.c | 3 + Bootloader/Source/modules/uefi/uefi.h | 3 + Bootloader/cmake/aarch64-uefi.cmake | 3 + Bootloader/justfile | 3 + Common/bootinfo.h | 20 +- Kernel/CMakeLists.txt | 3 + Kernel/Include/Arch/CPU.h | 3 + Kernel/Include/Arch/DTB.h | 3 + Kernel/Include/Arch/Exceptions.h | 3 + Kernel/Include/Arch/GIC.h | 3 + Kernel/Include/Arch/IO.h | 3 + Kernel/Include/Arch/Timer.h | 3 + Kernel/Include/IO/Serial.h | 3 + Kernel/Include/Lib/Align.h | 3 + Kernel/Include/Lib/Bytes.h | 3 + Kernel/Include/Lib/Rand.h | 3 + Kernel/Include/Lib/String.h | 3 + Kernel/Include/Lib/Stubs.h | 3 + Kernel/Include/Lib/VAArgs.h | 3 + Kernel/Include/OS/Log.h | 3 + Kernel/Include/OS/Panic.h | 3 + Kernel/Include/OS/Scheduler.h | 3 + Kernel/Include/Types.h | 2 +- Kernel/Include/VM/Heap.h | 3 + Kernel/Include/VM/PMM.h | 3 + Kernel/Include/VM/VMM.h | 3 + Kernel/Source/Arch/DTB.c | 3 + Kernel/Source/Arch/Exceptions.c | 3 + Kernel/Source/Arch/GIC.c | 3 + Kernel/Source/Arch/Timer.c | 3 + Kernel/Source/Arch/entry.S | 3 + Kernel/Source/Arch/vectors.S | 3 + Kernel/Source/IO/Serial.c | 3 + Kernel/Source/KernelMain.c | 4 +- Kernel/Source/Lib/String.c | 3 + Kernel/Source/Lib/Stubs.c | 3 + Kernel/Source/OS/Log.c | 3 + Kernel/Source/OS/Panic.c | 3 + Kernel/Source/OS/Scheduler.c | 3 + Kernel/Source/VM/Heap.c | 3 + Kernel/Source/VM/PMM.c | 3 + Kernel/Source/VM/VMM.c | 3 + Kernel/cmake/aarch64-bare.cmake | 3 + Kernel/justfile | 3 + Kernel/linker.ld | 10 +- LICENSE | 674 +++++++++++++++++++++ README.md | 7 +- justfile | 3 + 52 files changed, 841 insertions(+), 11 deletions(-) create mode 100644 Assets/ksOS.png create mode 100644 LICENSE diff --git a/Assets/ksOS.png b/Assets/ksOS.png new file mode 100644 index 0000000000000000000000000000000000000000..7a75e4d77976980cc03b43e7c2284b8c4a3d586a GIT binary patch literal 3695 zcmbtXc{tQ-8=l2788pUPRD&TRB{3t!Xk^AojV&aJkyLgil6^_CN6MD9jI5ER97;53 zF^x6Lkx3Y8Y{M94_@>kOy3YBo>-+xsp6hy_<-YIdz2EEi-|sfzq^XF|P9XpQAcDtX zEqS%`$AN%(IV<*DIj;cyElrJqpSsk;c*8ayoV`B)02TjnfPkzV8J-}7aKhSzM{aFx z{meg`e;~0*zbGEN6_faP@ekym@pth*?)mSse=>hfKp>Fk^&|g`=mcKnjX#lJ%@2}C z{ayK|{--rh#%q4A{6c$wz#`i)(@|-)nqp~tI85c6m$FX z63b}OfXjq(Hks=iOYC`pB@TCkvpCD8Z?3>u%bRPfu>IRsg*PDj>+9^bMaKO1h1nTz zkH;GTfG_}$#aIXCe9z%}OOSVvAFeR+h#NGQgZz=Z7wm%iUxhm!iL15O zJa%?RBrZ+jLy~-9Hw-I}?EO@OCG3dm%(`i)_b5)42$Mvbw`A@jV$(^q;a`#T$7X5r(%AuhOoVJW{3&>ef%NwRt^fblY(_ z8jPePk8~9Vuihsd613O30FX!CDbdvTU(3*q3qGUWVgu&CPAM0Iku4j(J*vS&x~LYi z>aw~<#cdKVN=&Gda##4GfyS{DCMY+;y9w#-oskR%?T3KvEOtw_^9pmHwc3dG^yqwvd|2$GTZy=oP+pL6@_R zB{&h4<+OAoLHV&O6O;PwYB`9@qxiZ$cayEU6I~%J+Gx!ggPcww3*2E(`wy?3Po_)) z%7HOhk-pFmp74i(7~u)23UkDy?n4LD2|mq=>m+2>l({nQH&(K^*ew*&jOrweA{h2s5KjqZ zLnr;bB5N@e&aVimd}E#}BsHn579rS%u()XEf9UOU6prLubi`Z<=-ELK?LNBpB&z!n zH7lC2H@`CHLny3kd)jcr;iYknUc7!9^Aux4zjzIkR?w_rE~*1!l9-y^vb(!hcbeoc zcz8O|ww$0Zo)lHxWJ+eT-f3|^?caa_NIUL$H{DWeO=}z`cm5XmRgcSIWjTNlsoJ-X zpNp1F%;d6U65$`Vu1M`QP0c#aPW=SIId-oAV~d!mb9=gX#zSz2%`6^ogO?vV%M#o% zbwePl=i-wy#t>xFbE=U}{%A`(?kNmT?*Uz}OM%2)GB;ko9})9)seL-*TMDF~n>C26 zX+rKBNHE47uZ*evtZIySyVvr0O1*-n=!ShqY2GVJZ>6|GLx~xr*zDvOY@3p)i(7X1 zu*_=mozYC?nl!&-B!aa7to|*y?nJVq3FDj#LiH_{64@g&euySXId*RVKkAVxgPSeH zp1H7@Ls#MJ(2mX84+m?SzN8~4C;n z{W({z1CxF&BJi0#sJ+#XO|El~VQQ!u0;{}xEAHM@fjoZP8iEX+L&terd5@4uZ1Vkb z{F$R7o;Q5%lZE(FCTI5vPzOKCT8boc}rOIu&mF!ia&6NLe=l7wk@yH>at&9!KW0o>X&& z1y#PPx+CT;ouq~a7G*?Xhoi){UGxBSSB2|7$W0mcdNo1XD>u^U5)e-@azEK7Tz>WY z5R}5iq6UcMr%;y&mnkMA_s;1G4!9|bMqK@Kk_4&-MXs%b8>XXzpJw^}(s$!I##!YG%B*2%T)s-QP%c%uW8Hl~`xaCZv=UaEtr zI?vV+SEpLVUn~{s8w{DcFzRf>;P)%-I+|u~gVH^={JD6>*VGOR z*~ZLoz(N00jDoO=%XIjeyB>3~pBdvm7Zj>7>297W=fi{P4jO@^G+k3$6k&Fznd{ut zHR~D`Q;o^@a9OU=Y3yGbP_L^UK9+g*KuKzfK*V6u2qIyyM1P%DQ=j22Jr;$EI<0Bd z|3xYDRf4hpt|P%{lte9n>f^>5ne51p8n|ZLQ88$HRsejb;a=dnVPLXTeiSbIMp*SN z&bQ>&`%gkoq-KMsom%9=9LANvSD6dS4HQhi@A(1A$cMs)Scn>z5;i?9U04=q1No=L@`N)3(CPoJC literal 0 HcmV?d00001 diff --git a/Bootloader/CMakeLists.txt b/Bootloader/CMakeLists.txt index b54cb4a..756019f 100644 --- a/Bootloader/CMakeLists.txt +++ b/Bootloader/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (c) 2026 0xKSor + cmake_minimum_required(VERSION 3.20) project(ksOS_bootloader LANGUAGES C ASM) diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index d08f24b..e86ea1b 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include "modules/uefi/uefi.h" #include "modules/elf/elf.h" #include "../../Common/bootinfo.h" diff --git a/Bootloader/Source/modules/elf/elf.h b/Bootloader/Source/modules/elf/elf.h index 2722c79..8150d86 100644 --- a/Bootloader/Source/modules/elf/elf.h +++ b/Bootloader/Source/modules/elf/elf.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include "../../modules/uefi/uefi.h" // IWYU pragma: keep diff --git a/Bootloader/Source/modules/uefi/efi_entry.c b/Bootloader/Source/modules/uefi/efi_entry.c index d6e1ec9..d5fc0ff 100644 --- a/Bootloader/Source/modules/uefi/efi_entry.c +++ b/Bootloader/Source/modules/uefi/efi_entry.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include "uefi.h" efi_handle_t IM = NULL; diff --git a/Bootloader/Source/modules/uefi/uefi.h b/Bootloader/Source/modules/uefi/uefi.h index 8bbf190..b7a2e50 100644 --- a/Bootloader/Source/modules/uefi/uefi.h +++ b/Bootloader/Source/modules/uefi/uefi.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once typedef unsigned char uint8_t; diff --git a/Bootloader/cmake/aarch64-uefi.cmake b/Bootloader/cmake/aarch64-uefi.cmake index d62a460..9b2393d 100644 --- a/Bootloader/cmake/aarch64-uefi.cmake +++ b/Bootloader/cmake/aarch64-uefi.cmake @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (c) 2026 0xKSor + set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR aarch64) diff --git a/Bootloader/justfile b/Bootloader/justfile index ab8a73c..3a86353 100644 --- a/Bootloader/justfile +++ b/Bootloader/justfile @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (c) 2026 0xKSor + BUILD_DIR := env_var_or_default("BUILD_DIR", justfile_directory() + "/.build") TEMP_DIR := env_var_or_default("TEMP_DIR", BUILD_DIR + "/temp") build: diff --git a/Common/bootinfo.h b/Common/bootinfo.h index d1aa387..7ac07f6 100644 --- a/Common/bootinfo.h +++ b/Common/bootinfo.h @@ -1,7 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once typedef unsigned int BIUInt32; -typedef unsigned long long BIUInt64; +typedef unsigned long long BIUInt64; typedef struct { BIUInt32* base; @@ -12,8 +15,8 @@ typedef struct { } BIFramebuffer; typedef struct { - void* map; - BIUInt64 mapSize; + void* map; + BIUInt64 mapSize; BIUInt64 descriptorSize; BIUInt32 mapKey; BIUInt32 descriptorVersion; @@ -24,12 +27,21 @@ typedef struct { void* kernelAddress; } BIKernelInfo; +typedef struct { + BIUInt64 physicalBase; + BIUInt64 size; + char name[32]; + BIUInt64 capabilities; +} BootModule; + typedef struct { BIUInt64 magic; BIKernelInfo kernelInfo; void* dtb; BIMemoryMap memoryMap; BIFramebuffer framebuffer; + BootModule modules[16]; + BIUInt32 moduleCount; } Bootinfo; -#define BOOTINFO_MAGIC 0x736F6E7961 \ No newline at end of file +#define BOOTINFO_MAGIC 0x736F6E7961 diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 3ac5557..8408bdd 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (c) 2026 0xKSor + cmake_minimum_required(VERSION 3.20) project(ksOSKernel LANGUAGES ASM C) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/Kernel/Include/Arch/CPU.h b/Kernel/Include/Arch/CPU.h index eebc81d..7c38579 100644 --- a/Kernel/Include/Arch/CPU.h +++ b/Kernel/Include/Arch/CPU.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Arch/DTB.h b/Kernel/Include/Arch/DTB.h index 215b4d7..b52b59e 100644 --- a/Kernel/Include/Arch/DTB.h +++ b/Kernel/Include/Arch/DTB.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Arch/Exceptions.h b/Kernel/Include/Arch/Exceptions.h index 1a68681..7871e15 100644 --- a/Kernel/Include/Arch/Exceptions.h +++ b/Kernel/Include/Arch/Exceptions.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Arch/GIC.h b/Kernel/Include/Arch/GIC.h index a89b26f..2635ddd 100644 --- a/Kernel/Include/Arch/GIC.h +++ b/Kernel/Include/Arch/GIC.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include #include diff --git a/Kernel/Include/Arch/IO.h b/Kernel/Include/Arch/IO.h index 980f76a..8f52f35 100644 --- a/Kernel/Include/Arch/IO.h +++ b/Kernel/Include/Arch/IO.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Arch/Timer.h b/Kernel/Include/Arch/Timer.h index f9fb0e4..2b083f6 100644 --- a/Kernel/Include/Arch/Timer.h +++ b/Kernel/Include/Arch/Timer.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include #include diff --git a/Kernel/Include/IO/Serial.h b/Kernel/Include/IO/Serial.h index 25dc8d0..0216231 100644 --- a/Kernel/Include/IO/Serial.h +++ b/Kernel/Include/IO/Serial.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Lib/Align.h b/Kernel/Include/Lib/Align.h index 7d86a1b..7e658ff 100644 --- a/Kernel/Include/Lib/Align.h +++ b/Kernel/Include/Lib/Align.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Lib/Bytes.h b/Kernel/Include/Lib/Bytes.h index ecb90c1..c0346a3 100644 --- a/Kernel/Include/Lib/Bytes.h +++ b/Kernel/Include/Lib/Bytes.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Lib/Rand.h b/Kernel/Include/Lib/Rand.h index 93b11af..335d377 100644 --- a/Kernel/Include/Lib/Rand.h +++ b/Kernel/Include/Lib/Rand.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include #include diff --git a/Kernel/Include/Lib/String.h b/Kernel/Include/Lib/String.h index 4203842..c318608 100644 --- a/Kernel/Include/Lib/String.h +++ b/Kernel/Include/Lib/String.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include #include diff --git a/Kernel/Include/Lib/Stubs.h b/Kernel/Include/Lib/Stubs.h index 313fa92..16031b8 100644 --- a/Kernel/Include/Lib/Stubs.h +++ b/Kernel/Include/Lib/Stubs.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Lib/VAArgs.h b/Kernel/Include/Lib/VAArgs.h index da688ef..96e240e 100644 --- a/Kernel/Include/Lib/VAArgs.h +++ b/Kernel/Include/Lib/VAArgs.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once typedef __builtin_va_list va_list; diff --git a/Kernel/Include/OS/Log.h b/Kernel/Include/OS/Log.h index a19fcd6..c9edd2e 100644 --- a/Kernel/Include/OS/Log.h +++ b/Kernel/Include/OS/Log.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/OS/Panic.h b/Kernel/Include/OS/Panic.h index cb31981..745b61a 100644 --- a/Kernel/Include/OS/Panic.h +++ b/Kernel/Include/OS/Panic.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/OS/Scheduler.h b/Kernel/Include/OS/Scheduler.h index 2dc4d5f..18c74d0 100644 --- a/Kernel/Include/OS/Scheduler.h +++ b/Kernel/Include/OS/Scheduler.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/Types.h b/Kernel/Include/Types.h index 96dba99..28d1bcf 100644 --- a/Kernel/Include/Types.h +++ b/Kernel/Include/Types.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 0xKarinyash +// Copyright (c) 2026 0xKSor #pragma once diff --git a/Kernel/Include/VM/Heap.h b/Kernel/Include/VM/Heap.h index da04352..1cf463e 100644 --- a/Kernel/Include/VM/Heap.h +++ b/Kernel/Include/VM/Heap.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/VM/PMM.h b/Kernel/Include/VM/PMM.h index da2c560..ec98216 100644 --- a/Kernel/Include/VM/PMM.h +++ b/Kernel/Include/VM/PMM.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include diff --git a/Kernel/Include/VM/VMM.h b/Kernel/Include/VM/VMM.h index 90301f6..c754d0d 100644 --- a/Kernel/Include/VM/VMM.h +++ b/Kernel/Include/VM/VMM.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #pragma once #include #include diff --git a/Kernel/Source/Arch/DTB.c b/Kernel/Source/Arch/DTB.c index 1a02290..2bc3b63 100644 --- a/Kernel/Source/Arch/DTB.c +++ b/Kernel/Source/Arch/DTB.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/Arch/Exceptions.c b/Kernel/Source/Arch/Exceptions.c index 1c4228f..1c07f50 100644 --- a/Kernel/Source/Arch/Exceptions.c +++ b/Kernel/Source/Arch/Exceptions.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/Arch/GIC.c b/Kernel/Source/Arch/GIC.c index d751cea..77af615 100644 --- a/Kernel/Source/Arch/GIC.c +++ b/Kernel/Source/Arch/GIC.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/Arch/Timer.c b/Kernel/Source/Arch/Timer.c index 62b2e74..d89265e 100644 --- a/Kernel/Source/Arch/Timer.c +++ b/Kernel/Source/Arch/Timer.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/Arch/entry.S b/Kernel/Source/Arch/entry.S index 77d9009..7fbe86c 100644 --- a/Kernel/Source/Arch/entry.S +++ b/Kernel/Source/Arch/entry.S @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + .section .text.boot, "ax" .global _start diff --git a/Kernel/Source/Arch/vectors.S b/Kernel/Source/Arch/vectors.S index 617f180..aa88ee2 100644 --- a/Kernel/Source/Arch/vectors.S +++ b/Kernel/Source/Arch/vectors.S @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + .macro ventry type .align 7 sub sp, sp, #288 // save 288 bytes of stack diff --git a/Kernel/Source/IO/Serial.c b/Kernel/Source/IO/Serial.c index 3775c9a..ba49b38 100644 --- a/Kernel/Source/IO/Serial.c +++ b/Kernel/Source/IO/Serial.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/KernelMain.c b/Kernel/Source/KernelMain.c index 14eac88..31cb0a7 100644 --- a/Kernel/Source/KernelMain.c +++ b/Kernel/Source/KernelMain.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include "../Common/bootinfo.h" #include #include @@ -33,7 +36,6 @@ void KernelMain(Bootinfo* bootinfo) { TimerInitialize(); CPUEnableInterrupts(); SchedulerInitialize(); - SchedulerYield(0); OSLog("Kernel initialized.\n"); } diff --git a/Kernel/Source/Lib/String.c b/Kernel/Source/Lib/String.c index 4e99f7c..3d4bf45 100644 --- a/Kernel/Source/Lib/String.c +++ b/Kernel/Source/Lib/String.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include diff --git a/Kernel/Source/Lib/Stubs.c b/Kernel/Source/Lib/Stubs.c index 4133542..6c456f5 100644 --- a/Kernel/Source/Lib/Stubs.c +++ b/Kernel/Source/Lib/Stubs.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include diff --git a/Kernel/Source/OS/Log.c b/Kernel/Source/OS/Log.c index 668381e..0efac33 100644 --- a/Kernel/Source/OS/Log.c +++ b/Kernel/Source/OS/Log.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/OS/Panic.c b/Kernel/Source/OS/Panic.c index ab9138e..b261479 100644 --- a/Kernel/Source/OS/Panic.c +++ b/Kernel/Source/OS/Panic.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/OS/Scheduler.c b/Kernel/Source/OS/Scheduler.c index d2d21a0..10b70af 100644 --- a/Kernel/Source/OS/Scheduler.c +++ b/Kernel/Source/OS/Scheduler.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/VM/Heap.c b/Kernel/Source/VM/Heap.c index 6735e55..369dee8 100644 --- a/Kernel/Source/VM/Heap.c +++ b/Kernel/Source/VM/Heap.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/Source/VM/PMM.c b/Kernel/Source/VM/PMM.c index d1095db..bcc1d3d 100644 --- a/Kernel/Source/VM/PMM.c +++ b/Kernel/Source/VM/PMM.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c index 0756043..5b9be6f 100644 --- a/Kernel/Source/VM/VMM.c +++ b/Kernel/Source/VM/VMM.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (c) 2026 0xKSor + #include #include #include diff --git a/Kernel/cmake/aarch64-bare.cmake b/Kernel/cmake/aarch64-bare.cmake index 461e28a..a460c16 100644 --- a/Kernel/cmake/aarch64-bare.cmake +++ b/Kernel/cmake/aarch64-bare.cmake @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (c) 2026 0xKSor + set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR aarch64) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) diff --git a/Kernel/justfile b/Kernel/justfile index ae01553..80900e6 100644 --- a/Kernel/justfile +++ b/Kernel/justfile @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (c) 2026 0xKSor + BUILD_DIR := env_var_or_default("BUILD_DIR", justfile_directory() + "/.build") TEMP_DIR := env_var_or_default("TEMP_DIR", BUILD_DIR + "/temp") build: diff --git a/Kernel/linker.ld b/Kernel/linker.ld index 35a10ce..f028280 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -1,3 +1,7 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright (c) 2026 0xKSor + */ + ENTRY(_start) KERNEL_PA = 0x40100000; @@ -23,12 +27,12 @@ SECTIONS .rodata : AT(ADDR(.rodata) - KERNEL_VA + KERNEL_PA) { *(.rodata*) } :text - + . = ALIGN(4096); .data : AT(ADDR(.data) - KERNEL_VA + KERNEL_PA) { *(.data*) } :data - + . = ALIGN(8); .bss : AT(ADDR(.bss) - KERNEL_VA + KERNEL_PA) { __bss_start = .; @@ -39,4 +43,4 @@ SECTIONS . = ALIGN(4096); _kernelEnd = .; -} \ No newline at end of file +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index f2b41ab..45330d9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ -# ksOS +# ![ksOS](Assets/ksOS.png) ksOS -Meow meow purrr nya meow :3 \ No newline at end of file +![arch](https://img.shields.io/badge/arch-ARM-0091BD?style=flat-square) ![lang](https://img.shields.io/badge/lang-C%20%7C%20ASM-6366F1?style=flat-square) ![license](https://img.shields.io/badge/license-GPL--3.0-brightgreen?style=flat-square) + +> *"Just for fun. Never serious. Meow meow"* +> — Linus Torvalds diff --git a/justfile b/justfile index 45f5896..83a2f0e 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (c) 2026 0xKSor + set quiet := true OS_NAME := os() -- 2.52.0