From 2261985e7c22d19e47d3043f56b5fd352f9e958d Mon Sep 17 00:00:00 2001 From: hwacha Date: Mon, 20 Apr 2026 15:51:40 +0900 Subject: [PATCH 1/3] wip swift in kernel --- Kernel/CMakeLists.txt | 33 +++++++++++++++++++-- Kernel/Source/entry.S | 59 ++------------------------------------ Kernel/Source/kernel.swift | 22 ++++++++++++++ Kernel/Source/stubs.c | 38 ++++++++++++++++++++++++ Kernel/linker.ld | 14 +++++++++ 5 files changed, 108 insertions(+), 58 deletions(-) create mode 100644 Kernel/Source/kernel.swift create mode 100644 Kernel/Source/stubs.c diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 7d0c196..ac39306 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,6 +1,10 @@ cmake_minimum_required(VERSION 3.10) project(ksOSKernel LANGUAGES ASM C) +set(SWIFT_TOOLCHAIN "$ENV{HOME}/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain") +set(SWIFTC "${SWIFT_TOOLCHAIN}/usr/bin/swiftc") +set(SWIFT_RESOURCE_DIR "${SWIFT_TOOLCHAIN}/usr/lib/swift") + add_compile_options(-ffreestanding -nostdlib -O0 -g) set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld) @@ -11,8 +15,33 @@ add_link_options( -Wl,-T,${LINKER_SCRIPT} ) -add_executable(kernel.elf Source/entry.S) +set(SWIFT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Source/kernel.swift) +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 + -resource-dir ${SWIFT_RESOURCE_DIR} + -c ${SWIFT_SOURCES} + -o ${SWIFT_OBJ} + DEPENDS ${SWIFT_SOURCES} + COMMENT "Compiling Swift kernel" +) + +set_source_files_properties(${SWIFT_OBJ} PROPERTIES + EXTERNAL_OBJECT TRUE + GENERATED TRUE +) + +add_executable(kernel.elf Source/entry.S Source/stubs.c ${SWIFT_OBJ}) + add_custom_command(TARGET kernel.elf POST_BUILD COMMAND ${LLVM_OBJCOPY} -O binary kernel.elf kernel.bin COMMENT "kernel.elf -> kernel.bin" -) \ No newline at end of file +) diff --git a/Kernel/Source/entry.S b/Kernel/Source/entry.S index c1179ce..2638f10 100644 --- a/Kernel/Source/entry.S +++ b/Kernel/Source/entry.S @@ -2,59 +2,6 @@ .global _start _start: - add x1, x0, #64 - ldr x2, [x1] // base - ldr x3, [x1, #16] // width - ldr x4, [x1, #24] // height - - mul x5, x3, x4 - mov x7, #5 - udiv x10, x5, x7 // stripe size - - // 0x00RRGGBB - // lblue: 5B CE FA - mov w11, #0xCEFA - movk w11, #0x5B, lsl #16 - - // pink: F5 A7 B8 - mov w12, #0xA7B8 - movk w12, #0xF5, lsl #16 - - // white: FF FF FF - mov w13, #0xFFFF - movk w13, #0xFF, lsl #16 - - mov x14, #0 // pixels in curr stripe - mov x15, #0 // stripe index - -fill_loop: - cbz x5, done - - cmp x15, #0 - b.eq set_blue - cmp x15, #1 - b.eq set_pink - cmp x15, #2 - b.eq set_white - cmp x15, #3 - b.eq set_pink - b set_blue - -set_blue: mov w6, w11; b draw -set_pink: mov w6, w12; b draw -set_white: mov w6, w13 - -draw: - str w6, [x2], #4 - sub x5, x5, #1 - add x14, x14, #1 - - cmp x14, x10 - b.lt fill_loop - - mov x14, #0 - add x15, x15, #1 - b fill_loop - -done: - b done \ No newline at end of file + bl kmain +.hang: + b .hang \ No newline at end of file diff --git a/Kernel/Source/kernel.swift b/Kernel/Source/kernel.swift new file mode 100644 index 0000000..384daaf --- /dev/null +++ b/Kernel/Source/kernel.swift @@ -0,0 +1,22 @@ +@_cdecl("kmain") +public func kernelMain(_ bootInfo: UInt) { + // Bootinfo offsets: fb starts at 64, then base(8), baseSize(8), width(8), height(8) + let fbBase = UnsafePointer(bitPattern: bootInfo &+ 64)!.pointee + let width = UnsafePointer(bitPattern: bootInfo &+ 80)!.pointee + let height = UnsafePointer(bitPattern: bootInfo &+ 88)!.pointee + + let pixels = UnsafeMutablePointer(bitPattern: fbBase)! + let total = Int(width) &* Int(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 + } +} diff --git a/Kernel/Source/stubs.c b/Kernel/Source/stubs.c new file mode 100644 index 0000000..57dad40 --- /dev/null +++ b/Kernel/Source/stubs.c @@ -0,0 +1,38 @@ +#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 embedded uses putchar for print(); stub so it links but does nothing +int putchar(int c) { return c; } + +// 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; } diff --git a/Kernel/linker.ld b/Kernel/linker.ld index e69de29..9247fbe 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -0,0 +1,14 @@ +ENTRY(_start) + +SECTIONS { + . = 0; + + .text : { + *(.text.boot) + *(.text*) + } + + .rodata : { *(.rodata*) } + .data : { *(.data*) } + .bss : { *(.bss*) *(COMMON) } +} From 02a99a01b0ec4c752ee1a52d3c80ea1755183dae Mon Sep 17 00:00:00 2001 From: hwacha Date: Mon, 20 Apr 2026 16:11:45 +0900 Subject: [PATCH 2/3] added support for other platforms --- Kernel/CMakeLists.txt | 52 ++++++++++++++++++++++++++++--- Kernel/cmake/aarch64-bare.cmake | 24 +++++++++++---- Kernel/linker.ld | 1 + justfile | 54 +++++++++++++++++++-------------- 4 files changed, 99 insertions(+), 32 deletions(-) diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index ac39306..4134daa 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,10 +1,53 @@ cmake_minimum_required(VERSION 3.10) project(ksOSKernel LANGUAGES ASM C) -set(SWIFT_TOOLCHAIN "$ENV{HOME}/Library/Developer/Toolchains/swift-6.2.3-RELEASE.xctoolchain") -set(SWIFTC "${SWIFT_TOOLCHAIN}/usr/bin/swiftc") -set(SWIFT_RESOURCE_DIR "${SWIFT_TOOLCHAIN}/usr/lib/swift") +# --- 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() +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, derive resource dir from its location + 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") + endif() + endif() +endif() + +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}") + +# --- Build --- add_compile_options(-ffreestanding -nostdlib -O0 -g) set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld) @@ -16,7 +59,7 @@ add_link_options( ) set(SWIFT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Source/kernel.swift) -set(SWIFT_OBJ ${CMAKE_CURRENT_BINARY_DIR}/kernel_swift.o) +set(SWIFT_OBJ ${CMAKE_CURRENT_BINARY_DIR}/kernel_swift.o) add_custom_command( OUTPUT ${SWIFT_OBJ} @@ -30,6 +73,7 @@ add_custom_command( -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" ) diff --git a/Kernel/cmake/aarch64-bare.cmake b/Kernel/cmake/aarch64-bare.cmake index 4494c10..8c0c1d2 100644 --- a/Kernel/cmake/aarch64-bare.cmake +++ b/Kernel/cmake/aarch64-bare.cmake @@ -3,14 +3,26 @@ set(CMAKE_SYSTEM_PROCESSOR aarch64) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) if(NOT LLVM_BIN) - execute_process(COMMAND brew --prefix llvm OUTPUT_VARIABLE LLVM_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) - set(LLVM_BIN "${LLVM_PREFIX}/bin") + if(APPLE) + execute_process( + COMMAND brew --prefix llvm + OUTPUT_VARIABLE LLVM_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(LLVM_BIN "${LLVM_PREFIX}/bin") + else() + find_program(_CLANG clang) + if(NOT _CLANG) + message(FATAL_ERROR "clang not found. Install: apt install clang lld / dnf install clang lld") + endif() + get_filename_component(LLVM_BIN "${_CLANG}" DIRECTORY) + endif() endif() -set(CMAKE_C_COMPILER "${LLVM_BIN}/clang") +set(CMAKE_C_COMPILER "${LLVM_BIN}/clang") set(CMAKE_ASM_COMPILER "${LLVM_BIN}/clang") -set(LLVM_OBJCOPY "${LLVM_BIN}/llvm-objcopy") +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}) \ No newline at end of file +set(CMAKE_C_COMPILER_TARGET ${TARGET_TRIPLE}) +set(CMAKE_ASM_COMPILER_TARGET ${TARGET_TRIPLE}) diff --git a/Kernel/linker.ld b/Kernel/linker.ld index 9247fbe..22e97ea 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -11,4 +11,5 @@ SECTIONS { .rodata : { *(.rodata*) } .data : { *(.data*) } .bss : { *(.bss*) *(COMMON) } + } diff --git a/justfile b/justfile index 207c749..1120d3b 100644 --- a/justfile +++ b/justfile @@ -3,28 +3,38 @@ set quiet := true OS_NAME := os() ARCH_NAME := arch() -OVMF_ARM := if OS_NAME == "macos" { - if ARCH_NAME == "aarch64" { - "/opt/homebrew/share/qemu/edk2-aarch64-code.fd" - } else { - "/usr/local/share/qemu/edk2-aarch64-code.fd" - } -} else { - "/usr/share/edk2/aarch64/QEMU_EFI.fd" -} - -ACCEL := if OS_NAME == "macos" { - if ARCH_NAME == "aarch64" { "-accel hvf" } else { "" } -} else { - "" -} - +# Homebrew prefix (arm64 mac vs x86_64 mac) HB_PREFIX := if ARCH_NAME == "aarch64" { "/opt/homebrew" } else { "/usr/local" } export PATH := HB_PREFIX + "/bin:" + HB_PREFIX + "/sbin:" + env_var("PATH") -ACCEL_INFO := if ACCEL == "" { "none (TCG)" } else { ACCEL } +# QEMU acceleration: HVF on Apple Silicon, KVM on aarch64 Linux, TCG otherwise +ACCEL := if OS_NAME == "macos" { + if ARCH_NAME == "aarch64" { "-accel hvf" } else { "" } +} else { + if ARCH_NAME == "aarch64" { "-accel kvm" } else { "" } +} -CPU := if ARCH_NAME == "aarch64" { "host" } else { "max" } +# CPU type: "host" with hardware virt, "max" for cross-arch TCG +CPU := if ARCH_NAME == "aarch64" { "host" } else { "max" } + +# AArch64 UEFI firmware +# Linux default is Fedora/RHEL path; override via OVMF_PATH env var: +# Debian/Ubuntu: /usr/share/qemu-efi-aarch64/QEMU_EFI.fd +# Arch: /usr/share/edk2-armvirt/aarch64/QEMU_CODE.fd +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") +} + +# Display backend +DISPLAY_FLAGS := if OS_NAME == "macos" { + "-display cocoa,show-cursor=on" +} else { + env_var_or_default("QEMU_DISPLAY", "-display sdl") +} + +ACCEL_INFO := if ACCEL == "" { "none (TCG)" } else { ACCEL } export BUILD_DIR := justfile_directory() + "/.build" export TEMP_DIR := BUILD_DIR + "/temp" @@ -56,18 +66,18 @@ _prep: @mcopy -i {{IMG_FILE}} {{BUILD_DIR}}/Kernel/ksOSKernel.bin ::/ksOSKernel.bin @run: _image - @echo "🚀 Launching..." + @echo "🚀 Launching (accel: {{ACCEL_INFO}})..." qemu-system-aarch64 {{ACCEL}} \ -machine virt,acpi=off \ -cpu {{CPU}} \ -m 512M \ -device ramfb \ - -display cocoa,show-cursor=on \ + {{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 - + @clean: - rm -rf {{BUILD_DIR}} \ No newline at end of file + rm -rf {{BUILD_DIR}} From ad0dcfc9a4f1a15c142504066e61ffcd30fbdb03 Mon Sep 17 00:00:00 2001 From: karina Date: Mon, 20 Apr 2026 11:14:40 +0400 Subject: [PATCH 3/3] docs: minor changes in comments --- Kernel/cmake/aarch64-bare.cmake | 2 +- justfile | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Kernel/cmake/aarch64-bare.cmake b/Kernel/cmake/aarch64-bare.cmake index 8c0c1d2..3b90c1b 100644 --- a/Kernel/cmake/aarch64-bare.cmake +++ b/Kernel/cmake/aarch64-bare.cmake @@ -13,7 +13,7 @@ if(NOT LLVM_BIN) else() find_program(_CLANG clang) if(NOT _CLANG) - message(FATAL_ERROR "clang not found. Install: apt install clang lld / dnf install clang lld") + message(FATAL_ERROR "clang not found.") endif() get_filename_component(LLVM_BIN "${_CLANG}" DIRECTORY) endif() diff --git a/justfile b/justfile index 1120d3b..f3c716a 100644 --- a/justfile +++ b/justfile @@ -3,31 +3,23 @@ set quiet := true OS_NAME := os() ARCH_NAME := arch() -# Homebrew prefix (arm64 mac vs x86_64 mac) HB_PREFIX := if ARCH_NAME == "aarch64" { "/opt/homebrew" } else { "/usr/local" } export PATH := HB_PREFIX + "/bin:" + HB_PREFIX + "/sbin:" + env_var("PATH") -# QEMU acceleration: HVF on Apple Silicon, KVM on aarch64 Linux, TCG otherwise ACCEL := if OS_NAME == "macos" { if ARCH_NAME == "aarch64" { "-accel hvf" } else { "" } } else { if ARCH_NAME == "aarch64" { "-accel kvm" } else { "" } } -# CPU type: "host" with hardware virt, "max" for cross-arch TCG CPU := if ARCH_NAME == "aarch64" { "host" } else { "max" } -# AArch64 UEFI firmware -# Linux default is Fedora/RHEL path; override via OVMF_PATH env var: -# Debian/Ubuntu: /usr/share/qemu-efi-aarch64/QEMU_EFI.fd -# Arch: /usr/share/edk2-armvirt/aarch64/QEMU_CODE.fd 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") } -# Display backend DISPLAY_FLAGS := if OS_NAME == "macos" { "-display cocoa,show-cursor=on" } else {