rumpk/core/fs/sfs.nim

189 lines
5.8 KiB
Nim

# 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.")