#pypp 0 #include #include #define SECTOR_BITS 9 #define BLOCK_MASK (~((1 << SECTOR_BITS) - 1)) #define ROOT_CLUSTER 0x7fffffff static unsigned _free extern unsigned _end void init_alloc (): _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK char *alloc_space (unsigned pages): unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK _free = ret + (pages << PAGE_BITS) return (char *)ret void *operator new[] (unsigned size): //kdebug ("new ") void *ret = (void *)_free size = (size + 3) & ~3 unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1) if rest < size: unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS for unsigned p = 0; p < pages; ++p: Iris::Page page = Iris::my_memory.create_page () page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME) Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS)) Iris::free_cap (page) _free += size //kdebug_num ((unsigned)ret) //kdebug ("+") //kdebug_num (size) //kdebug ("\n") return ret void *operator new (unsigned size): return new char[size] static Iris::WString dev static Iris::Num device_size static Iris::Page page static char *data static Iris::Num current_block static void read_block (Iris::Num idx, Iris::Page p = page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0): if p.code == page.code: if idx.value () == current_block.value () && offset == 0 && size == 1 << SECTOR_BITS: return current_block = idx //kdebug ("fat getting block: ") //kdebug_num (idx.h) //kdebug (":") //kdebug_num (idx.l) //kdebug ("+") //kdebug_num (size) //kdebug ("@") //kdebug_num (offset) //kdebug ("\n") dev.get_block (idx, size, offset, p) struct Fat: char oem[8] unsigned sector_size_bits unsigned sectors_per_cluster_bits unsigned reserved_sectors unsigned num_fats unsigned root_entries unsigned sectors unsigned media unsigned sectors_per_fat unsigned sectors_per_track unsigned heads unsigned hidden_sectors unsigned active_fat bool write_all_fats unsigned fs_version unsigned root_cluster unsigned fsinfo_sector unsigned boot_backup_sector unsigned drive unsigned current_head unsigned volume_id char label[0xb] unsigned bits unsigned clusters unsigned cluster_size_bits unsigned root_sectors unsigned header_sectors unsigned bad_clusters unsigned free_clusters unsigned last_alloced unsigned *fat unsigned first_free_cluster, first_bad_cluster void print_num (char const *pre, unsigned data): kdebug ("\t") kdebug (pre) unsigned bytes = 1 while bytes < 8 && data >> (bytes * 4): ++bytes kdebug_num (data, bytes) kdebug ("\n") void print_br (): kdebug ("\tOEM: '") for unsigned i = 0; i < 8; ++i: kdebug_char (oem[i]) kdebug ("'\n") print_num ("bytes per sector: ", 1 << sector_size_bits) print_num ("sectors per cluster: ", 1 << sectors_per_cluster_bits) print_num ("reserved sectors: ", reserved_sectors) print_num ("number of fats: ", num_fats) print_num ("entries in root directory: ", root_entries) print_num ("sectors: ", sectors) print_num ("media descriptor: ", media) print_num ("sectors per fat: ", sectors_per_fat) print_num ("sectors per track: ", sectors_per_track) print_num ("heads: ", heads) print_num ("hidden sectors: ", hidden_sectors) print_num ("active_fat: ", active_fat) kdebug ("\twrite all: ") kdebug (write_all_fats ? "yes\n" : "no\n") print_num ("fs version: ", fs_version) print_num ("root cluster: ", root_cluster) print_num ("fsinfo sector: ", fsinfo_sector) print_num ("boot sector backup sector: ", boot_backup_sector) print_num ("drive: ", drive) print_num ("current head: ", current_head) print_num ("volume id: ", volume_id) kdebug ("\tlabel: '") for unsigned i = 0; i < 0xb; ++i: kdebug_char (label[i]) kdebug ("'\n") print_num ("bits: ", bits) print_num ("clusters: ", clusters) print_num ("header sectors: ", header_sectors) unsigned read_num (char *data, unsigned bytes): unsigned ret = 0 for unsigned i = 0; i < bytes; ++i: ret |= (data[i] & 0xff) << (i * 8) return ret void map_fat_cluster (unsigned c, unsigned offset = 0): read_block ((hidden_sectors + reserved_sectors + ((c * bits + 8 * offset) >> (sector_size_bits + 3))) << sector_size_bits) unsigned make_bits (unsigned orig): unsigned ret for ret = 0; ret < 32; ++ret: if orig == 1 << ret: return ret Iris::panic (ret, "non-power of 2") return ret void reset (): read_block (0) if data[0x1fe] != 0x55 || (data[0x1ff] & 0xff) != 0xaa: kdebug ("invalid boot record signature in fat device\n") for unsigned i = 0; i < 8; ++i: oem[i] = data[3 + i] sector_size_bits = make_bits (read_num (data + 0xb, 2)) sectors_per_cluster_bits = make_bits (read_num (data + 0xd, 1)) cluster_size_bits = sector_size_bits + sectors_per_cluster_bits reserved_sectors = read_num (data + 0xe, 2) num_fats = read_num (data + 0x10, 1) root_entries = read_num (data + 0x11, 2) sectors = read_num (data + 0x13, 2) media = read_num (data + 0x15, 1) sectors_per_fat = read_num (data + 0x16, 2) sectors_per_track = read_num (data + 0x18, 2) heads = read_num (data + 0x1a, 2) hidden_sectors = read_num (data + 0x1c, 4) if !sectors: sectors = read_num (data + 0x20, 4) if Iris::Num (sectors).value () << sector_size_bits > device_size.value (): sectors = device_size.value () >> sector_size_bits kdebug ("warning: limiting sectors because of limited device size\n") root_sectors = (root_entries * 32 + (1 << sector_size_bits) - 1) >> sector_size_bits header_sectors = hidden_sectors + reserved_sectors + sectors_per_fat * num_fats + root_sectors clusters = (sectors - header_sectors) >> sectors_per_cluster_bits unsigned skip if clusters >= 65525: bits = 32 sectors_per_fat = read_num (data + 0x24, 4) active_fat = read_num (data + 0x28, 2) write_all_fats = active_fat & 0x80 active_fat &= 0xf fs_version = read_num (data + 0x2a, 2) root_cluster = read_num (data + 0x2c, 4) fsinfo_sector = read_num (data + 0x30, 2) boot_backup_sector = read_num (data + 0x32, 2) skip = 0x40 - 0x24 else: if clusters < 4085: bits = 12 else: bits = 16 skip = 0 active_fat = 0 write_all_fats = true fs_version = 0 root_cluster = 0 fsinfo_sector = 0 boot_backup_sector = 0 unsigned fat_entries_per_sector = (8 << sector_size_bits) / bits unsigned fat_entries = sectors_per_fat * fat_entries_per_sector if clusters + 2 > fat_entries: clusters = fat_entries - 2 kdebug ("warning: limiting clusters because of limited sector count\n") drive = read_num (data + skip + 0x24, 1) current_head = read_num (data + skip + 0x25, 1) if data[skip + 0x26] == 0x29: volume_id = read_num (data + skip + 0x27, 4) for unsigned i = 0; i < 0xb; ++i: label[i] = data[skip + 0x2b + i] char *id = data + skip + 0x36 if id[0] != 'F' || id[1] != 'A' || id[2] != 'T' || id[5] != ' ' || id[6] != ' ' || id[7] != ' ': kdebug ("warning: file system type field was not 'FATxx '\n") else: switch bits: case 12: if id[3] != '1' || id[4] != '2': kdebug ("warning: id for fat12 is not FAT12\n") break case 16: if id[3] != '1' || id[4] != '6': kdebug ("warning: id for fat16 is not FAT16\n") break case 32: if id[3] != '3' || id[4] != '2': kdebug ("warning: id for fat32 wat not FAT32") break else: volume_id = 0 for unsigned i = 0; i < 0xb; ++i: label[i] = 0 if fsinfo_sector: read_block (fsinfo_sector << sector_size_bits) if (data[0] & 0xff) != 0x52 || (data[1] & 0xff) != 0x52 || (data[2] & 0xff) != 0x6a || (data[3] & 0xff) != 0x41 || (data[0x1e4] & 0xff) != 0x72 || (data[0x1e5] & 0xff) != 0x72 || (data[0x1e6] & 0xff) != 0x4a || (data[0x1e7] & 0xff) != 0x61 || (data[0x1fe] & 0xff) != 0x55 || (data[0x1ff] & 0xff) != 0xaa: kdebug ("invalid signature in fsinfo structure\n") free_clusters = read_num (data + 0x1e8, 4) last_alloced = read_num (data + 0x1ec, 4) else: free_clusters = ~0 last_alloced = ~0 // Now read the FAT. bad_clusters = 0 fat = new unsigned[clusters] unsigned counted_free_clusters = 0 for unsigned c = 0; c < clusters; ++c: // reduced cluster. unsigned rc = c & (1 << sector_size_bits) - 1 // The next line does nothing most of the time. map_fat_cluster (c) switch bits: case 12: fat[c] = data[(rc + 2) * 2] & 0xff // There may be a sector boundary in the middle of the entry, so optionally reread. map_fat_cluster (c, 1) fat[c] |= (data[(rc + 2) * 2 + 1] & 0xff) << 8 if c & 1: fat[c] >>= 4 else: fat[c] &= 0xfff break case 16: fat[c] = read_num (data + (rc + 2) * 2, 2) break case 32: fat[c] = read_num (data + (rc + 2) * 4, 4) break // Correct for the crazy +2 offset, and keep a list of bad and free clusters. if fat[c] == 0: // Free cluster. fat[c] = first_free_cluster first_free_cluster = c ++counted_free_clusters else if fat[c] == 1: // Invalid value. Iris::panic (0, "entry is '1' in fat.") else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff: // Last cluster in chain. fat[c] = ~0 else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7: // Bad cluster. fat[c] = first_bad_cluster first_bad_cluster = c ++bad_clusters else: // Non-last cluster in chain. fat[c] -= 2 unsigned fat_lookup (unsigned first_cluster, unsigned cluster): while cluster--: first_cluster = fat[first_cluster] if first_cluster == ~0: kdebug ("sector beyond end of file requested\n") return ~0 return first_cluster struct File: Fat *fat unsigned size unsigned first_cluster char name[11] bool archive, readonly, system, hidden, directory, volume unsigned create_second, create_minute_hour, create_date, access_date, time, date void load_cluster (unsigned idx, Iris::Page p = page, unsigned offset = 0): unsigned cluster = fat->fat_lookup (first_cluster, idx >> fat->cluster_size_bits) kdebug ("loading cluster ") kdebug_num (idx) kdebug ("@") kdebug_num (cluster) kdebug (" from file\n") if cluster == ~0: kdebug ("invalid cluster requested from file\n") return read_block ((fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) << fat->sector_size_bits, p, 1 << fat->cluster_size_bits, offset) kdebug ("sector ") kdebug_num (fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) kdebug ("\n") void get_dir_entry (unsigned dir, unsigned idx, File *f): f->fat = this unsigned sector = idx >> (sector_size_bits - 5) unsigned num = (idx << 5) & ~BLOCK_MASK Iris::Num hwsector if dir == ROOT_CLUSTER: if sector < root_sectors: hwsector = header_sectors - root_sectors + sector else: hwsector = ~0 else: unsigned entry = fat_lookup (dir, sector) if entry == ~0: hwsector = ~0 else: hwsector = header_sectors + (Iris::Num (entry).value () << sectors_per_cluster_bits) if hwsector.value () == ~0: kdebug ("invalid sector requested from directory\n") f->first_cluster = ~0 return read_block (hwsector.value () << sector_size_bits) char *e = &data[num] for unsigned i = 0; i < 11; ++i: f->name[i] = e[i] f->archive = e[0xb] & 0x20 f->readonly = e[0xb] & 0x10 f->system = e[0xb] & 0x8 f->hidden = e[0xb] & 0x4 f->directory = e[0xb] & 0x2 f->volume = e[0xb] & 0x1 f->create_second = read_num (e + 0xd, 1) f->create_minute_hour = read_num (e + 0xe, 2) f->create_date = read_num (e + 0x10, 2) f->access_date = read_num (e + 0x12, 2) f->time = read_num (e + 0x16, 1) f->date = read_num (e + 0x18, 1) f->size = read_num (e + 0x1c, 4) f->first_cluster = (read_num (e + 0x14, 2) << 16 | read_num (e + 0x1a, 2)) - 2 // Capability encoding. // 0:ROOT_CLUSTER = non fat-32 root directory. // 0:cluster = other directory. // cluster:index = file index from directory at cluster. // cluster|0x80000000:index = filename for file with index from directory at cluster. Iris::Num start (): init_alloc () current_block = ~0 dev = Iris::my_parent.get_capability () if dev.get_align_bits () > SECTOR_BITS: kdebug ("fat device doesn't support 512 byte access") return 1 device_size = dev.get_size () data = (char *)0x15000; //alloc_space (1) page = Iris::my_memory.create_page () page.set_flags (Iris::Page::PAYING, Iris::Page::PAYING) Iris::my_memory.map (page, (unsigned)data) Fat fat fat.reset () fat.print_br () Iris::Cap root if fat.root_cluster: root = Iris::my_receiver.create_capability (Iris::Num (fat.root_cluster, 0)) else: root = Iris::my_receiver.create_capability (Iris::Num (ROOT_CLUSTER, 0)) Iris::my_parent.provide_capability (root.copy ()) Iris::free_cap (root) while true: Iris::wait () unsigned dir = Iris::recv.protected_data.h if dir & 0x80000000: // File name. unsigned idx = Iris::recv.protected_data.l Iris::Cap reply = Iris::get_reply () unsigned num = Iris::recv.data[1].l unsigned size = Iris::recv.data[0].h >> 16 unsigned cmd = Iris::recv.data[0].l Fat::File f fat.get_dir_entry (dir & ~0x80000000, idx, &f) switch cmd: case Iris::String::GET_SIZE: kdebug ("filename size requested\n") reply.invoke (11) break case Iris::String::GET_CHARS: //kdebug ("filename chars requested\n") /**/union { unsigned u[4]; char c[16]; } u for unsigned k = 0; k < 4; ++k: u.u[k] = 0 for unsigned k = 0; k + num < 11; ++k: u.c[k] = f.name[k + num] reply.invoke (Iris::Num (u.u[0], u.u[1]), Iris::Num (u.u[2], u.u[3])) break case Iris::String::GET_ALIGN_BITS: kdebug ("filename align requested\n") reply.invoke (0) break case Iris::String::GET_BLOCK: default: Iris::panic (Iris::recv.data[0].l, "invalid request for fat filename") Iris::free_cap (reply) else if dir: // File. unsigned idx = Iris::recv.protected_data.l Iris::Cap reply = Iris::get_reply () Iris::Cap arg = Iris::get_arg () Iris::Num num = Iris::recv.data[1] unsigned size = Iris::recv.data[0].h >> 16 unsigned offset = Iris::recv.data[0].h & 0xffff unsigned cmd = Iris::recv.data[0].l Fat::File f fat.get_dir_entry (dir, idx, &f) switch cmd: case Iris::String::GET_SIZE: kdebug ("file size requested\n") reply.invoke (f.size) break case Iris::String::GET_CHARS: kdebug ("file chars requested\n") unsigned mask = 1 << (fat.cluster_size_bits) - 1 f.load_cluster (num.l & ~mask) unsigned n = num.l & mask & ~0xf unsigned *dat = (unsigned *)(data + n) reply.invoke (Iris::Num (dat[0], dat[1]), Iris::Num (dat[2], dat[3])) break case Iris::String::GET_ALIGN_BITS: kdebug ("file align requested\n") reply.invoke (fat.cluster_size_bits) break case Iris::String::GET_BLOCK: kdebug ("file block requested\n") unsigned mask = 1 << (fat.cluster_size_bits) - 1 if offset > PAGE_SIZE: kdebug ("invalid offset requested\n") break if size + offset > PAGE_SIZE: size = PAGE_SIZE - offset for unsigned i = 0; i < size; i += 1 << fat.cluster_size_bits: f.load_cluster ((num.l & ~mask) + i, arg, i + offset) reply.invoke () break case Iris::WString::TRUNCATE: case Iris::WString::SET_CHARS: case Iris::WString::SET_BLOCK: Iris::panic (Iris::recv.data[0].l, "writing to files not supported yet") default: Iris::panic (Iris::recv.data[0].l, "invalid request for fat file") Iris::free_cap (reply) Iris::free_cap (arg) else: // Directory. if Iris::recv.protected_data.l != ROOT_CLUSTER: // Normal directory. switch Iris::recv.data[0].l: case Iris::Directory::GET_SIZE: kdebug ("dir size requested\n") Iris::recv.reply.invoke () break case Iris::Directory::GET_NAME: kdebug ("dir name requested\n") Iris::recv.reply.invoke () break case Iris::Directory::GET_FILE_RO: kdebug ("dir file requested\n") Iris::Cap reply = Iris::get_reply () Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l)) reply.invoke (0, 0, ret.copy ()) Iris::free_cap (reply) Iris::free_cap (ret) break case Iris::Directory::GET_FILE_INFO: kdebug ("dir file info requested\n") Iris::recv.reply.invoke () break case Iris::Directory::LOCK_RO: case Iris::Directory::UNLOCK_RO: kdebug ("dir lock or unlock requested\n") Iris::recv.reply.invoke () break default: kdebug ("invalid dir operation requested\n") Iris::recv.reply.invoke () break else: // Non-fat32 root directory. switch Iris::recv.data[0].l: case Iris::Directory::GET_SIZE: kdebug ("root size requested\n") Iris::recv.reply.invoke (fat.root_entries) break case Iris::Directory::GET_NAME: //kdebug ("root name requested\n") Iris::Cap reply = Iris::get_reply () Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l | 0x80000000)) reply.invoke (0, 0, ret.copy ()) Iris::free_cap (reply) Iris::free_cap (ret) break case Iris::Directory::GET_FILE_RO: kdebug ("root file requested\n") Iris::Cap reply = Iris::get_reply () Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l)) reply.invoke (0, 0, ret.copy ()) Iris::free_cap (reply) Iris::free_cap (ret) break case Iris::Directory::GET_FILE_INFO: kdebug ("root file info requested\n") Iris::recv.reply.invoke () break case Iris::Directory::LOCK_RO: case Iris::Directory::UNLOCK_RO: kdebug ("root lock or unlock requested\n") Iris::recv.reply.invoke () break default: kdebug ("invalid root operation requested\n") Iris::recv.reply.invoke () break