Initial import of ViperOS

This commit is contained in:
Viper
2026-07-19 12:38:20 +08:00
commit 6813947181
104 changed files with 26710 additions and 0 deletions

View File

@@ -0,0 +1,237 @@
from stdint import *
import fat32 as fs
import fat32_types as types
import fat32_part as part
import fat32_mkfs as mkfs_mod
import t, c
def print_fresult(res: types.FRESULT, msg: t.CConst) -> t.CInt:
if res == types.FRESULT.FR_OK:
print(f"[成功] {msg}")
return 0
else:
print(f"[失败] {msg}: {res}")
return -1
def print_fresult_void(res: types.FRESULT, msg: t.CConst):
print_fresult(res, msg)
def example_main() -> t.CInt:
print("=== FAT32 文件系统完整示例 ===")
print()
# 1. 扫描可用驱动器
print("--- 1. 扫描可用驱动器 ---")
res: types.FRESULT = fs.scan_drives()
print_fresult_void(res, "扫描驱动器")
drive_count: t.CInt = fs.get_drive_count()
print(f"找到 {drive_count} 个驱动器")
i: t.CInt
for i in range(drive_count):
letter: t.CChar = fs.get_drive_letter(i)
part_count: t.CInt = fs.get_partition_count(letter)
print(f" 驱动器 {i}: {letter}")
for j in range(part_count):
is_fat32: t.CInt = fs.is_partition_fat32(letter, j)
print(f" 分区 {j}: FAT32={is_fat32}")
print()
# 2. 挂载文件系统
print("--- 2. 挂载文件系统 ---")
res = fs.mount()
if print_fresult(res, "挂载文件系统") != 0:
print("提示: 可能需要先格式化磁盘")
print()
# 3. 文件系统信息
print("--- 3. 文件系统信息 ---")
mounted: t.CInt = fs.is_mounted()
print(f"已挂载: {mounted}")
if mounted:
total_clusters: t.CUInt32T = fs.get_total()
free_clusters: t.CUInt32T = fs.get_free()
cluster_size: t.CUInt32T = fs.get_cluster_size()
total_bytes: t.CUInt64T = t.CUInt64T(total_clusters) * t.CUInt64T(cluster_size)
free_bytes: t.CUInt64T = t.CUInt64T(free_clusters) * t.CUInt64T(cluster_size)
print(f"总簇数: {total_clusters}")
print(f"空闲簇数: {free_clusters}")
print(f"簇大小: {cluster_size} 字节")
print(f"总大小: {total_bytes} 字节")
print(f"空闲大小: {free_bytes} 字节")
print()
# 4. 元数据操作
print("--- 4. 元数据操作 ---")
fs.set_metadata(0x12345678)
metadata: t.CUInt32T = fs.get_metadata()
print(f"设置的元数据: 0x{metadata:08X}")
print()
# 5. 获取 FAT 时间
print("--- 5. 获取 FAT 时间 ---")
fattime: t.CUInt32T = fs.get_fattime()
print(f"当前 FAT 时间: 0x{fattime:08X}")
print()
# 6. 目录操作
if fs.is_mounted():
print("--- 6. 目录操作 ---")
# 创建目录
res = fs.mkdir("/test_dir_1")
print_fresult_void(res, "创建目录 /test_dir_1")
res = fs.mkdir("/test_dir_1/subdir")
print_fresult_void(res, "创建子目录 /test_dir_1/subdir")
res = fs.mkdir("/test_dir_2")
print_fresult_void(res, "创建目录 /test_dir_2")
print()
# 7. 文件操作
print("--- 7. 文件操作 ---")
# 创建并写入文件
fp1: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
if fp1 is not None:
test_data1: t.CConst = "Hello, World!"
written: t.CUInt32T = fs.write(fp1, test_data1, 13)
print(f"写入文件 /test_dir_1/file1.txt: {written} 字节")
fs.close(fp1)
# 打开追加
fp2: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_ALWAYS | types.FA_WRITE | types.FA_OPEN_APPEND)
if fp2 is not None:
test_data2: t.CConst = " Append data!"
written2: t.CUInt32T = fs.write(fp2, test_data2, 13)
print(f"追加写入: {written2} 字节")
fs.close(fp2)
# 读取文件
fp3: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_EXISTING | types.FA_READ)
if fp3 is not None:
buf: t.CArray[t.CUInt8T, 256]
read_bytes: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
print(f"读取字节数: {read_bytes}")
print(f"文件内容: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
# seek 和 tell
fs.seek(fp3, 5)
pos: t.CUInt32T = fs.tell(fp3)
print(f"seek 到位置 5, 当前位置: {pos}")
read_bytes2: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
print(f"从位置 5 读取: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
# 获取文件大小
fsize: t.CUInt32T = fs.size(fp3)
print(f"文件大小: {fsize} 字节")
fs.close(fp3)
# 创建另一个文件
fp4: types.fileobj | t.CPtr = fs.open("/test_dir_1/large_file.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
if fp4 is not None:
large_data: t.CArray[t.CUInt8T, 1024]
k: t.CInt
for k in range(1024):
large_data[k] = t.CUInt8T(ord('A') + (k % 26))
written3: t.CUInt32T = fs.write(fp4, t.CVoid(c.Addr(large_data[0]), t.CPtr), 1024)
print(f"创建大文件, 写入: {written3} 字节")
fs.close(fp4)
print()
# 8. 文件状态和属性
print("--- 8. 文件状态和属性 ---")
info: types.fileinfo
res = fs.stat("/test_dir_1/file1.txt", info)
print_fresult_void(res, "获取文件信息")
if res == types.FRESULT.FR_OK:
print(f" 文件名: {info.fname}")
print(f" 大小: {info.file_size} 字节")
print(f" 属性: 0x{info.attr:02X}")
print(f" 创建时间: 0x{info.ctime:04X}")
print(f" 创建日期: 0x{info.cdate:04X}")
print(f" 修改时间: 0x{info.mtime:04X}")
print(f" 修改日期: 0x{info.mdate:04X}")
print(f" 访问日期: 0x{info.adate:04X}")
# 修改属性
res = fs.chmod("/test_dir_1/file1.txt", types.AM_RDO, types.AM_RDO)
print_fresult_void(res, "设置文件为只读")
print()
# 9. 重命名和移动
print("--- 9. 重命名和移动 ---")
res = fs.rename("/test_dir_1/file1.txt", "/test_dir_1/renamed.txt")
print_fresult_void(res, "重命名文件")
res = fs.move("/test_dir_1/renamed.txt", "/test_dir_2/moved.txt")
print_fresult_void(res, "移动文件")
res = fs.rename("/test_dir_2", "/test_dir_renamed")
print_fresult_void(res, "重命名目录")
print()
# 10. 列出目录
print("--- 10. 列出目录 ---")
dp: types.dirobj
res = fs.opendir("/", dp)
if res == types.FRESULT.FR_OK:
print("根目录内容:")
dir_info: types.fileinfo
while True:
res = fs.readdir(dp, dir_info)
if res != types.FRESULT.FR_OK:
break
attr_str: t.CConst = ""
if dir_info.attr & types.AM_DIR:
attr_str = attr_str + "D"
else:
attr_str = attr_str + "F"
if dir_info.attr & types.AM_RDO:
attr_str = attr_str + "R"
if dir_info.attr & types.AM_HID:
attr_str = attr_str + "H"
if dir_info.attr & types.AM_SYS:
attr_str = attr_str + "S"
if dir_info.attr & types.AM_ARC:
attr_str = attr_str + "A"
print(f" [{attr_str}] {dir_info.fname} ({dir_info.file_size} 字节)")
fs.closedir(dp)
print()
# 11. 删除文件和目录
print("--- 11. 删除文件和目录 ---")
res = fs.remove("/test_dir_renamed/moved.txt")
print_fresult_void(res, "删除文件")
res = fs.remove("/test_dir_1/large_file.txt")
print_fresult_void(res, "删除大文件")
res = fs.rmdir("/test_dir_1/subdir")
print_fresult_void(res, "删除子目录")
res = fs.rmdir("/test_dir_1")
print_fresult_void(res, "删除目录 /test_dir_1")
res = fs.rmdir("/test_dir_renamed")
print_fresult_void(res, "删除目录 /test_dir_renamed")
print()
# 12. 卸载文件系统
print("--- 12. 卸载文件系统 ---")
res = fs.unmount()
print_fresult_void(res, "卸载文件系统")
print()
print("=== 示例完成 ===")
return 0

View File

@@ -0,0 +1,208 @@
from stdint import *
import string
import fat32_types as types
import fat32_time as ftime
import fat32_mkfs as mkfs_mod
import fat32_part as part
import fat32_diskio as diskio
import sched.sched as sched
import t, c
default_fs: types.volinfo = types.volinfo()
_fs_lock: t.CInt = 0
def lock():
global _fs_lock
while True:
c.Asm("cli")
if _fs_lock == 0:
_fs_lock = 1
c.Asm("sti")
return
c.Asm("sti")
sched.Scheduler._yield()
def unlock():
global _fs_lock
_fs_lock = 0
def mount() -> types.FRESULT:
default_fs.pdrv = 0
default_fs.hidden_sectors = 0
buf: t.CArray[t.CUInt8T, 512]
dres: types.DRESULT = diskio.read(0, c.Addr(buf[0]), 0, 1)
if dres == types.DRESULT.RES_OK:
if buf[0] == 0xEB or buf[0] == 0xE9:
default_fs.hidden_sectors = 0
else:
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
if sig == 0xAA55:
ptype: t.CUInt8T = buf[450]
if ptype != 0:
slba: t.CUInt32T = t.CUInt32T(buf[454]) | (t.CUInt32T(buf[455]) << 8) | (t.CUInt32T(buf[456]) << 16) | (t.CUInt32T(buf[457]) << 24)
default_fs.hidden_sectors = slba
if default_fs.mounted: return types.FRESULT.FR_OK
dsk_res: types.DRESULT = diskio.status(default_fs.pdrv)
if dsk_res != types.DRESULT.RES_OK:
dsk_res = diskio.init(default_fs.pdrv)
if dsk_res != types.DRESULT.RES_OK: return types.FRESULT.FR_NOT_READY
default_fs.winsect = 0xFFFFFFFFFFFFFFFF
default_fs.fat_winsect = 0xFFFFFFFFFFFFFFFF
wres: types.FRESULT = default_fs.win_read(0)
if wres != types.FRESULT.FR_OK: return types.FRESULT.FR_DISK_ERR
bps: t.CUInt16T = default_fs.win[11] | (t.CUInt16T(default_fs.win[12]) << 8)
spc: t.CUInt8T = default_fs.win[13]
rsc: t.CUInt16T = default_fs.win[14] | (t.CUInt16T(default_fs.win[15]) << 8)
nf: t.CUInt8T = default_fs.win[16]
if bps != 512: return types.FRESULT.FR_NO_FILESYSTEM
if spc == 0 or (spc & (spc - 1)) != 0: return types.FRESULT.FR_NO_FILESYSTEM
if rsc == 0: return types.FRESULT.FR_NO_FILESYSTEM
if nf == 0: return types.FRESULT.FR_NO_FILESYSTEM
root_ent: t.CUInt16T = default_fs.win[17] | (t.CUInt16T(default_fs.win[18]) << 8)
fat16sz: t.CUInt16T = default_fs.win[22] | (t.CUInt16T(default_fs.win[23]) << 8)
tot32: t.CUInt32T = t.CUInt32T(default_fs.win[32]) | (t.CUInt32T(default_fs.win[33]) << 8) | (t.CUInt32T(default_fs.win[34]) << 16) | (t.CUInt32T(default_fs.win[35]) << 24)
fat32sz: t.CUInt32T = t.CUInt32T(default_fs.win[36]) | (t.CUInt32T(default_fs.win[37]) << 8) | (t.CUInt32T(default_fs.win[38]) << 16) | (t.CUInt32T(default_fs.win[39]) << 24)
root_clus: t.CUInt32T = t.CUInt32T(default_fs.win[44]) | (t.CUInt32T(default_fs.win[45]) << 8) | (t.CUInt32T(default_fs.win[46]) << 16) | (t.CUInt32T(default_fs.win[47]) << 24)
if root_ent != 0 or fat16sz != 0: return types.FRESULT.FR_NO_FILESYSTEM
if fat32sz == 0: return types.FRESULT.FR_NO_FILESYSTEM
if tot32 == 0: return types.FRESULT.FR_NO_FILESYSTEM
if default_fs.win[510] != 0x55 or default_fs.win[511] != 0xAA: return types.FRESULT.FR_NO_FILESYSTEM
fsinfo_sec: t.CUInt16T = default_fs.win[48] | (t.CUInt16T(default_fs.win[49]) << 8)
bkboot_sec: t.CUInt16T = default_fs.win[50] | (t.CUInt16T(default_fs.win[51]) << 8)
default_fs.sector_size = 512
default_fs.cluster_sectors = spc
default_fs.cluster_size = t.CUInt32T(spc) * 512
default_fs.num_fats = nf
default_fs.reserved_sectors = rsc
default_fs.fat_size = fat32sz
default_fs.fat_start = t.CUInt64T(rsc)
default_fs.total_sectors = t.CUInt64T(tot32)
default_fs.root_cluster = root_clus
default_fs.fsinfo_sector = fsinfo_sec
default_fs.backup_sector = bkboot_sec
default_fs.vol_id = t.CUInt32T(default_fs.win[67]) | (t.CUInt32T(default_fs.win[68]) << 8) | (t.CUInt32T(default_fs.win[69]) << 16) | (t.CUInt32T(default_fs.win[70]) << 24)
data_sectors: t.CUInt64T = default_fs.total_sectors - t.CUInt64T(rsc) - t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
default_fs.total_clusters = t.CUInt32T(data_sectors / t.CUInt64T(spc))
default_fs.data_start = default_fs.fat_start + t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
default_fs.last_alloc = 2
default_fs.free_clusters = 0xFFFFFFFF
if fsinfo_sec != 0:
default_fs.fsinfo_read()
default_fs.mounted = 1
return types.FRESULT.FR_OK
def unmount() -> types.FRESULT:
return default_fs.unmount()
def format(sec_per_clus: t.CUInt8T = 0, vol_id: t.CUInt32T = 0) -> types.FRESULT:
return mkfs_mod.mkfs(default_fs.pdrv, sec_per_clus, vol_id)
def open(path: t.CConst | str, mode: t.CUInt8T) -> types.fileobj | t.CPtr:
return default_fs.file_open(path, mode)
def close(fp: types.fileobj | t.CPtr) -> types.FRESULT:
return fp.close()
def read(fp: types.fileobj | t.CPtr, buff: t.CVoid | t.CPtr, btr: t.CUInt32T) -> t.CUInt32T:
br: t.CUInt32T = 0
fp.read(buff, btr, c.Addr(br))
return br
def write(fp: types.fileobj | t.CPtr, buff: t.CConst | t.CVoid | t.CPtr, btw: t.CUInt32T) -> t.CUInt32T:
bw: t.CUInt32T = 0
fp.write(buff, btw, c.Addr(bw))
return bw
def seek(fp: types.fileobj | t.CPtr, offset: t.CUInt32T) -> types.FRESULT:
return fp.seek(offset)
def tell(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
return fp.tell()
def size(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
return fp.size()
def truncate(fp: types.fileobj | t.CPtr) -> types.FRESULT:
return fp.truncate()
def remove(path: t.CConst | str) -> types.FRESULT:
return default_fs.file_delete(path)
def rename(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
return default_fs.file_rename(old_path, new_path)
def move(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
return default_fs.file_rename(old_path, new_path)
def stat(path: t.CConst | str, info: types.fileinfo | t.CPtr) -> types.FRESULT:
return default_fs.file_stat(path, info)
def mkdir(path: t.CConst | str) -> types.FRESULT:
return default_fs.dir_make(path)
def rmdir(path: t.CConst | str) -> types.FRESULT:
return default_fs.dir_remove(path)
def opendir(path: t.CConst | str, dp: types.dirobj | t.CPtr) -> types.FRESULT:
return default_fs.dir_open_path(path, dp)
def readdir(dp: types.dirobj | t.CPtr, info: types.fileinfo | t.CPtr) -> types.FRESULT:
return default_fs.dir_read(dp, info)
def closedir(dp: types.dirobj | t.CPtr):
dp.is_open = 0
def chmod(path: t.CConst | str, attr: t.CUInt8T, mask: t.CUInt8T) -> types.FRESULT:
return default_fs.chmod(path, attr, mask)
def utime(path: t.CConst | str, mtime: t.CUInt16T, mdate: t.CUInt16T) -> types.FRESULT:
return default_fs.utime(path, mtime, mdate)
def get_free() -> t.CUInt32T:
if not default_fs.mounted: return 0
if default_fs.free_clusters == 0xFFFFFFFF:
return default_fs.count_free_clusters()
return default_fs.free_clusters
def get_total() -> t.CUInt32T:
if not default_fs.mounted: return 0
return default_fs.total_clusters
def get_cluster_size() -> t.CUInt32T:
if not default_fs.mounted: return 0
return default_fs.cluster_size
def is_mounted() -> t.CInt:
return default_fs.mounted
def last_error() -> t.CUInt32T:
return default_fs.last_error
def get_fattime() -> t.CUInt32T:
return ftime.get_fattime()
def get_metadata() -> t.CUInt32T:
return default_fs.metadata
def set_metadata(val: t.CUInt32T):
default_fs.metadata = val
def scan_drives() -> types.FRESULT:
return part.scan_drives()
def get_drive_count() -> t.CInt:
return part.get_drive_count()
def get_drive_letter(idx: t.CInt) -> t.CChar:
return part.get_drive_letter(idx)
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
return part.set_drive_letter(idx, letter)
def get_partition_count(letter: t.CChar) -> t.CInt:
return part.get_partition_count(letter)
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
return part.is_partition_fat32(letter, part_idx)

View File

@@ -0,0 +1,16 @@
from stdint import *
import fat32_types as types
import t, c
_read32 = types._read32
_read16 = types._read16
_write32 = types._write32
_write16 = types._write16
def is_eoc(cluster: t.CUInt32T) -> t.CInt:
return 1 if (cluster >= types.CLUSTER_EOC_MIN and cluster <= types.CLUSTER_EOC_MAX) else 0
def is_free(cluster: t.CUInt32T) -> t.CInt:
return 1 if cluster == types.CLUSTER_FREE else 0

View File

@@ -0,0 +1,13 @@
from stdint import *
import fat32_types as types
import t, c
sfn_checksum = types.sfn_checksum
uni2oem_placeholder = types.uni2oem_placeholder
lfn_get_char = types.lfn_get_char
lfn_set_char = types.lfn_set_char
lfn_extract = types.lfn_extract
sfn_from_lfn = types.sfn_from_lfn
sfn_to_str = types.sfn_to_str
_split_path = types._split_path

View File

@@ -0,0 +1,76 @@
import drivers.storage.ide.ide as ide
import fat32_types as types
import spinlock
import string
import t, c
MAX_DRIVES: t.CDefine = 4
drive_initialized: t.CArray[t.CInt, MAX_DRIVES]
drive_lock: spinlock._spinlock = spinlock._spinlock()
def status(pdrv: t.CUInt8T) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
return types.DRESULT.RES_OK
def init(pdrv: t.CUInt8T) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
drive_lock.lock()
err: t.CInt = ide.init()
if err != 0:
drive_lock.unlock()
return types.DRESULT.RES_NOTRDY
drive_initialized[pdrv] = 1
drive_lock.unlock()
return types.DRESULT.RES_OK
def read(pdrv: t.CUInt8T, buff: t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
drive_lock.lock()
i: t.CUInt32T
for i in range(count):
rd_res: t.CInt = ide.readSector(sector + i, buff + (i * 512))
if rd_res != 0:
drive_lock.unlock()
return types.DRESULT.RES_ERROR
drive_lock.unlock()
return types.DRESULT.RES_OK
def write(pdrv: t.CUInt8T, buff: t.CConst | t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
drive_lock.lock()
i: t.CUInt32T
for i in range(count):
if ide.writeSector(sector + i, buff + (i * 512)) != 0:
drive_lock.unlock()
return types.DRESULT.RES_ERROR
drive_lock.unlock()
return types.DRESULT.RES_OK
def ioctl(pdrv: t.CUInt8T, cmd: t.CUInt8T, buff: t.CVoid | t.CPtr) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
match cmd:
case types.GET_SECTOR_COUNT:
disk_size: t.CUInt64T = ide.getDiskSize()
if disk_size == 0:
c.Set(t.CUInt32T(buff, t.CPtr), 131072)
elif disk_size > 0xFFFFFFFF:
c.Set(t.CUInt32T(buff, t.CPtr), 0xFFFFFFFF)
else:
c.Set(t.CUInt32T(buff, t.CPtr), t.CUInt32T(disk_size))
return types.DRESULT.RES_OK
case types.GET_SECTOR_SIZE:
c.Set(t.CUInt16T(buff, t.CPtr), 512)
return types.DRESULT.RES_OK
case types.GET_BLOCK_SIZE:
c.Set(t.CUInt32T(buff, t.CPtr), 1)
return types.DRESULT.RES_OK
case types.CTRL_SYNC:
return types.DRESULT.RES_OK
case _:
return types.DRESULT.RES_PARERR

View File

@@ -0,0 +1,17 @@
from stdint import *
import fat32_types as types
import t, c
handle_table = types.handle_table
lock_table = types.lock_table
handles_initialized = types.handles_initialized
handles_init = types.handles_init
handle_alloc = types.handle_alloc
lock_check = types.lock_check
lock_acquire = types.lock_acquire
lock_release = types.lock_release
def handle_free(fp):
fp.is_open = 0
fp.lock_count = 0

View File

@@ -0,0 +1,143 @@
from stdint import *
import fat32_types as types
import fat32_diskio as diskio
import fat32_time as ftime
import string
import t, c
def _div_round_up(a: t.CUInt64T, b: t.CUInt64T) -> t.CUInt64T:
return (a + b - 1) / b
def _calc_fat_size(total_sectors: t.CUInt64T, reserved: t.CUInt32T, sec_per_clus: t.CUInt8T, num_fats: t.CUInt8T) -> t.CUInt32T:
tmp: t.CUInt64T = total_sectors - t.CUInt64T(reserved)
fat_sz: t.CUInt32T = 1
while True:
data_sectors: t.CUInt64T = tmp - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
needed: t.CUInt64T = _div_round_up(t.CUInt64T(total_clusters) * 4, 512)
if needed <= t.CUInt64T(fat_sz): break
fat_sz = t.CUInt32T(needed)
return fat_sz
def _write_boot_sector(pdrv: t.CUInt8T, total_sectors: t.CUInt64T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T, fat_sz: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
buf[0] = 0xEB; buf[1] = 0x58; buf[2] = 0x90
buf[3] = 'M'; buf[4] = 'S'; buf[5] = 'W'; buf[6] = 'I'; buf[7] = 'N'
buf[8] = '4'; buf[9] = '.'; buf[10] = '1'
types._write16(c.Addr(buf[0]), 11, 512)
buf[13] = sec_per_clus
types._write16(c.Addr(buf[0]), 14, 32)
buf[16] = 2
types._write16(c.Addr(buf[0]), 17, 0)
buf[21] = 0xF8
types._write16(c.Addr(buf[0]), 22, 0)
types._write16(c.Addr(buf[0]), 24, 63)
types._write16(c.Addr(buf[0]), 26, 255)
types._write32(c.Addr(buf[0]), 28, 0)
types._write32(c.Addr(buf[0]), 32, t.CUInt32T(total_sectors))
types._write32(c.Addr(buf[0]), 36, fat_sz)
types._write16(c.Addr(buf[0]), 40, 0)
types._write16(c.Addr(buf[0]), 42, 0)
types._write32(c.Addr(buf[0]), 44, 2)
types._write16(c.Addr(buf[0]), 48, 1)
types._write16(c.Addr(buf[0]), 50, 6)
buf[64] = 0x80
buf[66] = 0x29
types._write32(c.Addr(buf[0]), 67, vol_id)
vol_label: t.CArray[t.CChar, 11]
vol_label[0] = 'N'; vol_label[1] = 'O'; vol_label[2] = ' '; vol_label[3] = ' '
vol_label[4] = ' '; vol_label[5] = ' '; vol_label[6] = ' '; vol_label[7] = ' '
vol_label[8] = ' '; vol_label[9] = ' '; vol_label[10] = ' '
i: t.CInt
for i in range(11): buf[71 + i] = t.CUInt8T(vol_label[i])
buf[82] = 'F'; buf[83] = 'A'; buf[84] = 'T'; buf[85] = '3'
buf[86] = '2'; buf[87] = ' '; buf[88] = ' '; buf[89] = ' '
buf[510] = 0x55; buf[511] = 0xAA
return diskio.write(pdrv, c.Addr(buf[0]), 0, 1)
def _write_fsinfo(pdrv: t.CUInt8T, free_count: t.CUInt32T, next_free: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
types._write32(c.Addr(buf[0]), 0, 0x41615252)
types._write32(c.Addr(buf[0]), 484, 0x61417272)
types._write32(c.Addr(buf[0]), 488, free_count)
types._write32(c.Addr(buf[0]), 492, next_free)
types._write32(c.Addr(buf[0]), 508, 0xAA550000)
return diskio.write(pdrv, c.Addr(buf[0]), 1, 1)
def _init_fat(pdrv: t.CUInt8T, fat_start: t.CUInt64T, fat_sz: t.CUInt32T, root_cluster: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
types._write32(c.Addr(buf[0]), 0, 0x0FFFFFF8)
types._write32(c.Addr(buf[0]), 4, 0x0FFFFFFF)
types._write32(c.Addr(buf[0]), 8, 0x0FFFFFFF)
if root_cluster >= 2:
cluster_off: t.CUInt32T = root_cluster * 4
sector_off: t.CUInt32T = cluster_off / 512
byte_off: t.CUInt32T = cluster_off % 512
if sector_off == 0:
types._write32(c.Addr(buf[0]), byte_off, 0x0FFFFFFF)
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start), 1)
if res != types.DRESULT.RES_OK: return res
string.memset(c.Addr(buf[0]), 0, 512)
s: t.CUInt32T
for s in range(1, fat_sz):
res2: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start) + s, 1)
if res2 != types.DRESULT.RES_OK: return res2
return types.DRESULT.RES_OK
def _init_root_dir(pdrv: t.CUInt8T, root_sector: t.CUInt64T, sec_per_clus: t.CUInt8T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
s: t.CUInt8T
for s in range(sec_per_clus):
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(root_sector + t.CUInt64T(s)), 1)
if res != types.DRESULT.RES_OK: return res
return types.DRESULT.RES_OK
def _calc_sec_per_clus(total_sectors: t.CUInt64T) -> t.CUInt8T:
ts: t.CUInt64T = total_sectors
if ts < 532480: return 1
elif ts < 16777216: return 8
elif ts < 33554432: return 16
elif ts < 67108864: return 32
else: return 64
def mkfs(pdrv: t.CUInt8T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T) -> types.FRESULT:
if pdrv != types.DEV_DISK: return types.FRESULT.FR_INVALID_DRIVE
total_sectors_buf: t.CUInt32T = 0
diskio.ioctl(pdrv, types.GET_SECTOR_COUNT, c.Addr(total_sectors_buf))
total_sectors: t.CUInt64T = t.CUInt64T(total_sectors_buf)
if total_sectors < 65536: return types.FRESULT.FR_MKFS_ABORTED
if sec_per_clus == 0: sec_per_clus = _calc_sec_per_clus(total_sectors)
if sec_per_clus != 1 and sec_per_clus != 2 and sec_per_clus != 4 and sec_per_clus != 8 and sec_per_clus != 16 and sec_per_clus != 32 and sec_per_clus != 64 and sec_per_clus != 128:
return types.FRESULT.FR_INVALID_PARAMETER
if vol_id == 0: vol_id = ftime.get_fattime()
reserved: t.CUInt32T = 32
num_fats: t.CUInt8T = 2
fat_sz: t.CUInt32T = _calc_fat_size(total_sectors, reserved, sec_per_clus, num_fats)
data_sectors: t.CUInt64T = total_sectors - t.CUInt64T(reserved) - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
free_count: t.CUInt32T = total_clusters - 1
res: types.DRESULT = _write_boot_sector(pdrv, total_sectors, sec_per_clus, vol_id, fat_sz)
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
res2: types.DRESULT = _write_fsinfo(pdrv, free_count, 3)
if res2 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
boot_backup: t.CArray[t.CUInt8T, 512]
diskio.read(pdrv, c.Addr(boot_backup[0]), 0, 1)
diskio.write(pdrv, c.Addr(boot_backup[0]), 6, 1)
fsinfo_backup: t.CArray[t.CUInt8T, 512]
diskio.read(pdrv, c.Addr(fsinfo_backup[0]), 1, 1)
diskio.write(pdrv, c.Addr(fsinfo_backup[0]), 7, 1)
fat_start: t.CUInt64T = t.CUInt64T(reserved)
res3: types.DRESULT = _init_fat(pdrv, fat_start, fat_sz, 2)
if res3 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
fat2_start: t.CUInt64T = fat_start + t.CUInt64T(fat_sz)
res4: types.DRESULT = _init_fat(pdrv, fat2_start, fat_sz, 2)
if res4 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
root_sector: t.CUInt64T = fat2_start + t.CUInt64T(fat_sz)
res5: types.DRESULT = _init_root_dir(pdrv, root_sector, sec_per_clus)
if res5 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
return types.FRESULT.FR_OK

View File

@@ -0,0 +1,147 @@
from stdint import *
import fat32_types as types
import fat32_diskio as diskio
import string
import t, c
MAX_VOLUMES: t.CDefine = 4
MAX_PARTITIONS: t.CDefine = 4
MBR_SIGNATURE: t.CDefine = 0xAA55
PART_TYPE_FAT32: t.CDefine = 0x0C
PART_TYPE_FAT32_LBA: t.CDefine = 0x0B
PART_TYPE_FAT16: t.CDefine = 0x06
PART_TYPE_FAT16_LBA: t.CDefine = 0x0E
class partition_entry:
boot_flag: t.CUInt8T
start_chs: t.CArray[t.CUInt8T, 3]
part_type: t.CUInt8T
end_chs: t.CArray[t.CUInt8T, 3]
start_lba: t.CUInt32T
total_sectors: t.CUInt32T
drive_pdrv: t.CArray[t.CUInt8T, MAX_VOLUMES]
drive_num_parts: t.CArray[t.CInt, MAX_VOLUMES]
drive_letter_map: t.CArray[t.CChar, MAX_VOLUMES]
volume_mounted: t.CArray[t.CInt, MAX_VOLUMES]
part_types: t.CArray[t.CUInt8T, MAX_VOLUMES * MAX_PARTITIONS]
part_start_lbas: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
part_totals: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
part_is_fat32: t.CArray[t.CInt, MAX_VOLUMES * MAX_PARTITIONS]
num_drives: t.CInt = 0
def _init():
if num_drives > 0: return
i: t.CInt
for i in range(MAX_VOLUMES):
drive_letter_map[i] = 0
volume_mounted[i] = 0
drive_pdrv[i] = 0
drive_num_parts[i] = 0
j: t.CInt
for j in range(MAX_VOLUMES * MAX_PARTITIONS):
part_types[j] = 0
part_start_lbas[j] = 0
part_totals[j] = 0
part_is_fat32[j] = 0
def _part_idx(drive: t.CInt, part: t.CInt) -> t.CInt:
return drive * MAX_PARTITIONS + part
def parse_mbr(pdrv: t.CUInt8T, drive_idx: t.CInt) -> types.FRESULT:
buf: t.CArray[t.CUInt8T, 512]
res: types.DRESULT = diskio.read(pdrv, c.Addr(buf[0]), 0, 1)
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
if buf[0] == 0xEB or buf[0] == 0xE9:
return types.FRESULT.FR_NO_FILESYSTEM
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
if sig != MBR_SIGNATURE: return types.FRESULT.FR_NO_FILESYSTEM
drive_pdrv[drive_idx] = pdrv
drive_num_parts[drive_idx] = 0
i: t.CInt
for i in range(4):
base: t.CUInt32T = 446 + t.CUInt32T(i * 16)
ptype: t.CUInt8T = buf[base + 4]
slba: t.CUInt32T = t.CUInt32T(buf[base + 8]) | (t.CUInt32T(buf[base + 9]) << 8) | (t.CUInt32T(buf[base + 10]) << 16) | (t.CUInt32T(buf[base + 11]) << 24)
tsec: t.CUInt32T = t.CUInt32T(buf[base + 12]) | (t.CUInt32T(buf[base + 13]) << 8) | (t.CUInt32T(buf[base + 14]) << 16) | (t.CUInt32T(buf[base + 15]) << 24)
if ptype != 0 and tsec > 0:
pi: t.CInt = drive_num_parts[drive_idx]
if pi < MAX_PARTITIONS:
pidx: t.CInt = _part_idx(drive_idx, pi)
part_types[pidx] = ptype
part_start_lbas[pidx] = t.CUInt64T(slba)
part_totals[pidx] = t.CUInt64T(tsec)
part_is_fat32[pidx] = 1 if (ptype == PART_TYPE_FAT32 or ptype == PART_TYPE_FAT32_LBA) else 0
drive_num_parts[drive_idx] = pi + 1
return types.FRESULT.FR_OK
def scan_drives() -> types.FRESULT:
_init()
global num_drives
num_drives = 0
pdrv: t.CUInt8T
for pdrv in range(MAX_VOLUMES):
res: types.DRESULT = diskio.init(pdrv)
if res != types.DRESULT.RES_OK: continue
res2: types.FRESULT = parse_mbr(pdrv, num_drives)
if res2 == types.FRESULT.FR_OK and drive_num_parts[num_drives] > 0:
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
else:
drive_pdrv[num_drives] = pdrv
drive_num_parts[num_drives] = 1
pidx: t.CInt = _part_idx(num_drives, 0)
part_types[pidx] = PART_TYPE_FAT32_LBA
part_start_lbas[pidx] = 0
part_totals[pidx] = 0
part_is_fat32[pidx] = 1
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
num_drives = num_drives + 1
if num_drives >= MAX_VOLUMES: break
return types.FRESULT.FR_OK
def get_drive(letter: t.CChar) -> t.CInt:
_init()
i: t.CInt
for i in range(num_drives):
if drive_letter_map[i] == letter or drive_letter_map[i] == (letter - 32) or drive_letter_map[i] == (letter + 32):
return i
return -1
def get_pdrv(letter: t.CChar) -> t.CUInt8T:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
return drive_pdrv[idx]
def get_partition_start(letter: t.CChar, part_idx: t.CInt) -> t.CUInt64T:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
if part_idx >= drive_num_parts[idx]: return 0
pidx: t.CInt = _part_idx(idx, part_idx)
return part_start_lbas[pidx]
def get_partition_count(letter: t.CChar) -> t.CInt:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
return drive_num_parts[idx]
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
if part_idx >= drive_num_parts[idx]: return 0
pidx: t.CInt = _part_idx(idx, part_idx)
return part_is_fat32[pidx]
def get_drive_count() -> t.CInt:
return num_drives
def get_drive_letter(idx: t.CInt) -> t.CChar:
if idx < 0 or idx >= num_drives: return 0
return drive_letter_map[idx]
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
if idx < 0 or idx >= num_drives: return types.FRESULT.FR_INVALID_PARAMETER
drive_letter_map[idx] = letter
return types.FRESULT.FR_OK

View File

@@ -0,0 +1,64 @@
from stdint import *
import t, c
import asm
rtc_cmos_addr: t.CUInt16T = 0x70
rtc_cmos_data: t.CUInt16T = 0x71
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
asm.outb(rtc_cmos_addr, reg)
return asm.inb(rtc_cmos_data)
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
return (bcd >> 4) * 10 + (bcd & 0x0F)
def get_rtc_time() -> t.CUInt32T:
while cmos_read(0x0A) & 0x80: pass
sec: t.CUInt8T = cmos_read(0x00)
min_: t.CUInt8T = cmos_read(0x02)
hour: t.CUInt8T = cmos_read(0x04)
day: t.CUInt8T = cmos_read(0x07)
mon: t.CUInt8T = cmos_read(0x08)
year: t.CUInt8T = cmos_read(0x09)
reg_b: t.CUInt8T = cmos_read(0x0B)
if not (reg_b & 0x04):
sec = bcd_to_bin(sec)
min_ = bcd_to_bin(min_)
hour = bcd_to_bin(hour)
day = bcd_to_bin(day)
mon = bcd_to_bin(mon)
year = bcd_to_bin(year)
fat_year: t.CUInt16T = t.CUInt16T(year) + 2000 - 1980
if fat_year > 127: fat_year = 127
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(mon) << 5) | t.CUInt16T(day)
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(min_) << 5) | (t.CUInt16T(sec) / 2)
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)
def get_fattime() -> t.CUInt32T:
return get_rtc_time()
def to_year(ft: t.CUInt32T) -> t.CUInt16T:
return t.CUInt16T((ft >> 25) & 0x7F) + 1980
def to_month(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 21) & 0x0F)
def to_day(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 16) & 0x1F)
def to_hour(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 11) & 0x1F)
def to_minute(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 5) & 0x3F)
def to_second(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft & 0x1F) * 2)
def make(year: t.CUInt16T, month: t.CUInt8T, day: t.CUInt8T, hour: t.CUInt8T, minute: t.CUInt8T, second: t.CUInt8T) -> t.CUInt32T:
fat_year: t.CUInt16T = year - 1980
if fat_year > 127: fat_year = 127
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(month) << 5) | t.CUInt16T(day)
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(minute) << 5) | (t.CUInt16T(second) / 2)
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
import fat32