Pārlūkot izejas kodu

Boot Phase Done. Added Boot Animation For after kernel initalistion.

Aarav90-cpu 1 mēnesi atpakaļ
vecāks
revīzija
2c40294a47

+ 9 - 0
arkos/.gitignore

@@ -0,0 +1,9 @@
+# Build outputs
+finished/
+out_staging/
+
+# Compiled binaries (these are built into out_staging/ now)
+system/init
+system/swift_splash
+system/fb_helper.o
+system/signature.bin

+ 16 - 2
arkos/Makefile

@@ -1,11 +1,25 @@
+# Determine project root relative to this Makefile (arkos/Makefile)
+ROOT := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))/..)
+TOOLS := $(ROOT)/tools
+ARKOS := $(ROOT)/arkos
+CLANG := $(ARKOS)/prebuilts/clang/bin/clang
+
 .PHONY: build run clean
 
 build:
-	$(MAKE) -C /home/arkos/repo/tools
-	/home/arkos/repo/tools/build
+	@$(MAKE) --no-print-directory -C $(TOOLS)
+	@$(TOOLS)/build $(ARKOS)
 
 run:
 	@echo "Starting ArkOS Testing Window in QEMU..."
+	@qemu-system-x86_64 \
+		-m 2048 \
+		-smp 2 \
+		-drive file=finished/boot.img,format=raw,index=0,media=disk \
+		-drive file=finished/sys.img,format=raw,index=1,media=disk \
+		-drive file=finished/vend.img,format=raw,index=2,media=disk \
+		-vga virtio \
+		-enable-kvm 2>/dev/null || \
 	qemu-system-x86_64 \
 		-m 2048 \
 		-smp 2 \

+ 112 - 20
arkos/README.md

@@ -1,29 +1,121 @@
-# ARK OS
+# ArkOS
 
-I want to make a OS that is perfect for normal ad dev people!
+A Linux-based operating system built from scratch — designed to be easy to use, easy to compile, and open for customization.
 
-Making/Compiling/Using(few) a Linux Based OS : Hard
-Compiling Android : Heavy
-Windows: Bloated
-MacOS : Locked Down
+## ✨ Features
 
-So I want to make a OS 
+| Feature | Status |
+|---------|--------|
+| Custom BIOS bootloader (stage1 + stage2) | ✅ |
+| VESA graphics boot animation (60 FPS expanding dot) | ✅ |
+| Verified Boot (SHA256 key-signed OS binary) | ✅ |
+| Native Swift splash screen via Linux framebuffer | ✅ |
+| Linux kernel 7.0 with custom initramfs | ✅ |
+| Prebuilt Clang/LLVM toolchain | ✅ |
+| `.ark` configuration file format | ✅ |
+| Modular build system with progress output | ✅ |
+| Service Manager | 🔜 |
+| Package Manager | 🔜 |
 
- - Easy To use
- - Easy to Compile
- - Not Bloated
- - And open for customization and contributions
+## 🏗️ Building
 
-And that is why I am making ARK-OS!
+### Prerequisites
 
-## This OS is still under development under Phase 1 (The Base)
+| Tool | Purpose |
+|------|---------|
+| `clang` (prebuilt, included) | C compilation |
+| `swiftc` | Swift compilation |
+| `nasm` | x86 assembly |
+| `python3` | Boot image packing & signing |
+| `qemu-system-x86_64` | Testing |
+| `mkfs.ext4` | Disk image generation |
+| `cpio`, `gzip` | Initramfs packing |
 
- - booting and animation ✔️
- - frameworks and compiling ✔️
- - system and vendor ✔️
- - to .zip ✔️
- - swift implementation to print swift in text on display ✔️
- - Verified Booting
- - Color Drawing
+### Build & Run
 
+```bash
+cd arkos/
+make build    # Compiles everything, generates disk images
+make run      # Launches QEMU with the built images
+make clean    # Removes all build artifacts
+```
 
+The build system uses the prebuilt Clang toolchain at `prebuilts/clang/` for all C compilation. No system compiler dependency.
+
+### Build Output
+
+The build system shows modular progress:
+
+```
+╔══════════════════════════════════════╗
+║       ArkOS Build System v2.0        ║
+╚══════════════════════════════════════╝
+
+[ 1/14] Cleaning previous build
+[ 2/14] Creating staging directories
+[ 3/14] Integrating frameworks
+[ 4/14] Preparing boot files
+...
+[14/14] Generating disk images
+
+╔══════════════════════════════════════╗
+║          Build complete! ✓            ║
+╚══════════════════════════════════════╝
+```
+
+### Output Images
+
+All images are generated in `finished/`:
+
+| Image | Description |
+|-------|-------------|
+| `boot.img` | Bootloader + animation + kernel + initramfs |
+| `sys.img` | System partition (frameworks, libraries) |
+| `vend.img` | Vendor partition (DRM, keys, mirror info) |
+| `avb.img` | Android Verified Boot metadata |
+| `vbmeta.img` | Verified boot metadata |
+| `dtbo.img` | Device tree blob overlay |
+
+## 📁 Project Structure
+
+```
+arkos/
+├── boot/                    # Bootloader source & configs
+│   ├── source/              # Assembly source (bootloader.asm, stage2.asm)
+│   │   └── animationframes/ # Pre-generated boot animation frames
+│   ├── initramfs.img        # Base initramfs image
+│   └── *.ark                # Boot configuration files
+├── frameworks/              # OS frameworks (Swift, DRM, SwiftUI)
+├── hardware/                # Hardware abstraction layer (future)
+├── kernel/                  # Linux kernel source + prebuilt bzImage
+├── prebuilts/               # Prebuilt toolchains
+│   └── clang/               # LLVM/Clang 22 toolchain
+├── system/                  # Core system components
+│   ├── init.c               # PID 1 init process (Verified Boot)
+│   ├── swift_splash.swift   # Native Swift framebuffer splash
+│   ├── sha256.c/h           # SHA256 implementation for signing
+│   └── fb_helper.c          # Framebuffer ioctl helper
+├── vendor/                  # Vendor-specific files
+│   ├── verify/              # Verified Boot keys & signing tools
+│   ├── mirror/              # Mirror configuration
+│   └── Widewine/            # DRM (Widevine) integration
+├── arkrt/                   # ArkOS runtime (future)
+├── Makefile                 # Top-level build entry point
+└── finished/                # Build output (generated)
+```
+
+## 🔐 Verified Boot
+
+ArkOS implements a custom Verified Boot chain:
+
+1. The build system reads the signing key from `vendor/verify/securebuild.ark`
+2. `sign.py` computes `SHA256(KEY + swift_splash_binary)` → `signature.bin`
+3. At boot, `init.c` recomputes the hash and compares against `signature.bin`
+4. **Mismatch → Kernel Panic** (system halts with security warning)
+5. **Match → Boot continues** into the Swift splash screen
+
+> ⚠️ Never commit your real signing key to a public repository. Use `vendor/verify/key.py` to generate new keys.
+
+## 📄 License
+
+See [LICENSE](LICENSE) for details.

+ 2 - 2
arkos/boot/initramfs.ark

@@ -1,7 +1,7 @@
 # ArkOS Boot Loader Configuration
 Target_Kernel_Version = 7.0
-Initramfs_Source_Directory = /home/arkos/arkos/system/sysroot/
-Compiled_Image_Output = /home/arkos/arkos/boot/initramfs.img
+Initramfs_Source_Directory = system/sysroot/
+Compiled_Image_Output = boot/initramfs.img
 
 # Core Initialization Directives
 Compression_Format = gzip

+ 65 - 0
arkos/boot/source/animationframes/generate_frames.py

