feat(rumpk): Phase 4 - NPL Loader
THE PLATFORM HAS PURPOSE ======================== Rumpk now has a payload loading system: NPL (Nexus Payload). OUTPUT ------ [NPL] ✅ Verification PASSED [NPL] Executing payload... [NPL] ✅ Payload returned! [NPL] ✅ Bad sig rejected NPL FORMAT (128-byte header) ---------------------------- - Magic: \x7fNPL (4 bytes) - Version: 1 (1 byte) - Arch: 0xAA=ARM64, 0xEE=x86_64, 0x55=RISC-V (1 byte) - Flags: 2 bytes - Signature: 64 bytes (Ed25519 placeholder) - Body Size: 8 bytes - Reserved: 48 bytes IMPLEMENTATION -------------- core/npl.nim: - NPLHeader struct (packed, 128 bytes) - loadNpl() - validates magic, version, arch, signature - buildTestPayload() - creates test NPL in memory - Signature verification (mock: rejects 0xFF) TESTS VERIFIED -------------- 1. Valid payload: Loads and executes RET instruction 2. Bad signature: Correctly rejected (0xFF in sig[0]) 3. Cross-arch: Would reject wrong arch code PHASE SUMMARY ------------- ✅ Phase 1: Documentation (SPEC-008/009/010) ✅ Phase 2: Pure Zig libc (Freestanding Doctrine) ✅ Phase 3: Cooperative Fibers (Ping Pong) ✅ Phase 4: NPL Loader (with mock signature) → Phase 4.2: Ed25519 verification (Monocypher) → Phase 5: VisionFive 2 RISC-V hardware The unikernel can now load and execute signed payloads. Next: Real Ed25519 verification.
This commit is contained in:
parent
4cc268683d
commit
ee594df8a7
|
|
@ -0,0 +1,8 @@
|
||||||
|
0
|
||||||
|
5537 9466034 1767079280889767999 0d029e05059c175b5ce754f57f213b48 0 /home/markus/zWork/_Git/Nexus/core/rumpk/build/nimcache/@mnpl.nim.c
|
||||||
|
19164 69191110 1749873121000000000 fe5756ed84745fc96fd9dfb15050f599 0 /usr/lib/nim/nimbase.h
|
||||||
|
639 9459383 1767076381899751290 1b9448bcfa47e3161459266750e8ded4 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/limits.h
|
||||||
|
268 9459347 1767076422997272233 06a4c7da1c4987981a369ef3e003bda3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stddef.h
|
||||||
|
155 9459777 1767076495338437553 9cc523d7a8a3a0bbc7c7af0fabeafc0b 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stdbool.h
|
||||||
|
924 9459799 1767076530759032485 73bc6834aef9958f6652470b63d7814b 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stdint.h
|
||||||
|
499 9459330 1767076360432003062 357ccd6329b0128cce0610c1443c600d 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/string.h
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
0
|
0
|
||||||
15874 9465108 1767078402329925246 e5c92c416746964294e1e5d350d1d6c3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/build/nimcache/@mkernel.nim.c
|
23680 9466035 1767079280889767999 54c7101f99bb89eb7e9878f7b072ebef 0 /home/markus/zWork/_Git/Nexus/core/rumpk/build/nimcache/@mkernel.nim.c
|
||||||
19164 69191110 1749873121000000000 fe5756ed84745fc96fd9dfb15050f599 0 /usr/lib/nim/nimbase.h
|
19164 69191110 1749873121000000000 fe5756ed84745fc96fd9dfb15050f599 0 /usr/lib/nim/nimbase.h
|
||||||
639 9459383 1767076381899751290 1b9448bcfa47e3161459266750e8ded4 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/limits.h
|
639 9459383 1767076381899751290 1b9448bcfa47e3161459266750e8ded4 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/limits.h
|
||||||
268 9459347 1767076422997272233 06a4c7da1c4987981a369ef3e003bda3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stddef.h
|
268 9459347 1767076422997272233 06a4c7da1c4987981a369ef3e003bda3 0 /home/markus/zWork/_Git/Nexus/core/rumpk/core/include/stddef.h
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
{.push stackTrace: off, lineTrace: off.}
|
{.push stackTrace: off, lineTrace: off.}
|
||||||
|
|
||||||
import fiber
|
import fiber
|
||||||
|
import npl
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# HAL Imports from Zig (Layer 0)
|
# HAL Imports from Zig (Layer 0)
|
||||||
|
|
@ -43,16 +44,6 @@ proc nimPanic(msg: cstring) {.exportc: "panic", cdecl, noreturn.} =
|
||||||
kprint("\n")
|
kprint("\n")
|
||||||
rumpk_halt()
|
rumpk_halt()
|
||||||
|
|
||||||
# =========================================================
|
|
||||||
# Memory Allocator - Provided by Zig L0 (hal/stubs.zig)
|
|
||||||
# =========================================================
|
|
||||||
|
|
||||||
# Zig exports: malloc, free, realloc, calloc
|
|
||||||
# We just import them for any explicit usage
|
|
||||||
proc malloc(size: csize_t): pointer {.importc, cdecl.}
|
|
||||||
proc free(p: pointer) {.importc, cdecl.}
|
|
||||||
proc realloc(p: pointer, size: csize_t): pointer {.importc, cdecl.}
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Fiber Test: Ping Pong
|
# Fiber Test: Ping Pong
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
@ -81,6 +72,77 @@ proc thread_b_entry() {.cdecl.} =
|
||||||
while true:
|
while true:
|
||||||
{.emit: "asm volatile(\"wfi\");".}
|
{.emit: "asm volatile(\"wfi\");".}
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# NPL Loader Test
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
var npl_test_buffer {.align: 128.}: array[256, uint8]
|
||||||
|
|
||||||
|
proc test_npl_loader() =
|
||||||
|
kprintln("")
|
||||||
|
kprintln("╔═══════════════════════════════════════╗")
|
||||||
|
kprintln("║ NPL Loader Test (Phase 4) ║")
|
||||||
|
kprintln("╚═══════════════════════════════════════╝")
|
||||||
|
kprintln("")
|
||||||
|
|
||||||
|
# Build test payload with architecture-specific RET instruction
|
||||||
|
when defined(arm64) or defined(aarch64):
|
||||||
|
let retCode = [0xC0'u8, 0x03'u8, 0x5F'u8, 0xD6'u8]
|
||||||
|
let archCode = ARCH_ARM64
|
||||||
|
kprintln("[NPL] Building ARM64 test payload...")
|
||||||
|
elif defined(amd64) or defined(x86_64):
|
||||||
|
let retCode = [0xC3'u8]
|
||||||
|
let archCode = ARCH_X86_64
|
||||||
|
kprintln("[NPL] Building x86_64 test payload...")
|
||||||
|
elif defined(riscv64):
|
||||||
|
let retCode = [0x67'u8, 0x80'u8, 0x00'u8, 0x00'u8]
|
||||||
|
let archCode = ARCH_RISCV64
|
||||||
|
kprintln("[NPL] Building RISC-V test payload...")
|
||||||
|
else:
|
||||||
|
kprintln("[NPL] Unsupported architecture!")
|
||||||
|
return
|
||||||
|
|
||||||
|
buildTestPayload(addr npl_test_buffer, archCode, retCode)
|
||||||
|
kprintln("[NPL] Loading...")
|
||||||
|
|
||||||
|
let entry = loadNpl(addr npl_test_buffer[0], 256)
|
||||||
|
|
||||||
|
kprintln("[NPL] loadNpl returned")
|
||||||
|
|
||||||
|
if entry != nil:
|
||||||
|
kprintln("[NPL] ✅ Verification PASSED")
|
||||||
|
kprintln("[NPL] Executing payload...")
|
||||||
|
entry()
|
||||||
|
kprintln("[NPL] ✅ Payload returned!")
|
||||||
|
else:
|
||||||
|
kprintln("[NPL] ❌ Load failed")
|
||||||
|
|
||||||
|
proc test_npl_rejection() =
|
||||||
|
kprintln("")
|
||||||
|
kprintln("[NPL] Testing rejection...")
|
||||||
|
|
||||||
|
when defined(arm64) or defined(aarch64):
|
||||||
|
let retCode = [0xC0'u8, 0x03'u8, 0x5F'u8, 0xD6'u8]
|
||||||
|
let archCode = ARCH_ARM64
|
||||||
|
elif defined(amd64) or defined(x86_64):
|
||||||
|
let retCode = [0xC3'u8]
|
||||||
|
let archCode = ARCH_X86_64
|
||||||
|
elif defined(riscv64):
|
||||||
|
let retCode = [0x67'u8, 0x80'u8, 0x00'u8, 0x00'u8]
|
||||||
|
let archCode = ARCH_RISCV64
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
buildTestPayload(addr npl_test_buffer, archCode, retCode)
|
||||||
|
npl_test_buffer[8] = 0xFF'u8 # Trigger rejection
|
||||||
|
|
||||||
|
let entry = loadNpl(addr npl_test_buffer[0], 256)
|
||||||
|
|
||||||
|
if entry == nil:
|
||||||
|
kprintln("[NPL] ✅ Bad sig rejected")
|
||||||
|
else:
|
||||||
|
kprintln("[NPL] ❌ Should reject!")
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Kernel Main Entry
|
# Kernel Main Entry
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
@ -96,6 +158,11 @@ proc kmain() {.exportc, cdecl.} =
|
||||||
kprintln("")
|
kprintln("")
|
||||||
kprintln("[Rumpk L1] The Rubicon is crossed.")
|
kprintln("[Rumpk L1] The Rubicon is crossed.")
|
||||||
kprintln("[Rumpk L1] Zig + Nim = Sovereign Metal.")
|
kprintln("[Rumpk L1] Zig + Nim = Sovereign Metal.")
|
||||||
|
|
||||||
|
# Phase 4: NPL Loader Test
|
||||||
|
test_npl_loader()
|
||||||
|
test_npl_rejection()
|
||||||
|
|
||||||
kprintln("")
|
kprintln("")
|
||||||
kprintln("[Rumpk L1] Initializing Fibers...")
|
kprintln("[Rumpk L1] Initializing Fibers...")
|
||||||
|
|
||||||
|
|
@ -106,12 +173,10 @@ proc kmain() {.exportc, cdecl.} =
|
||||||
init_fiber(addr fiber_a, thread_a_entry, addr stack_a[0])
|
init_fiber(addr fiber_a, thread_a_entry, addr stack_a[0])
|
||||||
init_fiber(addr fiber_b, thread_b_entry, addr stack_b[0])
|
init_fiber(addr fiber_b, thread_b_entry, addr stack_b[0])
|
||||||
|
|
||||||
# Jump into the matrix
|
|
||||||
kprintln("[Kernel] Switching to Fiber A...")
|
kprintln("[Kernel] Switching to Fiber A...")
|
||||||
kprintln("")
|
kprintln("")
|
||||||
switch(addr fiber_a)
|
switch(addr fiber_a)
|
||||||
|
|
||||||
# We should never get here unless Fiber A switches back to Main
|
|
||||||
nimPanic("Main thread returned!")
|
nimPanic("Main thread returned!")
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
||||||
|
# RUMPK CORE // NPL FORMAT
|
||||||
|
# The Contract of Execution.
|
||||||
|
|
||||||
|
{.push stackTrace: off, lineTrace: off.}
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Constants
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
const NPL_MAGIC*: array[4, uint8] = [0x7F'u8, 0x4E'u8, 0x50'u8, 0x4C'u8]
|
||||||
|
const NPL_VERSION* = 1'u8
|
||||||
|
const ARCH_ARM64* = 0xAA'u8
|
||||||
|
const ARCH_X86_64* = 0xEE'u8
|
||||||
|
const ARCH_RISCV64* = 0x55'u8
|
||||||
|
const NPL_HEADER_SIZE* = 128
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Types
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
type
|
||||||
|
NPLHeader* {.packed.} = object
|
||||||
|
magic*: array[4, uint8]
|
||||||
|
version*: uint8
|
||||||
|
arch*: uint8
|
||||||
|
flags*: uint16
|
||||||
|
signature*: array[64, uint8]
|
||||||
|
body_size*: uint64
|
||||||
|
reserved*: array[48, uint8]
|
||||||
|
|
||||||
|
PayloadEntry* = proc() {.cdecl.}
|
||||||
|
|
||||||
|
# Global last error (avoids struct return issues)
|
||||||
|
var nplLastError*: cstring = nil
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Architecture Detection
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
proc currentArch*(): uint8 =
|
||||||
|
when defined(arm64) or defined(aarch64):
|
||||||
|
return ARCH_ARM64
|
||||||
|
elif defined(amd64) or defined(x86_64):
|
||||||
|
return ARCH_X86_64
|
||||||
|
elif defined(riscv64):
|
||||||
|
return ARCH_RISCV64
|
||||||
|
else:
|
||||||
|
return 0x00'u8
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Debug output
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||||
|
|
||||||
|
proc nplPrint(s: cstring) =
|
||||||
|
var i = 0
|
||||||
|
while s[i] != '\0':
|
||||||
|
inc i
|
||||||
|
console_write(cast[pointer](s), csize_t(i))
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# NPL Loader (returns nil on failure, sets nplLastError)
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
proc loadNpl*(rawPtr: pointer, maxLen: uint64): PayloadEntry =
|
||||||
|
nplLastError = nil
|
||||||
|
|
||||||
|
nplPrint("[NPL] loadNpl\n")
|
||||||
|
|
||||||
|
if rawPtr == nil:
|
||||||
|
nplLastError = "null pointer"
|
||||||
|
return nil
|
||||||
|
|
||||||
|
let header = cast[ptr NPLHeader](rawPtr)
|
||||||
|
|
||||||
|
# Check Magic
|
||||||
|
if header.magic[0] != NPL_MAGIC[0] or
|
||||||
|
header.magic[1] != NPL_MAGIC[1] or
|
||||||
|
header.magic[2] != NPL_MAGIC[2] or
|
||||||
|
header.magic[3] != NPL_MAGIC[3]:
|
||||||
|
nplLastError = "bad magic"
|
||||||
|
return nil
|
||||||
|
|
||||||
|
# Check Version
|
||||||
|
if header.version != NPL_VERSION:
|
||||||
|
nplLastError = "bad version"
|
||||||
|
return nil
|
||||||
|
|
||||||
|
# Check Architecture
|
||||||
|
if header.arch != currentArch():
|
||||||
|
nplLastError = "bad arch"
|
||||||
|
return nil
|
||||||
|
|
||||||
|
# Check Bounds
|
||||||
|
let totalSize = NPL_HEADER_SIZE.uint64 + header.body_size
|
||||||
|
if totalSize > maxLen:
|
||||||
|
nplLastError = "truncated"
|
||||||
|
return nil
|
||||||
|
|
||||||
|
# Get body pointer
|
||||||
|
let bodyPtr = cast[pointer](cast[uint64](rawPtr) + NPL_HEADER_SIZE.uint64)
|
||||||
|
|
||||||
|
# Verify Signature (dev mode: reject 0xFF)
|
||||||
|
if header.signature[0] == 0xFF'u8:
|
||||||
|
nplLastError = "sig fail"
|
||||||
|
return nil
|
||||||
|
|
||||||
|
nplPrint("[NPL] valid\n")
|
||||||
|
|
||||||
|
# Cast body to function pointer
|
||||||
|
return cast[PayloadEntry](bodyPtr)
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Helper: Build Test Payload
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
proc buildTestPayload*(buffer: ptr array[256, uint8], arch: uint8,
|
||||||
|
codeBytes: openArray[uint8]) =
|
||||||
|
# Clear buffer
|
||||||
|
for i in 0..<256:
|
||||||
|
buffer[i] = 0
|
||||||
|
|
||||||
|
let header = cast[ptr NPLHeader](buffer)
|
||||||
|
header.magic = NPL_MAGIC
|
||||||
|
header.version = NPL_VERSION
|
||||||
|
header.arch = arch
|
||||||
|
header.flags = 1
|
||||||
|
header.body_size = codeBytes.len.uint64
|
||||||
|
|
||||||
|
# Copy code to body
|
||||||
|
for i, b in codeBytes:
|
||||||
|
buffer[NPL_HEADER_SIZE + i] = b
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
Loading…
Reference in New Issue