feat: block partition support
authorMinep <zelong56@gmail.com>
Thu, 10 Nov 2022 02:04:20 +0000 (02:04 +0000)
committerMinep <zelong56@gmail.com>
Thu, 10 Nov 2022 02:05:34 +0000 (02:05 +0000)
feat: GUID Partition Table parsing
fix: regression

lunaix-os/hal/ahci/io_event.c
lunaix-os/includes/lunaix/blkpart_gpt.h [new file with mode: 0644]
lunaix-os/includes/lunaix/block.h
lunaix-os/kernel/block/blk_mapping.c
lunaix-os/kernel/block/blkio.c
lunaix-os/kernel/block/blkpart_gpt.c [new file with mode: 0644]
lunaix-os/kernel/block/block.c

index 543e1ce4056750386788dc4eb415be7d7d1754ed..632197cc82813fb5dd918bf51172700caa50e633 100644 (file)
@@ -9,7 +9,7 @@ void
 __ahci_hba_isr(const isr_param* param)
 {
     // ignore spurious interrupt
-    if (!hba.ports[HBA_RIS])
+    if (!hba.base[HBA_RIS])
         return;
 
     u32_t port_num = 31 - __builtin_clz(hba.base[HBA_RIS]);
diff --git a/lunaix-os/includes/lunaix/blkpart_gpt.h b/lunaix-os/includes/lunaix/blkpart_gpt.h
new file mode 100644 (file)
index 0000000..fdce191
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * @file blkpart_gpt.h
+ * @author Lunaixsky (lunaxisky@qq.com)
+ * @brief The GUID Partition Table (GPT)
+ * @version 0.1
+ * @date 2022-11-09
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#ifndef __LUNAIX_BLKPART_GPT_H
+#define __LUNAIX_BLKPART_GPT_H
+
+#include <lunaix/device.h>
+#include <lunaix/types.h>
+
+struct gpt_header
+{
+    u8_t signature[8];
+    u32_t rev;
+    u32_t hdr_size;
+    u32_t hdr_cksum;
+    u32_t reserved1;
+    u64_t hdr_lba;
+    u64_t hdr_backup_lba;
+    u64_t lba_start;
+    u64_t lba_end;
+    u8_t guid[16];
+    u64_t ents_lba;
+    u32_t ents_len;
+    u32_t ent_size;
+    u32_t ent_cksum;
+    // reserved start here
+} PACKED;
+
+struct gpt_entry
+{
+    u8_t pguid[16];
+    u8_t uguid[16];
+    u64_t start_lba;
+    u64_t end_lba;
+    u64_t attr_flags;
+    char name[72];
+} PACKED;
+
+int
+blkpart_probegpt(struct device* master);
+
+#endif /* __LUNAIX_BLKPART_GPT_H */
index 4b0c824d1ca06f77e3da46c9a53628da3b15ea09..551bc22818a64531fad899c05bfc2243ad82a261 100644 (file)
 
 struct block_dev
 {
-    char bdev_id[DEV_ID_SIZE];
-    char name[PARTITION_NAME_SIZE];
+    struct llist_header parts;
     struct blkio_context* blkio;
     struct device* dev;
+    char bdev_id[DEV_ID_SIZE];
+    char name[PARTITION_NAME_SIZE];
     void* driver;
+    u64_t start_lba;
     u64_t end_lba;
     u32_t blk_size;
 };
 
-struct lpt_entry
-{
-    char part_name[PARTITION_NAME_SIZE];
-    u64_t base_lba;
-    u64_t end_lba;
-} __attribute__((packed));
-
 // Lunaix Partition Table
 struct lpt_header
 {
@@ -56,4 +51,11 @@ blk_mapping_init();
 void
 blk_set_blkmapping(struct block_dev* bdev, void* fsnode);
 
+struct block_dev*
+blk_mount_part(struct block_dev* bdev,
+               const char* name,
+               size_t index,
+               u64_t start_lba,
+               u64_t end_lba);
+
 #endif /* __LUNAIX_BLOCK_H */
index 46e8f458ac59dc0189d5b130b193b7745a843a65..7dae2b8c67f2548f4f1a21c41f0a3a721fa62d61 100644 (file)
@@ -9,14 +9,6 @@ blk_mapping_init()
     blk_root = twifs_dir_node(NULL, "block");
 }
 
-void
-__blk_rd_size(struct twimap* map)
-{
-    struct block_dev* bdev = twimap_data(map, struct block_dev*);
-    size_t secsize = bdev->blk_size;
-    twimap_printf(map, "%u", bdev->end_lba * secsize);
-}
-
 void
 __blk_rd_lblksz(struct twimap* map)
 {
@@ -33,7 +25,29 @@ __blk_rd_name(struct twimap* map)
 }
 
 void
-blk_set_blkmapping(struct block_dev* bdev, void* fsnode)
+__blk_rd_start_lba(struct twimap* map)
+{
+    struct block_dev* bdev = twimap_data(map, struct block_dev*);
+    twimap_printf(map, "%d", bdev->start_lba);
+}
+
+void
+__blk_rd_end_lba(struct twimap* map)
+{
+    struct block_dev* bdev = twimap_data(map, struct block_dev*);
+    twimap_printf(map, "%d", bdev->end_lba);
+}
+
+void
+__blk_rd_size(struct twimap* map)
+{
+    struct block_dev* bdev = twimap_data(map, struct block_dev*);
+    twimap_printf(
+      map, "%u", (u32_t)(bdev->end_lba - bdev->start_lba) * bdev->blk_size);
+}
+
+void
+__map_internal(struct block_dev* bdev, void* fsnode)
 {
     struct twifs_node* dev_root = (struct twifs_node*)fsnode;
 
@@ -45,4 +59,25 @@ blk_set_blkmapping(struct block_dev* bdev, void* fsnode)
 
     map = twifs_mapping(dev_root, bdev, "name");
     map->read = __blk_rd_name;
+
+    map = twifs_mapping(dev_root, bdev, "begin");
+    map->read = __blk_rd_start_lba;
+
+    map = twifs_mapping(dev_root, bdev, "end");
+    map->read = __blk_rd_end_lba;
+}
+
+void
+blk_set_blkmapping(struct block_dev* bdev, void* fsnode)
+{
+    struct twifs_node* dev_root = (struct twifs_node*)fsnode;
+
+    __map_internal(bdev, dev_root);
+
+    struct block_dev *pos, *n;
+    llist_for_each(pos, n, &bdev->parts, parts)
+    {
+        struct twifs_node* part_node = twifs_dir_node(dev_root, pos->bdev_id);
+        __map_internal(pos, part_node);
+    }
 }
\ No newline at end of file
index bc0178c1be562c014fbee93b19979f94e7219c5c..7cfc354b8d1ddb2ea26174c8d435039d1ab9f645 100644 (file)
@@ -108,6 +108,7 @@ blkio_complete(struct blkio_req* req)
         req->completed(req);
     }
 
