# 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) # Markus Maiwald (Architect) | Voxis Forge (AI) # # Rumpk Phase 23: The Sovereign Filesystem (SFS) v2 # Features: Multi-Sector Files (Linked List), Block Alloc Map (BAM) # # DOCTRINE(SPEC-021): # This file currently implements the "Physics-Logic Hybrid" for Bootstrapping. # In Phase 37, this will be deprecated in favor of: # - L0: LittleFS (Atomic Physics) # - L1: SFS Overlay Daemon (Sovereign Logic in Userland) proc kprintln(s: cstring) {.importc, cdecl.} proc kprint(s: cstring) {.importc, cdecl.} proc kprint_hex(n: uint64) {.importc, cdecl.} # ========================================================= # SFS Configurations # ========================================================= const SFS_MAGIC* = 0x31534653'u32 const SEC_SB = 0 SEC_BAM = 1 SEC_DIR = 2 # Linked List Payload: 508 bytes data + 4 bytes next_sector CHUNK_SIZE = 508 EOF_MARKER = 0xFFFFFFFF'u32 type Superblock* = object magic*: uint32 disk_size*: uint32 DirEntry* = object filename*: array[32, char] start_sector*: uint32 size_bytes*: uint32 reserved*: array[24, byte] 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.} # ========================================================= # Helpers # ========================================================= # Removed sfs_set_bam (unused) proc sfs_alloc_sector(): uint32 = # Simple allocator: Scan BAM for first 0 bit virtio_blk_read(SEC_BAM, addr io_buffer[0]) for i in 0..<512: if io_buffer[i] != 0xFF: # Found a byte with free space for b in 0..7: if (io_buffer[i] and byte(1 shl b)) == 0: # Found free bit let sec = uint32(i * 8 + b) # Mark applied in sfs_set_bam but for efficiency do it here/flush io_buffer[i] = io_buffer[i] or byte(1 shl b) virtio_blk_write(SEC_BAM, addr io_buffer[0]) return sec return 0 # Error / Full # ========================================================= # SFS API # ========================================================= proc sfs_is_mounted*(): bool = sfs_mounted proc sfs_format*() = kprintln("[SFS] Formatting disk...") # 1. Clear IO Buffer for i in 0..511: io_buffer[i] = 0 # 2. Setup Superblock io_buffer[0] = byte('S') io_buffer[1] = byte('F') io_buffer[2] = byte('S') io_buffer[3] = byte('2') # Disk size placeholder (32MB = 65536 sectors) io_buffer[4] = 0x00; io_buffer[5] = 0x00; io_buffer[6] = 0x01; io_buffer[7] = 0x00 virtio_blk_write(SEC_SB, addr io_buffer[0]) # 3. Clear BAM for i in 0..511: io_buffer[i] = 0 # Mark sectors 0, 1, 2 as used io_buffer[0] = 0x07 virtio_blk_write(SEC_BAM, addr io_buffer[0]) # 4. Clear Directory for i in 0..511: io_buffer[i] = 0 virtio_blk_write(SEC_DIR, addr io_buffer[0]) kprintln("[SFS] Format Complete.") proc sfs_mount*() = kprintln("[SFS] Mounting System v2...") # 1. Read Sector 0 (Superblock) virtio_blk_read(SEC_SB, addr io_buffer[0]) # 2. Check Magic (SFS2) if io_buffer[0] == byte('S') and io_buffer[1] == byte('F') and io_buffer[2] == byte('S') and io_buffer[3] == byte('2'): kprintln("[SFS] Mount SUCCESS. Version 2 (Linked Chain).") sfs_mounted = true elif io_buffer[0] == 0 and io_buffer[1] == 0: kprintln("[SFS] Fresh disk detected.") sfs_format() sfs_mounted = true else: kprint("[SFS] Mount FAILED. Invalid Magic/Ver. Found: ") kprint_hex(cast[uint64](io_buffer[0])) kprintln("") proc sfs_list*() = if not sfs_mounted: return virtio_blk_read(SEC_DIR, addr io_buffer[0]) kprintln("[SFS] Files:") var offset = 0 while offset < 512: if io_buffer[offset] != 0: var name: string = "" for i in 0..31: let c = char(io_buffer[offset+i]) if c == '\0': break name.add(c) kprint(" - ") kprintln(cstring(name)) offset += 64 proc sfs_get_files*(): string = var res = "" if not sfs_mounted: return res virtio_blk_read(SEC_DIR, addr io_buffer[0]) for offset in countup(0, 511, 64): if io_buffer[offset] != 0: var name = "" for i in 0..31: let c = char(io_buffer[offset+i]) if c == '\0': break name.add(c) res.add(name) res.add("\n") return res proc sfs_write_file*(name: cstring, data: cstring, data_len: int) {.exportc, cdecl.} = if not sfs_mounted: return virtio_blk_read(SEC_DIR, addr io_buffer[0]) var dir_offset = -1 var file_exists = false # 1. Find File or Free Slot for offset in countup(0, 511, 64): if io_buffer[offset] != 0: var entry_name = "" for i in 0..31: if io_buffer[offset+i] == 0: break entry_name.add(char(io_buffer[offset+i])) if entry_name == $name: dir_offset = offset file_exists = true # For existing files, efficient rewrite logic is complex (reuse chain vs new). # V2 Simplification: Just create NEW chain, orphan old one (leak) for now. # Future: Walk old chain and free in BAM. break elif dir_offset == -1: dir_offset = offset if dir_offset == -1: kprintln("[SFS] Error: Directory Full.") return # 2. Chunk and Write Data var remaining = data_len var data_ptr = 0 var first_sector = 0'u32 var current_sector = 0'u32 # For the first chunk current_sector = sfs_alloc_sector() if current_sector == 0: kprintln("[SFS] Error: Disk Full.") return first_sector = current_sector while remaining > 0: var sector_buf: array[512, byte] # Fill Data let chunk_size = if remaining > CHUNK_SIZE: CHUNK_SIZE else: remaining for i in 0.. 0: next_sector = sfs_alloc_sector() if next_sector == 0: next_sector = EOF_MARKER # Disk full, truncated remaining = 0 # Write Next Pointer sector_buf[508] = byte(next_sector and 0xFF) sector_buf[509] = byte((next_sector shr 8) and 0xFF) sector_buf[510] = byte((next_sector shr 16) and 0xFF) sector_buf[511] = byte((next_sector shr 24) and 0xFF) # Flush Sector virtio_blk_write(uint64(current_sector), addr sector_buf[0]) current_sector = next_sector if current_sector == EOF_MARKER: break # 3. Update Directory Entry # Need to read Dir again as buffer was used for BAM/Data virtio_blk_read(SEC_DIR, addr io_buffer[0]) let n_str = $name for i in 0..31: if i < n_str.len: io_buffer[dir_offset+i] = byte(n_str[i]) else: io_buffer[dir_offset+i] = 0 io_buffer[dir_offset+32] = byte(first_sector and 0xFF) io_buffer[dir_offset+33] = byte((first_sector shr 8) and 0xFF) io_buffer[dir_offset+34] = byte((first_sector shr 16) and 0xFF) io_buffer[dir_offset+35] = byte((first_sector shr 24) and 0xFF) let sz = uint32(data_len) io_buffer[dir_offset+36] = byte(sz and 0xFF) io_buffer[dir_offset+37] = byte((sz shr 8) and 0xFF) io_buffer[dir_offset+38] = byte((sz shr 16) and 0xFF) io_buffer[dir_offset+39] = byte((sz shr 24) and 0xFF) virtio_blk_write(SEC_DIR, addr io_buffer[0]) kprintln("[SFS] Multi-Sector Write Complete.") 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: var entry_name = "" for i in 0..31: if io_buffer[offset+i] == 0: break entry_name.add(char(io_buffer[offset+i])) if entry_name == $name: start_sector = uint32(io_buffer[offset+32]) or (uint32(io_buffer[offset+33]) shl 8) or (uint32(io_buffer[offset+34]) shl 16) or (uint32(io_buffer[offset+35]) shl 24) file_size = uint32(io_buffer[offset+36]) or (uint32(io_buffer[offset+37]) shl 8) or (uint32(io_buffer[offset+38]) shl 16) or (uint32(io_buffer[offset+39]) shl 24) found = true break if not found: return -1 # Read Chain var current_sector = start_sector var dest_addr = cast[int](dest) var remaining = int(file_size) if remaining > max_len: remaining = max_len var total_read = 0 while remaining > 0 and current_sector != EOF_MARKER and current_sector != 0: var sector_buf: array[512, byte] virtio_blk_read(uint64(current_sector), addr sector_buf[0]) # Extract Payload let payload_size = min(remaining, CHUNK_SIZE) # Be careful not to overflow dest buffer if payload_size > remaining (handled by min) copyMem(cast[pointer](dest_addr), addr sector_buf[0], payload_size) dest_addr += payload_size remaining -= payload_size total_read += payload_size # Next Sector current_sector = uint32(sector_buf[508]) or (uint32(sector_buf[509]) shl 8) or (uint32(sector_buf[510]) shl 16) or (uint32(sector_buf[511]) shl 24) return total_read proc vfs_register_sfs(name: string, size: uint64) {.importc, cdecl.} proc sfs_sync_vfs*() = if not sfs_mounted: return virtio_blk_read(SEC_DIR, addr io_buffer[0]) for offset in countup(0, 511, 64): if io_buffer[offset] != 0: var name = "" for i in 0..31: let c = char(io_buffer[offset+i]) if c == '\0': break name.add(c) let f_size = uint32(io_buffer[offset+36]) or (uint32(io_buffer[offset+37]) shl 8) or (uint32(io_buffer[offset+38]) shl 16) or (uint32(io_buffer[offset+39]) shl 24) vfs_register_sfs(name, uint64(f_size))