Set up a FAT32 mount

先閱讀:https://grasslab.github.io/osdi/en/labs/lab8.html#background

Get the FAT32 partition

Parse MBR 來取得各個 partition 的資訊,Parse FAT32 Boot Sector 取得 metadata

include/mbr.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
struct mbr_partition {
    unsigned char status_flag;              //0x0
    unsigned char partition_begin_head;     //0x1
    unsigned short partition_begin_sector;  //0x2-0x3
    unsigned char partition_type;           //0x4
    unsigned char partition_end_head;       //0x5
    unsigned short partition_end_sector;    //0x6-0x7
    unsigned int starting_sector;           //0x8-0xB
    unsigned int number_of_sector;          //0xC-0xF
};

include/fat32.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Ref: https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Bootsector
struct fat32_boot_sector {
    char jump[3];  // 0x0
    char oem[8];   // 0x3

    // BIOS Parameter Block
    uint16_t bytes_per_logical_sector;   // 0xB-0xC
    uint8_t logical_sector_per_cluster;  // 0xD
    uint16_t n_reserved_sectors;         // 0xE-0xF
    uint8_t n_file_alloc_tabs;           // 0x10
    uint16_t n_max_root_dir_entries_16;  // 0x11-0x12
    uint16_t n_logical_sectors_16;       // 0x13-0x14
    uint8_t media_descriptor;            // 0x15
    uint16_t logical_sector_per_fat_16;  // 0x16-0x17

    // DOS3.31 BPB
    uint16_t physical_sector_per_track;  // 0x18-0x19
    uint16_t n_heads;                    // 0x1A-0x1B
    uint32_t n_hidden_sectors;           // 0x1C-0x1F
    uint32_t n_sectors_32;               // 0x20-0x23

    // FAT32 Extended BIOS Parameter Block
    uint32_t n_sectors_per_fat_32;              // 0x24-0x27
    uint16_t mirror_flag;                       // 0x28-0x29
    uint16_t version;                           // 0x2A-0x2B
    uint32_t root_dir_start_cluster_num;        // 0x2C-0x2F
    uint16_t fs_info_sector_num;                // 0x30-0x31
    uint16_t boot_sector_bak_first_sector_num;  // 0x32-0x33
    uint32_t reserved[3];                       // 0x34-0x3F
    uint8_t physical_drive_num;                 // 0x40
    uint8_t unused;                             // 0x41
    uint8_t extended_boot_signature;            // 0x42
    uint32_t volume_id;                         // 0x43-0x46
    uint8_t volume_label[11];                   // 0x47-0x51
    uint8_t fat_system_type[8];                 // 0x52-0x59
} __attribute__((packed));

FAT32 metadata

src/fat32.h

1
2
3
4
5
6
7
8
struct fat32_metadata {
    uint32_t fat_region_blk_idx;
    uint32_t n_fat;
    uint32_t sector_per_fat;
    uint32_t data_region_blk_idx;
    uint32_t first_cluster;
    uint8_t sector_per_cluster;
};

src/fat32.c

1
struct fat32_metadata fat32_metadata;

Mount partition

src/main.c

1
2
3
4
void boot_init() {
    ...
    sd_mount();
}

include/fat32.h

1
2
3
4
5
struct fat32_internal {
    uint32_t first_cluster;
    uint32_t dirent_cluster;
    uint32_t size;
};

src/sdhost.c

掛在 sdcard 在 /sdp1 下,並同時 parse FAT32 的 metadata 並儲存

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// read MBR and mount partition
int sd_mount() {
    // read MBR
    char buf[BLOCK_SIZE];
    readblock(0, buf);

    // check boot signature
    if (buf[510] != 0x55 || buf[511] != 0xAA) {
        return -1;
    }

    // parse first partition only
    struct mbr_partition p1;
    memcpy(&p1, buf + 446, sizeof(struct mbr_partition));

    // mount partition
    readblock(p1.starting_sector, buf);
    // route each filesystem
    if (p1.partition_type == 0x0b) {  // FAT32 with CHS addressing
        // create FAT32's root directory object
        char mountpoint[8] = "/sdp1";
        vfs_mkdir(mountpoint);
        vfs_mount("sdcard", mountpoint, "fat32");

        // store metadata
        struct fat32_boot_sector* boot_sector = (struct fat32_boot_sector*)buf;
        fat32_metadata.data_region_blk_idx = p1.starting_sector +
                                             boot_sector->n_sectors_per_fat_32 * boot_sector->n_file_alloc_tabs +
                                             boot_sector->n_reserved_sectors;
        fat32_metadata.fat_region_blk_idx = p1.starting_sector + boot_sector->n_reserved_sectors;
        fat32_metadata.n_fat = boot_sector->n_file_alloc_tabs;
        fat32_metadata.sector_per_fat = boot_sector->n_sectors_per_fat_32;
        fat32_metadata.first_cluster = boot_sector->root_dir_start_cluster_num;
        fat32_metadata.sector_per_cluster = boot_sector->logical_sector_per_cluster;

        // get mount node
        struct vnode* mount_dir;
        char path_remain[128];
        traversal(mountpoint, &mount_dir, path_remain);

        // fill internal data of mount node
        struct fat32_internal* root_internal = (struct fat32_internal*)kmalloc(sizeof(struct fat32_internal));
        root_internal->first_cluster = boot_sector->root_dir_start_cluster_num;
        mount_dir->internal = root_internal;
    }

    return 0;
}

src/fat32.c

跟 tmpfs 長很像

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int fat32_setup_mount(struct filesystem* fs, struct mount* mount) {
    mount->fs = fs;
    mount->root = fat32_create_dentry(NULL, "/", DIRECTORY);
    return 0;
}

struct dentry* fat32_create_dentry(struct dentry* parent, const char* name, int type) {
    struct dentry* dentry = (struct dentry*)kmalloc(sizeof(struct dentry));
    strcpy(dentry->name, name);
    dentry->parent = parent;
    list_head_init(&dentry->list);
    list_head_init(&dentry->childs);
    if (parent != NULL) {
        list_add(&dentry->list, &parent->childs);
    }
    dentry->vnode = fat32_create_vnode(dentry);
    dentry->mountpoint = NULL;
    dentry->type = type;
    return dentry;
}

struct vnode* fat32_create_vnode(struct dentry* dentry) {
    struct vnode* vnode = (struct vnode*)kmalloc(sizeof(struct vnode));
    vnode->dentry = dentry;
    vnode->f_ops = fat32_f_ops;
    vnode->v_ops = fat32_v_ops;
    return vnode;
}
comments powered by Disqus