rumpk/core/fs/sfs.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 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