diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 7d0c196..4134daa 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,6 +1,53 @@ cmake_minimum_required(VERSION 3.10) project(ksOSKernel LANGUAGES ASM 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() + +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) @@ -11,8 +58,34 @@ 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} + COMMAND ${LLVM_OBJCOPY} --remove-section=.swift_modhash ${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/cmake/aarch64-bare.cmake b/Kernel/cmake/aarch64-bare.cmake index 4494c10..3b90c1b 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.") + 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 e69de29..22e97ea 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -0,0 +1,15 @@ +ENTRY(_start) + +SECTIONS { + . = 0; + + .text : { + *(.text.boot) + *(.text*) + } + + .rodata : { *(.rodata*) } + .data : { *(.data*) } + .bss : { *(.bss*) *(COMMON) } + +} diff --git a/justfile b/justfile index 207c749..f3c716a 100644 --- a/justfile +++ b/justfile @@ -3,29 +3,31 @@ 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" -} +HB_PREFIX := if ARCH_NAME == "aarch64" { "/opt/homebrew" } else { "/usr/local" } +export PATH := HB_PREFIX + "/bin:" + HB_PREFIX + "/sbin:" + env_var("PATH") ACCEL := if OS_NAME == "macos" { if ARCH_NAME == "aarch64" { "-accel hvf" } else { "" } } else { - "" + if ARCH_NAME == "aarch64" { "-accel kvm" } else { "" } } -HB_PREFIX := if ARCH_NAME == "aarch64" { "/opt/homebrew" } else { "/usr/local" } -export PATH := HB_PREFIX + "/bin:" + HB_PREFIX + "/sbin:" + env_var("PATH") +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") +} + +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 } -CPU := if ARCH_NAME == "aarch64" { "host" } else { "max" } - export BUILD_DIR := justfile_directory() + "/.build" export TEMP_DIR := BUILD_DIR + "/temp" export BOOT_BIN := BUILD_DIR + "/Bootloader/BOOTAA64.EFI" @@ -56,18 +58,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}}