@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+"""
+Generate boot animation frames: ONLY the nucleus expanding.
+The orbiting electrons are handled by Swift after the kernel boots.
+Output: animation.bin (concatenated raw 32-bit BGRA frames, 200x200 each)
+"""
+import math
+import os
+import struct
+import sys
+
+FRAME_COUNT = 60
+WIDTH = 200
+HEIGHT = 200
+CX = WIDTH / 2.0
+CY = HEIGHT / 2.0
+NUCLEUS_MAX_R = 28.0
+
+
+def main():
+    if len(sys.argv) < 2:
+        print("Usage: generate_frames.py <output-dir>")
+        sys.exit(1)
+
+    out_dir = sys.argv[1]
+    os.makedirs(out_dir, exist_ok=True)
+    out_path = os.path.join(out_dir, "animation.bin")
+
+    all_frames = bytearray()
+
+    for f in range(FRAME_COUNT):
+        # Ease-out cubic expansion
+        p = f / float(FRAME_COUNT - 1)
+        p = 1.0 - (1.0 - p) ** 3
+        radius = p * NUCLEUS_MAX_R
+
+        frame = bytearray()
+        for y in range(HEIGHT):
+            for x in range(WIDTH):
+                dx = x - CX
+                dy = y - CY
+                dist = math.sqrt(dx * dx + dy * dy)
+
+                if dist < radius:
+                    val = 255
+                elif dist < radius + 1.5:
+                    val = int(255 * (1.0 - (dist - radius) / 1.5))
+                else:
+                    val = 0
+
+                # 32-bit BGRA
+                frame.extend(struct.pack('BBBB', val, val, val, 0xFF))
+
+        all_frames.extend(frame)
+
+    with open(out_path, 'wb') as fp:
+        fp.write(all_frames)
+
+    size_kb = len(all_frames) // 1024
+    print(f"  Generated {FRAME_COUNT} frames ({WIDTH}x{HEIGHT}x32bpp) "
+          f"-> animation.bin ({size_kb} KB)")
+
+
+if __name__ == '__main__':
+    main()

+ 19 - 13
arkos/boot/source/stage2.asm

@@ -1,17 +1,19 @@
 [BITS 16]
 [ORG 0x7E00]
 
-    ; Set VESA Video Mode (1024x768x32)
+    ; Set VESA Video Mode (1024x768x32 - Bochs VBE mode)
     mov ax, 0x4F02
-    mov bx, 0x4118
+    mov bx, 0x4144       ; mode 0x144 + LFB bit = 32bpp guaranteed
     int 0x10
 
-    ; Get VBE Mode Info to find the LFB address
+    ; Get VBE Mode Info to find the LFB address and pitch
     mov ax, 0x4F01
-    mov cx, 0x118
+    mov cx, 0x0144
     mov di, 0x3000
     int 0x10
-    mov edi, [0x3028] ; LFB Physical Address
+    movzx eax, word [0x3010] ; BytesPerScanLine (actual pitch)
+    mov [screen_pitch], eax
+    mov edi, [0x3028]     ; LFB Physical Address
     mov [lfb_addr], edi
 
     ; Enter Unreal Mode
@@ -57,25 +59,28 @@
     mov edi, 0x2000000
     call read_sectors_high
 
-    ; Play Animation
-    mov ecx, 100 ; 100 frames
+    ; Play Animation (nucleus expansion only — electrons done by Swift later)
+    mov ecx, 60
     mov esi, 0x2000000 ; Source of animation frames
 .play_anim:
     push ecx
     mov edi, [lfb_addr]
     ; Center X = (1024-200)/2 = 412
     ; Center Y = (768-200)/2 = 284
-    ; Dest offset = (284 * 1024 + 412) * 3 = 873684
-    add edi, 873684
-    
+    ; Dest offset = 284 * pitch + 412 * 4
+    mov eax, 284
+    imul eax, dword [screen_pitch]
+    add eax, 412 * 4
+    add edi, eax
+
     mov cx, 200 ; 200 lines
 .draw_line:
     push ecx
     push edi
-    mov ecx, 150 ; 200 pixels * 3 bytes (24-bit) = 600 bytes = 150 dwords
+    mov ecx, 200 ; 200 pixels * 4 bytes (32bpp) = 800 bytes = 200 dwords
     a32 rep movsd
     pop edi
-    add edi, 1024 * 3 ; Next line on screen (3072 bytes)
+    add edi, [screen_pitch] ; Advance by actual pitch
     pop ecx
     dec cx
     jnz .draw_line
@@ -312,7 +317,8 @@ initramfs_size_bytes: dd 0
 animation_lba:        dd 0
 animation_size_sectors: dd 0
 lfb_addr:             dd 0
-cmd_line: db "console=tty0 init=/init root=/dev/sdb rw quiet splash vt.global_cursor_default=0 fbcon=nodefer", 0
+screen_pitch:         dd 0
+cmd_line: db "console=tty0 loglevel=0 logo.nologo init=/init root=/dev/sdb rw quiet vt.global_cursor_default=0", 0
 
 align 4
 dap:

+ 3 - 3
arkos/kernel/Makefile

@@ -2263,7 +2263,7 @@ arkos_install_kernel:
 		cp arch/x86/boot/bzImage prebuilt/bzImage; \
 		echo "ArkOS: Successfully installed custom kernel to prebuilt/bzImage"; \
 	fi
-	@mkdir -p /home/arkos/arkos/system/ark-sysroot
-	@$(MAKE) INSTALL_MOD_PATH=/home/arkos/arkos/system/ark-sysroot modules_install || true
-	@$(MAKE) INSTALL_HDR_PATH=/home/arkos/arkos/system/ark-sysroot/usr headers_install || true
+	@mkdir -p $(CURDIR)/../system/ark-sysroot
+	@$(MAKE) INSTALL_MOD_PATH=$(CURDIR)/../system/ark-sysroot modules_install || true
+	@$(MAKE) INSTALL_HDR_PATH=$(CURDIR)/../system/ark-sysroot/usr headers_install || true
 	@echo "ArkOS: Modules and Headers installed to ark-sysroot!"

BIN
arkos/system/fb_helper.o


BIN
arkos/system/init


+ 4 - 7
arkos/system/init.c

@@ -6,7 +6,7 @@
 #include <sys/wait.h>
 #include <fcntl.h>
 #include <string.h>
-#include "sha256.h"
+#include "../vendor/verify/sha256.h"
 
 #ifndef ARK_KEY
 #define ARK_KEY "UNKNOWN_KEY"
