/* DKM FAT32 Driver — read-only FAT32 filesystem parser * Stage 2, optional, depends on "vfs" and "block". * Reads from an embedded FAT32 test image (boot module "dkm:test_fat32"). * Parses BPB, walks FAT, reads root dir, lists files, reads a file. */ #include #include "../dkm_shared.h" #include "../dkm_instr.h" DKM_STAT_DECL(fat0_reads); DKM_STAT_DECL(fat0_fat_walks); /* --------------------------------------------------------------- * FAT32-specific types (DKM ABI types come from dkm_shared.h) * --------------------------------------------------------------- */ struct limine_file { u64 revision; void *address; u64 size; char *path; char *cmdline; u8 _pad[56]; }; struct limine_module_response { u64 revision; u64 module_count; struct limine_file **modules; }; /* --------------------------------------------------------------- * FAT32 BPB * --------------------------------------------------------------- */ typedef struct __attribute__((packed)) { u8 jmp[3]; char oem[8]; u16 bytes_per_sector; u8 sectors_per_cluster; u16 reserved_sector_count; u8 fat_count; u16 root_entry_count; u16 total_sectors_16; u8 media; u16 sectors_per_fat_16; u16 sectors_per_track; u16 heads; u32 hidden_sectors; u32 total_sectors_32; /* FAT32 extended */ u32 sectors_per_fat; u16 flags; u16 version; u32 root_cluster; u16 fsinfo_sector; u16 backup_boot; u8 reserved[12]; u8 drive; u8 nt_flags; u8 signature; u32 serial; char label[11]; char type[8]; u8 code[420]; u16 boot_sig; } fat32_bpb; typedef struct __attribute__((packed)) { char name[11]; u8 attr; u8 nt_reserved; u8 creation_tenth; u16 creation_time; u16 creation_date; u16 access_date; u16 cluster_high; u16 write_time; u16 write_date; u16 cluster_low; u32 file_size; } fat32_dir_entry; /* --------------------------------------------------------------- * Driver descriptor * --------------------------------------------------------------- */ static const char *const g_depends[] = { "vfs", "block" }; static const char *const g_provides[] = { "fat32" }; __attribute__((visibility("default"), used)) const struct dkm_driver_desc driver_desc = { .magic=DKM_DRIVER_MAGIC, .abi_version=DKM_ABI_VERSION, .desc_size=sizeof(struct dkm_driver_desc), .name="fat32", .version="0.1.0", .vendor="Deshab", .driver_class=7, .stage=2, .flags=0, .priority=0, .depends=g_depends, .depends_count=2, .provides=g_provides, .provides_count=1, .min_kernel_abi=1, }; /* --------------------------------------------------------------- * Helpers * --------------------------------------------------------------- */ static const struct dkm_log_api *g_log; static u8 g_block_image[65536]; static int fat32_bpb_valid(const u8 *disk, u64 disk_size) { if (!disk || disk_size < 512) return 0; const fat32_bpb *bpb = (const fat32_bpb *)disk; if (bpb->boot_sig != 0xAA55) return 0; if (bpb->bytes_per_sector != 512) return 0; if (bpb->sectors_per_cluster == 0) return 0; if (bpb->reserved_sector_count == 0) return 0; if (bpb->fat_count == 0) return 0; if (bpb->sectors_per_fat == 0) return 0; if (bpb->root_cluster < 2) return 0; return 1; } static void log_hex(const char *p, u64 v) { static const char h[] = "0123456789abcdef"; char b[19]; u32 i=0; b[i++]='0'; b[i++]='x'; for (int j=15;j>=0;j--) b[i++]=h[(v>>(j*4))&0xf]; b[i]=0; g_log->info(p); g_log->info(b); } static u32 read_u32_le(const u8 *p) { return (u32)p[0]|((u32)p[1]<<8)|((u32)p[2]<<16)|((u32)p[3]<<24); } static u16 read_u16_le(const u8 *p) { return (u16)p[0]|((u16)p[1]<<8); } static int strneq(const char *a, const char *b, int n) { for (int i=0;iinfo(buf); } static const u8 *fat32_find_boot_module_image(const struct dkm_kernel_api *api, u64 *size_out) { const struct limine_module_response *rsp = (const struct limine_module_response *)api->boot_modules_response; if (!rsp) return NULL; for (u64 i=0;imodule_count;i++) { struct limine_file *f=rsp->modules[i]; if (f&&f->cmdline&&strneq(f->cmdline,"dkm:test_fat32",13)) { if (size_out) *size_out=f->size; return (const u8*)f->address; } } return NULL; } static const u8 *fat32_select_disk_image(const struct dkm_kernel_api *api, u64 *size_out) { if (api->block && api->block->device_count && api->block->read && api->block->sector_size) { u32 count = api->block->device_count(); log_hex("[fat32] block devices=", count); if (count > 0 && api->block->sector_size(0) == 512) { const char *name = api->block->device_name ? api->block->device_name(0) : NULL; g_log->info("[fat32] trying block provider"); if (name) g_log->info(name); int st = api->block->read(0, 0, 128, g_block_image); log_hex("[fat32] block read status=", (u64)(i64)st); if (st == 0 && fat32_bpb_valid(g_block_image, sizeof(g_block_image))) { g_log->info("[fat32] using block provider image"); if (size_out) *size_out = sizeof(g_block_image); return g_block_image; } g_log->warn("[fat32] block provider image is not FAT32; fallback"); } } u64 module_size = 0; const u8 *module = fat32_find_boot_module_image(api, &module_size); if (module) { g_log->info("[fat32] using boot module image"); if (size_out) *size_out = module_size; return module; } return NULL; } /* --------------------------------------------------------------- * Driver entry * --------------------------------------------------------------- */ __attribute__((visibility("default"))) int driver_init(const struct dkm_kernel_api *api, struct dkm_driver_handle *handle) { (void)handle; if (!api||!api->log) return -1; g_log=api->log; dkm_instr_init(api); u64 disk_size = 0; const u8 *disk = fat32_select_disk_image(api, &disk_size); if (!disk) { g_log->warn("[fat32] no FAT32 image source"); return 0; } if (!fat32_bpb_valid(disk, disk_size)) { g_log->warn("[fat32] invalid FAT32 BPB"); return 0; } g_log->info("[fat32] parsing FAT32 image"); const fat32_bpb *bpb=(const fat32_bpb*)disk; u32 bps=bpb->bytes_per_sector; u32 spc=bpb->sectors_per_cluster; u32 rsc=bpb->reserved_sector_count; u32 spf=bpb->sectors_per_fat; u32 root_clus=bpb->root_cluster; log_hex("[fat32] bytes/sec=",bps); log_hex("[fat32] sec/cluster=",spc); log_hex("[fat32] fat start sec=",rsc); log_hex("[fat32] sec/fat=",spf); log_hex("[fat32] root cluster=",root_clus); /* read root directory */ u32 cluster_size = bps * spc; u32 fat_start = rsc * bps; u32 data_start = fat_start + spf * bps; g_log->info("[fat32] root dir entries:"); u32 clus = root_clus; while (clus >= 2 && clus < 0x0FFFFFF8) { u32 clus_off = data_start + (clus - 2) * cluster_size; const fat32_dir_entry *dir = (const fat32_dir_entry *)(disk + clus_off); for (u32 e=0; e*32 < cluster_size; e++) { if (dir[e].name[0]==0) break; if ((u8)dir[e].name[0]==0xE5) continue; if (dir[e].attr==0x0F) continue; /* skip LFN */ if (dir[e].attr & 0x08) continue; /* skip volume label */ g_log->info("[fat32] "); log_name11(dir[e].name); log_hex("[fat32] size=",dir[e].file_size); /* try to read README.TXT content */ if (strneq(dir[e].name,"README TXT",11)) { DKM_STAT_INC(fat0_reads); u32 f_clus = read_u16_le((const u8*)&dir[e].cluster_low); u32 f_off = data_start + (f_clus - 2)*cluster_size; u32 f_size = dir[e].file_size; g_log->info("[fat32] --- README.TXT content ---"); u32 n = f_size < 128 ? f_size : 128; char line[80]; u32 lp=0; for (u32 k=0;k=78||k==n-1) { line[lp]=0; g_log->info("[fat32] "); g_log->info(line); lp=0; } } g_log->info("[fat32] --- end ---"); } } /* read next cluster from FAT */ u32 fat_ent_off = fat_start + clus * 4; clus = read_u32_le(disk + fat_ent_off) & 0x0FFFFFFF; DKM_STAT_INC(fat0_fat_walks); } g_log->info("[fat32] driver ready"); return 0; } __attribute__((visibility("default"))) int driver_exit(struct dkm_driver_handle *handle) { (void)handle; return 0; }