From ef6028c523d7e3d1768806a6d0e5cf468826111a Mon Sep 17 00:00:00 2001
From: 6902140 <3356142450@qq.com>
Date: Sat, 27 May 2023 22:23:56 +0800
Subject: [PATCH] add fs and vfs

---
 include/constrains.h         |   3 +
 include/fs/bio.h             |  62 ++++++
 include/fs/ext2/ext2_disk.h  |   0
 include/fs/ext2/ext2_file.h  |   0
 include/fs/ext2/ext2_mem.h   |   0
 include/fs/fat/fat32_disk.h  | 414 +++++++++++++++++++++++++++++++++++
 include/fs/fat/fat32_file.h  |  49 +++++
 include/fs/fat/fat32_mem.h   | 181 +++++++++++++++
 include/fs/fat/fat32_stack.h |  36 +++
 include/fs/fcntl.h           |  32 +++
 include/fs/fdtable.h         |  24 ++
 include/fs/stat.h            |  53 +++++
 include/fs/vfs/fs.h          | 155 +++++++++++++
 include/fs/vfs/fs_macro.h    |   7 +
 include/fs/vfs/ops.h         |  13 ++
 include/kernel/options.h     |  28 +++
 include/vfs/fs.h             | 155 +++++++++++++
 include/vfs/fs_macro.h       |   7 +
 include/vfs/ops.h            |  13 ++
 kernel/pcb_life.c            | 119 ++++++++++
 20 files changed, 1351 insertions(+)
 create mode 100644 include/fs/bio.h
 create mode 100644 include/fs/ext2/ext2_disk.h
 create mode 100644 include/fs/ext2/ext2_file.h
 create mode 100644 include/fs/ext2/ext2_mem.h
 create mode 100644 include/fs/fat/fat32_disk.h
 create mode 100644 include/fs/fat/fat32_file.h
 create mode 100644 include/fs/fat/fat32_mem.h
 create mode 100644 include/fs/fat/fat32_stack.h
 create mode 100644 include/fs/fcntl.h
 create mode 100644 include/fs/fdtable.h
 create mode 100644 include/fs/stat.h
 create mode 100644 include/fs/vfs/fs.h
 create mode 100644 include/fs/vfs/fs_macro.h
 create mode 100644 include/fs/vfs/ops.h
 create mode 100644 include/kernel/options.h
 create mode 100644 include/vfs/fs.h
 create mode 100644 include/vfs/fs_macro.h
 create mode 100644 include/vfs/ops.h

diff --git a/include/constrains.h b/include/constrains.h
index 9b8ca5c..9654943 100644
--- a/include/constrains.h
+++ b/include/constrains.h
@@ -88,4 +88,7 @@
 
 #define NOFILE 128                // open files per process
 
+
+
+#define NFILE 100                 // open files per system
 #endif