@@ -25,8 +25,6 @@ void trigger_kernel_panic(const char *msg) {
 }
 
 int verify_os_signature() {
-    printf("ArkOS Verified Boot: Verifying OS signature...\n");
-    
     // Read signature.bin
     int sig_fd = open("/signature.bin", O_RDONLY);
     if (sig_fd < 0) {
@@ -84,7 +82,6 @@ int verify_os_signature() {
         return 0;
     }
     
-    printf("ArkOS Verified Boot: OK! Key and Signature match.\n");
     return 1;
 }
 
@@ -107,13 +104,13 @@ int main() {
         if (fd > 2) close(fd);
     }
     
-    printf("ArkOS C Init Wrapper: Environment mounted.\n");
+    // Force black background, clear screen, hide cursor (prevents white flash)
+    printf("\033[0;40m\033[2J\033[H\033[?25l");
+    fflush(stdout);
     
     // VERIFIED BOOT CHECK
     verify_os_signature();
     
-    printf("ArkOS C Init Wrapper: Launching Swift Splash...\n");
-    
     // Launch the swift application
     pid_t pid = fork();
     if (pid == 0) {

+ 0 - 1
arkos/system/signature.bin

@@ -1 +0,0 @@
-da08a866b0859630952bb4e19b3f4f4d7a19395d4aae262a8b2da7519520968e

BIN
arkos/system/swift_splash


+ 310 - 53
arkos/system/swift_splash.swift

@@ -3,7 +3,8 @@ import Foundation
 import Glibc
 #endif
 
-// Define our structs to match the C structs
+// ── Framebuffer structs ──
+
 struct fb_bitfield {
     var offset: UInt32 = 0
     var length: UInt32 = 0
@@ -41,7 +42,9 @@ struct fb_var_screeninfo {
 }
 
 struct fb_fix_screeninfo {
-    var id: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
+    var id: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8,
+             Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8) =
+        (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
     var smem_start: UInt = 0
     var smem_len: UInt32 = 0
     var type: UInt32 = 0
@@ -63,71 +66,325 @@ func get_vinfo(_ fd: Int32, _ vinfo: UnsafeMutableRawPointer) -> Int32
 @_silgen_name("get_finfo")
 func get_finfo(_ fd: Int32, _ finfo: UnsafeMutableRawPointer) -> Int32
 
-func drawSwiftSplash() {
-    let fbPath = "/dev/fb0"
+// ══════════════════════════════════════════════════════════════════
+//  Anti-Aliased High-Resolution Back-Buffered Renderer
+// ══════════════════════════════════════════════════════════════════
+
+let AW = 600
+let AH = 600
+let AC = 300
+let ABUFSZ = AW * AH * 4
+
+// Geometry (Nucleus matches bootloader MAX_R exactly)
+let NUC_R    = 28
+let INNER_R  = 120
+let OUTER_R  = 200
+let ELEC_R   = 12
+let RING_T   = 2.0
+
+// Draw filled disk with anti-aliasing (smooth corners)
+func diskAA(_ p: UnsafeMutablePointer<UInt8>, _ cx: Double, _ cy: Double, _ r: Double, _ val: UInt8) {
+    let y0 = max(0, Int(cy - r - 2))
+    let y1 = min(AH - 1, Int(cy + r + 2))
+    let x0 = max(0, Int(cx - r - 2))
+    let x1 = min(AW - 1, Int(cx + r + 2))
     
-    let fd = open(fbPath, O_RDWR)
-    if fd < 0 {
-        print("Error: Cannot open framebuffer at \\(fbPath).")
-        return
-    }
+    let rInner = r - 0.5
+    let rInnerSq = rInner * rInner
+    let rOuter = r + 0.5
+    let rOuterSq = rOuter * rOuter
     
-    var vinfo = fb_var_screeninfo()
-    if get_vinfo(fd, &vinfo) < 0 {
-        print("Error reading variable information.")
-        close(fd)
-        return
+    let fVal = Double(val)
+    for y in y0...y1 {
+        let dy = Double(y) - cy
+        let dySq = dy * dy
+        let rowBase = y * AW * 4
+        for x in x0...x1 {
+            let dx = Double(x) - cx
+            let distSq = dx * dx + dySq
+            if distSq < rInnerSq {
+                let off = rowBase + x * 4
+                p[off]     = max(p[off], val)
+                p[off + 1] = max(p[off + 1], val)
+                p[off + 2] = max(p[off + 2], val)
+            } else if distSq < rOuterSq {
+                let dist = sqrt(distSq)
+                let alpha = rOuter - dist
+                let v = UInt8(fVal * alpha)
+                let off = rowBase + x * 4
+                p[off]     = max(p[off], v)
+                p[off + 1] = max(p[off + 1], v)
+                p[off + 2] = max(p[off + 2], v)
+            }
+        }
     }
+}
+
+// Draw ring outline with anti-aliasing (smooth curves)
+func ringAA(_ p: UnsafeMutablePointer<UInt8>, _ cx: Double, _ cy: Double, _ r: Double, _ t: Double, _ val: UInt8) {
+    let scan = r + t + 2
+    let y0 = max(0, Int(cy - scan))
+    let y1 = min(AH - 1, Int(cy + scan))
+    let x0 = max(0, Int(cx - scan))
+    let x1 = min(AW - 1, Int(cx + scan))
     
-    var finfo = fb_fix_screeninfo()
-    if get_finfo(fd, &finfo) < 0 {
-        print("Error reading fixed information.")
-        close(fd)
-        return
-    }
+    let rInMin = r - t - 0.5
+    let rInMax = r - t + 0.5
+    let rOutMin = r + t - 0.5
+    let rOutMax = r + t + 0.5
     
-    print("Screen is \\(vinfo.xres)x\\(vinfo.yres), \\(vinfo.bits_per_pixel)bpp")
+    let rInMinSq = rInMin * rInMin
+    let rInMaxSq = rInMax * rInMax
+    let rOutMinSq = rOutMin * rOutMin
+    let rOutMaxSq = rOutMax * rOutMax
     
-    // Clear the screen and print the SWIFT ASCII art to the console FIRST
-    print("\u{1B}[2J\u{1B}[H", terminator: "")
+    let tOuter = t + 0.5
+    let fVal = Double(val)
+    
+    for y in y0...y1 {
+        let dy = Double(y) - cy
+        let dySq = dy * dy
+        let rowBase = y * AW * 4
+        for x in x0...x1 {
+            let dx = Double(x) - cx
+            let d = dx * dx + dySq
+            if d >= rInMaxSq && d <= rOutMinSq {
+                // Fully inside the ring
+                let off = rowBase + x * 4
+                p[off]     = max(p[off], val)
+                p[off + 1] = max(p[off + 1], val)
+                p[off + 2] = max(p[off + 2], val)
+            } else if (d >= rInMinSq && d < rInMaxSq) || (d > rOutMinSq && d <= rOutMaxSq) {
+                // On the inner or outer edge
+                let dist = sqrt(d)
+                let diff = abs(dist - r)
+                let alpha = tOuter - diff
+                let v = UInt8(fVal * alpha)
+                let off = rowBase + x * 4
+                p[off]     = max(p[off], v)
+                p[off + 1] = max(p[off + 1], v)
+                p[off + 2] = max(p[off + 2], v)
+            }
+        }
+    }
+}
+
+// Blit buffer to framebuffer
+func blit(_ src: UnsafeMutablePointer<UInt8>,
+          _ fbp: UnsafeMutablePointer<UInt8>,
+          _ sx: Int, _ sy: Int,
+          _ lineLen: Int, _ scrH: Int) {
+    for y in 0..<AH {
+        let fy = sy + y
+        if fy < 0 || fy >= scrH { continue }
+        memcpy(fbp + fy * lineLen + sx * 4,
+               src + y * AW * 4,
+               AW * 4)
+    }
+}
+
+// ══════════════════════════════════════════════════════════════════
+
+func drawSwiftSplash() {
+    let fd = open("/dev/fb0", O_RDWR)
+    if fd < 0 { print("Error: Cannot open /dev/fb0"); return }
+
+    var vinfo = fb_var_screeninfo()
+    if get_vinfo(fd, &vinfo) < 0 { close(fd); return }
+
+    var finfo = fb_fix_screeninfo()
+    if get_finfo(fd, &finfo) < 0 { close(fd); return }
+
+    let scrW    = Int(vinfo.xres)
+    let scrH    = Int(vinfo.yres)
+    let bpp     = Int(vinfo.bits_per_pixel) / 8
+    let lineLen = Int(finfo.line_length)
+    let scrSz   = Int(finfo.smem_len)
+
+    let fb_ptr = mmap(nil, scrSz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
+    if fb_ptr == MAP_FAILED { close(fd); return }
+    let fbp = fb_ptr!.bindMemory(to: UInt8.self, capacity: scrSz)
+
+    // ── Clear entire screen to BLACK immediately ──
+    memset(fbp, 0, scrSz)
+
+    // Allocate raw pointer buffers
+    let tpl  = UnsafeMutablePointer<UInt8>.allocate(capacity: ABUFSZ)  // template
+    let work = UnsafeMutablePointer<UInt8>.allocate(capacity: ABUFSZ)  // workspace
+
+    // Centered coordinates
+    let sx = (scrW - AW) / 2
+    let sy = (scrH - AH) / 2
+
+    // ── Pre-render static nucleus template (rings drawn dynamically in phases) ──
+    memset(tpl, 0, ABUFSZ)
+    diskAA(tpl, Double(AC), Double(AC), Double(NUC_R), 255)
+
+    // ── Phase 1: Spawn & Orbit Expansion (35 frames) ──
+    for frame in 0..<35 {
+        memset(work, 0, ABUFSZ)
+        
+        let t = Double(frame) / 34.0
+        let easeOut = 1.0 - pow(1.0 - t, 3.0) // ease-out cubic
+        
+        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)
+        }
+        if curOuterR > Double(NUC_R) {
+            ringAA(work, Double(AC), Double(AC), curOuterR, RING_T, ringBright)
+        }
+        
+        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
+            let ey = Double(AC) + sin(a) * curInnerR
+            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
+            let ey = Double(AC) + sin(a) * curOuterR
+            diskAA(work, ex, ey, curElR, 255)
+        }
+        
+        blit(work, fbp, sx, sy, lineLen, scrH)
+        usleep(16666) // 60 fps target
+    }
+
+    // ── Pre-render static stable orbit template for Phase 2 ──
+    memset(tpl, 0, ABUFSZ)
+    diskAA(tpl, Double(AC), Double(AC), Double(NUC_R), 255)
+    ringAA(tpl, Double(AC), Double(AC), Double(INNER_R), RING_T, 60)
+    ringAA(tpl, Double(AC), Double(AC), Double(OUTER_R), RING_T, 60)
+
+    // ── Phase 2: Stable Orbiting (150 frames ≈ 2.5 seconds at 60fps) ──
+    for frame in 0..<150 {
+        memcpy(work, tpl, ABUFSZ)
+        
+        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)
+            let ey = Double(AC) + sin(a) * Double(INNER_R)
+            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)
+            let ey = Double(AC) + sin(a) * Double(OUTER_R)
+            diskAA(work, ex, ey, Double(ELEC_R), 255)
+        }
+        
+        blit(work, fbp, sx, sy, lineLen, scrH)
+        usleep(16666)
+    }
+
+    // ── Phase 3: Spiral Inward & Crash (30 frames) ──
+    let baseAngle = (35.0 * 0.10) + (150.0 * 0.05)
+    for frame in 0..<30 {
+        memset(work, 0, ABUFSZ)
+        
+        let t = Double(frame) / 29.0
+        let easeIn = t * t
+        
+        let curInner = Double(INNER_R) * (1.0 - easeIn)
+        let curOuter = Double(OUTER_R) * (1.0 - easeIn)
+        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)))
+        }
+        if curOuter > nucG + 2.0 {
+            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 {
+            for i in 0..<2 {
+                let a = angle + Double(i) * Double.pi
+                diskAA(work, Double(AC) + cos(a) * curInner,
+                       Double(AC) + sin(a) * curInner, curElR, 255)
+            }
+            for i in 0..<2 {
+                let a = -angle * 0.6 + Double(i) * Double.pi
+                diskAA(work, Double(AC) + cos(a) * curOuter,
+                       Double(AC) + sin(a) * curOuter, curElR, 255)
+            }
+        }
+        
+        blit(work, fbp, sx, sy, lineLen, scrH)
+        usleep(16666)
+    }
+
+    // ── Phase 4: Flash & Fade to Black (20 frames) ──
+    let finalNucG = Double(NUC_R) + 20.0
+    for frame in 0..<20 {
+        memset(work, 0, ABUFSZ)
+        let t = Double(frame) / 19.0
+        let flashR = min(Double(AC - 1), finalNucG + t * 240.0)
+        let bright = UInt8(max(0.0, 255.0 * (1.0 - t)))
+        if bright > 0 {
+            diskAA(work, Double(AC), Double(AC), flashR, bright)
+        }
+        blit(work, fbp, sx, sy, lineLen, scrH)
+        usleep(16666)
+    }
+
+    // ── Clear to BLACK ──
+    memset(fbp, 0, scrSz)
+
+    // ── Splash screen ──
+    print("\u{1B}[0;40m\u{1B}[2J\u{1B}[H", terminator: "")
     print("""
       SSSS  W   W  IIIII  FFFFF  TTTTT
-     S      W   W    I    F        T  
-      SSS   W W W    I    FFF      T  
-         S  WW WW    I    F        T  
-     SSSS   W   W  IIIII  F        T  
+     S      W   W    I    F        T
+      SSS   W W W    I    FFF      T
+         S  WW WW    I    F        T
+     SSSS   W   W  IIIII  F        T
     """)
     print("\nArkOS Initialized. Drawing 'Swift' via native Swift runtime!\n")
 
