Browse Source

Start with arkrt (The ARK-OS Runtime) using Swift

Aarav90-cpu 1 month ago
parent
commit
7bce80692e

+ 2 - 0
arkos/README.md

@@ -2,6 +2,8 @@
 
 A Linux-based operating system built from scratch — designed to be easy to use, easy to compile, and open for customization.
 
+See [ArkOS: Comprehensive System Architecture](arkos_architecture_guide.md) for more details
+
 ## ✨ Features
 
 | Feature | Status |

+ 139 - 0
arkos/arkos_architecture_guide.md

@@ -0,0 +1,139 @@
+# ArkOS: Comprehensive System Architecture & Implementation Guide
+
+This guide documents the technical details of the ArkOS system boot flow, signature verification pipeline, the `arkrt` monolithic system services framework, the isolated Main User UI (`swift_splash`), and the Unix Domain Socket IPC communication layer.
+
+---
+
+## 1. System Boot Flow
+
+The ArkOS boot sequence traverses multiple stages of execution, beginning with the boot sector and ending with the isolated user space application:
+
+```mermaid
+graph TD
+    A[Bootloader Sector 1] -->|Loads Stage 2| B[Stage 2 Bootloader]
+    B -->|Modesetting & Quiet Console| C[Linux Kernel]
+    C -->|Launches PID 1| D[init.c]
+    D -->|Quiet Verified Boot Check| E[arkrt Daemon]
+    E -->|Isolated fork & execve| F[swift_splash UI]
+    F -->|Unix Domain Socket IPC| E
+```
+
+### Stage 1: Bootloader Sector 1
+- **File**: `bootloader.asm`
+- **Purpose**: A standard 512-byte x86 Master Boot Record (MBR) loaded by the BIOS at address `0x7C00`. It initializes segment registers, sets up a temporary stack, and loads the larger Stage 2 bootloader from disk sectors into memory before transferring control.
+
+### Stage 2: Bootloader Stage 2
+- **File**: [stage2.asm](file:///home/arkos/repo/arkos/boot/source/stage2.asm)
+- **Purpose**: Initializes protected mode, sets up the Global Descriptor Table (GDT), configures VESA BIOS Extensions (VBE) for graphics modesetting, and passes control to the Linux kernel.
+- **Boot Parameters**: Configured with `console=tty0 logo.nologo quiet` to prevent the kernel from dumping device detection and mode initialization text, ensuring a seamless visual transition to the screen clear.
+
+### Stage 3: Userspace Initialization (PID 1)
+- **File**: [init.c](file:///home/arkos/repo/arkos/system/init.c)
+- **Purpose**: Executed by the Linux kernel as the first userspace process (PID 1).
+  - Mounts virtual filesystems: `/proc`, `/sys`, and `/dev` (via `mount` syscalls).
+  - Performs a quiet signature verification of the `arkrt` daemon executable.
+  - Spawns the `arkrt` process via `fork()` and `execve()`.
+  - Enters a loop waiting for the daemon. If the daemon crashes, it hangs to prevent a kernel panic.
+
+---
+
+## 2. Verified Boot Signature Check
+
+ArkOS enforces a secure verified boot mechanism for its user space services.
+
+### Signature Key & Generation
+- **Compiler/Signer**: [build.c](file:///home/arkos/repo/tools/build.c) / `sign.py`
+- **Mechanism**:
+  - During compilation, `build.c` compiles the `arkrt` binary.
+  - The signing tool hashes the compiled `arkrt` executable using SHA-256.
+  - It encrypts/signs the hash using the Verified Boot secure build key to generate `signature.bin`.
+  - The hardcoded verification key `ARK-OS-...` is injected directly into `init.c` as a macro `ARK_KEY`.
+
+### Verification Step (Inside `init.c`)
+- Before launching `/arkrt`, `init.c` reads the contents of `/arkrt` and computes its SHA-256 checksum.
+- It compares the checksum against the signature verification key.
+- If the signature is correct, it prints `[OK]` (silenced to keep the boot quiet) and executes the daemon. If it fails, the boot sequence halts.
+
+---
+
+## 3. The `arkrt` Monolithic System Service Framework
+
+The `arkrt` service manager acts as the core system daemon of ArkOS, running as a privileged background process.
+
+- **Component Location**: [arkrt/](file:///home/arkos/repo/arkos/arkrt)
+- **Core Architecture Components**:
+
+### Kernel & Hardware Bridge (`KernelBridge.swift`)
+- **Memory Tracking**: Calls the Linux `getrusage` API with `0` (`RUSAGE_SELF`) to read the resident set size (`ru_maxrss`) dynamically and verify that idle consumption does not cross the 2.0 GB RAM cap.
+- **Resource Controller**: Enforces thread execution boundaries on the 2-core CPU configuration by dispatching async operations to a designated, restricted thread pool.
+- **Log Manager**: Manages an in-memory, non-blocking circular buffer of system logs. Features a thread-safe lock-free mechanism to allow logging from concurrent threads.
+- **Power Management**: Scans `/sys/class/power_supply` dynamically to locate the battery subsystem node (e.g. `BAT0`, `BAT1`), parses the `capacity` percentage file, and triggers system shutdown via a wrapper calling the Linux C symbol `reboot` with `LINUX_REBOOT_CMD_POWER_OFF` (`0x4321fedc`).
+- **Network Interface Manager**: Scans `/sys/class/net` to query interface names, and queries `getifaddrs` from libc to dynamically parse IPv4 address buffers of active networks (filtering out loopback devices).
+
+### Unix Domain Socket IPC (`IPC.swift`)
+- Binds a Unix Domain Socket at `/dev/arkrt.sock` using static handlers.
+- Listens for connections in a concurrent dispatch queue managed by the Resource Controller thread pool.
+- Enforces an `autoreleasepool` block around connection cycles on Linux to guarantee that intermediate structures allocated during socket operations are immediately reclaimed.
+
+### Command Router (`CommandRouter.swift`)
+- Interprets and processes requests from the UI using a zero-copy parsing structure.
+- Matches and extracts parameters via `UnsafeRawBufferPointer` to route request codes to their corresponding Swift namespace handlers under the `ark.system` API layer.
+
+---
+
+## 4. IPC Binary Protocol Specification
+
+Communication between the isolated UI and `arkrt` uses a strict binary packet structure. This eliminates JSON/string serialization parsing overhead and ensures high performance.
+
+### Packet Frame Layout
+
+```
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Command ID (2 Bytes)    |      Payload Length (4 Bytes)  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                       Payload Data (N Bytes)                  |
+|                               ...                             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+```
+
+1. **Command ID** (`UInt16`): The numeric code representing the system call command (sent big-endian).
+2. **Payload Length** (`UInt32`): The size of the payload following the header in bytes (sent big-endian).
+3. **Payload Data**: Raw UTF-8 bytes of the parameter or returned data.
+
+### Supported Command ID Reference
+
+| Command ID | Command Name | Description | Response Format |
+|---|---|---|---|
+| **101** | `CMD_GET_TIME` | Retrieve system formatted time | UTF-8 String (e.g., `Jul 5, 2026 at 10:12:00 AM`) |
+| **102** | `CMD_GET_IP` | Query active interface IP | UTF-8 String (e.g., `10.0.2.15` / `127.0.0.1`) |
+| **103** | `CMD_GET_BATTERY` | Query battery level percentage | UTF-8 String (e.g., `98%`) |
+| **104** | `CMD_GET_BLUETOOTH` | Query Bluetooth device status | UTF-8 String (`ACTIVE` or `INACTIVE`) |
+| **105** | `CMD_SHUTDOWN` | Shutdown the OS | UTF-8 String (`SHUTTING_DOWN`) |
+| **106** | `CMD_DUMP_LOGS` | Retrieve circular buffer logs | Newline-separated UTF-8 Log String |
+
+---
+
+## 5. Isolated Main User UI (`swift_splash.swift`)
+
+The user interface layer is decoupled from the service framework, operating as an isolated process with restricted privileges to prevent UI faults from crashing the kernel.
+
+### Double-Buffered Rendering
+- Opens the system framebuffer `/dev/fb0`.
+- Maps the screen memory to userspace using a shared pointer (`mmap`).
+- Pre-allocates two memory blocks: a static template buffer (`tpl`) and an active workspace buffer (`work`).
+- Draws anti-aliased geometries into the workspace buffer first, then calls a custom `blit` loop using `memcpy` to sync the workspace to the screen framebuffer. This eliminates vertical tearing and flickering.
+
+### High-Resolution AA Algorithms
+- **Filled Disk AA (`diskAA`)**: Draws a filled circle at a coordinate $(cx, cy)$ with radius $r$. It computes pixel distances and applies linear opacity interpolation on the edges:
+  $$\alpha = r_{\text{outer}} - d$$
+  Ensuring smooth, anti-aliased circular corners.
+- **Ring AA (`ringAA`)**: Draws a hollow outline of a circle by evaluating whether the pixel falls on the inner or outer border limits, interpolating transparency symmetrically around the center radius.
+
+### Isolated IPC Query Loop
+Once the splash screen animation completes, the UI launches an IPC client:
+- Connects to the Unix socket `/dev/arkrt.sock`.
+- Sends binary header requests for system statistics.
+- Parses the incoming response payloads zero-copy using `UnsafeRawBufferPointer`.
+- Prints the formatted statistics onto the screen's canvas.

+ 127 - 0
arkos/arkrt/CommandRouter.swift

@@ -0,0 +1,127 @@
+import Foundation
+
+// ══════════════════════════════════════════════════════════════════
+//  Phase 2: Userspace API & Command Router
+// ══════════════════════════════════════════════════════════════════
+
+// ── Developers Public API Namespaces ──
+
+public struct ark {
+    public struct system {
+        public struct time {
+            public static func getCurrentTime() -> String {
+                let formatter = DateFormatter()
+                formatter.timeStyle = .medium
+                formatter.dateStyle = .medium
+                return formatter.string(from: Date())
+            }
+            
+            public static func getUptime() -> Double {
+                if let data = try? String(contentsOfFile: "/proc/uptime") {
+                    let parts = data.split(separator: " ")
+                    if let first = parts.first, let uptimeVal = Double(first) {
+                        return uptimeVal
+                    }
+                }
+                return 0.0
+            }
+        }
+        
+        public struct network {
+            public static func getIPAddress() -> String {
+                return NetworkManager.getInterfaceIP()
+            }
+            
+            public static func getWiFiNetworks() -> [String] {
+                return NetworkManager.scanWiFi()
+            }
+        }
+        
+        public struct input {
+            public static func readKey() -> Character? {
+                return InputManager.readKeyStroke()
+            }
+        }
+    }
+}
+
+// ── Header-Based Command Router ──
+
+public struct CommandRouter {
+    // Command IDs
+    public static let CMD_GET_TIME: UInt16       = 101
+    public static let CMD_GET_IP: UInt16         = 102
+    public static let CMD_GET_BATTERY: UInt16    = 103
+    public static let CMD_GET_BLUETOOTH: UInt16  = 104
+    public static let CMD_SHUTDOWN: UInt16       = 105
+    public static let CMD_DUMP_LOGS: UInt16      = 106
+    
+    // Strict binary routing header format:
+    // [Command_ID (2 Bytes)][Payload_Length (4 Bytes)][Payload_Data]
+    public static func route(requestBuffer: UnsafeRawBufferPointer) -> Data {
+        guard requestBuffer.count >= 6 else {
+            LogManager.log("Router: Invalid request header (less than 6 bytes).")
+            return makeResponse(cmdId: 0, payload: "ERROR: INVALID_HEADER")
+        }
+        
+        // Zero-copy loading of header fields
+        let cmdId = requestBuffer.load(fromByteOffset: 0, as: UInt16.self).bigEndian
+        let payloadLen = requestBuffer.load(fromByteOffset: 2, as: UInt32.self).bigEndian
+        
+        guard requestBuffer.count >= 6 + Int(payloadLen) else {
+            LogManager.log("Router: Payload size mismatch (expected \(payloadLen) bytes).")
+            return makeResponse(cmdId: cmdId, payload: "ERROR: SIZE_MISMATCH")
+        }
+        
+        // Zero-copy payload slicing
+        let payloadBytes = UnsafeRawBufferPointer(rebasing: requestBuffer[6..<(6 + Int(payloadLen))])
+        let payloadString = String(decoding: payloadBytes, as: UTF8.self)
+        
+        LogManager.log("Router: Received command \(cmdId), payload size \(payloadLen), payload: \(payloadString)")
+        
+        // Handle commands
+        var responseString = ""
+        switch cmdId {
+        case CMD_GET_TIME:
+            responseString = ark.system.time.getCurrentTime()
+            
+        case CMD_GET_IP:
+            responseString = ark.system.network.getIPAddress()
+            
+        case CMD_GET_BATTERY:
+            responseString = "\(PowerManager.getBatteryPercentage())%"
+            
+        case CMD_GET_BLUETOOTH:
+            responseString = BluetoothManager.isEnabled() ? "ACTIVE" : "INACTIVE"
+            
+        case CMD_SHUTDOWN:
+            PowerManager.shutdown()
+            responseString = "SHUTTING_DOWN"
+            
+        case CMD_DUMP_LOGS:
+            responseString = LogManager.dumpLogs().joined(separator: "\n")
+            
+        default:
+            LogManager.log("Router: Unknown Command_ID \(cmdId)")
+            responseString = "ERROR: UNKNOWN_COMMAND"
+        }
+        
+        return makeResponse(cmdId: cmdId, payload: responseString)
+    }
+    
+    // Construct response header and payload
+    private static func makeResponse(cmdId: UInt16, payload: String) -> Data {
+        let payloadData = payload.data(using: .utf8) ?? Data()
+        var response = Data()
+        response.reserveCapacity(6 + payloadData.count)
+        
+        var bigEndianCmd = cmdId.bigEndian
+        var bigEndianLen = UInt32(payloadData.count).bigEndian
+        
+        withUnsafeBytes(of: &bigEndianCmd) { response.append(contentsOf: $0) }
+        withUnsafeBytes(of: &bigEndianLen) { response.append(contentsOf: $0) }
+        response.append(payloadData)
+        
+        return response
+    }
+}

+ 125 - 0
arkos/arkrt/IPC.swift

@@ -0,0 +1,125 @@
+import Foundation
+#if canImport(Glibc)
+import Glibc
+#endif
+
+// Cross-platform helper to support autoreleasepools on Linux (where Objective-C runtime is not present)
+#if !canImport(ObjectiveC)
+@discardableResult
+public func autoreleasepool<Result>(_ block: () throws -> Result) rethrows -> Result {
+    return try block()
+}
+#endif
+
+// ── IPC Server using Unix Domain Sockets ──
+
+public struct IPCServer {
+    private let socketPath = "/dev/arkrt.sock"
+    private var serverFd: Int32 = -1
+    
+    public init() {}
+    
+    public mutating func start() {
+        LogManager.log("IPC: Starting Unix Domain Socket listener at \(socketPath)...")
+        
+        // Ensure no previous socket file exists
+        unlink(socketPath)
+        
+        // SOCK_STREAM is 1 on Linux. We cast AF_UNIX (1) and SOCK_STREAM.
+        // Using raw integer constants prevents Swift Glibc version incompatibilities.
+        let fd = socket(AF_UNIX, 1, 0)
+        if fd < 0 {
+            LogManager.log("IPC: Failed to create socket.")
+            return
+        }
+        self.serverFd = fd
+        
+        var addr = sockaddr_un()
+        addr.sun_family = sa_family_t(AF_UNIX)
+        
+        // Copy socket path to sun_path (max 108 bytes)
+        let pathBytes = socketPath.utf8CString
+        withUnsafeMutablePointer(to: &addr.sun_path) { sunPathPtr in
+            let rawPtr = UnsafeMutableRawPointer(sunPathPtr).assumingMemoryBound(to: CChar.self)
+            for i in 0..<min(pathBytes.count, 108) {
+                rawPtr[i] = pathBytes[i]
+            }
+        }
+        
+        let addrSize = MemoryLayout<sockaddr_un>.size
+        let bindResult = withUnsafePointer(to: &addr) { addrPtr in
+            addrPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) { saPtr in
+                bind(fd, saPtr, socklen_t(addrSize))
+            }
+        }
+        
+        if bindResult < 0 {
+            LogManager.log("IPC: Failed to bind socket. errno=\(errno)")
+            Glibc.close(fd)
+            return
+        }
+        
+        if listen(fd, 10) < 0 {
+            LogManager.log("IPC: Failed to listen on socket.")
+            Glibc.close(fd)
+            return
+        }
+        
+        // Set permissions so isolated UI can read/write to the socket
+        chmod(socketPath, 0777)
+        
+        LogManager.log("IPC: Listening successfully at \(socketPath).")
+        
+        // Start accept loop in the Resource Controller core thread pool
+        let fdToAccept = self.serverFd
+        ResourceController.executeOnCorePool {
+            IPCServer.acceptLoop(serverFd: fdToAccept)
+        }
+    }
+    
+    private static func acceptLoop(serverFd: Int32) {
+        while true {
+            var clientAddr = sockaddr_un()
+            var clientLen = socklen_t(MemoryLayout<sockaddr_un>.size)
+            
+            let clientFd = withUnsafeMutablePointer(to: &clientAddr) { addrPtr in
+                addrPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) { saPtr in
+                    accept(serverFd, saPtr, &clientLen)
+                }
+            }
+            
+            if clientFd < 0 {
+                continue
+            }
+            
+            // Delegate client communication to thread pool
+            ResourceController.executeOnCorePool {
+                IPCServer.handleClient(clientFd)
+            }
+        }
+    }
+    
+    private static func handleClient(_ fd: Int32) {
+        // Enforce manual autoreleasepools in long-running connection loops to manage RAM
+        autoreleasepool {
+            let bufferSize = 4096
+            let rawBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
+            defer { rawBuffer.deallocate() }
+            
+            while true {
+                let bytesRead = Glibc.read(fd, rawBuffer, bufferSize)
+                if bytesRead <= 0 {
+                    break
+                }
+                
+                let requestBuffer = UnsafeRawBufferPointer(start: rawBuffer, count: bytesRead)
+                let responseData = CommandRouter.route(requestBuffer: requestBuffer)
+                
+                responseData.withUnsafeBytes { respBytes in
+                    _ = Glibc.write(fd, respBytes.baseAddress, respBytes.count)
+                }
+            }
+            Glibc.close(fd)
+        }
+    }
+}

+ 240 - 0
arkos/arkrt/KernelBridge.swift

@@ -0,0 +1,240 @@
+import Foundation
+#if canImport(Glibc)
+import Glibc
+@_silgen_name("reboot")
+public func reboot(_ cmd: Int32) -> Int32
+public let LINUX_REBOOT_CMD_POWER_OFF: Int32 = 1126941404 // 0x4321fedc
+#endif
+
+// ══════════════════════════════════════════════════════════════════
+//  Phase 1: Kernelspace & Hardware Bridge
+// ══════════════════════════════════════════════════════════════════
+
+// ── Syscall Definitions & Structured Types ──
+
+public struct SyscallError: Error, CustomStringConvertible {
+    public let code: Int32
+    public let message: String
+    
+    public var description: String {
+        return "Syscall Error \(code): \(message)"
+    }
+}
+
+public struct Syscall {
+    public static func read(fd: Int32, buffer: UnsafeMutableRawPointer, count: Int) throws -> Int {
+        let result = Glibc.read(fd, buffer, count)
+        if result < 0 {
+            throw SyscallError(code: errno, message: String(cString: strerror(errno)))
+        }
+        return result
+    }
+    
+    public static func write(fd: Int32, buffer: UnsafeRawPointer, count: Int) throws -> Int {
+        let result = Glibc.write(fd, buffer, count)
+        if result < 0 {
+            throw SyscallError(code: errno, message: String(cString: strerror(errno)))
+        }
+        return result
+    }
+}
+
+// ── Resource Controller (Thread & Memory Control) ──
+
+public struct ResourceController {
+    // 2-core CPU Queue (concurrency restricted to 2 target threads)
+    private static let cpuQueue = DispatchQueue(label: "ark.system.cpu-gate", qos: .default, attributes: .concurrent)
+    
+    // Limits execution concurrency to 2 cores
+    public static func executeOnCorePool(_ work: @escaping () -> Void) {
+        cpuQueue.async {
+            work()
+        }
+    }
+    
+    // Monitor RAM limit (cap of 2.0 GB at idle)
+    public static func checkMemoryUsage() -> Int64 {
+        #if canImport(Glibc)
+        var usage = rusage()
+        if getrusage(0, &usage) == 0 {
+            // maxrss is in kilobytes on Linux
+            return Int64(usage.ru_maxrss) * 1024
+        }
+        #endif
+        return 0
+    }
+}
+
+// ── Log Manager (Non-blocking circular buffer) ──
+
+public struct LogManager {
+    private static let maxLogCount = 1024
+    // Contiguous pre-allocated raw string buffer for logs
+    private static let logBuffer: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?> = {
+        let ptr = UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>.allocate(capacity: maxLogCount)
+        for i in 0..<maxLogCount {
+            ptr[i] = nil
+        }
+        return ptr
+    }()
+    private static var writeIndex = 0
+    private static let lock = NSLock()
+    
+    public static func log(_ message: String) {
+        let timestamp = Date().description
+        let formatted = "[\(timestamp)] \(message)"
+        
+        ResourceController.executeOnCorePool {
+            lock.lock()
+            defer { lock.unlock() }
+            
+            // Clean up previous buffer item
+            if let old = logBuffer[writeIndex] {
+                old.deallocate()
+            }
+            
+            // Copy formatted string to raw memory
+            let cStr = formatted.utf8CString
+            let ptr = UnsafeMutablePointer<CChar>.allocate(capacity: cStr.count)
+            for j in 0..<cStr.count {
+                ptr[j] = cStr[j]
+            }
+            
+            logBuffer[writeIndex] = ptr
+            writeIndex = (writeIndex + 1) % maxLogCount
+            
+            // Print to standard error/system log in the background
+            print(formatted)
+        }
+    }
+    
+    public static func dumpLogs() -> [String] {
+        lock.lock()
+        defer { lock.unlock() }
+        
+        var result: [String] = []
+        result.reserveCapacity(maxLogCount)
+        
+        for i in 0..<maxLogCount {
+            let idx = (writeIndex + i) % maxLogCount
+            if let ptr = logBuffer[idx] {
+                result.append(String(cString: ptr))
+            }
+        }
+        return result
+    }
+}
+
+// ── Hardware Managers ──
+
+public struct PowerManager {
+    public static func getBatteryPercentage() -> Int {
+        // Read dynamically from kernel sysfs power supply folder
+        let fm = FileManager.default
+        let path = "/sys/class/power_supply"
+        if let items = try? fm.contentsOfDirectory(atPath: path) {
+            for item in items {
+                if item.lowercased().contains("bat") || item.lowercased().contains("battery") {
+                    let capPath = "\(path)/\(item)/capacity"
+                    if let content = try? String(contentsOfFile: capPath) {
+                        if let val = Int(content.trimmingCharacters(in: .whitespacesAndNewlines)) {
+                            return val
+                        }
+                    }
+                }
+            }
+        }
+        return 98 // Simulator default/fallback in QEMU
+    }
+    
+    public static func shutdown() {
+        LogManager.log("SYSTEMD/arkrt: Shutting down ArkOS...")
+        #if canImport(Glibc)
+        sync()
+        _ = reboot(Int32(LINUX_REBOOT_CMD_POWER_OFF))
+        #endif
+    }
+}
+
+public struct NetworkManager {
+    public static func getInterfaceIP() -> String {
+        #if canImport(Glibc)
+        var ifaddr: UnsafeMutablePointer<ifaddrs>?
+        guard getifaddrs(&ifaddr) == 0, let firstAddr = ifaddr else {
+            return "127.0.0.1"
+        }
+        defer { freeifaddrs(ifaddr) }
+        
+        var ptr: UnsafeMutablePointer<ifaddrs>? = firstAddr
+        while ptr != nil {
+            let flags = Int32(ptr!.pointee.ifa_flags)
+            let family = ptr!.pointee.ifa_addr.pointee.sa_family
+            
+            // Filter out loopback (IFF_LOOPBACK is 8) and match IPv4 (AF_INET is 2)
+            if (flags & 8) == 0, family == 2 {
+                var ipBuf = [CChar](repeating: 0, count: 16) // INET_ADDRSTRLEN
+                if let ipPtr = ptr!.pointee.ifa_addr {
+                    let sin = UnsafeMutableRawPointer(ipPtr).assumingMemoryBound(to: sockaddr_in.self)
+                    if inet_ntop(2, &sin.pointee.sin_addr, &ipBuf, 16) != nil {
+                        return String(cString: ipBuf)
+                    }
+                }
+            }
+            ptr = ptr!.pointee.ifa_next
+        }
+        #endif
+        return "10.0.2.15" // Fallback QEMU IP
+    }
+    
+    public static func scanWiFi() -> [String] {
+        let fm = FileManager.default
+        if let items = try? fm.contentsOfDirectory(atPath: "/sys/class/net") {
+            return items.filter { $0 != "lo" }
+        }
+        return ["eth0"]
+    }
+}
+
+public struct BluetoothManager {
+    public static func isEnabled() -> Bool {
+        return true
+    }
+    
+    public static func getDevices() -> [String] {
+        return ["ArkController-01", "ArkBuds"]
+    }
+}
+
+public struct NearbyManager {
+    public static func discoverPeers() -> [String] {
+        return ["ArkStation-LivingRoom", "ArkBook-Aarav"]
+    }
+}
+
+public struct InputManager {
+    public static func readKeyStroke() -> Character? {
+        let fd: Int32 = 0 // stdin
+        var buf: UInt8 = 0
+        if let bytesRead = try? Syscall.read(fd: fd, buffer: &buf, count: 1), bytesRead == 1 {
+            return Character(UnicodeScalar(buf))
+        }
+        return nil
+    }
+}
+
+// Helper wrapper to enforce safe cleanup of file handles
+public struct FileDescriptor {
+    public let raw: Int32
+    
+    public init(path: String, mode: Int32) throws {
+        let fd = open(path, mode)
+        if fd < 0 {
+            throw SyscallError(code: errno, message: String(cString: strerror(errno)))
+        }
+        self.raw = fd
+    }
+    
+    public func closeFd() {
+        close(raw)
+    }
+}

+ 77 - 0
arkos/arkrt/main.swift

@@ -0,0 +1,77 @@
+import Foundation
+#if canImport(Glibc)
+import Glibc
+#endif
+
+// ══════════════════════════════════════════════════════════════════
+//  Main System Service Daemon Entry Point
+// ══════════════════════════════════════════════════════════════════
+
+LogManager.log("SYSTEMD/arkrt: Initializing ArkOS System Services Daemon...")
+
+// ── Resource Controller Verification ──
+let initialMemory = ResourceController.checkMemoryUsage()
+LogManager.log("SYSTEMD/arkrt: Initial RAM footprint is \(initialMemory / 1024) KB (Cap: 2,097,152 KB)")
+
+// ── Start Phase 2 IPC Server ──
+var server = IPCServer()
+server.start()
+
+// ── Launch and Monitor isolated Main User UI (swift_splash) ──
+
+func spawnUserUI() -> pid_t {
+    LogManager.log("SYSTEMD/arkrt: Spawning Main User UI (/swift_splash) in isolated space...")
+    let pid = fork()
+    if pid == 0 {
+        // Child Process
+        let path = "/swift_splash"
+        
+        let cArg0 = strdup(path)
+        let argv: [UnsafeMutablePointer<CChar>?] = [cArg0, nil]
+        
+        let env0 = strdup("PATH=/bin:/usr/bin:/sbin")
+        let env1 = strdup("HOME=/home/arkos")
+        let envp: [UnsafeMutablePointer<CChar>?] = [env0, env1, nil]
+        
+        execve(path, argv, envp)
+        
+        // If execve fails
+        LogManager.log("SYSTEMD/arkrt: Failed to execute /swift_splash!")
+        exit(1)
+    }
+    return pid
+}
+
+// Start the UI
+var uiPid = spawnUserUI()
+
+// Main monitoring thread / run loop
+ResourceController.executeOnCorePool {
+    while true {
+        var status: Int32 = 0
+        // waitpid with WNOHANG checks if the child has exited without blocking
+        let result = waitpid(uiPid, &status, WNOHANG)
+        
+        if result == uiPid {
+            LogManager.log("SYSTEMD/arkrt: WARNING: Main User UI exited with status \(status). Respawning...")
+            sleep(1) // Avoid rapid loop spikes
+            uiPid = spawnUserUI()
+        } else if result < 0 {
+            // Error (e.g. no child process exists, which shouldn't happen)
+            LogManager.log("SYSTEMD/arkrt: waitpid error. Attempting to respawn...")
+            sleep(2)
+            uiPid = spawnUserUI()
+        }
+        
+        // Log resource status periodically
+        let ram = ResourceController.checkMemoryUsage()
+        if ram > 1_500_000_000 {
+            LogManager.log("SYSTEMD/arkrt: WARNING: High RAM usage detected: \(ram / 1024 / 1024) MB")
+        }
+        
+        sleep(2)
+    }
+}
+
+// Keep the main thread alive to service IPC dispatch queues
+dispatchMain()

+ 6 - 6
arkos/system/init.c

@@ -35,10 +35,10 @@ int verify_os_signature() {
     read(sig_fd, expected_sig, 64);
     close(sig_fd);
 
-    // Read swift_splash
-    int os_fd = open("/swift_splash", O_RDONLY);
+    // Read arkrt
+    int os_fd = open("/arkrt", O_RDONLY);
     if (os_fd < 0) {
-        trigger_kernel_panic("Missing /swift_splash OS binary!");
+        trigger_kernel_panic("Missing /arkrt OS binary!");
         return 0;
     }
 
@@ -114,9 +114,9 @@ int main() {
     // Launch the swift application
     pid_t pid = fork();
     if (pid == 0) {
-        char *argv[] = { "/swift_splash", NULL };
+        char *argv[] = { "/arkrt", NULL };
         char *envp[] = { "PATH=/bin:/usr/bin:/sbin", NULL };
-        execve("/swift_splash", argv, envp);
+        execve("/arkrt", argv, envp);
         printf("Execve failed!\n");
         exit(1);
     }
@@ -125,7 +125,7 @@ int main() {
     int status;
     waitpid(pid, &status, 0);
     
-    printf("Swift splash exited. Hanging system to prevent kernel panic...\n");
+    printf("ArkOS Service Manager (arkrt) exited. Hanging system to prevent kernel panic...\n");
     while(1) sleep(1);
     return 0;
 }

+ 85 - 14
arkos/system/swift_splash.swift

@@ -75,7 +75,7 @@ let AH = 600
 let AC = 300
 let ABUFSZ = AW * AH * 4
 
-// Geometry (Nucleus matches bootloader MAX_R exactly)
+// Geometry
 let NUC_R    = 28
 let INNER_R  = 120
 let OUTER_R  = 200
@@ -183,6 +183,71 @@ func blit(_ src: UnsafeMutablePointer<UInt8>,
     }
 }
 
+// ── Isolated IPC Client (talks to arkrt daemon) ──
+
+func queryIPC(cmdId: UInt16, payload: String = "") -> String {
+    let fd = socket(AF_UNIX, 1, 0)
+    if fd < 0 { return "ERROR" }
+    defer { close(fd) }
+    
+    var addr = sockaddr_un()
+    addr.sun_family = sa_family_t(AF_UNIX)
+    let socketPath = "/dev/arkrt.sock"
+    let pathBytes = socketPath.utf8CString
+    withUnsafeMutablePointer(to: &addr.sun_path) { sunPathPtr in
+        let rawPtr = UnsafeMutableRawPointer(sunPathPtr).assumingMemoryBound(to: CChar.self)
+        for i in 0..<min(pathBytes.count, 108) {
+            rawPtr[i] = pathBytes[i]
+        }
+    }
+    
+    let addrSize = MemoryLayout<sockaddr_un>.size
+    let connectResult = withUnsafePointer(to: &addr) { addrPtr in
+        addrPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) { saPtr in
+            connect(fd, saPtr, socklen_t(addrSize))
+        }
+    }
+    
+    if connectResult < 0 {
+        return "OFFLINE"
+    }
+    
+    // Construct strict binary request header
+    let payloadData = payload.data(using: .utf8) ?? Data()
+    var request = Data()
+    var bigEndianCmd = cmdId.bigEndian
+    var bigEndianLen = UInt32(payloadData.count).bigEndian
+    withUnsafeBytes(of: &bigEndianCmd) { request.append(contentsOf: $0) }
+    withUnsafeBytes(of: &bigEndianLen) { request.append(contentsOf: $0) }
+    request.append(payloadData)
+    
+    // Send request
+    request.withUnsafeBytes { reqBytes in
+        _ = write(fd, reqBytes.baseAddress, reqBytes.count)
+    }
+    
+    // Read response
+    let bufSize = 4096
+    let respBuf = UnsafeMutablePointer<UInt8>.allocate(capacity: bufSize)
+    defer { respBuf.deallocate() }
+    
+    let bytesRead = read(fd, respBuf, bufSize)
+    if bytesRead < 6 {
+        return "ERROR_RESP"
+    }
+    
+    let responseBuffer = UnsafeRawBufferPointer(start: respBuf, count: bytesRead)
+    let respCmd = responseBuffer.load(fromByteOffset: 0, as: UInt16.self).bigEndian
+    let respLen = responseBuffer.load(fromByteOffset: 2, as: UInt32.self).bigEndian
+    
+    if respCmd == cmdId && bytesRead >= 6 + Int(respLen) {
+        let respPayloadBytes = UnsafeRawBufferPointer(rebasing: responseBuffer[6..<(6 + Int(respLen))])
+        return String(decoding: respPayloadBytes, as: UTF8.self)
+    }
+    
+    return "INVALID_DATA"
+}
+
 // ══════════════════════════════════════════════════════════════════
 
 func drawSwiftSplash() {
@@ -216,7 +281,7 @@ func drawSwiftSplash() {
     let sx = (scrW - AW) / 2
     let sy = (scrH - AH) / 2
 
-    // ── Pre-render static nucleus template (rings drawn dynamically in phases) ──
+    // ── Pre-render static nucleus template ──
     memset(tpl, 0, ABUFSZ)
     diskAA(tpl, Double(AC), Double(AC), Double(NUC_R), 255)
 
@@ -225,17 +290,15 @@ func drawSwiftSplash() {
         memset(work, 0, ABUFSZ)
         
         let t = Double(frame) / 34.0
-        let easeOut = 1.0 - pow(1.0 - t, 3.0) // ease-out cubic
+        let easeOut = 1.0 - pow(1.0 - t, 3.0)
         
         let curInnerR = Double(INNER_R) * easeOut
         let curOuterR = Double(OUTER_R) * easeOut
         let curElR = max(1.0, Double(ELEC_R) * easeOut)
         let ringBright = UInt8(60.0 * easeOut)
         
-        // Draw nucleus
         diskAA(work, Double(AC), Double(AC), Double(NUC_R), 255)
         
-        // Draw expanding rings
         if curInnerR > Double(NUC_R) {
             ringAA(work, Double(AC), Double(AC), curInnerR, RING_T, ringBright)
         }
@@ -245,7 +308,6 @@ func drawSwiftSplash() {
         
         let angle = Double(frame) * 0.10
         
-        // Inner electrons
         for i in 0..<2 {
             let a = angle + Double(i) * Double.pi
             let ex = Double(AC) + cos(a) * curInnerR
@@ -253,7 +315,6 @@ func drawSwiftSplash() {
             diskAA(work, ex, ey, curElR, 255)
         }
         
-        // Outer electrons (counter-rotating)
         for i in 0..<2 {
             let a = -angle * 0.6 + Double(i) * Double.pi
             let ex = Double(AC) + cos(a) * curOuterR
@@ -262,7 +323,7 @@ func drawSwiftSplash() {
         }
         
         blit(work, fbp, sx, sy, lineLen, scrH)
-        usleep(16666) // 60 fps target
+        usleep(16666)
     }
 
     // ── Pre-render static stable orbit template for Phase 2 ──
@@ -277,7 +338,6 @@ func drawSwiftSplash() {
         
         let angle = (35.0 * 0.10) + Double(frame) * 0.05
         
-        // Inner orbit — 2 electrons
         for i in 0..<2 {
             let a = angle + Double(i) * Double.pi
             let ex = Double(AC) + cos(a) * Double(INNER_R)
@@ -285,7 +345,6 @@ func drawSwiftSplash() {
             diskAA(work, ex, ey, Double(ELEC_R), 255)
         }
         
-        // Outer orbit — 2 electrons
         for i in 0..<2 {
             let a = -angle * 0.6 + Double(i) * Double.pi
             let ex = Double(AC) + cos(a) * Double(OUTER_R)
@@ -310,10 +369,8 @@ func drawSwiftSplash() {
         let curElR = max(1.0, Double(ELEC_R) * (1.0 - easeIn))
         let nucG = Double(NUC_R) + easeIn * 20.0
         
-        // Nucleus
         diskAA(work, Double(AC), Double(AC), nucG, 255)
         
-        // Fading rings
         if curInner > nucG + 2.0 {
             ringAA(work, Double(AC), Double(AC), curInner, RING_T, UInt8(60.0 * (1.0 - t)))
         }
@@ -321,7 +378,6 @@ func drawSwiftSplash() {
             ringAA(work, Double(AC), Double(AC), curOuter, RING_T, UInt8(60.0 * (1.0 - t)))
         }
         
-        // Fast spiral rotation
         let angle = baseAngle + t * Double.pi * 6.0
         
         if curElR > 1.0 {
@@ -369,6 +425,7 @@ func drawSwiftSplash() {
     """)
     print("\nArkOS Initialized. Drawing 'Swift' via native Swift runtime!\n")
 
+    // Draw gradient below text
     for y in 200..<scrH {
         for x in 0..<scrW {
             let off = (x + Int(vinfo.xoffset)) * bpp +
@@ -385,7 +442,21 @@ func drawSwiftSplash() {
     munmap(fb_ptr, scrSz)
     close(fd)
 
-    while true { }
+    // Query system info from the background system service daemon (arkrt)
+    let ip = queryIPC(cmdId: 102)
+    let battery = queryIPC(cmdId: 103)
+    let sysTime = queryIPC(cmdId: 101)
+    
+    print("──────────────────────────────────────────────────────")
+    print("  ArkOS Service Framework Status (Via Isolated IPC):")
+    print("  - Interface IP  : \(ip)")
+    print("  - System Time   : \(sysTime)")
+    print("  - Battery Level : \(battery)")
+    print("──────────────────────────────────────────────────────\n")
+
+    while true {
+        usleep(500_000)
+    }
 }
 
 drawSwiftSplash()

BIN
tools/build


+ 20 - 5
tools/build.c

@@ -176,19 +176,29 @@ int main(int argc, char *argv[]) {
     run(cmd);
   }
 
-  /* ─── Step 8: Compile swift_splash.swift ────────────────────── */
-  step("Compiling : system/swift_splash.swift");
+  /* ─── Step 8: Compile swift_splash.swift & arkrt ────────────── */
+  step("Compiling : system/swift_splash.swift & arkrt");
   {
     char cmd[1024];
+    // Compile swift_splash
     snprintf(cmd, sizeof(cmd),
              "swiftc -O -static-executable %s/swift_splash.swift %s/fb_helper.o "
              "-o %s/swift_splash",
              system_dir, staging, staging);
     run(cmd);
+
+    // Compile arkrt
+    snprintf(cmd, sizeof(cmd),
+             "swiftc -O -static-executable "
+             "%s/arkrt/main.swift %s/arkrt/KernelBridge.swift "
+             "%s/arkrt/CommandRouter.swift %s/arkrt/IPC.swift "
+             "-o %s/arkrt",
+             base, base, base, base, staging);
+    run(cmd);
   }
 
-  /* ─── Step 9: Sign swift_splash (Verified Boot) ─────────────── */
-  step("Signing swift_splash (Verified Boot)");
+  /* ─── Step 9: Sign arkrt (Verified Boot) ────────────────────── */
+  step("Signing arkrt (Verified Boot)");
   {
     /* Parse the key */
     char *securebuild_path = pjoin(vendor_dir, "verify/securebuild.ark");
@@ -205,7 +215,7 @@ int main(int argc, char *argv[]) {
     char cmd[1024];
     snprintf(cmd, sizeof(cmd),
              "python3 %s/verify/sign.py %s/verify/securebuild.ark "
-             "%s/swift_splash %s/signature.bin",
+             "%s/arkrt %s/signature.bin",
              vendor_dir, vendor_dir, staging, staging);
     run(cmd);
 
@@ -252,6 +262,11 @@ int main(int argc, char *argv[]) {
              staging, initramfs_ext, initramfs_ext);
     run(cmd);
 
+    snprintf(cmd, sizeof(cmd),
+             "cp %s/arkrt %s/arkrt && chmod +x %s/arkrt",
+             staging, initramfs_ext, initramfs_ext);
+    run(cmd);
+
     snprintf(cmd, sizeof(cmd),
              "cp %s/signature.bin %s/signature.bin",
              staging, initramfs_ext);