+    // FIXME Not working in first process! Need a dummy process.
     // Wake all blocked processes on completion,
     //  albeit should be no more than one process in everycase (by design)
     pwake_all(&req->wait);
diff --git a/lunaix-os/kernel/block/blkpart_gpt.c b/lunaix-os/kernel/block/blkpart_gpt.c
new file mode 100644 (file)
index 0000000..4f9beec
--- /dev/null
@@ -0,0 +1,84 @@
+#include <klibc/string.h>
+#include <lunaix/blkpart_gpt.h>
+#include <lunaix/block.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/status.h>
+
+#include <lib/crc.h>
+
+#define GPT_BLKSIZE 512
+#define LBA2OFF(lba) (lba * GPT_BLKSIZE)
+#define ENT_PER_BLK (GPT_BLKSIZE / sizeof(struct gpt_entry))
+
+#define GPTSIG_LO 0x20494645UL
+#define GPTSIG_HI 0x54524150UL
+
+static u8_t NULL_GUID[16] = { 0 };
+
+int
+blkpart_parse(struct device* master, struct gpt_header* header)
+{
+    struct block_dev* bdev = (struct block_dev*)master->underlay;
+    if (!bdev)
+        return ENODEV;
+
+    int errno;
+    u32_t ent_lba = (u32_t)header->ents_lba;
+    struct gpt_entry* ents_parial = (struct gpt_entry*)valloc(GPT_BLKSIZE);
+
+    for (size_t i = 0; i < header->ents_len; i++) {
+        if (!(i % ENT_PER_BLK)) {
+            errno = master->read(
+              master, ents_parial, LBA2OFF(ent_lba++), GPT_BLKSIZE);
+            if (errno < 0) {
+                goto done;
+            }
+        }
+
+        struct gpt_entry* ent = &ents_parial[i % ENT_PER_BLK];
+
+        // assuming the entries are not scattered around
+        if (!memcmp(ent->pguid, NULL_GUID, 16)) {
+            break;
+        }
+
+        // Convert UEFI's 512B LB representation into local LBA range.
+        u64_t slba_local = (ent->start_lba * GPT_BLKSIZE) / bdev->blk_size;
+        u64_t elba_local = (ent->end_lba * GPT_BLKSIZE) / (u64_t)bdev->blk_size;
+
+        // we ignore the partition name, as it rarely used.
+        blk_mount_part(bdev, NULL, i, slba_local, elba_local);
+    }
+
+done:
+    vfree(ents_parial);
+    return errno;
+}
+
+int
+blkpart_probegpt(struct device* master)
+{
+    int errno;
+    struct gpt_header* gpt_hdr = (struct gpt_header*)valloc(GPT_BLKSIZE);
+
+    if ((errno = master->read(master, gpt_hdr, LBA2OFF(1), LBA2OFF(1))) < 0) {
+        goto done;
+    }
+
+    if (*(u32_t*)&gpt_hdr->signature != GPTSIG_LO ||
+        *(u32_t*)&gpt_hdr->signature[4] != GPTSIG_HI) {
+        return 0;
+    }
+
+    u32_t crc = gpt_hdr->hdr_cksum;
+    gpt_hdr->hdr_cksum = 0;
+    if (crc32b((void*)gpt_hdr, sizeof(*gpt_hdr)) != crc) {
+        // FUTURE check the backup header
+        return EINVAL;
+    }
+
+    errno = blkpart_parse(master, gpt_hdr);
+done:
+    vfree(gpt_hdr);
+    return errno;
+}
\ No newline at end of file
index 7f1b0ddc8489f7f9b0b8049c791677d609da48e1..216c0ef79a1eb7ea3e1be549c3dbc1646701dcb5 100644 (file)
@@ -8,6 +8,8 @@
 #include <lunaix/mm/valloc.h>
 #include <lunaix/syslog.h>
 
