From: Minep Date: Thu, 10 Nov 2022 02:04:20 +0000 (+0000) Subject: feat: block partition support X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/97901724584e74554916b89dfb8e95dc6497e687 feat: block partition support feat: GUID Partition Table parsing fix: regression --- diff --git a/lunaix-os/hal/ahci/io_event.c b/lunaix-os/hal/ahci/io_event.c index 543e1ce..632197c 100644 --- a/lunaix-os/hal/ahci/io_event.c +++ b/lunaix-os/hal/ahci/io_event.c @@ -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 index 0000000..fdce191 --- /dev/null +++ b/lunaix-os/includes/lunaix/blkpart_gpt.h @@ -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 +#include + +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 */ diff --git a/lunaix-os/includes/lunaix/block.h b/lunaix-os/includes/lunaix/block.h index 4b0c824..551bc22 100644 --- a/lunaix-os/includes/lunaix/block.h +++ b/lunaix-os/includes/lunaix/block.h @@ -11,22 +11,17 @@ 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 */ diff --git a/lunaix-os/kernel/block/blk_mapping.c b/lunaix-os/kernel/block/blk_mapping.c index 46e8f45..7dae2b8 100644 --- a/lunaix-os/kernel/block/blk_mapping.c +++ b/lunaix-os/kernel/block/blk_mapping.c @@ -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 diff --git a/lunaix-os/kernel/block/blkio.c b/lunaix-os/kernel/block/blkio.c index bc0178c..7cfc354 100644 --- a/lunaix-os/kernel/block/blkio.c +++ b/lunaix-os/kernel/block/blkio.c @@ -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 index 0000000..4f9beec --- /dev/null +++ b/lunaix-os/kernel/block/blkpart_gpt.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include + +#include + +#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 diff --git a/lunaix-os/kernel/block/block.c b/lunaix-os/kernel/block/block.c index 7f1b0dd..216c0ef 100644 --- a/lunaix-os/kernel/block/block.c +++ b/lunaix-os/kernel/block/block.c @@ -8,6 +8,8 @@ #include #include +#include + #include #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