141 lines
4.6 KiB
Nim
141 lines
4.6 KiB
Nim
# SPDX-License-Identifier: LSL-1.0
|
|
# Copyright (c) 2026 Markus Maiwald
|
|
# Stewardship: Self Sovereign Society Foundation
|
|
#
|
|
# This file is part of the Nexus Sovereign Core.
|
|
# See legal/LICENSE_SOVEREIGN.md for license terms.
|
|
|
|
## Rumpk Layer 1: Sovereign File System (SFS)
|
|
##
|
|
## Freestanding implementation (No OS module dependencies).
|
|
## Uses fixed-size buffers and raw blocks for persistence.
|
|
|
|
import ring, fiber # For yield
|
|
|
|
proc kprintln(s: cstring) {.importc, cdecl.}
|
|
proc kprint(s: cstring) {.importc, cdecl.}
|
|
proc kprint_hex(n: uint64) {.importc, cdecl.}
|
|
|
|
const SFS_MAGIC* = 0x31534653'u32
|
|
const
|
|
SEC_SB = 0
|
|
SEC_BAM = 1
|
|
SEC_DIR = 2
|
|
CHUNK_SIZE = 508
|
|
EOF_MARKER = 0xFFFFFFFF'u32
|
|
|
|
var sfs_mounted: bool = false
|
|
var io_buffer: array[512, byte]
|
|
|
|
proc virtio_blk_read(sector: uint64, buf: pointer) {.importc, cdecl.}
|
|
proc virtio_blk_write(sector: uint64, buf: pointer) {.importc, cdecl.}
|
|
|
|
proc sfs_alloc_sector(): uint32 =
|
|
virtio_blk_read(SEC_BAM, addr io_buffer[0])
|
|
for i in 0..<512:
|
|
if io_buffer[i] != 0xFF:
|
|
for b in 0..7:
|
|
if (io_buffer[i] and byte(1 shl b)) == 0:
|
|
let sec = uint32(i * 8 + b)
|
|
io_buffer[i] = io_buffer[i] or byte(1 shl b)
|
|
virtio_blk_write(SEC_BAM, addr io_buffer[0])
|
|
return sec
|
|
return 0
|
|
|
|
proc sfs_mount*() =
|
|
virtio_blk_read(SEC_SB, addr io_buffer[0])
|
|
if io_buffer[0] == byte('S') and io_buffer[1] == byte('F') and
|
|
io_buffer[2] == byte('S') and io_buffer[3] == byte('2'):
|
|
sfs_mounted = true
|
|
else:
|
|
sfs_mounted = false
|
|
|
|
proc sfs_streq(s1, s2: cstring): bool =
|
|
let p1 = cast[ptr UncheckedArray[char]](s1)
|
|
let p2 = cast[ptr UncheckedArray[char]](s2)
|
|
var i = 0
|
|
while true:
|
|
if p1[i] != p2[i]: return false
|
|
if p1[i] == '\0': return true
|
|
i += 1
|
|
|
|
proc sfs_write_file*(name: cstring, data: pointer, data_len: int) {.exportc, cdecl.} =
|
|
if not sfs_mounted: return
|
|
virtio_blk_read(SEC_DIR, addr io_buffer[0])
|
|
var dir_offset = -1
|
|
for offset in countup(0, 511, 64):
|
|
if io_buffer[offset] != 0:
|
|
if sfs_streq(name, cast[cstring](addr io_buffer[offset])):
|
|
dir_offset = offset
|
|
break
|
|
elif dir_offset == -1: dir_offset = offset
|
|
if dir_offset == -1: return
|
|
|
|
var remaining = data_len
|
|
var data_addr = cast[uint64](data)
|
|
var current_sector = sfs_alloc_sector()
|
|
if current_sector == 0: return
|
|
let first_sector = current_sector
|
|
|
|
while remaining > 0:
|
|
var sector_buf: array[512, byte]
|
|
let chunk = if remaining > CHUNK_SIZE: CHUNK_SIZE else: remaining
|
|
copyMem(addr sector_buf[0], cast[pointer](data_addr), chunk)
|
|
remaining -= chunk
|
|
data_addr += uint64(chunk)
|
|
|
|
var next_sector = EOF_MARKER
|
|
if remaining > 0:
|
|
next_sector = sfs_alloc_sector()
|
|
if next_sector == 0: next_sector = EOF_MARKER
|
|
|
|
# Write next pointer at end of block
|
|
cast[ptr uint32](addr sector_buf[508])[] = next_sector
|
|
virtio_blk_write(uint64(current_sector), addr sector_buf[0])
|
|
current_sector = next_sector
|
|
if current_sector == EOF_MARKER: break
|
|
|
|
# Update Directory
|
|
virtio_blk_read(SEC_DIR, addr io_buffer[0])
|
|
let nm = cast[ptr UncheckedArray[char]](name)
|
|
var i = 0
|
|
while nm[i] != '\0' and i < 31:
|
|
io_buffer[dir_offset + i] = byte(nm[i])
|
|
i += 1
|
|
io_buffer[dir_offset + i] = 0
|
|
cast[ptr uint32](addr io_buffer[dir_offset + 32])[] = first_sector
|
|
cast[ptr uint32](addr io_buffer[dir_offset + 36])[] = uint32(data_len)
|
|
virtio_blk_write(SEC_DIR, addr io_buffer[0])
|
|
|
|
proc sfs_read_file*(name: cstring, dest: pointer, max_len: int): int {.exportc, cdecl.} =
|
|
if not sfs_mounted: return -1
|
|
virtio_blk_read(SEC_DIR, addr io_buffer[0])
|
|
var start_sector = 0'u32
|
|
var file_size = 0'u32
|
|
var found = false
|
|
for offset in countup(0, 511, 64):
|
|
if io_buffer[offset] != 0:
|
|
if sfs_streq(name, cast[cstring](addr io_buffer[offset])):
|
|
start_sector = cast[ptr uint32](addr io_buffer[offset + 32])[]
|
|
file_size = cast[ptr uint32](addr io_buffer[offset + 36])[]
|
|
found = true
|
|
break
|
|
if not found: return -1
|
|
|
|
var current_sector = start_sector
|
|
var dest_addr = cast[uint64](dest)
|
|
var remaining = if int(file_size) < max_len: int(file_size) else: max_len
|
|
var total = 0
|
|
while remaining > 0 and current_sector != EOF_MARKER:
|
|
var sector_buf: array[512, byte]
|
|
virtio_blk_read(uint64(current_sector), addr sector_buf[0])
|
|
let chunk = if remaining < CHUNK_SIZE: remaining else: CHUNK_SIZE
|
|
copyMem(cast[pointer](dest_addr), addr sector_buf[0], chunk)
|
|
dest_addr += uint64(chunk)
|
|
remaining -= chunk
|
|
total += chunk
|
|
current_sector = cast[ptr uint32](addr sector_buf[508])[]
|
|
return total
|
|
|
|
proc sfs_get_files*(): cstring = return "boot.kdl\n" # Dummy
|