\ No newline at end of file
diff --git a/include/fs/bio.h b/include/fs/bio.h
new file mode 100644
index 0000000..dbcceaa
--- /dev/null
+++ b/include/fs/bio.h
@@ -0,0 +1,62 @@
+#ifndef __BIO_H__
+#define __BIO_H__
+
+#include "common.h"
+#include "list.h"
+#include "atomic/atomic.h"
+#include "atomic/semaphore.h"
+#include "fs/vfs/fs_macro.h"
+
+enum bh_state_bits {
+    BH_Uptodate, /* Contains valid data */
+    BH_Dirty,    /* Is dirty */
+    BH_Lock,     /* Is locked */
+    BH_Req,      /* Has been submitted for I/O */
+};
+
+struct buffer_head {
+    struct semaphore sem_lock;
+    struct semaphore sem_disk_done;
+    uint64 b_state; // buffer state
+    int valid;      // has data been read from disk?
+    int disk;       // does disk "own" buf?
+    uint dev;
+    uint blockno;
+    atomic_t refcnt;
+    // struct buffer_head *prev; // LRU cache list
+    // struct buffer_head *next;
+    list_head_t lru;
+    uchar data[BSIZE];
+    int dirty; // dirty
+};
+
+struct bio_vec {
+    // <page,offset,len>
+    struct page *bv_page;
+    uint bv_len;
+    uint bv_offset;
+};
+
+struct bio {
+    atomic_t bi_cnt;           // ref
+    ushort bi_idx;             // current idx
+    struct bio_vec *bi_io_vec; // bio vecs list
+    uint64 bi_rw;              // read or write
+    uint bi_bdev;              // device no
+    ushort bi_vcnt;            // total number
+};
+
+// bio.c
+void binit(void);
+struct buffer_head *bread(uint, uint);
+void brelse(struct buffer_head *);
+void bwrite(struct buffer_head *);
+int bpin(struct buffer_head *);
+int bunpin(struct buffer_head *);
+
+int init_bio(void);
+int submit_bio(int, struct bio *);
+int free_bio(struct bio *);
+
+void fat32_bzero(int, int);
+#endif // __BIO_H__
\ No newline at end of file
diff --git a/include/fs/ext2/ext2_disk.h b/include/fs/ext2/ext2_disk.h
new file mode 100644
index 0000000..e69de29
diff --git a/include/fs/ext2/ext2_file.h b/include/fs/ext2/ext2_file.h
new file mode 100644
index 0000000..e69de29
diff --git a/include/fs/ext2/ext2_mem.h b/include/fs/ext2/ext2_mem.h
new file mode 100644
index 0000000..e69de29
diff --git a/include/fs/fat/fat32_disk.h b/include/fs/fat/fat32_disk.h
new file mode 100644
index 0000000..1f3481e
--- /dev/null
+++ b/include/fs/fat/fat32_disk.h
@@ -0,0 +1,414 @@
+#ifndef __FAT32_DISK_H__
+#define __FAT32_DISK_H__
+
+#include "common.h"
+
+/*
+    FAT32
+    +---------------------------+
+    | 0:    Boot Sector         |
+    +---------------------------+
+    | 1:       FsInfo           |
+    +---------------------------+
+    | 6: Backup BPB Structure   |
+    +---------------------------+
+    | 7: Backup FsInfo Structure|
+    +---------------------------+
+    |     FAT Region (FAT1)     |
+    +---------------------------+
+    |     FAT Region (FAT2)     |
+    +---------------------------+
+    |    Data Region (Cluster 2)|
+    +---------------------------+
+    |    Data Region (Cluster 3)|
+    +---------------------------+
+    |           ...             |
+    +---------------------------+
+    |    Data Region (Cluster n)|
+    +---------------------------+
+*/
+// /*BPB (BIOS Parameter Block)*/
+// #define BS_JmpBoot 0      /* jump instruction (3-byte) */
+// #define BS_OEMName 3      /* OEM name (8-byte) */
+// #define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */
+// #define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */
+// #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */
+// #define BPB_NumFATs 16    /* Number of FATs (BYTE) */
+// #define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */
+// #define BPB_TotSec16 19   /* Volume size (16-bit) [sector] (WORD) */
+// #define BPB_Media 21      /* Media descriptor byte (BYTE) */
+// #define BPB_FATSz16 22    /* FAT size (16-bit) [sector] (WORD) */
+// #define BPB_SecPerTrk 24  /* Number of sectors per track for int13h [sector] (WORD) */
+// #define BPB_NumHeads 26   /* Number of heads for int13h (WORD) */
+// #define BPB_HiddSec 28    /* Volume offset from top of the drive (DWORD) */
+// #define BPB_TotSec 32     /* Volume size (32-bit) [sector] (DWORD) */
+
+// /*Extended Boot Record*/
+// #define BPB_FATSz 36     /* FAT32: FAT size [sector] (DWORD) */
+// #define BPB_ExtFlags 40  /* FAT32: Extended flags (WORD) */
+// #define BPB_FSVer 42     /* FAT32: Filesystem version (WORD) */
+// #define BPB_RootClus 44  /* FAT32: Root directory cluster (DWORD) */
+// #define BPB_FSInfo 48    /* FAT32: Offset of FSINFO sector (WORD) */
+// #define BPB_BkBootSec 50 /* FAT32: Offset of backup boot sector (WORD) */
+// #define BPB_Reserved 52  /* FAT32: Reserved. Must be set to 0x0.*/
+
+// #define BS_DrvNum 64     /* FAT32: Physical drive number for int13h (BYTE) */
+// #define BS_NTres 65      /* FAT32: Error flag (BYTE) */
+// #define BS_BootSig 66    /* FAT32: Extended boot signature (BYTE) */
+// #define BS_VolID 67      /* FAT32: Volume serial number (DWORD) */
+// #define BS_VolLab 71     /* FAT32: Volume label string (8-byte) */
+// #define BS_FilSysType 82 /* FAT32: Filesystem type string (8-byte) */
+// #define BS_BootCode 90   /* FAT32: Boot code (420-byte) */
+// #define BS_BootSign 510  /* Signature word (WORD) */
+
+// /*FSInfo Structure (FAT32 only)*/
+// #define FSI_LeadSig 0      /* FAT32 FSI: Leading signature (DWORD) */
+// #define FSI_Reserved1 4    /* FAT32 FSI: Reserved1. This field should be always initialized to zero.*/
+// #define FSI_StrucSig 484   /* FAT32 FSI: Structure signature (DWORD) */
+// #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */
+// #define FSI_Nxt_Free 492   /* FAT32 FSI: Last allocated cluster (DWORD) */
+// #define FSI_Reserved2 496  /* FAT32 FSI: Reserved. This field should be always initialized to zero.*/
+// #define FSI_TrailSig 512   /* FAT32 FSI: */
+// /*reserved, may be used in the future*/
+// #define ClnShutBitMask 0x08000000
+// // If bit is 1, volume is "clean".If bit is 0, volume is "dirty".
+// #define HrdErrBitMask 0x04000000
+// // If this bit is 1, no disk read/write errors were encountered.
+// // If this bit is 0, the file system driver encountered a disk I/O error on theVolume the last time it was mounted,
+// // which is an indicator that some sectorsmay have gone bad on the volume.
+// #define NAME0_NOT_VALID(x) (x == 0x20)
+// #define NAME_CHAR_NOT_VALID(x) ((x < 0x20 && x != 0x05) || (x == 0x22) || (x >= 0x2A && x <= 0x2C) || (x >= 0x2E && x <= 0x2F) || (x >= 0x3A || x <= 0x3F) || (x >= 0x5B && x <= 0x5D) || (x == 0x7C))
+// // " * + , . / : ; < =	> ? [ \ ] |
+// #define FCB_NUM(x) (sizeof(x) / sizeof(dirent_s_t))
+extern struct _superblock fat32_sb;
+
+// the sector of bpb and fsinfo
+#define SECTOR_BPB 0
+#define SECTOR_FSINFO 1
+#define SECTOR_BPB_BACKUP 6
+#define SECTOR_FSINFO_BACKUP 7
+
+// some useful field of fat32 super block
+#define __BPB_RootEntCnt 0
+#define __BPB_BytsPerSec (fat32_sb.sector_size)
+#define __TotSec (fat32_sb.n_sectors)
+#define __BPB_ResvdSecCnt (fat32_sb.fat32_sb_info.fatbase)
+#define __BPB_NumFATs (fat32_sb.fat32_sb_info.n_fats)
+#define __FATSz (fat32_sb.fat32_sb_info.n_sectors_fat)
+#define __BPB_SecPerClus (fat32_sb.sectors_per_block)
+#define __Free_Count (fat32_sb.fat32_sb_info.free_count)
+#define __Nxt_Free (fat32_sb.fat32_sb_info.nxt_free)
+#define __CLUSTER_SIZE (fat32_sb.cluster_size)
+#define FAT_BASE __BPB_ResvdSecCnt
+
+#define FAT_SFN_LENGTH 11 // 短文件名长度
+#define FAT_LFN_LENGTH 13 // 长文件名长度
+
+/* some useful macro from manual */
+// 1. number of root directory sectors (not important in fat32 file system)
+// (0*32+512-1)/512 FAT32 没有Root Directory 的概念,所以一直是0
+#define RootDirSectors (((__BPB_RootEntCnt * 32) + (__BPB_BytsPerSec - 1)) / __BPB_BytsPerSec)
+
+// 2. the first data sector num(sector number index from 0)
+// 假设一个FAT32区域占2017个扇区: 32 + (2 * 2017) + 0
+#define FirstDataSector ((__BPB_ResvdSecCnt) + ((__BPB_NumFATs) * (__FATSz)) + (RootDirSectors))
+
+// 3. the first sector number of cluster N
+// 假设一个簇两个扇区,保留区有32个扇区,一个fat区域占2017个扇区,有两个fat区域:(N-2)*2+32+(2*2017)+0
+#define FirstSectorofCluster(N) (((N)-2) * (__BPB_SecPerClus) + (FirstDataSector))
+
+// 4. the number of sectors in data region
+// 就是用总的数量减去保留扇区,然后减去FAT的扇区
+// remeber, RootDirSectors is always 0
+#define DataSec ((__TotSec) - ((__BPB_ResvdSecCnt) + ((__BPB_NumFATs) * (__FATSz)) + (RootDirSectors)))
+
+// 5. the count of clusters in data region
+// remeber, cluster 0 and cluster 1 can not used!!!
+#define CountofClusters ((DataSec) / (__BPB_SecPerClus))
+
+// 6. the maxium of FAT entry
+// 最后一个簇
+#define FAT_CLUSTER_MAX ((CountofClusters) + 1)
+
+// 7. 每个BLOCK每个FCB的数量
+#define FCB_PER_BLOCK ((__BPB_BytsPerSec) / sizeof(dirent_s_t))
+
+// 8. bytes of (FAT32 entry)
+#define FATOffset(N) ((N)*4)
+
+// 9. the sector number of fat entry
+// 保留区域的扇区个数+一个扇区对应4字节的FAT表项的偏移/一个扇区多少个字节,就可以算出这个FAT表项在那个扇区
+#define ThisFATEntSecNum(N) ((__BPB_ResvdSecCnt) + ((FATOffset(N)) / (__BPB_BytsPerSec)))
+
+// 10. the offset of an entry within a sector
+// 算出FAT表项在对应扇区的具体多少偏移的位置
+#define ThisFATEntOffset(N) ((FATOffset(N)) % (__BPB_BytsPerSec))
+
+// remember ,the valid number of bits of the FAT32 entry is 28
+#define FAT_VALID_MASK 0x0FFFFFFF
+
+// 11. read the FAT32 cluster entry value
+// 读FAT32 的entry
+#define FAT32ClusEntryVal(SectorBuf, N) ((*((DWORD *)&((char *)SectorBuf)[(ThisFATEntOffset(N))])) & FAT_VALID_MASK)
+
+// 12. set the FAT32 cluster entry value
+// 写FAT32 的entry
+#define SetFAT32ClusEntryVal(SecBuff, N, Val)                                                                    \
+    do {                                                                                                         \
+        int fat_entry_val = Val & FAT_VALID_MASK;                                                                \
+        *((DWORD *)&SecBuff[ThisFATEntOffset(N)]) = (*((DWORD *)&SecBuff[ThisFATEntOffset(N)])) & 0xF0000000;    \
+        *((DWORD *)&SecBuff[ThisFATEntOffset(N)]) = (*((DWORD *)&SecBuff[ThisFATEntOffset(N)])) | fat_entry_val; \
+    } while (0);
+
+// FAT[0] and FAT[1] is reserved !!!
+// FAT[0]: 0FFF FFF8
+// FAT[1]: 0FFF FFFF
+
+/*some useful macro for fat chain travel*/
+// 1. reach the end of fat32 chain?
+#define ISEOF(FATContent) ((FATContent) >= 0x0FFFFFF8)
+
+// 2. EOC and FREE
+#define EOC 0xFFFFFFFF
+#define FREE_MASK 0x00000000
+
+// 3. NAME0 flag
+#define NAME0_FREE_ONLY(x) (x == 0xE5)
+#define NAME0_FREE_ALL(x) (x == 0x00)
+#define NAME0_FREE_BOOL(x) (NAME0_FREE_ONLY(x) || NAME0_FREE_ALL(x))
+#define NAME0_SPECIAL(x) (x == 0x05) // 0xE5伪装->0x05
+
+/* File attribute bits for directory entry*/
+// 1.  some attrs definition
+#define ATTR_READ_ONLY 0x01 // Read only 0000_0001
+#define ATTR_HIDDEN 0x02    // Hidden 0000_0010
+#define ATTR_SYSTEM 0x04    // System 0000_0100
+#define ATTR_VOLUME_ID 0x08 // VOLUME_ID 0000_1000
+#define ATTR_ARCHIVE 0x20   // Archive 0010_0000
+#define ATTR_DIRECTORY 0x10 // Directory 0001_0000
+// 2. long directory attr
+#define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
+#define ATTR_LONG_NAME_MASK (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID | ATTR_DIRECTORY | ATTR_ARCHIVE)
+
+// 3. is dir? and is long dir entry?
+#define DIR_BOOL(x) ((x)&ATTR_DIRECTORY)
+
+// 4. set attr to dir and set attr to none dir
+#define DIR_SET(x) ((x) = ((x)&FREE_MASK) | ATTR_DIRECTORY)
+// we suppose it is archive if a file is not a directory when initialized
+#define NONE_DIR_SET(x) ((x) = ((x)&FREE_MASK) | ATTR_ARCHIVE)
+
+// 5. read only ?
+#define READONLY_GET(x) ((x)&ATTR_READ_ONLY)
+
+// first cluster number
+#define DIR_FIRST_CLUS(high, low) ((high << 16) | (low))
+#define DIR_FIRST_HIGH(x) ((x) >> 16)
+#define DIR_FIRST_LOW(x) ((x)&0x0000FFFF)
+
+// The maximum length of the name and the maximum length of the path
+// 1. short
+#define NAME_SHORT_MAX 8
+#define PATH_SHORT_MAX 80
+// 2. long
+// $ % ' - _ @ ~ ` ! ( ) { } ^ # & is allowed for fat32 file system allowed long directory
+#define NAME_LONG_MAX 255
+#define PATH_LONG_MAX 260
+
+// some useful macro related to long dirent
+#define FIRST_LONG_ENTRY 0x01
+#define LAST_LONG_ENTRY 0x40
+#define LONG_DIRENT_CNT 20
+
+#define LONG_NAME_BOOL(x) (((x) ^ ATTR_LONG_NAME) == 0)
+#define LAST_LONG_ENTRY_BOOL(x) ((x)&LAST_LONG_ENTRY)
+#define LAST_LONG_ENTRY_SET(x) ((x) = ((x) | LAST_LONG_ENTRY))
+
+// long name char macro
+#define LONG_NAME_CHAR_MASK(x) ((x)&0xFF)
+#define LONG_NAME_CHAR_VALID(x) (((x) != 0x0000) && ((x) != 0xFFFF))
+#define LONG_NAME_CHAR_SET(x) (((ushort)(x)) & 0x00FF)
+
+// NOTE: inum index from 0 (root is 0)
+// allocate an ino for each fat32 short entry
+#define FCB_PER_BLOCK ((__BPB_BytsPerSec) / sizeof(dirent_s_t))
+#define SECTOR_TO_FATINUM(s, offset) (((s)-FirstDataSector) * (FCB_PER_BLOCK) + (offset) + 1)
+#define INUM_TRANSFER(ino) ((ino == 0) ? 0 : ino - 1)
+#define FATINUM_TO_SECTOR(ino) (INUM_TRANSFER(ino) / (FCB_PER_BLOCK) + FirstDataSector)
+#define FATINUM_TO_OFFSET(ino) (INUM_TRANSFER(ino) % (FCB_PER_BLOCK))
+
+// the logistic number of cluster for position : off
+// start from 0
+#define LOGISTIC_C_NUM(off) ((off) / (__BPB_SecPerClus * __BPB_BytsPerSec))
+#define LOGISTIC_C_OFFSET(off) ((off) % (__BPB_SecPerClus * __BPB_BytsPerSec))
+// the logistic number of sector for position : off
+// start form 0
+#define LOGISTIC_S_NUM(off) (LOGISTIC_C_OFFSET(off) / __BPB_BytsPerSec)
+#define LOGISTIC_S_OFFSET(off) (LOGISTIC_C_OFFSET(off) % __BPB_BytsPerSec)
+
+// misc
+// 1. the length of a dir file
+#define DIRLENGTH(ip) ((ip->fat32_i.cluster_cnt) * __CLUSTER_SIZE)
+// 2. the fat32 entry number of a sector
+#define FAT_PER_SECTOR ((__BPB_BytsPerSec) / 4)
+// 3. the maxium of FCB (short and long entry)
+#define FCB_MAX_LENGTH 672 // (20+1)*32
+// 4. first long directory in the data region ?
+#define first_long_dir(ip) (ip == fat32_sb.fat32_sb_info.root_entry && off == 0)
+
+// for debug: the start addr of the cluster in the fat32.img
+#define FSIMG_STARTADDR (FirstDataSector * __BPB_BytsPerSec)
+
+// compare the s and t
+#define fat32_namecmp(s, t) (strncmp(s, t, PATH_LONG_MAX))
+
+// FAT32 Boot Record
+typedef struct FAT32_BootRecord {
+    /*FAT common field*/
+
+    uchar Jmpboot[3]; // Jump instruction to boot code.
+    // 0xEB 0x?? 0x??
+    uchar OEMName[8]; // OEM Name Identifier.
+    // Can be set by a FAT implementation to any desired value.
+    uint16 BytsPerSec; // Count of bytes per sector(*)
+                       // 512 1024 2048 4096
+    uint8 SecPerClus;  // Number of sectors per allocation unit.
+    // 1 2 4 8 16 32 64 128
+    uint16 RsvdSecCnt; // Number of reserved sectors in the reserved region
+    // of the volume starting at the first sector of the volume.
+    uint8 NumFATs; // The count of file allocation tables (FATs) on the volume.
+    // 1 or 2
+    uchar RootEntCnt[2]; // for FAT32 , set to 0
+    uint16 TotSec16;     // the count of all sectors in all four regions of the volume
+    uchar Media;         // For removable media, 0xF0 is frequently used.
+    uchar FATSz16[2];    // On FAT32 volumes this field must be 0, and BPB_FATSz32 contains the FAT size count.
+    uint16 SecPerTrk;    // Sectors per track for interrupt 0x13.
+    uint16 NumHeads;     // Number of heads for interrupt 0x13.
+    uint32 HiddSec;      // Count of hidden sectors preceding the partition that contains this FAT volume.
+    uint32 TotSec32;     // the count of all sectors in all four regions of the volume.
+
+    /*special for FAT32*/
+    uint32 FATSz32;    // 32-bit count of sectors occupied by ONE FAT
+    uchar ExtFlags[2]; //  0-3 : Zero-based number of active FAT
+    // 4-6 : Reserved
+    // 7 : 0 means the FAT is mirrored at runtime into all FATs
+    //     1 means only one FAT is active; it is the one referenced in bits 0-3
+    // 8-15 : Reserved
+    uchar FSVer[2];
+    // High byte is major revision number
+    // Low byte is minor revision number
+    uint32 RootClus;
+    // cluster number of the first cluster of the root directory,
+    // usually 2 but not required to be 2
+    uint16 FSInfo;
+    // Sector number of FSINFO structure
+    // in the reserved area of the FAT32 volume. Usually 1.
+    uint16 BkBootSec;
+    // If non-zero, indicates the sector number
+    // in the reserved area of the volume of a copy of the boot record.
+    // Usually 6. No value other than 6 is recommended.
+    uchar Reserved1[12];
+    // Reserved for future expansion
+    uint8 DrvNum;
+    // driver number
+    uchar Reserved2;
+    uchar BootSig;
+    // Signature (must be 0x28 or 0x29).
+    uchar VolID[4]; // Volume ID 'Serial' number
+    uchar VolLab[11];
+    // Volume label string.
+    uchar FilSysType[8];
+    // System identifier string  "FAT32 "
+    uchar BootCode[420];
+    // Boot code.
+    uchar BootSign[2];
+    // Bootable partition signature 0xAA55.
+} __attribute__((packed)) fat_bpb_t;
+
+// FAT32 Fsinfo
+typedef struct FAT32_Fsinfo {
+    uchar LeadSig[4]; // validate that this is in fact an FSInfo sector
+    // Value 0x41615252
+    uchar Reserved1[480]; // is currently reserved for future expansion
+    uchar StrucSig[4];    // is more localized in the sector to the location of the fields that are used
+    // Value 0x61417272
+    uint32 Free_Count; // the last known free cluster count on the volume.
+    // If the value is 0xFFFFFFFF, then the free count is unknown and must be computed.
+    uint32 Nxt_Free;
+    // the cluster number at which the driver should start looking for free clusters
+    uchar Reserved2[12];
+    uchar TrailSig[4]; // validate that this is in fact an FSInfo sector
+    // Value 0xAA550000
+} __attribute__((packed)) fsinfo_t;
+
+// Date
+// typedef struct __date_t {
+//     uchar day : 5;   // 0~31
+//     uchar month : 4; // Jan ~ Dec
+//     uchar year : 7;  // form 1980 (1980~2107)
+// } __attribute__((packed)) uint16;
+
+// // Time
+// typedef struct __time_t {
+//     uchar second_per_2 : 5; // 2-second increments 0~59
+//     uchar minute : 6;       // number of minutes 0~59
+//     uchar hour : 5;         // hours 0~23
+// } __attribute__((packed)) uint16;
+
+// typedef struct __date_t {
+//     uchar day;   // 0~31
+//     uchar month; // Jan ~ Dec
+//     uchar year;  // form 1980 (1980~2107)
+// } __attribute__((packed)) uint16;
+
+// // Time
+// typedef struct __time_t {
+//     uchar second_per_2; // 2-second increments 0~59
+//     uchar minute;       // number of minutes 0~59
+//     uchar hour;         // hours 0~23
+// } __attribute__((packed)) uint16;
+
+// Directory Structure (short name)
+typedef struct Short_Dir_t {
+    uchar DIR_Name[FAT_SFN_LENGTH]; // directory name
+    uchar DIR_Attr;                 // directory attribute
+    uchar DIR_Dev;                  // reserved, but we use it as DEVICE
+    // DIR_NTRes
+    uchar DIR_CrtTimeTenth; // create time
+    // Count of tenths of a second
+    // 0 <= DIR_CrtTimeTenth <= 199
+    // uint16 DIR_CrtTime;    // create time, 2 bytes
+    uint16 DIR_CrtTime;    // create time, 2 bytes
+    uint16 DIR_CrtDate;    // create date, 2 bytes
+    uint16 DIR_LstAccDate; // last access date, 2 bytes
+    uint16 DIR_FstClusHI;  // High word of first data cluster number
+    uint16 DIR_WrtTime;    // Last modification (write) time.
+    uint16 DIR_WrtDate;    // Last modification (write) date.
+    uint16 DIR_FstClusLO;  // Low word of first data cluster number
+    uint32 DIR_FileSize;   // 32-bit quantity containing size
+} __attribute__((packed)) dirent_s_t;
+
+// Directory Structure (long name)
+typedef struct Long_Dir_t {
+    uchar LDIR_Ord;       // The order of this entry in the sequence
+    uint16 LDIR_Name1[5]; // characters 1 through 5
+    uchar LDIR_Attr;      // Attributes
+    uchar LDIR_Type;      // Must be set to 0.
+    uchar LDIR_Chksum;    // Checksum of name
+    uint16 LDIR_Name2[6]; // characters 6 through 11
+    uint16 LDIR_Nlinks;   // (Must be set to 0, but we use it as nlinks)
+    // LDIR_FstClusLO
+    uint16 LDIR_Name3[2]; // characters 12 and 13
+} __attribute__((packed)) dirent_l_t;
+
+typedef uint32 FAT_entry_t;
+
+// 1. mount fat32 file system
+int fat32_fs_mount(int, struct _superblock *);
+
+// 2. bpb parser
+int fat32_boot_sector_parser(struct _superblock *, fat_bpb_t *);
+
+// 3. fsinfo parser
+int fat32_fsinfo_parser(struct _superblock *, fsinfo_t *);
+#endif
\ No newline at end of file
diff --git a/include/fs/fat/fat32_file.h b/include/fs/fat/fat32_file.h
new file mode 100644
index 0000000..2d40eee
--- /dev/null
+++ b/include/fs/fat/fat32_file.h
@@ -0,0 +1,49 @@
+#ifndef __FAT32_FILE_H__
+#define __FAT32_FILE_H__
+
+#include "common.h"
+
+extern struct devsw devsw[];
+
+void fat32_fileinit(void);
+struct file *fat32_filedup(struct file *);
+ssize_t fat32_fileread(struct file *, uint64, int n);
+int fat32_filestat(struct file *, uint64 addr);
+ssize_t fat32_filewrite(struct file *, uint64, int n);
+void fat32_getcwd(char *buf);
+ssize_t fat32_getdents(struct inode *dp, char *buf, size_t len);
+// implement file_operations( ==ignore== )
+// char *fat32_getcwd(char *__user buf, size_t size);
+// int fat32_pipe2(int fd[2], int flags);
+// int fat32_dup(int fd);
+// int fat32_dup3(int oldfd, int newfd, int flags);
+// int fat32_chdir(const char *path);
+// int fat32_openat(int dirfd, const char *pathname, int flags, mode_t mode);
+// int fat32_close(int fd);
+// ssize_t fat32_getdents64(int fd, void *dirp, size_t count);
+// ssize_t fat32_read(int fd, void *buf, size_t count);
+// ssize_t fat32_write(int fd, const void *buf, size_t count);
+// int fat32_linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags);
+// int fat32_unlinkat(int dirfd, const char *pathname, int flags);
+// int fat32_mkdirat(int dirfd, const char *pathname, mode_t mode);
+// int fat32_umount2(const char *target, int flags);
+// int fat32_mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
+// int fat32_fstat(int fd, struct kstat *statbuf);
+
+// inline const struct file_operations *get_fat32_fops() {
+//     const static struct file_operations fat32_file_operations = {
+//         .chdir = fat32_chdir,
+//         .close = fat32_close,
+//         .dup3 = fat32_dup3,
+//         // .fstat = fat32_fstat,
+//         .getcwd = fat32_getcwd,
+//         .getdents64 = fat32_getdents64,
+//         .linkat = fat32_linkat,
+//         .mkdirat = fat32_mkdirat,
+//         .mount = fat32_mount,
+//         .write = fat32_write,
+//     };
+
+//     return &fat32_file_operations;
+// }
+#endif
\ No newline at end of file
diff --git a/include/fs/fat/fat32_mem.h b/include/fs/fat/fat32_mem.h
new file mode 100644
index 0000000..a4de40b
--- /dev/null
+++ b/include/fs/fat/fat32_mem.h
@@ -0,0 +1,181 @@
+#ifndef __FAT32_MEM_H__
+#define __FAT32_MEM_H__
+
+#include "common.h"
+#include "fat32_disk.h"
+#include "fat32_stack.h"
+#include "fs/stat.h"
+
+struct inode;
+
+// Oscomp
+struct fat_dirent_buf {
+    uint64 d_ino;            // 索引结点号
+    int64 d_off;             // 到下一个dirent的偏移
+    unsigned short d_reclen; // 当前dirent的长度
+    unsigned char d_type;    // 文件类型
+    char d_name[];           // 文件名
+};
+
+// fat32 super block information
+struct fat32_sb_info {
+    // read-only
+    uint fatbase;        // FAT base sector
+    uint n_fats;         // Number of FATs (1 or 2)
+    uint n_sectors_fat;  // Number of sectors per FAT
+    uint root_cluster_s; // Root directory base cluster (start)
+
+    // FSINFO ~ may modify
+    uint free_count;
+    uint nxt_free;
+};
+
+// fat32 inode information
+struct fat32_inode_info {
+    // on-disk structure
+    char fname[NAME_LONG_MAX];
+    uchar Attr;             // directory attribute
+    uchar DIR_CrtTimeTenth; // create time
+    uint16 DIR_CrtTime;     // create time, 2 bytes
+    uint16 DIR_CrtDate;     // create date, 2 bytes
+    uint16 DIR_LstAccDate;  // last access date, 2 bytes
+    // (DIR_FstClusHI << 16) | (DIR_FstClusLO)
+    uint32 cluster_start; // start num
+    uint16 DIR_WrtTime;   // Last modification (write) time.
+    uint16 DIR_WrtDate;   // Last modification (write) date.
+    uint32 DIR_FileSize;  // file size (bytes)
+
+    // in memory structure
+    uint32 cluster_end; // end num
+    uint64 cluster_cnt; // number of clusters
+    uint32 parent_off;  // offset in parent clusters
+};
+
+// 0. init the root fat32 inode
+struct inode *fat32_root_inode_init(struct _superblock *);
+
+// 1. traverse the fat32 chain
+uint fat32_fat_travel(struct inode *, uint);
+
+// 2. return the next cluster number
+uint fat32_next_cluster(uint);
+
+// 3. allocate a new cluster
+uint fat32_cluster_alloc(uint);
+
+// 4. allocate a new fat entry
+uint fat32_fat_alloc();
+
+// 5. set the fat entry to given value
+void fat32_fat_set(uint, uint);
+
+// 6. current fat32 inode
+// struct inode *namei(char *);
+
+// 7. the parent of current fat32 inode
+// struct inode *namei_parent(char *, char *);
+
+struct inode *fat32_inode_dup(struct inode *);
+void fat32_inode_update(struct inode *);
+void fat32_inode_trunc(struct inode *);
+
+void fat32_inode_lock(struct inode *);
+void fat32_inode_unlock(struct inode *);
+void fat32_inode_put(struct inode *);
+void fat32_inode_unlock_put(struct inode *);
+
+int fat32_filter_longname(dirent_l_t *, char *);
+struct inode *fat32_inode_dirlookup(struct inode *, const char *, uint *);
+struct inode *fat32_inode_get(uint, uint, const char *, uint);
+void fat32_inode_stati(struct inode *, struct kstat *);
+
+uint fat32_inode_read(struct inode *, int, uint64, uint, uint);
+
+// 9. write the data given the fat32 inode, offset and length
+uint fat32_inode_write(struct inode *, int, uint64, uint, uint);
+
+// 10. dup a existed fat32 inode
+struct inode *fat32_inode_dup(struct inode *);
+
+// 11. find a existed or new fat32 inode
+struct inode *fat32_inode_get(uint, uint, const char *, uint);
+
+// 12. lock the fat32 inode
+void fat32_inode_lock(struct inode *);
+
+// 13. unlock the fat32 inode
+void fat32_inode_unlock(struct inode *);
+
+// 14. put the fat32 inode
+void fat32_inode_put(struct inode *);
+
+// 15. unlock and put the fat32 inode
+void fat32_inode_unlock_put(struct inode *);
+
+// 16. truncate the fat32 inode
+void fat32_inode_trunc(struct inode *);
+
+// 17. update the fat32 inode in the disk
+void fat32_inode_update(struct inode *);
+
+// 18. cat the Name1, Name2 and Name3 of dirent_l
+int fat32_filter_longname(dirent_l_t *, char *);
+
+// 19. reverse the dirent_l to get the long name
+ushort fat32_longname_popstack(Stack_t *, uchar *, char *);
+
+// 20. the check sum of dirent_l
+uchar ChkSum(uchar *);
+
+// 21. lookup the inode given its parent inode and name
+struct inode *fat32_inode_dirlookup(struct inode *, const char *, uint *);
+struct inode *fat32_inode_get(uint, uint, const char *, uint);
+void fat32_inode_stati(struct inode *, struct kstat *);
+int fat32_inode_delete(struct inode *dp, struct inode *ip);
+
+// 22. create the fat32 inode
+struct inode *fat32_inode_create(char *path, uchar type, short major, short minor);
+
+// 23. allocate the fat32 inode
+struct inode *fat32_inode_alloc(struct inode *, char *, uchar);
+
+// 24. init the fat32 fcb (short + long)
+int fat32_fcb_init(struct inode *, const uchar *, uchar, char *);
+
+// 25. the number of files with the same name prefix
+uint fat32_find_same_name_cnt(struct inode *, char *);
+
+// 26. the right fcb insert offset ?
+uint fat32_dir_fcb_insert_offset(struct inode *, uchar);
+
+// 27. is empty?
+int fat32_isdirempty(struct inode *);
+
+// 28. timer to string
+int fat32_time_parser(uint16 *, char *, int);
+
+// 29. date to string
+int fat32_date_parser(uint16 *, char *);
+
+// 30. delete fat32 inode
+int fat32_inode_delete(struct inode *, struct inode *);
+
+// 31. acquire the time now
+uint16 fat32_inode_get_time(int *);
+
+// 32. acquire the date now
+uint16 fat32_inode_get_date();
+
+// 33. zero the cluster given cluster num
+void fat32_zero_cluster(uint64 c_num);
+
+// 34. short name parser
+void fat32_short_name_parser(dirent_s_t dirent_l, char *name_buf);
+
+// 35. load inode from disk
+int fat32_inode_load_from_disk(struct inode *ip);
+
+// 36. is the inode a directory?
+int fat32_isdir(struct inode *);
+
+#endif
\ No newline at end of file
diff --git a/include/fs/fat/fat32_stack.h b/include/fs/fat/fat32_stack.h
new file mode 100644
index 0000000..b441119
--- /dev/null
+++ b/include/fs/fat/fat32_stack.h
@@ -0,0 +1,36 @@
+#ifndef __FAT32_STACK_H__
+#define __FAT32_STACK_H__
+
+#include "common.h"
+#include "fs/fat/fat32_disk.h"
+#define CAPACITY 30
+
+typedef dirent_l_t elemtype;
+
+struct Stack {
+    int top;
+    elemtype *data;
+};
+typedef struct Stack Stack_t;
+
+// 1. 初始化栈
+void stack_init(Stack_t *);
+
+// 2. 判断栈是否为空
+int stack_is_empty(Stack_t *);
+
+// 3. 判断栈是否已满
+int stack_is_full(Stack_t *);
+
+// 4. 入栈操作
+void stack_push(Stack_t *, elemtype);
+
+// 5. 出栈操作
+elemtype stack_pop(Stack_t *);
+
+// 6. 获取栈顶元素
+elemtype stack_peek(Stack_t *);
+
+// 7. 释放栈分配的空间
+void stack_free(Stack_t *);
+#endif
\ No newline at end of file
diff --git a/include/fs/fcntl.h b/include/fs/fcntl.h
new file mode 100644
index 0000000..15193a6
--- /dev/null
+++ b/include/fs/fcntl.h
@@ -0,0 +1,32 @@
+#ifndef __FCNTL_H__
+#define __FCNTL_H__
+
+// f_flags
+#define O_RDONLY 0x000
+#define O_WRONLY 0x001
+#define O_RDWR 0x002
+#define O_CREATE 0x40
+#define O_DIRECTORY 0x0200000
+// #define O_CREATE 0x200      // for xv6
+#define O_TRUNC 0x400
+#define F_WRITEABLE(fp) ((fp)->f_flags > 0 ? 1 : 0)
+#define F_READABLE(fp) (((fp)->f_flags & O_WRONLY) == O_WRONLY ? 0 : 1)
+
+// f_mode
+#define IMODE_READONLY 0x01
+#define IMODE_NONE 0x00
+
+#define PROT_NONE 0x0
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+#define PROT_EXEC 0x4
+
+#define MAP_FILE 0
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+
+#define AT_FDCWD -100
+
+#define F_WRITEABLE(fp) ((fp)->f_flags > 0 ? 1 : 0)
+#define F_READABLE(fp) (((fp)->f_flags & O_WRONLY) == O_WRONLY ? 0 : 1)
+#endif // __FCNTL_H__
diff --git a/include/fs/fdtable.h b/include/fs/fdtable.h
new file mode 100644
index 0000000..9be2f8f
--- /dev/null
+++ b/include/fs/fdtable.h
@@ -0,0 +1,24 @@
+#ifndef __FDTABLE_H__
+#define __FDTABLE_H__
+
+#include "param.h"
+#include "atomic/spinlock.h"
+#include "atomic/atomic.h"
+
+struct file;
+struct fd {
+    struct file *file;
+    uint flags;
+};
+
+typedef fd fd_t;
+// descriptor table
+struct fdtable {
+    atomic_t ref;
+    struct spinlock lock;
+    fd_t ofile[NOFILE];
+    uint max_fds; // max fd
+    uint cur_fd;  // current fd
+};
+
+#endif // __FDTABLE_H__
\ No newline at end of file
diff --git a/include/fs/stat.h b/include/fs/stat.h
new file mode 100644
index 0000000..caad8fd
--- /dev/null
+++ b/include/fs/stat.h
@@ -0,0 +1,53 @@
+#ifndef __FS_STAT_H__
+#define __FS_STAT_H__
+
+// since mkfs will use kernel header file, add this condition preprocess
+#ifndef USER
+#include "common.h"
+#endif
+
+#define TFILE 2 // for xv6
+
+// type
+#define T_DIR 1    // Directory
+#define T_FILE 2   // File
+#define T_DEVICE 3 // Device
+
+// device
+#define mkrdev(ma, mi) ((uint)((ma) << 8 | (mi)))
+#define CONSOLE 1
+
+typedef unsigned long int dev_t;
+typedef unsigned long int ino_t;
+typedef unsigned long int nlink_t;
+typedef unsigned int uid_t;
+typedef unsigned int gid_t;
+typedef long int off_t;
+typedef long int blksize_t;
+typedef long int blkcnt_t;
+typedef unsigned int mode_t;
+typedef long int off_t;
+
+struct kstat {
+    uint64 st_dev;
+    uint64 st_ino;
+    mode_t st_mode;
+    uint32 st_nlink;
+    uint32 st_uid;
+    uint32 st_gid;
+    uint64 st_rdev;
+    unsigned long __pad;
+    off_t st_size;
+    uint32 st_blksize;
+    int __pad2;
+    uint64 st_blocks;
+    long st_atime_sec;
+    long st_atime_nsec;
+    long st_mtime_sec;
+    long st_mtime_nsec;
+    long st_ctime_sec;
+    long st_ctime_nsec;
+    unsigned __unused[2];
+};
+
+#endif // __FS_STAT_H__
diff --git a/include/fs/vfs/fs.h b/include/fs/vfs/fs.h
new file mode 100644
index 0000000..924b297
--- /dev/null
+++ b/include/fs/vfs/fs.h
@@ -0,0 +1,155 @@
+#ifndef __VFS_FS_H__
+#define __VFS_FS_H__
+
+#include "common.h"
+#include "param.h"
+#include "atomic/spinlock.h"
+#include "atomic/semaphore.h"
+#include "fs/stat.h"
+#include "fs/fcntl.h"
+#include "fs/vfs/fs.h"
+#include "fs/fat/fat32_mem.h"
+
+struct kstat;
+extern struct ftable _ftable;
+
+union file_type {
+    struct pipe *f_pipe;    // FD_PIPE
+    struct inode *f_inode; // FDINODE and FD_DEVICE
+};
+
+typedef enum {
+    FAT32=1,
+    EXT2,
+} fs_t;
+
+struct _superblock {
+    struct semaphore sem; /* binary semaphore */
+    uint8 s_dev;          // device number
+
+    uint32 s_blocksize;       // 逻辑块的数量
+    uint32 sectors_per_block; // 每个逻辑块的扇区个数
+    uint cluster_size;        // size of a cluster
+
+    // uint32 s_blocksize_bits;
+    uint n_sectors;   // Number of sectors
+    uint sector_size; // size of a sector
+
+    struct super_operations *s_op;
+    struct inode *s_mount;
+    struct inode *root;
+
+    union {
+        struct fat32_sb_info fat32_sb_info;
+        // struct xv6fs_sb_info xv6fs_sb;
+        // void *generic_sbp;
+    };
+};
+
+// abstarct everything in memory
+struct file {
+    type_t f_type;
+    ushort f_mode;
+    uint32 f_pos;
+    ushort f_flags;
+    ushort f_count;
+    short f_major; // FD_DEVICE
+
+    int f_owner;                        /* pid or -pgrp where SIGIO should be sent */
+    union file_type f_tp;               
+    const struct file_operations *f_op; // don't use pointer (bug maybe)!!!!
+    unsigned long f_version;
+};
+
+
+struct ftable {
+    struct spinlock lock;
+    struct file file[NFILE];
+};
+
+// #define NAME_MAX 10
+// struct _dirent {
+//     long d_ino;
+//     char d_name[NAME_MAX + 1];
+// };
+
+
+// abstract datas in disk
+struct inode {
+    uint8 i_dev;
+    uint32 i_ino;  // 对任意给定的文件系统的唯一编号标识:由具体文件系统解释
+    uint16 i_mode; // 访问权限和所有权
+    int ref;       // Reference count
+    int valid;
+    // Note: fat fs does not support hard link, reserve for vfs interface
+    uint16 i_nlink;
+    uint i_uid;
+    uint i_gid;
+    uint64 i_rdev;
+    uint32 i_size;
+    uint16 i_type;
+
+    long i_atime;     // access time
+    long i_mtime;     // modify time
+    long i_ctime;     // create time
+    uint64 i_blksize; // bytes of one block
+    uint64 i_blocks;  // numbers of blocks
+    // uint32 i_blksize;
+    // uint32 i_blocks;
+    struct semaphore i_sem; /* binary semaphore */
+    // struct sleeplock i_sem;
+
+    const struct inode_operations *i_op;
+    struct _superblock *i_sb;
+    struct inode *i_mount;
+    // struct wait_queue *i_wait;
+    struct inode *parent;
+
+    fs_t fs_type;
+    union {
+        struct fat32_inode_info fat32_i;
+        // struct xv6inode_info xv6_i;
+        // struct ext2inode_info ext2_i;
+        // void *generic_ip;
+    };
+
+};
+
+struct file_operations {
+    struct file* (*alloc) (void);
+    struct file* (*dup) (struct file*);
+    ssize_t (*read) (struct file*, uint64 __user, int);
+    ssize_t (*write) (struct file*, uint64 __user, int);
+    int (*fstat) (struct file *, uint64 __user);
+};
+
+
+struct inode_operations {
+    void (*iunlock_put) (struct inode* self);
+    void (*iunlock) (struct inode* self);
+    void (*iput) (struct inode* self);
+    void (*ilock) (struct inode* self);
+    void (*itrunc) (struct inode* self);
+    void (*iupdate) (struct inode* self);
+    struct inode* (*idup) (struct inode* self);
+    int (*idir) (struct inode* self);   // is self a directory
+
+    // for directory inode
+    struct inode* (*idirlookup) (struct inode* self, const char* name, uint* poff);
+    int (*idelete) (struct inode* dp, struct inode* ip);
+    int (*idempty) (struct inode* dp);
+    ssize_t (*igetdents) (struct inode *dp, char *buf, size_t len);
+};
+
+
+struct linux_dirent {
+    uint64 d_ino;            // 索引结点号
+    int64 d_off;             // 到下一个dirent的偏移
+    unsigned short d_reclen; // 当前dirent的长度
+    unsigned char d_type;    // 文件类型
+    char d_name[];           //文件名
+};
+
+
+
+#endif // __VFS_FS_H__
\ No newline at end of file
diff --git a/include/fs/vfs/fs_macro.h b/include/fs/vfs/fs_macro.h
new file mode 100644
index 0000000..fcd4f63
--- /dev/null
+++ b/include/fs/vfs/fs_macro.h
@@ -0,0 +1,7 @@
+#ifndef __VFS_FS_MACRO_H__
+#define __VFS_FS_MACRO_H__
+
+#define CONSOLE 1
+#define BSIZE 512
+
+#endif // __FS_MACRO_H__
\ No newline at end of file
diff --git a/include/fs/vfs/ops.h b/include/fs/vfs/ops.h
new file mode 100644
index 0000000..d92cf11
--- /dev/null
+++ b/include/fs/vfs/ops.h
@@ -0,0 +1,13 @@
+#include "fs.h"
+
+// file layer
+struct file *filealloc(void);
+void generic_fileclose(struct file *);
+extern const struct file_operations* (*get_fileops[])(void);
+
+
+// inode layer
+struct inode* find_inode(char *path, int dirfd, char *name);
+struct inode* namei(char *path);
+struct inode* namei_parent(char *path, char *name);
+extern const struct inode_operations* (*get_inodeops[])(void);
\ No newline at end of file
diff --git a/include/kernel/options.h b/include/kernel/options.h
new file mode 100644
index 0000000..8160b8d
--- /dev/null
+++ b/include/kernel/options.h
@@ -0,0 +1,28 @@
+#ifndef __OPTIONS_H__
+#define __OPTIONS_H__
+
+// CLONE options
+#define CLONE_VM 0x00000100             /* set if VM shared between processes */
+#define CLONE_FILES 0x00000400          /* Set if open files shared between processes */
+#define CLONE_FS 0x00000200             /* set if fs info shared between processes */
+#define CLONE_THREAD 0x00010000         /* Set to add to same thread group */
+#define CLONE_SIGHAND 0x00000800        /* Set if signal handlers shared.  */
+#define CLONE_PARENT_SETTID 0x00100000  /* Store TID in userlevel buffer before MM copy.*/
+#define CLONE_SETTLS 0x00080000         /* Set TLS info.  */
+#define CLONE_CHILD_CLEARTID 0x00200000 /* Register exit futex and memory location to clear.  */
+#define CLONE_CHILD_SETTID 0x01000000   /* Store TID in userlevel buffer in the child.  */
+
+// waitpid options
+#define WNOHANG 0x00000001
+#define WUNTRACED 0x00000002
+#define WCONTINUED 0x00000008
+
+#define WSTOPPED WUNTRACED
+#define WEXITED 0x00000004
+
+#define WNOWAIT 0x01000000     /* Don't reap, just poll status.  */
+#define __WNOTHREAD 0x20000000 /* Don't wait on children of other threads in this group */
+#define __WALL 0x40000000      /* Wait on all children, regardless of type */
+#define __WCLONE 0x80000000    /* Wait only on non-SIGCHLD children */
+
+#endif
\ No newline at end of file
diff --git a/include/vfs/fs.h b/include/vfs/fs.h
new file mode 100644
index 0000000..4110160
--- /dev/null
+++ b/include/vfs/fs.h
@@ -0,0 +1,155 @@
+#ifndef __VFS_FS_H__
+#define __VFS_FS_H__
+
+#include "types.h"
+
+#include "kernel/locks.h"
+#include "kernel/semaphore.h"
+#include "fs/stat.h"
+#include "fs/fcntl.h"
+#include "fs/vfs/fs.h"
+#include "fs/fat/fat32_mem.h"
+
+struct kstat;
+extern struct ftable _ftable;
+
+union file_type {
+    struct pipe *f_pipe;    // FD_PIPE
+    struct inode *f_inode; // FDINODE and FD_DEVICE
+};
+
+typedef enum {
+    FAT32=1,
+    EXT2,
+} fs_t;
+
+struct _superblock {
+    struct semaphore sem; /* binary semaphore */
+    uint8_t s_dev;          // device number
+
+    uint32_t s_blocksize;       // 逻辑块的数量
+    uint32_t sectors_per_block; // 每个逻辑块的扇区个数
+    unsigned int cluster_size;        // size of a cluster
+
+    // unsigned int32_t s_blocksize_bits;
+    unsigned int n_sectors;   // Number of sectors
+    unsigned int sector_size; // size of a sector
+
+    struct super_operations *s_op;
+    struct inode *s_mount;
+    struct inode *root;
+
+    union {
+        struct fat32_sb_info fat32_sb_info;
+        // struct xv6fs_sb_info xv6fs_sb;
+        // void *generic_sbp;
+    };
+};
+
+// abstarct everything in memory
+struct file {
+    type_t f_type;
+    ushort f_mode;
+    uint32_t f_pos;
+    ushort f_flags;
+    ushort f_count;
+    short f_major; // FD_DEVICE
+
+    int f_owner;                        /* pid or -pgrp where SIGIO should be sent */
+    union file_type f_tp;               
+    const struct file_operations *f_op; // don't use pointer (bug maybe)!!!!
+    unsigned long f_version;
+};
+
+
+struct ftable {
+    spinlock_t lock;
+    struct file file[NFILE];
+};
+
+// #define NAME_MAX 10
+// struct _dirent {
+//     long d_ino;
+//     char d_name[NAME_MAX + 1];
+// };
+
+
+// abstract datas in disk
+struct inode {
+    uint8_t i_dev;
+    uint32_t i_ino;  // 对任意给定的文件系统的唯一编号标识:由具体文件系统解释
+    uint16_t i_mode; // 访问权限和所有权
+    int ref;       // Reference count
+    int valid;
+    // Note: fat fs does not support hard link, reserve for vfs interface
+    uint16_t i_nlink;
+    unsigned int i_uid;
+    unsigned int i_gid;
+    uint64_t i_rdev;
+    uint32_t i_size;
+    uint16_t i_type;
+
+    long i_atime;     // access time
+    long i_mtime;     // modify time
+    long i_ctime;     // create time
+    uint64_t i_blksize; // bytes of one block
+    uint64_t i_blocks;  // numbers of blocks
+    // uint32_t i_blksize;
+    // uint32_t i_blocks;
+    struct semaphore i_sem; /* binary semaphore */
+    // struct sleeplock i_sem;
+
+    const struct inode_operations *i_op;
+    struct _superblock *i_sb;
+    struct inode *i_mount;
+    // struct wait_queue *i_wait;
+    struct inode *parent;
+
+    fs_t fs_type;
+    union {
+        struct fat32_inode_info fat32_i;
+        // struct xv6inode_info xv6_i;
+        // struct ext2inode_info ext2_i;
+        // void *generic_ip;
+    };
+
+};
+
+struct file_operations {
+    struct file* (*alloc) (void);
+    struct file* (*dup) (struct file*);
+    ssize_t (*read) (struct file*, uint64_t __user, int);
+    ssize_t (*write) (struct file*, uint64_t __user, int);
+    int (*fstat) (struct file *, uint64_t __user);
+};
+
+
+struct inode_operations {
+    void (*iunlock_put) (struct inode* self);
+    void (*iunlock) (struct inode* self);
+    void (*iput) (struct inode* self);
+    void (*ilock) (struct inode* self);
+    void (*itrunc) (struct inode* self);
+    void (*iupdate) (struct inode* self);
+    struct inode* (*idup) (struct inode* self);
+    int (*idir) (struct inode* self);   // is self a directory
+
+    // for directory inode
+    struct inode* (*idirlookup) (struct inode* self, const char* name, unsigned int* poff);
+    int (*idelete) (struct inode* dp, struct inode* ip);
+    int (*idempty) (struct inode* dp);
+    ssize_t (*igetdents) (struct inode *dp, char *buf, size_t len);
+};
+
+
+struct linux_dirent {
+    uint64_t d_ino;            // 索引结点号
+    int64 d_off;             // 到下一个dirent的偏移
+    unsigned short d_reclen; // 当前dirent的长度
+    unsigned char d_type;    // 文件类型
+    char d_name[];           //文件名
+};
+
+
+
+#endif // __VFS_FS_H__
\ No newline at end of file
diff --git a/include/vfs/fs_macro.h b/include/vfs/fs_macro.h
new file mode 100644
index 0000000..fcd4f63
--- /dev/null
+++ b/include/vfs/fs_macro.h
@@ -0,0 +1,7 @@
+#ifndef __VFS_FS_MACRO_H__
+#define __VFS_FS_MACRO_H__
+
+#define CONSOLE 1
+#define BSIZE 512
+
+#endif // __FS_MACRO_H__
\ No newline at end of file
diff --git a/include/vfs/ops.h b/include/vfs/ops.h
new file mode 100644
index 0000000..d92cf11
--- /dev/null
+++ b/include/vfs/ops.h
@@ -0,0 +1,13 @@
+#include "fs.h"
+
+// file layer
+struct file *filealloc(void);
+void generic_fileclose(struct file *);
+extern const struct file_operations* (*get_fileops[])(void);
+
+
+// inode layer
+struct inode* find_inode(char *path, int dirfd, char *name);
+struct inode* namei(char *path);
+struct inode* namei_parent(char *path, char *name);
+extern const struct inode_operations* (*get_inodeops[])(void);
\ No newline at end of file
diff --git a/kernel/pcb_life.c b/kernel/pcb_life.c
index 6ec04a3..63f4efe 100644
--- a/kernel/pcb_life.c
+++ b/kernel/pcb_life.c
@@ -7,6 +7,8 @@
 #include "trap/traps.h"
 #include "kernel/kstdio.h"
 #include "kernel/kdebug.h"
