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()