소스 검색

:new: 在fat32文件系统中按照路径寻找文件

fslongjin 2 년 전
부모
커밋
9b382dab60
10개의 변경된 파일590개의 추가작업 그리고 53개의 파일을 삭제
  1. 5 2
      kernel/Makefile
  2. 1 1
      kernel/common/printk.h
  3. 20 0
      kernel/filesystem/MBR.c
  4. 24 11
      kernel/filesystem/MBR.h
  5. 424 22
      kernel/filesystem/fat32/fat32.c
  6. 91 10
      kernel/filesystem/fat32/fat32.h
  7. 13 5
      kernel/main.c
  8. 5 2
      tools/create_hdd_image.sh
  9. 4 0
      tools/mount_virt_disk.sh
  10. 3 0
      tools/umount_virt_disk.sh

+ 5 - 2
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

+ 1 - 1
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 //紫
 

+ 20 - 0
kernel/filesystem/MBR.c

@@ -0,0 +1,20 @@
+#include "MBR.h"
+#include <common/kprint.h>
+#include <driver/disk/ahci/ahci.h>
+
+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];
+}

+ 24 - 11
kernel/filesystem/MBR.h

@@ -11,34 +11,47 @@
 #pragma once
 #include <common/glib.h>
 
+#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);

+ 424 - 22
kernel/filesystem/fat32/fat32.c

@@ -1,42 +1,444 @@
 #include "fat32.h"
 #include <common/kprint.h>
 #include <driver/disk/ahci/ahci.h>
+#include <filesystem/MBR.h>
+#include <process/spinlock.h>
+#include <mm/slab.h>
+
+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);
 }

+ 91 - 10
kernel/filesystem/fat32/fat32.h

@@ -13,6 +13,8 @@
 
 #include <filesystem/MBR.h>
 
+#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 fat32文件系统短目录项,大小为32bytes
+ *
+ */
+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 读取指定磁盘上的第0个分区的fat32文件系统
- * 
- * @param disk_num 
+ * @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*
  */
-void fat32_FS_init(int disk_num);
+struct fat32_Directory_t *fat32_path_walk(uint32_t part_id, char *path, uint64_t flags);
+
+void fat32_init();

+ 13 - 5
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)
     {

+ 5 - 2
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/"

+ 4 - 0
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/ 

+ 3 - 0
tools/umount_virt_disk.sh

@@ -0,0 +1,3 @@
+sudo umount ../bin/disk_mount/
+rm -rf ../bin/disk_mount/
+sudo losetup -d /dev/loop1