# Markus Maiwald (Architect) | Voxis Forge (AI) # Rumpk Phase 11: The Sovereign Filesystem (SFS) # Simple Flat System (Contiguous, Directory-based, No Inodes) # import ../ion # Removing to avoid cycle and ambiguity # import ../kernel # Removing to avoid cycle proc kprintln(s: cstring) {.importc, cdecl.} proc kprint(s: cstring) {.importc, cdecl.} proc kprint_hex(n: uint64) {.importc, cdecl.} # ========================================================= # SFS Definitions # ========================================================= const SFS_MAGIC = 0x31534653'u32 # "SFS1" in Little Endian (S=53, F=46, S=53, 1=31 -> 31 53 46 53? No, S is lowest addr) # "SFS1" as string: bufs[0]=S, buf[1]=F... # u32 representation depends on Endianness. # On Little Endian (RISC-V): # 0x31534653 -> LSB is 0x53 (S). MSB is 0x31 (1). # So "SFS1" in memory. type Superblock* = object magic*: uint32 disk_size*: uint32 # in sectors? or bytes? Nipbox wrote u64 bytes. Let's use sectors for kernel simplicity? # Stack layout alignment might be issue. Let's read raw bytes. DirEntry* = object filename*: array[32, char] start_sector*: uint32 size_bytes*: uint32 reserved*: array[24, byte] # Pad to 64 bytes? 32+4+4 = 40. 64-40=24. # 512 / 64 = 8 entries per sector. # ========================================================= # SFS State # ========================================================= var sfs_mounted: bool = false var io_buffer: array[512, byte] # Kernel IO Buffer for FS ops # ========================================================= # SFS Driver # ========================================================= # Import HAL block ops proc virtio_blk_read(sector: uint64, buf: pointer) {.importc, cdecl.} proc virtio_blk_write(sector: uint64, buf: pointer) {.importc, cdecl.} proc sfs_mount*() = kprintln("[SFS] Mounting System...") # 1. Read Sector 0 (Superblock) virtio_blk_read(0, addr io_buffer[0]) # 2. Check Magic # "SFS1" -> 0x53, 0x46, 0x53, 0x31 if io_buffer[0] == 0x53 and io_buffer[1] == 0x46 and io_buffer[2] == 0x53 and io_buffer[3] == 0x31: kprintln("[SFS] Mount SUCCESS. Magic: SFS1") sfs_mounted = true else: kprint("[SFS] Mount FAILED. Invalid Magic. Found: ") kprint_hex(cast[uint64](io_buffer[0])) kprint(" ") kprint_hex(cast[uint64](io_buffer[1])) kprint(" ") kprint_hex(cast[uint64](io_buffer[2])) kprintln("") proc sfs_list*() = if not sfs_mounted: kprintln("[SFS] Error: Not mounted.") return # Read Sector 1 (Directory Table) virtio_blk_read(1, addr io_buffer[0]) kprintln("[SFS] Files:") # Parse Entries (assuming 64 bytes stride for now if nipbox holds it) # Actually nipbox `mkfs` just zeroed it. var found = false var offset = 0 while offset < 512: if io_buffer[offset] != 0: # Found entry 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)) found = true offset += 64 if not found: kprintln(" (Empty)") proc sfs_write_file*(name: cstring, data: cstring, data_len: int) = if not sfs_mounted: kprintln("[SFS] Write Error: Not mounted.") return # 1. Read Directory Table (Sector 1) virtio_blk_read(1, addr io_buffer[0]) var free_slot_offset = -1 var found_file_offset = -1 var max_sector: uint32 = 1 var offset = 0 while offset < 512: if io_buffer[offset] != 0: var entry_name: string = "" for i in 0..31: if io_buffer[offset+i] == 0: break entry_name.add(char(io_buffer[offset+i])) if entry_name == $name: found_file_offset = offset var s_sect: uint32 = 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) if s_sect > max_sector: max_sector = s_sect elif free_slot_offset == -1: free_slot_offset = offset offset += 64 # 2. Determine Target Sector var target_sector: uint32 = 0 var target_offset = 0 if found_file_offset != -1: kprintln("[SFS] Overwriting existing file...") target_offset = found_file_offset target_sector = uint32(io_buffer[target_offset+32]) or (uint32(io_buffer[target_offset+33]) shl 8) or (uint32(io_buffer[target_offset+34]) shl 16) or (uint32(io_buffer[target_offset+35]) shl 24) elif free_slot_offset != -1: kprintln("[SFS] Creating new file...") target_offset = free_slot_offset target_sector = max_sector + 1 else: kprintln("[SFS] Error: Directory Full.") return # 3. Write Data kprint("[SFS] Writing to Sector: ") kprint_hex(uint64(target_sector)) kprintln("") var data_buf: array[512, byte] for i in 0..511: data_buf[i] = 0 for i in 0 ..< data_len: if i < 512: data_buf[i] = byte(data[i]) virtio_blk_write(uint64(target_sector), addr data_buf[0]) # 4. Update Directory Entry var n_str = $name for i in 0..31: if i < n_str.len: io_buffer[target_offset+i] = byte(n_str[i]) else: io_buffer[target_offset+i] = 0 io_buffer[target_offset+32] = byte(target_sector and 0xFF) io_buffer[target_offset+33] = byte((target_sector shr 8) and 0xFF) io_buffer[target_offset+34] = byte((target_sector shr 16) and 0xFF) io_buffer[target_offset+35] = byte((target_sector shr 24) and 0xFF) var sz = uint32(data_len) io_buffer[target_offset+36] = byte(sz and 0xFF) io_buffer[target_offset+37] = byte((sz shr 8) and 0xFF) io_buffer[target_offset+38] = byte((sz shr 16) and 0xFF) io_buffer[target_offset+39] = byte((sz shr 24) and 0xFF) # 5. Write Directory Table Back virtio_blk_write(1, addr io_buffer[0]) kprintln("[SFS] Write Complete.")