-    let screensize = Int(finfo.smem_len)
-    
-    let fb_ptr = mmap(nil, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
-    if fb_ptr == MAP_FAILED {
-        print("Error: Failed to map framebuffer device to memory.")
-        close(fd)
-        return
-    }
-    
-    let fbp = fb_ptr!.bindMemory(to: UInt8.self, capacity: screensize)
-    
-    // Draw a gradient or pattern starting below the text (e.g., from y=200)
-    for y in 200..<Int(vinfo.yres) {
-        for x in 0..<Int(vinfo.xres) {
-            let location = (x + Int(vinfo.xoffset)) * Int(vinfo.bits_per_pixel / 8) + (y + Int(vinfo.yoffset)) * Int(finfo.line_length)
-            
-            if vinfo.bits_per_pixel == 32 {
-                fbp[location] = UInt8((x * 255) / Int(vinfo.xres)) // Blue
-                fbp[location + 1] = UInt8((y * 255) / Int(vinfo.yres)) // Green
-                fbp[location + 2] = 255 - UInt8((x * 255) / Int(vinfo.xres)) // Red
-                fbp[location + 3] = 0 // Transparency
-            }
+    for y in 200..<scrH {
+        for x in 0..<scrW {
+            let off = (x + Int(vinfo.xoffset)) * bpp +
+                      (y + Int(vinfo.yoffset)) * lineLen
+            fbp[off]     = UInt8((x * 255) / scrW)
+            fbp[off + 1] = UInt8((y * 255) / scrH)
+            fbp[off + 2] = 255 - UInt8((x * 255) / scrW)
+            fbp[off + 3] = 0
         }
     }
-    
-    munmap(fb_ptr, screensize)
+
+    tpl.deallocate()
+    work.deallocate()
+    munmap(fb_ptr, scrSz)
     close(fd)
-    
-    // Simulate hanging as the OS shell
+
     while true { }
 }
 

+ 1 - 1
arkos/system/swiftframework.ark

@@ -1,2 +1,2 @@
 Swift = ../framework/Swift/
-SwiftUI = ../framework/SwiftUIFramework
+SwiftUIFramework = ../framework/SwiftUIFramework/ParticleUI

+ 0 - 0
arkos/system/sha256.c → arkos/vendor/verify/sha256.c


+ 0 - 0
arkos/system/sha256.h → arkos/vendor/verify/sha256.h


+ 2 - 2
tools/Makefile

@@ -1,5 +1,5 @@
-CC=gcc
-CFLAGS=-Wall -Wextra -O2
+CC ?= cc
+CFLAGS = -Wall -Wextra -O2
 
 all: build
 

+ 87 - 2
tools/README.md

@@ -1,2 +1,87 @@
-# ARK-OS-Tools
-The Build Tools and Clone Tools for ARK-OS
+# ArkOS Build Tools
+
+The build orchestration layer for ArkOS. These tools compile, sign, pack, and assemble the entire operating system into bootable disk images.
+
+## Components
+
+### `build.c` — Build Orchestrator
+
+The main build driver. Accepts the ArkOS base directory as its first argument and executes all build phases sequentially with modular `[step/total]` progress output.
+
+**Usage:**
+```bash
+# Called automatically by the top-level Makefile:
+./build /path/to/arkos
+
+# Or build the tool manually:
+make            # Compiles build.c + ark_parser.c → ./build
+make clean      # Removes compiled binary
+```
+
+**What it does (14 steps):**
+1. Cleans previous build artifacts
+2. Creates staging directories (`out_staging/`)
+3. Copies frameworks to staging
+4. Copies boot files to staging
+5. Copies vendor files to staging
+6. Verifies kernel `.config` exists
+7. Compiles `fb_helper.c` with prebuilt Clang
+8. Compiles `swift_splash.swift` with `swiftc`
+9. Signs `swift_splash` binary (Verified Boot)
+10. Compiles `init.c` + `sha256.c` with prebuilt Clang
+11. Packs initramfs (base + init + swift_splash + signature)
+12. Assembles bootloader + stage2 with `nasm`
+13. Generates `boot.img` via `pack_boot.py`
+14. Generates disk images (`sys.img`, `vend.img`, `avb.img`, etc.)
+
+All intermediate artifacts go into `out_staging/`. Final outputs go into `finished/`.
+
+---
+
+### `ark_parser.c` / `ark_parser.h` — `.ark` Config Parser
+
+A lightweight C library for parsing ArkOS's custom `.ark` configuration file format.
+
+**Supported syntax:**
+```
+# Comments start with #
+key = value           # Global key-value pairs
+standalone_value      # Standalone values (e.g., signing keys)
+
+[SectionName]         # Named sections
+section_key = value
+```
+
+**API:**
+```c
+ArkConfig* ark_parse(const char* filepath);
+const char* ark_get_global(ArkConfig* config, const char* key);
+const char* ark_get_section_val(ArkConfig* config, const char* section, const char* key);
+void ark_set_global(ArkConfig* config, const char* key, const char* value);
+void ark_dump(ArkConfig* config, const char* filepath);
+void ark_free(ArkConfig* config);
+```
+
+---
+
+### `pack_boot.py` — Boot Image Packager
+
+Assembles the final `boot.img` by concatenating the bootloader, stage2, animation frames, kernel, and initramfs into a single raw disk image. Patches stage2 binary variables (LBA offsets, sector counts) in-place.
+
+**Usage:**
+```bash
+python3 pack_boot.py --base-dir /path/to/arkos
+```
+
+**Disk layout:**
+```
+Sector 0        : Stage 1 bootloader (512 bytes)
+Sectors 1-7     : Stage 2 bootloader (3.5 KB)
+Sectors 8+      : Animation data
+Sectors N+      : bzImage (Linux kernel)
+Sectors M+      : initramfs.img
+```
+
+## License
+
+See [LICENSE](LICENSE) for details.

BIN
tools/build


+ 343 - 161
tools/build.c

@@ -1,3 +1,12 @@
+/*
+ * ArkOS Build System
+ * ------------------
+ * Orchestrates the full OS build pipeline.
+ * All paths are relative to the base directory passed as argv[1].
+ *
+ * Usage: build <arkos-base-dir>
+ */
+
 #include "ark_parser.h"
 #include <dirent.h>
 #include <stdio.h>
@@ -6,191 +15,364 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-void run_cmd(const char *cmd) {
-  printf("Executing: %s\n", cmd);
+/* ── Build step counter ─────────────────────────────────────────── */
+
+#define TOTAL_STEPS 14
+
+static int current_step = 0;
+
+static void step(const char *desc) {
+  current_step++;
+  printf("\n\033[1;36m[%2d/%d]\033[0m %s\n", current_step, TOTAL_STEPS, desc);
+}
+
+/* ── Helpers ────────────────────────────────────────────────────── */
+
+static void run(const char *cmd) {
+  printf("  \033[0;90m$ %s\033[0m\n", cmd);
   int ret = system(cmd);
   if (ret != 0) {
-    printf("Command failed: %s\n", cmd);
+    fprintf(stderr, "  \033[1;31m✗ Command failed (exit %d)\033[0m\n", ret);
   }
 }
 
-int main() {
-  const char *base_dir = "/home/arkos/repo/arkos";
-  const char *out_dir = "/home/arkos/repo/arkos/finished";
-  const char *staging_sys = "/home/arkos/repo/arkos/out_staging/system";
-  const char *staging_vend = "/home/arkos/repo/arkos/out_staging/vendor";
-  const char *staging_boot = "/home/arkos/repo/arkos/out_staging/boot";
-
-  printf("Cleaning up previous build directories...\n");
-  run_cmd("chmod -R 777 /home/arkos/repo/arkos/out_staging 2>/dev/null || true");
-  run_cmd("rm -rf /home/arkos/repo/arkos/finished /home/arkos/repo/arkos/out_staging");
-  run_cmd("mkdir -p /home/arkos/repo/arkos/finished "
-          "/home/arkos/repo/arkos/out_staging/system/frameworks "
-          "/home/arkos/repo/arkos/out_staging/vendor "
-          "/home/arkos/repo/arkos/out_staging/boot");
-
-  printf("Phase 1: Frameworks Integration\n");
-  DIR *d = opendir("/home/arkos/repo/arkos/frameworks");
-  if (d) {
-    struct dirent *dir;
-    while ((dir = readdir(d)) != NULL) {
-      if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
-        continue;
-      if (strcmp(dir->d_name, "DRM") == 0 ||
-          strcmp(dir->d_name, "SwiftUIFramework") == 0) {
-        printf("Skipping explicitly excluded framework: %s\n", dir->d_name);
-        continue;
+/* Join two path components. Caller must free. */
+static char *pjoin(const char *a, const char *b) {
+  size_t len = strlen(a) + 1 + strlen(b) + 1;
+  char *out = malloc(len);
+  snprintf(out, len, "%s/%s", a, b);
+  return out;
+}
+
+/* ── Main ───────────────────────────────────────────────────────── */
+
+int main(int argc, char *argv[]) {
+  if (argc < 2) {
+    fprintf(stderr, "Usage: %s <arkos-base-dir>\n", argv[0]);
+    return 1;
+  }
+
+  const char *base = argv[1]; /* e.g. /home/user/repo/arkos */
+
+  /* Derive the repo root (one level up from base) */
+  char *repo = pjoin(base, "..");
+
+  /* Key directories */
+  char *out_dir      = pjoin(base, "finished");
+  char *staging      = pjoin(base, "out_staging");
+  char *staging_sys  = pjoin(staging, "system");
+  char *staging_fw   = pjoin(staging, "system/frameworks");
+  char *staging_vend = pjoin(staging, "vendor");
+  char *staging_boot = pjoin(staging, "boot");
+
+  /* Compiler for OS components (host gcc for now) */
+  const char *cc = "gcc";
+
+  /* Source directories */
+  char *fw_dir     = pjoin(base, "frameworks");
+  char *boot_dir   = pjoin(base, "boot");
+  char *vendor_dir = pjoin(base, "vendor");
+  char *system_dir = pjoin(base, "system");
+  char *kernel_dir = pjoin(base, "kernel");
+
+  printf("\n\033[1;35mArkOS Build System v2.0\033[0m\n");
+
+  /* ─── Step 1: Clean ─────────────────────────────────────────── */
+  step("Cleaning previous build");
+  {
+    char cmd[1024];
+    snprintf(cmd, sizeof(cmd),
+             "chmod -R 777 %s 2>/dev/null || true", staging);
+    run(cmd);
+    snprintf(cmd, sizeof(cmd), "rm -rf %s %s", out_dir, staging);
+    run(cmd);
+  }
+
+  /* ─── Step 2: Create staging directories ────────────────────── */
+  step("Creating staging directories");
+  {
+    char cmd[1024];
+    snprintf(cmd, sizeof(cmd),
+             "mkdir -p %s %s %s %s",
+             out_dir, staging_fw, staging_vend, staging_boot);
+    run(cmd);
+  }
+
+  /* ─── Step 3: Copy frameworks ───────────────────────────────── */
+  step("Integrating frameworks");
+  {
+    DIR *d = opendir(fw_dir);
+    if (d) {
+      struct dirent *ent;
+      while ((ent = readdir(d)) != NULL) {
+        if (ent->d_name[0] == '.')
+          continue;
+        /* Skip excluded frameworks */
+        if (strcmp(ent->d_name, "DRM") == 0 ||
+            strcmp(ent->d_name, "SwiftUIFramework") == 0) {
+          printf("  Skipping excluded framework: %s\n", ent->d_name);
+          continue;
+        }
+        char cmd[1024];
+        snprintf(cmd, sizeof(cmd), "cp -r %s/%s %s/",
+                 fw_dir, ent->d_name, staging_fw);
+        run(cmd);
       }
-      char cmd[512];
-      snprintf(cmd, sizeof(cmd),
-               "cp -r /home/arkos/repo/arkos/frameworks/%s "
-               "/home/arkos/repo/arkos/out_staging/system/frameworks/",
-               dir->d_name);
-      run_cmd(cmd);
+      closedir(d);
     }
-    closedir(d);
   }
 
-  printf("Phase 2: Boot Folder Perfectification\n");
-  d = opendir("/home/arkos/repo/arkos/boot");
-  if (d) {
-    struct dirent *dir;
-    while ((dir = readdir(d)) != NULL) {
-      if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
-        continue;
-      if (strcmp(dir->d_name, "DRM") == 0) {
-        printf("Skipping boot/DRM folder\n");
-        continue;
+  /* ─── Step 4: Copy boot files ───────────────────────────────── */
+  step("Preparing boot files");
+  {
+    DIR *d = opendir(boot_dir);
+    if (d) {
+      struct dirent *ent;
+      while ((ent = readdir(d)) != NULL) {
+        if (ent->d_name[0] == '.')
+          continue;
+        if (strcmp(ent->d_name, "DRM") == 0) {
+          printf("  Skipping boot/DRM\n");
+          continue;
+        }
+        char cmd[1024];
+        snprintf(cmd, sizeof(cmd), "cp -r %s/%s %s/",
+                 boot_dir, ent->d_name, staging_boot);
+        run(cmd);
       }
-      char cmd[512];
-      snprintf(
-          cmd, sizeof(cmd),
-          "cp -r /home/arkos/repo/arkos/boot/%s /home/arkos/repo/arkos/out_staging/boot/",
-          dir->d_name);
-      run_cmd(cmd);
+      closedir(d);
     }
-    closedir(d);
   }
 
-  printf("Phase 3: Vendor Folder Preparation\n");
-  run_cmd("cp -r /home/arkos/repo/arkos/vendor/* "
-          "/home/arkos/repo/arkos/out_staging/vendor/ 2>/dev/null || true");
-
-  printf("Phase 4: Kernel Config Verification\n");
-  if (access("/home/arkos/repo/arkos/kernel/.config", F_OK) != -1) {
-    printf("Kernel config found at /home/arkos/repo/arkos/kernel/.config. Kernel is "
-           "prepared.\n");
-  } else {
-    printf("WARNING: Kernel .config not found!\n");
+  /* ─── Step 5: Copy vendor files ─────────────────────────────── */
+  step("Preparing vendor files");
+  {
+    char cmd[1024];
+    snprintf(cmd, sizeof(cmd),
+             "cp -r %s/* %s/ 2>/dev/null || true",
+             vendor_dir, staging_vend);
+    run(cmd);
   }
 
-  printf("Phase 5: Prebuilts Tagging\n");
-  run_cmd("mkdir -p /home/arkos/repo/arkos/prebuilts");
-  ArkConfig *prebuilts_ark =
-      ark_parse("/home/arkos/repo/arkos/prebuilts/prebuilts.ark");
-  d = opendir("/home/arkos/src");
-  if (d) {
-    struct dirent *dir;
-    while ((dir = readdir(d)) != NULL) {
-      char path[512];
-      snprintf(path, sizeof(path), "/home/arkos/src/%s", dir->d_name);
-      if (strstr(dir->d_name, "LLVM"))
-        ark_set_global(prebuilts_ark, "LLVM", path);
-      else if (strstr(dir->d_name, "Swift"))
-        ark_set_global(prebuilts_ark, "Swift", path);
-      else if (strstr(dir->d_name, "glibc"))
-        ark_set_global(prebuilts_ark, "glibc", path);
-      else if (strstr(dir->d_name, "linux-kernel"))
-        ark_set_global(prebuilts_ark, "Kernel-Src", path);
+  /* ─── Step 6: Verify kernel config ──────────────────────────── */
+  step("Verifying kernel configuration");
+  {
+    char *kconfig = pjoin(kernel_dir, ".config");
+    if (access(kconfig, F_OK) != -1) {
+      printf("  \033[0;32m✓\033[0m Kernel .config found\n");
+    } else {
+      printf("  \033[1;33m⚠ WARNING:\033[0m Kernel .config not found!\n");
     }
-    closedir(d);
+    free(kconfig);
+  }
+
+  /* ─── Step 7: Compile fb_helper.c ───────────────────────────── */
+  step("Compiling : system/fb_helper.c");
+  {
+    char cmd[1024];
+    snprintf(cmd, sizeof(cmd),
+             "%s -c %s/fb_helper.c -o %s/fb_helper.o",
+             cc, system_dir, staging);
+    run(cmd);
   }
-  ark_dump(prebuilts_ark, "/home/arkos/repo/arkos/prebuilts/prebuilts.ark");
-  ark_free(prebuilts_ark);
-  printf("Prebuilts tagged and mapped to "
-         "/home/arkos/repo/arkos/prebuilts/prebuilts.ark\n");
-
-  printf("Phase 6: Image Generation\n");
-  run_cmd(
-      "dd if=/dev/zero of=/home/arkos/repo/arkos/finished/sys.img bs=1M count=2048");
-  run_cmd("mkfs.ext4 -d /home/arkos/repo/arkos/out_staging/system "
-          "/home/arkos/repo/arkos/finished/sys.img");
-
-  run_cmd(
-      "dd if=/dev/zero of=/home/arkos/repo/arkos/finished/vend.img bs=1M count=100");
-  run_cmd("mkfs.ext4 -d /home/arkos/repo/arkos/out_staging/vendor "
-          "/home/arkos/repo/arkos/finished/vend.img");
-
-    printf("Preparing Linux Kernel & Native Swift Initramfs...\n");
-    
-    // Compile fb_helper.c and Native Swift Initramfs executable
-    run_cmd("gcc -c /home/arkos/repo/arkos/system/fb_helper.c -o /home/arkos/repo/arkos/system/fb_helper.o");
-    run_cmd("swiftc -static-executable /home/arkos/repo/arkos/system/swift_splash.swift /home/arkos/repo/arkos/system/fb_helper.o -o /home/arkos/repo/arkos/system/swift_splash");
-    
-    // Parse the key for Verified Boot
-    ArkConfig *securebuild_boot = ark_parse("/home/arkos/repo/arkos/vendor/verify/securebuild.ark");
+
+  /* ─── Step 8: Compile swift_splash.swift ────────────────────── */
+  step("Compiling : system/swift_splash.swift");
+  {
+    char cmd[1024];
+    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);
+  }
+
+  /* ─── Step 9: Sign swift_splash (Verified Boot) ─────────────── */
+  step("Signing swift_splash (Verified Boot)");
+  {
+    /* Parse the key */
+    char *securebuild_path = pjoin(vendor_dir, "verify/securebuild.ark");
+    ArkConfig *sbc = ark_parse(securebuild_path);
     char ark_key[256] = "NO_KEY";
-    for (int i = 0; i < securebuild_boot->standalone_count; i++) {
-        if (strstr(securebuild_boot->standalone[i], "ARK-OS-") != NULL) {
-            strncpy(ark_key, securebuild_boot->standalone[i], sizeof(ark_key)-1);
-            break;
-        }
+    for (int i = 0; i < sbc->standalone_count; i++) {
+      if (strstr(sbc->standalone[i], "ARK-OS-") != NULL) {
+        strncpy(ark_key, sbc->standalone[i], sizeof(ark_key) - 1);
+        break;
+      }
     }
-    ark_free(securebuild_boot);
-    
-    // Run the signing script
-    run_cmd("python3 /home/arkos/repo/arkos/vendor/verify/sign.py /home/arkos/repo/arkos/vendor/verify/securebuild.ark /home/arkos/repo/arkos/system/swift_splash /home/arkos/repo/arkos/system/signature.bin");
-    
-    // Compile C init wrapper with the SHA256 code and the key macro
-    char init_cmd[1024];
-    snprintf(init_cmd, sizeof(init_cmd), "gcc -static /home/arkos/repo/arkos/system/sha256.c /home/arkos/repo/arkos/system/init.c -DARK_KEY=\\\"%s\\\" -o /home/arkos/repo/arkos/system/init", ark_key);
-    run_cmd(init_cmd);
-    
-    // Pack into initramfs with glibc libraries
-    run_cmd("rm -rf /home/arkos/repo/arkos/out_staging/initramfs_ext && mkdir -p /home/arkos/repo/arkos/out_staging/initramfs_ext");
-    run_cmd("cd /home/arkos/repo/arkos/out_staging/initramfs_ext && zcat /home/arkos/repo/arkos/boot/initramfs.img | cpio -id 2>/dev/null");
-    run_cmd("cp /home/arkos/repo/arkos/system/init /home/arkos/repo/arkos/out_staging/initramfs_ext/init && chmod +x /home/arkos/repo/arkos/out_staging/initramfs_ext/init");
-    run_cmd("cp /home/arkos/repo/arkos/system/swift_splash /home/arkos/repo/arkos/out_staging/initramfs_ext/swift_splash && chmod +x /home/arkos/repo/arkos/out_staging/initramfs_ext/swift_splash");
-    run_cmd("cp /home/arkos/repo/arkos/system/signature.bin /home/arkos/repo/arkos/out_staging/initramfs_ext/signature.bin");
-    run_cmd("cd /home/arkos/repo/arkos/out_staging/initramfs_ext && find . | cpio -H newc -o > /home/arkos/repo/arkos/finished/initramfs.img 2>/dev/null");
-
-    // Assemble Stage 1 and Stage 2 Bootloader
-    run_cmd("python3 /home/arkos/repo/arkos/boot/source/animationframes/generate_frames.py");
-    run_cmd("nasm -f bin /home/arkos/repo/arkos/boot/source/bootloader.asm -o /home/arkos/repo/arkos/out_staging/bootloader.bin");
-    run_cmd("nasm -f bin /home/arkos/repo/arkos/boot/source/stage2.asm -o /home/arkos/repo/arkos/out_staging/stage2.bin");
-
-    // Construct the self-booting boot.img
-    run_cmd("python3 /home/arkos/repo/tools/pack_boot.py");
-
-  printf("Phase 7: Verify keys and generate avb.img\n");
-  ArkConfig *securebuild =
-      ark_parse("/home/arkos/repo/arkos/vendor/verify/securebuild.ark");
-  int has_keys = 0;
-  for (int i = 0; i < securebuild->standalone_count; i++) {
-    if (strstr(securebuild->standalone[i], "ARK-OS-") != NULL) {
-      has_keys = 1;
-      break;
+    ark_free(sbc);
+
+    char cmd[1024];
+    snprintf(cmd, sizeof(cmd),
+             "python3 %s/verify/sign.py %s/verify/securebuild.ark "
+             "%s/swift_splash %s/signature.bin",
+             vendor_dir, vendor_dir, staging, staging);
+    run(cmd);
+
+    free(securebuild_path);
+
+    /* ─── Step 10: Compile init.c + vendor/verify/sha256.c ──── */
+    step("Compiling : system/init.c + vendor/verify/sha256.c");
+    {
+      char cmd2[1024];
+      snprintf(cmd2, sizeof(cmd2),
+               "%s -static %s/verify/sha256.c %s/init.c "
+               "-I%s/verify -DARK_KEY=\"\\\"%s\\\"\" -o %s/init",
+               cc, vendor_dir, system_dir, vendor_dir, ark_key, staging);
+      run(cmd2);
     }
   }
-  if (has_keys) {
-    printf("Found signing keys, generating avb.img\n");
-    run_cmd(
-        "dd if=/dev/zero of=/home/arkos/repo/arkos/finished/avb.img bs=1M count=1");
-  } else {
-    printf("No signing keys found, skipping avb.img\n");
+
+  /* ─── Step 11: Pack initramfs ───────────────────────────────── */
+  step("Packing initramfs");
+  {
+    char *initramfs_ext = pjoin(staging, "initramfs_ext");
+    char *base_initramfs = pjoin(boot_dir, "initramfs.img");
+
+    char cmd[2048];
+
+    /* Extract base initramfs */
+    snprintf(cmd, sizeof(cmd),
+             "rm -rf %s && mkdir -p %s", initramfs_ext, initramfs_ext);
+    run(cmd);
+
+    snprintf(cmd, sizeof(cmd),
+             "cd %s && zcat %s | cpio -id 2>/dev/null",
+             initramfs_ext, base_initramfs);
+    run(cmd);
+
+    /* Copy compiled binaries from staging into initramfs */
+    snprintf(cmd, sizeof(cmd),
+             "cp %s/init %s/init && chmod +x %s/init",
+             staging, initramfs_ext, initramfs_ext);
+    run(cmd);
+
+    snprintf(cmd, sizeof(cmd),
+             "cp %s/swift_splash %s/swift_splash && chmod +x %s/swift_splash",
+             staging, initramfs_ext, initramfs_ext);
+    run(cmd);
+
+    snprintf(cmd, sizeof(cmd),
+             "cp %s/signature.bin %s/signature.bin",
+             staging, initramfs_ext);
+    run(cmd);
+
+    /* Repack */
+    snprintf(cmd, sizeof(cmd),
+             "cd %s && find . | cpio -H newc -o > %s/initramfs.img 2>/dev/null",
+             initramfs_ext, out_dir);
+    run(cmd);
+
+    free(initramfs_ext);
+    free(base_initramfs);
+  }
+
+  /* ─── Step 12: Assemble bootloader + stage2 ─────────────────── */
+  step("Assembling bootloader");
+  {
+    char cmd[1024];
+
+    /* Generate animation frames */
+    snprintf(cmd, sizeof(cmd),
+             "python3 %s/source/animationframes/generate_frames.py %s",
+             boot_dir, staging);
+    run(cmd);
+
+    snprintf(cmd, sizeof(cmd),
+             "nasm -f bin %s/source/bootloader.asm -o %s/bootloader.bin",
+             boot_dir, staging);
+    run(cmd);
+
+    snprintf(cmd, sizeof(cmd),
+             "nasm -f bin %s/source/stage2.asm -o %s/stage2.bin",
+             boot_dir, staging);
+    run(cmd);
+  }
+
+  /* ─── Step 13: Generate boot.img ────────────────────────────── */
+  step("Generating boot.img");
+  {
+    char cmd[1024];
+    snprintf(cmd, sizeof(cmd),
+             "python3 %s/tools/pack_boot.py --base-dir %s",
+             repo, base);
+    run(cmd);
+  }
+
+  /* ─── Step 14: Generate disk images ─────────────────────────── */
+  step("Generating disk images");
+  {
+    char cmd[1024];
+
+    /* sys.img */
+    snprintf(cmd, sizeof(cmd),
+             "dd if=/dev/zero of=%s/sys.img bs=1M count=2048 2>/dev/null",
+             out_dir);
+    run(cmd);
+    snprintf(cmd, sizeof(cmd),
+             "mkfs.ext4 -d %s %s/sys.img 2>/dev/null",
+             staging_sys, out_dir);
+    run(cmd);
+
+    /* vend.img */
+    snprintf(cmd, sizeof(cmd),
+             "dd if=/dev/zero of=%s/vend.img bs=1M count=100 2>/dev/null",
+             out_dir);
+    run(cmd);
+    snprintf(cmd, sizeof(cmd),
+             "mkfs.ext4 -d %s %s/vend.img 2>/dev/null",
+             staging_vend, out_dir);
+    run(cmd);
+
+    /* avb.img (Verified Boot) */
+    char *securebuild_path = pjoin(vendor_dir, "verify/securebuild.ark");
+    ArkConfig *sbc = ark_parse(securebuild_path);
+    int has_keys = 0;
+    for (int i = 0; i < sbc->standalone_count; i++) {
+      if (strstr(sbc->standalone[i], "ARK-OS-") != NULL) {
+        has_keys = 1;
+        break;
+      }
+    }
+    if (has_keys) {
+      printf("  \033[0;32m✓\033[0m Signing keys found, generating avb.img\n");
+      snprintf(cmd, sizeof(cmd),
+               "dd if=/dev/zero of=%s/avb.img bs=1M count=1 2>/dev/null",
+               out_dir);
+      run(cmd);
+    } else {
+      printf("  \033[1;33m⚠\033[0m No signing keys found, skipping avb.img\n");
+    }
+    ark_free(sbc);
+    free(securebuild_path);
+
+    /* vbmeta.img + dtbo.img */
+    snprintf(cmd, sizeof(cmd),
+             "dd if=/dev/zero of=%s/vbmeta.img bs=1M count=1 2>/dev/null",
+             out_dir);
+    run(cmd);
+    snprintf(cmd, sizeof(cmd),
+             "dd if=/dev/zero of=%s/dtbo.img bs=1M count=1 2>/dev/null",
+             out_dir);
+    run(cmd);
   }
-  ark_free(securebuild);
 
-  printf("Phase 8: vbmeta and dtbo (extra)\n");
-  run_cmd(
-      "dd if=/dev/zero of=/home/arkos/repo/arkos/finished/vbmeta.img bs=1M count=1");
-  run_cmd(
-      "dd if=/dev/zero of=/home/arkos/repo/arkos/finished/dtbo.img bs=1M count=1");
+  printf("\n\033[1;32mBuild complete!\033[0m Run \033[1mmake run\033[0m to test.\n\n");
 
-  printf("Phase 9: Zipping output\n");
-  run_cmd("cd /home/arkos/repo/arkos && zip -r finished/ArkOS.zip finished/ > "
-          "/dev/null");
+  /* Cleanup heap */
+  free(repo);
+  free(out_dir);
+  free(staging);
+  free(staging_sys);
+  free(staging_fw);
+  free(staging_vend);
+  free(staging_boot);
+  /* cc is a string literal, no free needed */
+  free(fw_dir);
+  free(boot_dir);
+  free(vendor_dir);
+  free(system_dir);
+  free(kernel_dir);
 
-  printf("Build complete. Outputs are in %s\n", out_dir);
   return 0;
 }

+ 66 - 32
tools/pack_boot.py

@@ -1,79 +1,113 @@
+#!/usr/bin/env python3
+"""
+ArkOS Boot Image Packager
+-------------------------
+Packs bootloader, stage2, animation, kernel and initramfs into a single boot.img.
+All paths are derived from --base-dir (the arkos/ directory).
+
+Usage: python3 pack_boot.py --base-dir /path/to/arkos
+"""
+
+import argparse
 import os
 import struct
 import sys
 
+
 def align_up(val, align):
     return (val + align - 1) & ~(align - 1)
 
+
 def main():
-    bootloader_path = '/home/arkos/repo/arkos/out_staging/bootloader.bin'
-    stage2_path = '/home/arkos/repo/arkos/out_staging/stage2.bin'
-    kernel_path = '/home/arkos/repo/arkos/kernel/prebuilts/bzImage'
-    initramfs_path = '/home/arkos/repo/arkos/finished/initramfs.img'
-    out_path = '/home/arkos/repo/arkos/finished/boot.img'
+    parser = argparse.ArgumentParser(description="ArkOS boot image packager")
+    parser.add_argument("--base-dir", required=True,
+                        help="Path to the arkos/ base directory")
+    args = parser.parse_args()
+
+    base = args.base_dir
+
+    bootloader_path = os.path.join(base, "out_staging", "bootloader.bin")
+    stage2_path     = os.path.join(base, "out_staging", "stage2.bin")
+    kernel_path     = os.path.join(base, "kernel", "prebuilts", "bzImage")
+    initramfs_path  = os.path.join(base, "finished", "initramfs.img")
+    animation_path  = os.path.join(base, "out_staging", "animation.bin")
+    out_path        = os.path.join(base, "finished", "boot.img")
 
     if not os.path.exists(kernel_path):
-        kernel_path = '/boot/vmlinuz-linux-zen' # fallback
+        kernel_path = "/boot/vmlinuz-linux-zen"  # fallback
 
-    with open(bootloader_path, 'rb') as f:
+    with open(bootloader_path, "rb") as f:
         bootloader = bytearray(f.read())
-    
-    with open(stage2_path, 'rb') as f:
+
+    with open(stage2_path, "rb") as f:
         stage2 = bytearray(f.read())
 
-    with open(kernel_path, 'rb') as f:
+    with open(kernel_path, "rb") as f:
         kernel = f.read()
 
-    with open(initramfs_path, 'rb') as f:
+    with open(initramfs_path, "rb") as f:
         initramfs = f.read()
 
-    animation_path = '/home/arkos/repo/arkos/out_staging/animation.bin'
     if os.path.exists(animation_path):
-        with open(animation_path, 'rb') as f:
+        with open(animation_path, "rb") as f:
             animation = f.read()
     else:
-        animation = b''
-        
+        animation = b""
+
     # Calculate LBA sectors (each sector is 512 bytes)
     bootloader_sectors = 1
-    
-    # Stage 2 MUST be exactly 7 sectors max (since bootloader.asm reads 7 sectors)
+
+    # Stage 2 MUST be exactly 7 sectors (bootloader.asm reads 7 sectors)
     stage2_padded_size = 7 * 512
-    stage2 += b'\0' * (stage2_padded_size - len(stage2))
+    stage2 += b"\0" * (stage2_padded_size - len(stage2))
 
     animation_lba = bootloader_sectors + 7
     animation_size_sectors = align_up(len(animation), 512) // 512
-    animation_padded = animation + b'\0' * (animation_size_sectors * 512 - len(animation))
+    animation_padded = animation + b"\0" * (
+        animation_size_sectors * 512 - len(animation)
+    )
 
     bzimage_lba = animation_lba + animation_size_sectors
     bzimage_size_sectors = align_up(len(kernel), 512) // 512
-    kernel_padded = kernel + b'\0' * (bzimage_size_sectors * 512 - len(kernel))
+    kernel_padded = kernel + b"\0" * (bzimage_size_sectors * 512 - len(kernel))
 
     initramfs_lba = bzimage_lba + bzimage_size_sectors
     initramfs_size_sectors = align_up(len(initramfs), 512) // 512
-    initramfs_padded = initramfs + b'\0' * (initramfs_size_sectors * 512 - len(initramfs))
+    initramfs_padded = initramfs + b"\0" * (
+        initramfs_size_sectors * 512 - len(initramfs)
+    )
     initramfs_size_bytes = len(initramfs)
 
-    # Now we must patch stage2!
-    # The default bytes for these 7 dwords in memory are:
-    pattern = struct.pack('<IIIIIII', 8, 0, 0, 0, 0, 0, 0)
+    # Patch stage2 variables (7 consecutive dwords starting with default 8,0,0,0,0,0,0)
+    pattern = struct.pack("<IIIIIII", 8, 0, 0, 0, 0, 0, 0)
     idx = stage2.find(pattern)
     if idx == -1:
         print("ERROR: Could not find variables in stage2 to patch!")
         sys.exit(1)
-    
-    print(f"Patching Stage2 at offset {idx}")
-    patched_vars = struct.pack('<IIIIIII', bzimage_lba, bzimage_size_sectors, initramfs_lba, initramfs_size_sectors, initramfs_size_bytes, animation_lba, animation_size_sectors)
-    stage2[idx:idx+28] = patched_vars
 
-    with open(out_path, 'wb') as f:
+    print(f"  Patching stage2 at offset {idx}")
+    patched_vars = struct.pack(
+        "<IIIIIII",
+        bzimage_lba,
+        bzimage_size_sectors,
+        initramfs_lba,
+        initramfs_size_sectors,
+        initramfs_size_bytes,
+        animation_lba,
+        animation_size_sectors,
+    )
+    stage2[idx : idx + 28] = patched_vars
+
+    with open(out_path, "wb") as f:
         f.write(bootloader)
         f.write(stage2)
         f.write(animation_padded)
         f.write(kernel_padded)
         f.write(initramfs_padded)
-    
-    print(f"boot.img built successfully! Total size: {os.path.getsize(out_path)} bytes")
 
-if __name__ == '__main__':
+    total = os.path.getsize(out_path)
+    print(f"  boot.img built successfully! ({total:,} bytes)")
+
+
+if __name__ == "__main__":
     main()