+#include <lunaix/blkpart_gpt.h>
+
 #include <lunaix/spike.h>
 
 #define BLOCK_EREAD 1
@@ -46,7 +48,7 @@ __block_read(struct device* dev, void* buf, size_t offset, size_t len)
 {
     int errno;
     struct block_dev* bdev = (struct block_dev*)dev->underlay;
-    size_t bsize = bdev->blk_size, rd_block = offset / bsize,
+    size_t bsize = bdev->blk_size, rd_block = offset / bsize + bdev->start_lba,
            r = offset % bsize, rd_size = 0;
 
     if (!(len = MIN(len, ((size_t)bdev->end_lba - rd_block + 1) * bsize))) {
@@ -60,10 +62,12 @@ __block_read(struct device* dev, void* buf, size_t offset, size_t len)
     if (r) {
         tmp_buf = vzalloc(bsize);
         rd_size = MIN(len, bsize - r);
-        vbuf->buf.size = rd_size;
+        vbuf->buf.size = bsize;
         vbuf->buf.buffer = tmp_buf;
 
-        vbuf_alloc(vbuf, buf + rd_size, len - rd_size);
+        if ((len - rd_size)) {
+            vbuf_alloc(vbuf, buf + rd_size, len - rd_size);
+        }
     }
 
     req = blkio_vrd(vbuf, rd_block, NULL, NULL, 0);
@@ -71,6 +75,10 @@ __block_read(struct device* dev, void* buf, size_t offset, size_t len)
 
     pwait(&req->wait);
 
+    // XXX temporary work-around
+    //      in case pwait used in proc0. Need a dummy process!
+    wait_if((req->flags & BLKIO_PENDING));
+
     if (!(errno = req->errcode)) {
         memcpy(buf, tmp_buf + r, rd_size);
         errno = len;
@@ -91,7 +99,7 @@ int
 __block_write(struct device* dev, void* buf, size_t offset, size_t len)
 {
     struct block_dev* bdev = (struct block_dev*)dev->underlay;
-    size_t bsize = bdev->blk_size, rd_block = offset / bsize,
+    size_t bsize = bdev->blk_size, rd_block = offset / bsize + bdev->start_lba,
            r = offset % bsize;
 
     if (!(len = MIN(len, ((size_t)bdev->end_lba - rd_block + 1) * bsize))) {
@@ -117,6 +125,10 @@ __block_write(struct device* dev, void* buf, size_t offset, size_t len)
 
     pwait(&req->wait);
 
+    // XXX temporary work-around
+    //      in case pwait used in proc0. Need a dummy process!
+    wait_if((req->flags & BLKIO_PENDING));
+
     int errno = req->errcode;
     if (!errno) {
         errno = len;
@@ -138,7 +150,7 @@ block_alloc_dev(const char* blk_id, void* driver, req_handler ioreq_handler)
 {
     struct block_dev* bdev = cake_grab(lbd_pile);
     memset(bdev, 0, sizeof(struct block_dev));
-
+    llist_init_head(&bdev->parts);
     strncpy(bdev->name, blk_id, PARTITION_NAME_SIZE);
 
     bdev->blkio = blkio_newctx(ioreq_handler);
@@ -158,6 +170,13 @@ block_mount(struct block_dev* bdev, devfs_exporter fs_export)
         goto error;
     }
 
+    errno = blkpart_probegpt(bdev->dev);
+    if (errno < 0) {
+        kprintf(KERROR "Corrupted partition table. (%d)", errno);
+    } else if (!errno) {
+        // TODO try other PT parser...
+    }
+
     struct twifs_node* dev_root = twifs_dir_node(blk_sysroot, bdev->bdev_id);
     blk_set_blkmapping(bdev, dev_root);
     fs_export(bdev, dev_root);
@@ -184,4 +203,33 @@ __block_register(struct block_dev* bdev)
     strcpy(bdev->bdev_id, dev->name_val);
     dev_registry[free_slot++] = bdev;
     return 1;
+}
+
+struct block_dev*
+blk_mount_part(struct block_dev* bdev,
+               const char* name,
+               size_t index,
+               u64_t start_lba,
+               u64_t end_lba)
+{
+    struct block_dev* pbdev = cake_grab(lbd_pile);
+    memcpy(pbdev, bdev, sizeof(*bdev));
+
+    struct device* dev =
+      device_addvol(NULL, pbdev, "%sp%d", bdev->bdev_id, index + 1);
+    dev->write = __block_write;
+    dev->read = __block_read;
+
+    pbdev->start_lba = start_lba;
+    pbdev->end_lba = end_lba;
+    pbdev->dev = dev;
+
+    strcpy(pbdev->bdev_id, dev->name_val);
+    if (name) {
+        strncpy(pbdev->name, name, PARTITION_NAME_SIZE);
+    }
+
+    llist_append(&bdev->parts, &pbdev->parts);
+
+    return pbdev;
 }
\ No newline at end of file