Working kernel written on C and userspace-ready #1
@@ -1,5 +1,7 @@
|
|||||||
.build
|
.build
|
||||||
|
build
|
||||||
.vscode
|
.vscode
|
||||||
.DS_Store
|
.DS_Store
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
ide-swift-toolchain.txt
|
||||||
.cache
|
.cache
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CompileFlags:
|
||||||
|
CompilationDatabase: ../.build/temp/Kernel
|
||||||
+32
-137
@@ -1,150 +1,45 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(ksOSKernel LANGUAGES ASM C)
|
project(ksOSKernel LANGUAGES ASM C)
|
||||||
set(KERNEL_MODULE_NAME "Kernel")
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
# --- Locate Swift toolchain with Embedded Swift stdlib ---
|
file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
|
||||||
# Priority: cmake var > env var > auto-detect
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/KernelMain.c
|
||||||
if(NOT SWIFT_TOOLCHAIN AND DEFINED ENV{SWIFT_TOOLCHAIN})
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/entry.S
|
||||||
set(SWIFT_TOOLCHAIN "$ENV{SWIFT_TOOLCHAIN}")
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/vectors.S
|
||||||
endif()
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/**/*.c
|
||||||
|
)
|
||||||
|
|
||||||
if(SWIFT_TOOLCHAIN)
|
add_executable(Kernel ${KERNEL_SOURCES})
|
||||||
set(SWIFTC "${SWIFT_TOOLCHAIN}/usr/bin/swiftc")
|
target_include_directories(Kernel PRIVATE
|
||||||
set(SWIFT_RESOURCE_DIR "${SWIFT_TOOLCHAIN}/usr/lib/swift")
|
${CMAKE_CURRENT_SOURCE_DIR}/Include/
|
||||||
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
${CMAKE_CURRENT_SOURCE_DIR}/../Common
|
||||||
# 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")
|
target_compile_options(Kernel PRIVATE
|
||||||
set(SWIFTC "${_SWIFTC_EXE}")
|
$<$<COMPILE_LANGUAGE:C>:
|
||||||
set(SWIFT_RESOURCE_DIR "${_SWIFTC_USR}/lib/swift")
|
-ffreestanding
|
||||||
elseif(EXISTS "${_SWIFTC_USR}/lib/swift/lib/swift/embedded")
|
-fno-stack-protector
|
||||||
set(SWIFTC "${_SWIFTC_EXE}")
|
-fno-builtin
|
||||||
set(SWIFT_RESOURCE_DIR "${_SWIFTC_USR}/lib/swift/lib/swift")
|
-Wall -Wextra
|
||||||
endif()
|
-g
|
||||||
endif()
|
-mgeneral-regs-only
|
||||||
endif()
|
>
|
||||||
|
)
|
||||||
|
|
||||||
if(NOT SWIFTC OR NOT EXISTS "${SWIFT_RESOURCE_DIR}/embedded")
|
target_link_options(Kernel PRIVATE
|
||||||
message(FATAL_ERROR
|
|
||||||
"Swift toolchain with Embedded Swift not found.\n"
|
|
||||||
"Install a swift.org toolchain and pass -DSWIFT_TOOLCHAIN=<root> "
|
|
||||||
"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)
|
|
||||||
add_link_options(
|
|
||||||
-fuse-ld=lld
|
|
||||||
-nostdlib
|
-nostdlib
|
||||||
-static
|
-static
|
||||||
-Wl,-T,${LINKER_SCRIPT}
|
-no-pie
|
||||||
|
-T "${CMAKE_CURRENT_SOURCE_DIR}/linker.ld"
|
||||||
|
-z max-page-size=0x1000
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SWIFT_SOURCES
|
set_target_properties(Kernel PROPERTIES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Source/kernel.swift
|
OUTPUT_NAME "Kernel.elf"
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Source/Arch/dtb.swift
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Source/IO/uart.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
|
|
||||||
-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_source_files_properties(${SWIFT_OBJ} PROPERTIES
|
add_custom_command(TARGET Kernel POST_BUILD
|
||||||
EXTERNAL_OBJECT TRUE
|
COMMAND ${LLVM_OBJCOPY} -O binary ${CMAKE_BINARY_DIR}/Kernel.elf ${CMAKE_BINARY_DIR}/Kernel.bin
|
||||||
GENERATED TRUE
|
COMMENT "Generating ksOSKernel.bin from Kernel.elf"
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(kernel.elf Source/Arch/entry.S Source/Support/stubs.c ${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\""
|
|
||||||
"\"-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}\"")
|
|
||||||
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()
|
|
||||||
|
|
||||||
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"
|
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
static inline void CPUYield() {
|
||||||
|
__asm__ volatile ("yield" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CPUWaitForInterrupt() {
|
||||||
|
__asm__ volatile ("wfi" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CPUDisableInterrupts() {
|
||||||
|
__asm__ volatile ("msr daifset, #3" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
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(Address address) {
|
||||||
|
UInt32 value = *(volatile UInt32*)address;
|
||||||
|
__asm__ volatile ("dsb ld" ::: "memory"); // wait till my read is finished physically
|
||||||
|
return value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kUARTBaseAddress = 0x09000000, // TODO: make it dynamic by parsing DTB
|
||||||
|
};
|
||||||
|
|
||||||
|
Int32 IOSerialPutCharacter(ASCII character);
|
||||||
|
Int32 IOSerialPutString(const ASCII* string);
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
#include <Lib/VAArgs.h>
|
||||||
|
|
||||||
|
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, ...);
|
||||||
@@ -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)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kOSLogBufferSize = 1024,
|
||||||
|
};
|
||||||
|
|
||||||
|
void OSLog(const ASCII* format, ...);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <Arch/Exceptions.h>
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void OSPanicException(ExceptionsContext* frame);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// 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 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;
|
||||||
|
|
||||||
|
typedef _Bool Boolean;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#include <Arch/Exceptions.h>
|
||||||
|
#include <Arch/CPU.h>
|
||||||
|
#include <IO/Serial.h>
|
||||||
|
#include <OS/Panic.h>
|
||||||
|
|
||||||
|
void ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) {
|
||||||
|
OSPanicException(frame);
|
||||||
|
}
|
||||||
@@ -1,81 +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
|
|
||||||
case .endNode:
|
|
||||||
continue
|
|
||||||
case .nop:
|
|
||||||
continue
|
|
||||||
case .end:
|
|
||||||
finished = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
.section .text.boot, "ax"
|
.section .text.boot, "ax"
|
||||||
.global _start
|
.global _start
|
||||||
|
|
||||||
_start:
|
_start:
|
||||||
bl kmain
|
bl ExceptionsVectorsInit
|
||||||
.hang:
|
bl KernelMain
|
||||||
b .hang
|
b .
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <IO/Serial.h>
|
||||||
|
#include <Arch/IO.h>
|
||||||
|
#include <Arch/CPU.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -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..<message.utf8CodeUnitCount {
|
|
||||||
_serialPutchar(Int32(message.utf8Start[i]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include <OS/Log.h>
|
||||||
|
|
||||||
|
void KernelMain(void) {
|
||||||
|
OSLog("Hi meow! ;3\n");
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
#include <Lib/String.h>
|
||||||
|
#include <Lib/VAArgs.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#include <OS/Log.h>
|
||||||
|
#include <Lib/String.h>
|
||||||
|
#include <Lib/VAArgs.h>
|
||||||
|
#include <IO/Serial.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#include <OS/Panic.h>
|
||||||
|
#include <OS/Log.h>
|
||||||
|
#include <Arch/CPU.h>
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrintSeparator() {
|
||||||
|
OSLog("--------------------------------\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__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)
|
||||||
|
|
||||||
|
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();
|
||||||
|
CPUWaitForInterrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include "bootinfo.h"
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
@_cdecl("kmain")
|
|
||||||
public func kernelMain(_ bootInfo: UnsafeMutablePointer<Bootinfo>) {
|
|
||||||
kprint("Test nya")
|
|
||||||
}
|
|
||||||
@@ -3,26 +3,53 @@ set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
|||||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||||
|
|
||||||
if(NOT LLVM_BIN)
|
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(
|
execute_process(
|
||||||
COMMAND brew --prefix llvm
|
COMMAND brew --prefix llvm
|
||||||
OUTPUT_VARIABLE LLVM_PREFIX
|
OUTPUT_VARIABLE LLVM_PREFIX
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
RESULT_VARIABLE BREW_PREFIX_RESULT
|
||||||
)
|
)
|
||||||
set(LLVM_BIN "${LLVM_PREFIX}/bin")
|
if(BREW_PREFIX_RESULT EQUAL 0 AND EXISTS "${LLVM_PREFIX}/bin/clang")
|
||||||
else()
|
set(_CLANG "${LLVM_PREFIX}/bin/clang")
|
||||||
find_program(_CLANG clang)
|
|
||||||
if(NOT _CLANG)
|
|
||||||
message(FATAL_ERROR "clang not found.")
|
|
||||||
endif()
|
endif()
|
||||||
get_filename_component(LLVM_BIN "${_CLANG}" DIRECTORY)
|
|
||||||
endif()
|
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()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_C_COMPILER "${LLVM_BIN}/clang")
|
set(CMAKE_C_COMPILER "${LLVM_BIN}/clang")
|
||||||
set(CMAKE_ASM_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(TARGET_TRIPLE aarch64-none-elf)
|
||||||
set(CMAKE_C_COMPILER_TARGET ${TARGET_TRIPLE})
|
set(CMAKE_C_COMPILER_TARGET ${TARGET_TRIPLE})
|
||||||
set(CMAKE_ASM_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)
|
||||||
|
set(CMAKE_C_LINK_FLAGS "")
|
||||||
|
set(CMAKE_C_LINK_EXECUTABLE
|
||||||
|
"${TERMOS_LD_LLD} <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|||||||
+2
-1
@@ -6,8 +6,9 @@ build:
|
|||||||
|
|
||||||
cmake --build {{TEMP_DIR}}/Kernel
|
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"
|
@echo "✅ Kernel ready at: {{BUILD_DIR}}/Kernel/ksOSKernel.bin"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf {{TEMP_DIR}}/Kernel
|
rm -rf {{TEMP_DIR}}/Kernel
|
||||||
|
rm -f compile_commands.json
|
||||||
Reference in New Issue
Block a user