+#include "kernel/options.h"
+
 struct proc proc[NPROC];
 
 struct proc* initproc;
@@ -116,6 +118,100 @@ void forkret(void) {
 
 
 
+
+int do_clone(int flags, uint64_t stack, pid_t ptid, uint64_t tls, pid_t *ctid) {
+    int pid;
+    struct proc *np;
+    struct proc *p = current();
+
+    // Allocate process.
+    if ((np = allocproc()) == 0) {
+        return -1;
+    }
+    // copy saved user registers.
+    *(np->trapframe) = *(p->trapframe);
+    // Cause fork to return 0 in the child.
+    np->trapframe->a0 = 0;
+
+    /* Copy vma */
+    // if (vmacopy(np) < 0) {
+    //     freeproc(np);
+    //     spinlock_release(&np->lock);
+    //     return -1;
+    // }
+
+    // Copy user memory from parent to child.
+    // TODO : mmap
+    // if (flags & CLONE_VM) {
+    //     np->pagetable = p->pagetable;
+    // } else {
+    //     if (uvmcopy(p->pagetable, np->pagetable, p->sz) < 0) {
+    //         freeproc(np);
+    //         release(&np->lock);
+    //         return -1;
+    //     }
+    // }
+    // np->sz = p->sz;
+    // // increment reference counts on open file descriptors.
+    // // TODO : fdtable
+    // if (flags & CLONE_FILES) {
+    //     // for (int i = 0; i < NOFILE; i++)
+    //     //     if (p->_ofile[i])
+    //     //         np->_ofile[i] = p->_ofile[i];
+    // } else {
+    //     for (int i = 0; i < NOFILE; i++)
+    //         if (p->_ofile[i])
+    //             np->_ofile[i] = fat32_filedup(p->_ofile[i]);
+    //     // TODO : clone a completely same fdtable
+    // }
+    // TODO : vfs inode cmd
+    // np->_cwd = fat32_inode_dup(p->_cwd);
+
+    // TODO : signal
+    if (flags & CLONE_SIGHAND) {
+        np->sig = p->sig;
+    } else {
+        // TODO : create a new signal
+    }
+    // TODO : mount point CLONE_FS
+
+    // store the parent pid
+    // if (flags & CLONE_PARENT_SETTID) {
+    //     if (either_copyin(&ptid, 1, p->pid, sizeof(pid_t)) == -1)
+    //         return -1;
+    // }
+    // // set the tls (Thread-local Storage,TLS)
+    // // RISC-V使用TP寄存器
+    // if (flags & CLONE_SETTLS) {
+    //     // np->trapframe->tp = tls;
+    // }
+    // 子线程中存储子线程 ID 的变量指针
+    // if (flags & CLONE_CHILD_SETTID) {
+    //     np->ctid = ctid;
+    // }
+    if (stack) {
+        np->trapframe->sp = stack;
+    }
+    memcpy(np->name, p->name, sizeof(p->name));
+
+    pid = np->pid;
+    np->parent = p;
+    // acquire(&p->lock);
+    // appendChild(p, np);
+    // release(&p->lock);
+
+#ifdef __DEBUG_PROC__
+    printfRed("clone : %d -> %d\n", p->pid, np->pid); // debug
+#endif
+
+    PCB_Q_changeState(np, RUNNABLE);
+    spinlock_release(&np->lock);
+    return pid;
+}
+
+
+
+
 struct proc *allocproc(void) {
     struct proc *p;
 
@@ -180,4 +276,27 @@ void freeproc(struct proc *p) {
     p->exit_state = 0;
 
     PCB_Q_changeState(p, _UNUSED);
+}
+
+
+
+void do_exit(int status){
+    struct proc* p=current();
+    ASSERT(p!=initproc,"init shounld not exit \0",1);
+
+    //free p's mem
+
+    //close p's open file
+
+    //give children to init
+
+    spinlock_acquire(&p->lock);
+    p->exit_state = status << 8;
+    PCB_Q_changeState(p, ZOMBIE);
+    sema_signal(&p->parent->sem_wait_chan_parent);
+    sema_signal(&p->sem_wait_chan_self);
+    sched();
+
+    ASSERT(1==0,"zombie shoudnt come here",0);
+
 }
\ No newline at end of file
-- 
GitLab