144 lines
6.5 KiB
Python
144 lines
6.5 KiB
Python
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
|