From 9b382dab605838e39b2a4447e214d0b37ef8faf4 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Wed, 20 Apr 2022 19:55:36 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20=E5=9C=A8fat32=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E4=B8=AD=E6=8C=89=E7=85=A7=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E5=AF=BB=E6=89=BE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/Makefile | 7 +- kernel/common/printk.h | 2 +- kernel/filesystem/MBR.c | 20 ++ kernel/filesystem/MBR.h | 35 ++- kernel/filesystem/fat32/fat32.c | 446 ++++++++++++++++++++++++++++++-- kernel/filesystem/fat32/fat32.h | 101 +++++++- kernel/main.c | 18 +- tools/create_hdd_image.sh | 7 +- tools/mount_virt_disk.sh | 4 + tools/umount_virt_disk.sh | 3 + 10 files changed, 590 insertions(+), 53 deletions(-) create mode 100644 kernel/filesystem/MBR.c create mode 100644 tools/mount_virt_disk.sh create mode 100644 tools/umount_virt_disk.sh diff --git a/kernel/Makefile b/kernel/Makefile index 798d340d..fe84d15c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -85,6 +85,9 @@ softirq.o: exception/softirq.c fat32.o: filesystem/fat32/fat32.c gcc $(CFLAGS) -c filesystem/fat32/fat32.c -o filesystem/fat32/fat32.o +MBR.o: filesystem/MBR.c + gcc $(CFLAGS) -c filesystem/MBR.c -o filesystem/MBR.o + # IPI的代码 ifeq ($(ARCH), x86_64) OBJ_LIST += ipi.o @@ -145,9 +148,9 @@ all: kernel objcopy -I elf64-x86-64 -O elf64-x86-64 -R ".comment" -R ".eh_frame" kernel ../bin/kernel/kernel.elf # -kernel: head.o entry.o main.o printk.o trap.o mm.o slab.o irq.o pic.o process.o sched.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o HPET.o softirq.o timer.o fat32.o $(OBJ_LIST) +kernel: head.o entry.o main.o printk.o trap.o mm.o slab.o irq.o pic.o process.o sched.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o HPET.o softirq.o timer.o fat32.o MBR.o $(OBJ_LIST) ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o mm/mm.o mm/slab.o process/process.o syscall/syscall.o driver/multiboot2/multiboot2.o \ - common/cpu.o smp/smp.o smp/apu_boot.o exception/softirq.o sched/sched.o filesystem/fat32/fat32.o \ + common/cpu.o smp/smp.o smp/apu_boot.o exception/softirq.o sched/sched.o filesystem/fat32/fat32.o filesystem/MBR.o \ driver/acpi/acpi.o driver/interrupt/pic.o driver/keyboard/ps2_keyboard.o driver/mouse/ps2_mouse.o driver/disk/ata.o driver/pci/pci.o driver/disk/ahci/ahci.o driver/timers/rtc/rtc.o driver/timers/HPET/HPET.o driver/timers/timer.o \ $(LD_LIST) \ -T link.lds diff --git a/kernel/common/printk.h b/kernel/common/printk.h index 048e303a..2baaac85 100644 --- a/kernel/common/printk.h +++ b/kernel/common/printk.h @@ -21,7 +21,7 @@ #define ORANGE 0x00ff8000 //橙 #define YELLOW 0x00ffff00 //黄 #define GREEN 0x0000ff00 //绿 -#define ORANGEBLUE 0x000000ff //蓝 +#define BLUE 0x000000ff //蓝 #define INDIGO 0x0000ffff //靛 #define PURPLE 0x008000ff //紫 diff --git a/kernel/filesystem/MBR.c b/kernel/filesystem/MBR.c new file mode 100644 index 00000000..bfaad4ee --- /dev/null +++ b/kernel/filesystem/MBR.c @@ -0,0 +1,20 @@ +#include "MBR.h" +#include +#include + +struct MBR_disk_partition_table_t MBR_partition_tables[MBR_MAX_AHCI_CTRL_NUM][MBR_MAX_AHCI_PORT_NUM] = {0}; + +/** + * @brief 读取磁盘的分区表 + * + * @param ahci_ctrl_num ahci控制器编号 + * @param ahci_port_num ahci端口编号 + */ +struct MBR_disk_partition_table_t *MBR_read_partition_table(uint8_t ahci_ctrl_num, uint8_t ahci_port_num) +{ + unsigned char buf[512]; + memset(buf, 0, 512); + ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, 0, 1, (uint64_t)&buf, ahci_ctrl_num, ahci_port_num); + MBR_partition_tables[ahci_ctrl_num][ahci_port_num] = *(struct MBR_disk_partition_table_t *)buf; + return &MBR_partition_tables[ahci_ctrl_num][ahci_port_num]; +} \ No newline at end of file diff --git a/kernel/filesystem/MBR.h b/kernel/filesystem/MBR.h index 15202cb2..b1c29f51 100644 --- a/kernel/filesystem/MBR.h +++ b/kernel/filesystem/MBR.h @@ -11,34 +11,47 @@ #pragma once #include +#define MBR_MAX_AHCI_CTRL_NUM 4 // 系统支持的最大的ahci控制器数量 +#define MBR_MAX_AHCI_PORT_NUM 32 // 系统支持的每个ahci控制器对应的MBR磁盘数量(对应ahci磁盘号) + /** * @brief MBR硬盘分区表项的结构 * */ struct MBR_disk_partition_table_entry_t { - uint8_t flags; // 引导标志符,标记此分区为活动分区 - uint8_t starting_head; // 起始磁头号 + uint8_t flags; // 引导标志符,标记此分区为活动分区 + uint8_t starting_head; // 起始磁头号 uint16_t starting_sector : 6, // 起始扇区号 starting_cylinder : 10; // 起始柱面号 - uint8_t type; // 分区类型ID - uint8_t ending_head; // 结束磁头号 + uint8_t type; // 分区类型ID + uint8_t ending_head; // 结束磁头号 + + uint16_t ending_sector : 6, // 结束扇区号 + ending_cylinder : 10; // 结束柱面号 - uint16_t ending_sector:6, // 结束扇区号 - ending_cylinder:10; // 结束柱面号 - uint32_t starting_LBA; // 起始逻辑扇区 uint32_t total_sectors; // 分区占用的磁盘扇区数 -}__attribute__((packed)); +} __attribute__((packed)); /** * @brief MBR磁盘分区表结构体 - * + * */ struct MBR_disk_partition_table_t { uint8_t reserved[446]; - struct MBR_disk_partition_table_entry_t DPTE[4]; // 磁盘分区表项 + struct MBR_disk_partition_table_entry_t DPTE[4]; // 磁盘分区表项 uint16_t BS_TrailSig; -}__attribute__((packed)); +} __attribute__((packed)); + +extern struct MBR_disk_partition_table_t MBR_partition_tables[MBR_MAX_AHCI_CTRL_NUM][MBR_MAX_AHCI_PORT_NUM]; // 导出全局的MBR磁盘分区表 + +/** + * @brief 读取磁盘的分区表 + * + * @param ahci_ctrl_num ahci控制器编号 + * @param ahci_port_num ahci端口编号 + */ +struct MBR_disk_partition_table_t *MBR_read_partition_table(uint8_t ahci_ctrl_num, uint8_t ahci_port_num); \ No newline at end of file diff --git a/kernel/filesystem/fat32/fat32.c b/kernel/filesystem/fat32/fat32.c index 1b70fb7f..197f3763 100644 --- a/kernel/filesystem/fat32/fat32.c +++ b/kernel/filesystem/fat32/fat32.c @@ -1,42 +1,444 @@ #include "fat32.h" #include #include +#include +#include +#include + +struct fat32_partition_info_t fat32_part_info[FAT32_MAX_PARTITION_NUM] = {0}; +static int total_fat32_parts = 0; +static int max_fat32_parts_id = -1; +static uint64_t fat32_part_info_bmp[FAT32_MAX_PARTITION_NUM / 64 + 1] = {0}; + +static spinlock_t fat32_part_reg_lock; /** - * @brief 读取指定磁盘上的第0个分区的fat32文件系统 - * - * @param disk_num + * @brief 注册指定磁盘上的指定分区的fat32文件系统 + * + * @param ahci_ctrl_num ahci控制器编号 + * @param ahci_port_num ahci控制器端口编号 + * @param part_num 磁盘分区编号 + * + * @return int 全局fat32分区id */ -void fat32_FS_init(int disk_num) +int fat32_register_partition(uint8_t ahci_ctrl_num, uint8_t ahci_port_num, uint8_t part_num) { - int i; - unsigned char buf[512]; - struct MBR_disk_partition_table_t DPT; - struct fat32_BootSector_t fat32_bootsector; - struct fat32_FSInfo_t fat32_fsinfo; + for (int i = 0; i <= max_fat32_parts_id; ++i) + { + if (fat32_part_info_bmp[i / 64] & (1 << (i % 64))) + { + // 已经注册 + if (ahci_ctrl_num == fat32_part_info[i].ahci_ctrl_num && ahci_port_num == fat32_part_info[i].ahci_port_num && part_num == fat32_part_info[i].part_num) + return i; + } + } + + // 注册分区 + spin_lock(&fat32_part_reg_lock); + int current_part_id; + for (int i = 0; i <= max_fat32_parts_id; ++i) + { + if ((fat32_part_info_bmp[i / 64] & (1 << (i % 64))) == 0) + { + current_part_id = i; + break; + } + } + ++max_fat32_parts_id; + current_part_id = max_fat32_parts_id; + fat32_part_info_bmp[current_part_id / 64] |= (1 << (current_part_id % 64)); + spin_unlock(&fat32_part_reg_lock); + + fat32_part_info[current_part_id].ahci_ctrl_num = ahci_ctrl_num; + fat32_part_info[current_part_id].ahci_port_num = ahci_port_num; + fat32_part_info[current_part_id].part_num = part_num; + fat32_part_info[current_part_id].partition_id = current_part_id; + + struct MBR_disk_partition_table_t *DPT = MBR_read_partition_table(ahci_ctrl_num, ahci_port_num); - memset(buf, 0, 512); - ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, 0, 1, (uint64_t)&buf, 0, 0); - DPT = *(struct MBR_disk_partition_table_t *)buf; // for(i = 0 ;i < 512 ; i++) // color_printk(PURPLE,WHITE,"%02x",buf[i]); - printk_color(ORANGE, BLACK, "DPTE[0] start_LBA:%#018lx\ttype:%#018lx\n", DPT.DPTE[0].starting_LBA, DPT.DPTE[0].type); + printk_color(ORANGE, BLACK, "DPTE[0] start_LBA:%#018lx\ttype:%#018lx\n", DPT->DPTE[part_num].starting_LBA, DPT->DPTE[part_num].type); memset(buf, 0, 512); - ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, DPT.DPTE[0].starting_LBA, 1, (uint64_t)&buf, 0, 0); + ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, DPT->DPTE[part_num].starting_LBA, 1, (uint64_t)&buf, ahci_ctrl_num, ahci_port_num); - fat32_bootsector = *(struct fat32_BootSector_t *)buf; - // for(i = 0 ;i < 512 ; i++) - // printk_color(PURPLE,WHITE,"%02x",buf[i]); - printk_color(ORANGE, BLACK, "FAT32 Boot Sector\n\tBPB_FSInfo:%#018lx\n\tBPB_BkBootSec:%#018lx\n\tBPB_TotSec32:%#018lx\n", fat32_bootsector.BPB_FSInfo, fat32_bootsector.BPB_BkBootSec, fat32_bootsector.BPB_TotSec32); + fat32_part_info[current_part_id].bootsector = *(struct fat32_BootSector_t *)buf; + + // 计算数据区起始扇区号 + fat32_part_info[current_part_id].first_data_sector = DPT->DPTE[part_num].starting_LBA + fat32_part_info[current_part_id].bootsector.BPB_RsvdSecCnt + + fat32_part_info[current_part_id].bootsector.BPB_FATSz32 * fat32_part_info[current_part_id].bootsector.BPB_NumFATs; + // 计算FAT1的起始扇区号 + fat32_part_info[current_part_id].FAT1_base_sector = DPT->DPTE[part_num].starting_LBA + fat32_part_info[current_part_id].bootsector.BPB_RsvdSecCnt; + // 计算FAT2的起始扇区号 + fat32_part_info[current_part_id].FAT2_base_sector = fat32_part_info[current_part_id].FAT1_base_sector + fat32_part_info[current_part_id].bootsector.BPB_FATSz32; + // 计算每个簇的大小 + fat32_part_info[current_part_id].bytes_per_clus = fat32_part_info[current_part_id].bootsector.BPB_BytesPerSec * fat32_part_info[current_part_id].bootsector.BPB_SecPerClus; + + kdebug("fat32_part_info[current_part_id].FAT1_base_sector=%#018lx", fat32_part_info[current_part_id].FAT1_base_sector); + printk_color(ORANGE, BLACK, "FAT32 Boot Sector\n\tBPB_FSInfo:%#018lx\n\tBPB_BkBootSec:%#018lx\n\tBPB_TotSec32:%#018lx\n", fat32_part_info[current_part_id].bootsector.BPB_FSInfo, fat32_part_info[current_part_id].bootsector.BPB_BkBootSec, fat32_part_info[current_part_id].bootsector.BPB_TotSec32); memset(buf, 0, 512); - ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, DPT.DPTE[0].starting_LBA+ fat32_bootsector.BPB_FSInfo, 1, (uint64_t)&buf, 0, 0); + ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, DPT->DPTE[part_num].starting_LBA + fat32_part_info[current_part_id].bootsector.BPB_FSInfo, 1, (uint64_t)&buf, ahci_ctrl_num, ahci_port_num); - - fat32_fsinfo = *(struct fat32_FSInfo_t *)buf; + fat32_part_info[current_part_id].fsinfo = *(struct fat32_FSInfo_t *)buf; // for(i = 0 ;i < 512 ; i++) // printk_color(PURPLE,WHITE,"%02x",buf[i]); - printk_color(ORANGE, BLACK, "FAT32 FSInfo\n\tFSI_LeadSig:%#018lx\n\tFSI_StrucSig:%#018lx\n\tFSI_Free_Count:%#018lx\n", fat32_fsinfo.FSI_LeadSig, fat32_fsinfo.FSI_StrucSig, fat32_fsinfo.FSI_Free_Count); + printk_color(ORANGE, BLACK, "FAT32 FSInfo\n\tFSI_LeadSig:%#018lx\n\tFSI_StrucSig:%#018lx\n\tFSI_Free_Count:%#018lx\n", fat32_part_info[current_part_id].fsinfo.FSI_LeadSig, fat32_part_info[current_part_id].fsinfo.FSI_StrucSig, fat32_part_info[current_part_id].fsinfo.FSI_Free_Count); + kdebug("fat32_part_info[part_id].bootsector.BPB_RootClus = %#018lx", fat32_part_info[current_part_id].bootsector.BPB_RootClus); + return current_part_id; +} + +/** + * @brief 读取指定簇的FAT表项 + * + * @param part_id 分区id + * @param cluster + * @return uint32_t 下一个簇的簇号 + */ +uint32_t fat32_read_FAT_entry(uint32_t part_id, uint32_t cluster) +{ + + uint32_t fat_ent_per_sec = (fat32_part_info[part_id].bootsector.BPB_BytesPerSec >> 2); // 该值应为2的n次幂 + uint32_t buf[256]; + memset(buf, 0, fat32_part_info[part_id].bootsector.BPB_BytesPerSec); + + ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, fat32_part_info[part_id].FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)&buf, fat32_part_info[part_id].ahci_ctrl_num, fat32_part_info[part_id].ahci_port_num); + + uint32_t ret = buf[cluster & (fat_ent_per_sec - 1)] & 0x0fffffff; + + return ret; +} + +/** + * @brief 写入指定簇的FAT表项 + * + * @param part_id 分区id + * @param cluster + * @param value 要写入该fat表项的值 + * @return uint32_t 下一个簇的簇号 + */ +uint32_t fat32_write_FAT_entry(uint32_t part_id, uint32_t cluster, uint32_t value) +{ + uint32_t fat_ent_per_sec = (fat32_part_info[part_id].bootsector.BPB_BytesPerSec >> 2); // 该值应为2的n次幂 + uint32_t buf[256]; + memset(buf, 0, fat32_part_info[part_id].bootsector.BPB_BytesPerSec); + + ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, fat32_part_info[part_id].FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)&buf, fat32_part_info[part_id].ahci_ctrl_num, fat32_part_info[part_id].ahci_port_num); + + buf[cluster & (fat_ent_per_sec - 1)] = (buf[cluster & (fat_ent_per_sec - 1)] & 0xf0000000) | (value & 0x0fffffff); + // 向FAT1和FAT2写入数据 + ahci_operation.transfer(ATA_CMD_WRITE_DMA_EXT, fat32_part_info[part_id].FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)&buf, fat32_part_info[part_id].ahci_ctrl_num, fat32_part_info[part_id].ahci_port_num); + ahci_operation.transfer(ATA_CMD_WRITE_DMA_EXT, fat32_part_info[part_id].FAT2_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)&buf, fat32_part_info[part_id].ahci_ctrl_num, fat32_part_info[part_id].ahci_port_num); + + return 0; +} + +/** + * @brief 在父目录中寻找指定的目录项 + * + * @param part_id 分区id + * @param name 目录项名字 + * @param name_len 目录项名字长度 + * @param dentry 父目录 + * @param flags + * @return struct fat32_Directory_t* 目标目录项 + */ +struct fat32_Directory_t *fat32_lookup(uint32_t part_id, char *name, int name_len, struct fat32_Directory_t *dentry, int flags) +{ + int errcode = 0; + uint8_t *buf = kmalloc(fat32_part_info[part_id].bytes_per_clus, 0); + memset(buf, 0, fat32_part_info[part_id].bytes_per_clus); + + // 计算父目录项的起始簇号 + uint32_t cluster = ((dentry->DIR_FstClusHI << 16) | (dentry->DIR_FstClusLO)) & 0x0fffffff; + /* + kdebug("dentry->DIR_FstClusHI=%#010lx", dentry->DIR_FstClusHI); + kdebug("dentry->DIR_FstClusLo=%#010lx", dentry->DIR_FstClusLO); + kdebug("cluster=%#010lx", cluster); + */ + while (true) + { + + // 计算父目录项的起始LBA扇区号 + uint64_t sector = fat32_part_info[part_id].first_data_sector + (cluster - 2) * fat32_part_info[part_id].bootsector.BPB_SecPerClus; + //kdebug("fat32_part_info[part_id].bootsector.BPB_SecPerClus=%d",fat32_part_info[part_id].bootsector.BPB_SecPerClus); + //kdebug("sector=%d",sector); + + // 读取父目录项的起始簇数据 + ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, sector, fat32_part_info[part_id].bootsector.BPB_SecPerClus, (uint64_t)buf, 0, 0); + //ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, sector, fat32_part_info[part_id].bootsector.BPB_SecPerClus, (uint64_t)buf, fat32_part_info[part_id].ahci_ctrl_num, fat32_part_info[part_id].ahci_port_num); + + struct fat32_Directory_t *tmp_dEntry = (struct fat32_Directory_t *)buf; + + // 查找短目录项 + for (int i = 0; i < fat32_part_info[part_id].bytes_per_clus; i += 32, ++tmp_dEntry) + { + // 跳过长目录项 + if (tmp_dEntry->DIR_Attr == ATTR_LONG_NAME) + continue; + + // 跳过无效页表项、空闲页表项 + if (tmp_dEntry->DIR_Name[0] == 0xe5 || tmp_dEntry->DIR_Name[0] == 0x00 || tmp_dEntry->DIR_Name[0] == 0x05) + continue; + + // 找到长目录项,位于短目录项之前 + struct fat32_LongDirectory_t *tmp_ldEntry = (struct fat32_LongDirectory_t *)tmp_dEntry - 1; + + int js = 0; + // 遍历每个长目录项 + while (tmp_ldEntry->LDIR_Attr == ATTR_LONG_NAME && tmp_ldEntry->LDIR_Ord != 0xe5) + { + // 比较name1 + for (int x = 0; x < 5; ++x) + { + if (js > name_len && tmp_ldEntry->LDIR_Name1[x] == 0xffff) + continue; + else if (js > name_len || tmp_ldEntry->LDIR_Name1[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 + goto continue_cmp_fail; + } + + // 比较name2 + for (int x = 0; x < 6; ++x) + { + if (js > name_len && tmp_ldEntry->LDIR_Name2[x] == 0xffff) + continue; + else if (js > name_len || tmp_ldEntry->LDIR_Name2[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 + goto continue_cmp_fail; + } + + // 比较name3 + for (int x = 0; x < 2; ++x) + { + if (js > name_len && tmp_ldEntry->LDIR_Name3[x] == 0xffff) + continue; + else if (js > name_len || tmp_ldEntry->LDIR_Name3[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 + goto continue_cmp_fail; + } + + if (js >= name_len) // 找到需要的目录项,返回 + { + struct fat32_Directory_t *p = (struct fat32_Directory_t *)kmalloc(sizeof(struct fat32_Directory_t), 0); + *p = *tmp_dEntry; + kfree(buf); + return p; + } + + --tmp_ldEntry; // 检索下一个长目录项 + } + + // 不存在长目录项,匹配短目录项的基础名 + js = 0; + for (int x = 0; x < 8; ++x) + { + switch (tmp_dEntry->DIR_Name[x]) + { + case ' ': + if (!(tmp_dEntry->DIR_Attr & ATTR_DIRECTORY)) // 不是文件夹(是文件) + { + if (name[js] == '.') + continue; + else if (tmp_dEntry->DIR_Name[x] == name[js]) + { + ++js; + break; + } + else + goto continue_cmp_fail; + } + else // 是文件夹 + { + if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) // 当前位正确匹配 + { + ++js; + break; // 进行下一位的匹配 + } + else if (js == name_len) + continue; + else + goto continue_cmp_fail; + } + break; + + // 当前位是字母 + case 'A' ... 'Z': + case 'a' ... 'z': + if (tmp_dEntry->DIR_NTRes & LOWERCASE_BASE) // 为兼容windows系统,检测DIR_NTRes字段 + { + if (js < name_len && (tmp_dEntry->DIR_Name[x] + 32 == name[js])) + { + ++js; + break; + } + else + goto continue_cmp_fail; + } + else + { + if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) + { + ++js; + break; + } + else + goto continue_cmp_fail; + } + break; + case '0' ... '9': + if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) + { + ++js; + break; + } + else + goto continue_cmp_fail; + + break; + default: + ++js; + break; + } + } + + // 若短目录项为文件,则匹配扩展名 + if (!(tmp_dEntry->DIR_Attr & ATTR_DIRECTORY)) + { + ++js; + for (int x = 8; x < 11; ++x) + { + switch (tmp_dEntry->DIR_Name[x]) + { + // 当前位是字母 + case 'A' ... 'Z': + case 'a' ... 'z': + if (tmp_dEntry->DIR_NTRes & LOWERCASE_EXT) // 为兼容windows系统,检测DIR_NTRes字段 + { + if ((tmp_dEntry->DIR_Name[x] + 32 == name[js])) + { + ++js; + break; + } + else + goto continue_cmp_fail; + } + else + { + if (tmp_dEntry->DIR_Name[x] == name[js]) + { + ++js; + break; + } + else + goto continue_cmp_fail; + } + break; + case '0' ... '9': + case ' ': + if (tmp_dEntry->DIR_Name[x] == name[js]) + { + ++js; + break; + } + else + goto continue_cmp_fail; + + break; + + default: + goto continue_cmp_fail; + break; + } + } + } + struct fat32_Directory_t *p = (struct fat32_Directory_t *)kmalloc(sizeof(struct fat32_Directory_t), 0); + *p = *tmp_dEntry; + kfree(buf); + return p; + continue_cmp_fail:; + } + + // 当前簇没有发现目标文件名,寻找下一个簇 + cluster = fat32_read_FAT_entry(part_id, cluster); + + if (cluster >= 0x0ffffff7) // 寻找完父目录的所有簇,都没有找到目标文件名 + { + kfree(buf); + return NULL; + } + } +} + +/** + * @brief 按照路径查找文件 + * + * @param part_id fat32分区id + * @param path + * @param flags + * @return struct fat32_Directory_t* + */ +struct fat32_Directory_t *fat32_path_walk(uint32_t part_id, char *path, uint64_t flags) +{ + // 去除路径前的斜杠 + while (*path == '/') + ++path; + + if ((!*path) || (*path == '\0')) + return NULL; + + struct fat32_Directory_t *parent = (struct fat32_Directory_t *)kmalloc(sizeof(struct fat32_Directory_t), 0); + char *dEntry_name = kmalloc(PAGE_4K_SIZE, 0); + + memset(parent, 0, sizeof(struct fat32_Directory_t)); + memset(dEntry_name, 0, PAGE_4K_SIZE); + + parent->DIR_FstClusLO = fat32_part_info[part_id].bootsector.BPB_RootClus & 0xffff; + parent->DIR_FstClusHI = (fat32_part_info[part_id].bootsector.BPB_RootClus >> 16) & 0xffff; + + while (true) + { + // 提取出下一级待搜索的目录名或文件名,并保存在dEntry_name中 + char *tmp_path = path; + while ((*path && *path != '\0') && (*path != '/')) + ++path; + int tmp_path_len = path - tmp_path; + memcpy(dEntry_name, tmp_path, tmp_path_len); + dEntry_name[tmp_path_len] = '\0'; + //kdebug("dEntry_name=%s", dEntry_name); + struct fat32_Directory_t *next_dir = fat32_lookup(part_id, dEntry_name, tmp_path_len, parent, flags); + + if (next_dir == NULL) + { + // 搜索失败 + kerror("cannot find the file/dir : %s", dEntry_name); + kfree(dEntry_name); + kfree(parent); + return NULL; + } + + while (*path == '/') + ++path; + + if ((!*path) || (*path == '\0')) // 已经到达末尾 + { + if (flags & 1) // 返回父目录 + { + kfree(dEntry_name); + kfree(next_dir); + return parent; + } + + kfree(dEntry_name); + kfree(parent); + return next_dir; + } + + *parent = *next_dir; + kfree(next_dir); + } +} + +void fat32_init() +{ + spin_init(&fat32_part_reg_lock); } \ No newline at end of file diff --git a/kernel/filesystem/fat32/fat32.h b/kernel/filesystem/fat32/fat32.h index 2800286c..d9eba3ac 100644 --- a/kernel/filesystem/fat32/fat32.h +++ b/kernel/filesystem/fat32/fat32.h @@ -13,6 +13,8 @@ #include +#define FAT32_MAX_PARTITION_NUM 128 // 系统支持的最大的fat32分区数量 + /** * @brief fat32文件系统引导扇区结构体 * @@ -56,22 +58,101 @@ struct fat32_BootSector_t /** * @brief fat32文件系统的FSInfo扇区结构体 - * + * */ struct fat32_FSInfo_t { - uint32_t FSI_LeadSig; // FS info扇区标志符 数值为0x41615252 + uint32_t FSI_LeadSig; // FS info扇区标志符 数值为0x41615252 uint8_t FSI_Reserved1[480]; // 保留使用,全部置为0 - uint32_t FSI_StrucSig; // 另一个标志符,数值为0x61417272 - uint32_t FSI_Free_Count; // 上一次记录的空闲簇数量,这是一个参考值 - uint32_t FSI_Nxt_Free; // 空闲簇的起始搜索位置,这是为驱动程序提供的参考值 + uint32_t FSI_StrucSig; // 另一个标志符,数值为0x61417272 + uint32_t FSI_Free_Count; // 上一次记录的空闲簇数量,这是一个参考值 + uint32_t FSI_Nxt_Free; // 空闲簇的起始搜索位置,这是为驱动程序提供的参考值 uint8_t FSI_Reserved2[12]; // 保留使用,全部置为0 - uint32_t FSI_TrailSig; // 结束标志,数值为0xaa550000 + uint32_t FSI_TrailSig; // 结束标志,数值为0xaa550000 } __attribute__((packed)); +#define ATTR_READ_ONLY (1 << 0) +#define ATTR_HIDDEN (1 << 1) +#define ATTR_SYSTEM (1 << 2) +#define ATTR_VOLUME_ID (1 << 3) +#define ATTR_DIRECTORY (1 << 4) +#define ATTR_ARCHIVE (1 << 5) +#define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID) + /** - * @brief 读取指定磁盘上的第0个分区的fat32文件系统 - * - * @param disk_num + * @brief fat32文件系统短目录项,大小为32bytes + * */ -void fat32_FS_init(int disk_num); \ No newline at end of file +struct fat32_Directory_t +{ + unsigned char DIR_Name[11]; + unsigned char DIR_Attr; // 文件属性 + unsigned char DIR_NTRes; // EXT|BASE => 8(BASE).3(EXT) + // BASE:LowerCase(8),UpperCase(0) + // EXT:LowerCase(16),UpperCase(0) + unsigned char DIR_CrtTimeTenth; // 文件创建的毫秒级时间戳 + unsigned short DIR_CrtTime; // 文件创建时间 + unsigned short DIR_CrtDate; // 文件创建日期 + unsigned short DIR_LastAccDate; // 文件的最后访问日期 + unsigned short DIR_FstClusHI; // 起始簇号(高16bit) + unsigned short DIR_WrtTime; // 最后写入时间 + unsigned short DIR_WrtDate; // 最后写入日期 + unsigned short DIR_FstClusLO; // 起始簇号(低16bit) + unsigned int DIR_FileSize; // 文件大小 +} __attribute__((packed)); + +#define LOWERCASE_BASE (8) +#define LOWERCASE_EXT (16) + +/** + * @brief fat32文件系统长目录项,大小为32bytes + * + */ +struct fat32_LongDirectory_t +{ + unsigned char LDIR_Ord; // 长目录项的序号 + unsigned short LDIR_Name1[5]; // 长文件名的第1-5个字符,每个字符占2bytes + unsigned char LDIR_Attr; // 目录项属性必须为ATTR_LONG_NAME + unsigned char LDIR_Type; // 如果为0,则说明这是长目录项的子项 + unsigned char LDIR_Chksum; // 短文件名的校验和 + unsigned short LDIR_Name2[6]; // 长文件名的第6-11个字符,每个字符占2bytes + unsigned short LDIR_FstClusLO; // 必须为0 + unsigned short LDIR_Name3[2]; // 长文件名的12-13个字符,每个字符占2bytes +} __attribute__((packed)); + +struct fat32_partition_info_t +{ + uint16_t partition_id; // 全局fat32分区id + uint8_t ahci_ctrl_num; + uint8_t ahci_port_num; + uint8_t part_num; // 硬盘中的分区号 + + struct fat32_BootSector_t bootsector; + struct fat32_FSInfo_t fsinfo; + + uint64_t first_data_sector; // 数据区起始扇区号 + uint64_t bytes_per_clus; // 每簇字节数 + uint64_t FAT1_base_sector; // FAT1表的起始簇号 + uint64_t FAT2_base_sector; // FAT2表的起始簇号 +}; + +/** + * @brief 注册指定磁盘上的指定分区的fat32文件系统 + * + * @param ahci_ctrl_num ahci控制器编号 + * @param ahci_port_num ahci控制器端口编号 + * @param part_num 磁盘分区编号 + */ +int fat32_register_partition(uint8_t ahci_ctrl_num, uint8_t ahci_port_num, uint8_t part_num); + +/** + * @brief 按照路径查找文件 + * + * @param part_id fat32分区id + * @param path + * @param flags + * @return struct fat32_Directory_t* + */ +struct fat32_Directory_t *fat32_path_walk(uint32_t part_id, char *path, uint64_t flags); + +void fat32_init(); \ No newline at end of file diff --git a/kernel/main.c b/kernel/main.c index d7d2de70..440117eb 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -147,6 +147,7 @@ void system_initialize() // ata_init(); pci_init(); ahci_init(); + fat32_init(); // test_slab(); // test_mm(); @@ -155,7 +156,6 @@ void system_initialize() current_pcb->preempt_count = 0; process_init(); HPET_init(); - } //操作系统内核从这里开始执行 @@ -182,11 +182,19 @@ void Start_Kernel(void) system_initialize(); + int part_id = fat32_register_partition(0, 0, 0); + struct fat32_Directory_t *dentry = fat32_path_walk(part_id, "a.txt", 0); + if (dentry != NULL) + printk_color(BLUE, BLACK, "Find a.txt\nDIR_FstClusHI:%#018lx\tDIR_FstClusLO:%#018lx\tDIR_FileSize:%#018lx\n", dentry->DIR_FstClusHI, dentry->DIR_FstClusLO, dentry->DIR_FileSize); + else + printk_color(BLUE, BLACK, "Can`t find file\n"); - fat32_FS_init(0); + dentry = fat32_path_walk(part_id, "xx/12.png", 0); + if (dentry != NULL) + printk_color(BLUE, BLACK, "Find xx/12.png\nDIR_FstClusHI:%#018lx\tDIR_FstClusLO:%#018lx\tDIR_FileSize:%#018lx\n", dentry->DIR_FstClusHI, dentry->DIR_FstClusLO, dentry->DIR_FileSize); + else + printk_color(BLUE, BLACK, "Can`t find file\n"); - - // show_welcome(); // test_mm(); @@ -215,7 +223,7 @@ void Start_Kernel(void) // ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0xc8, ICR_APIC_FIXED, ICR_No_Shorthand, true, 1); // 测试ipi - //int last_sec = rtc_now.second; + // int last_sec = rtc_now.second; /* while (1) { diff --git a/tools/create_hdd_image.sh b/tools/create_hdd_image.sh index f2346f80..d39b22cd 100644 --- a/tools/create_hdd_image.sh +++ b/tools/create_hdd_image.sh @@ -1,4 +1,7 @@ echo "Creating virtual disk image..." qemu-img create -f raw disk.img 16M -mkfs.vfat -f 32 disk.img -echo "Successfully created disk image, please move it to folder ../bin/" +fdisk disk.img +sudo losetup -P /dev/loop1 --show disk.img +lsblk +#mkfs.vfat -F 32 /dev/loop1p1 +echo "Successfully created disk image, please make a FAT32 filesystem on it and move it to folder ../bin/" diff --git a/tools/mount_virt_disk.sh b/tools/mount_virt_disk.sh new file mode 100644 index 00000000..7c4b9d23 --- /dev/null +++ b/tools/mount_virt_disk.sh @@ -0,0 +1,4 @@ +sudo losetup -P /dev/loop1 --show ../bin/disk.img +lsblk +mkdir -p ../bin/disk_mount/ +sudo mount /dev/loop1p1 ../bin/disk_mount/ \ No newline at end of file diff --git a/tools/umount_virt_disk.sh b/tools/umount_virt_disk.sh new file mode 100644 index 00000000..c68cfaae --- /dev/null +++ b/tools/umount_virt_disk.sh @@ -0,0 +1,3 @@ +sudo umount ../bin/disk_mount/ +rm -rf ../bin/disk_mount/ +sudo losetup -d /dev/loop1 \ No newline at end of file