Code-base clean-up and refactoring (#47)
[lunaix-os.git] / lunaix-os / kernel / block / blkpart_gpt.c
1 #include <klibc/string.h>
2 #include <lunaix/blkpart_gpt.h>
3 #include <lunaix/block.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/status.h>
6 #include <lunaix/syslog.h>
7
8 #include <asm/muldiv64.h>
9
10 #include <klibc/crc.h>
11
12 #define GPT_BLKSIZE 512
13 #define LBA2OFF(lba) ((lba) * GPT_BLKSIZE)
14 #define ENT_PER_BLK (GPT_BLKSIZE / sizeof(struct gpt_entry))
15
16 #define GPTSIG_LO 0x20494645UL
17 #define GPTSIG_HI 0x54524150UL
18
19 static u8_t NULL_GUID[16] = { 0 };
20
21 LOG_MODULE("GPT")
22
23 int
24 blkpart_parse(struct device* master, struct gpt_header* header)
25 {
26     struct block_dev* bdev = (struct block_dev*)master->underlay;
27     if (!bdev)
28         return ENODEV;
29
30     int errno = 0;
31     u32_t ent_lba = (u32_t)header->ents_lba;
32     struct gpt_entry* ents_parial = (struct gpt_entry*)valloc(GPT_BLKSIZE);
33
34     for (size_t i = 0; i < header->ents_len; i++) {
35         if (!(i % ENT_PER_BLK)) {
36             errno = master->ops.read(
37               master, ents_parial, LBA2OFF(ent_lba++), GPT_BLKSIZE);
38             if (errno < 0) {
39                 goto done;
40             }
41         }
42
43         struct gpt_entry* ent = &ents_parial[i % ENT_PER_BLK];
44
45         // assuming the entries are not scattered around
46         if (!memcmp(ent->pguid, NULL_GUID, 16)) {
47             break;
48         }
49
50         // Convert UEFI's 512B LB representation into local LBA range.
51         u64_t slba_local = udiv64(ent->start_lba * GPT_BLKSIZE, bdev->blk_size);
52         u64_t elba_local = udiv64(ent->end_lba * GPT_BLKSIZE, bdev->blk_size);
53
54         kprintf("%s: guid part#%d: %d..%d",
55                 bdev->bdev_id,
56                 i,
57                 (u32_t)slba_local,
58                 (u32_t)elba_local);
59         // we ignore the partition name, as it rarely used.
60         blk_mount_part(bdev, NULL, i, slba_local, elba_local);
61     }
62
63 done:
64     vfree(ents_parial);
65     return errno;
66 }
67
68 int
69 blkpart_probegpt(struct device* master)
70 {
71     int errno;
72     struct gpt_header* gpt_hdr = (struct gpt_header*)valloc(GPT_BLKSIZE);
73
74     if ((errno = master->ops.read(master, gpt_hdr, LBA2OFF(1), LBA2OFF(1))) <
75         0) {
76         goto done;
77     }
78
79     if (*(u32_t*)&gpt_hdr->signature != GPTSIG_LO ||
80         *(u32_t*)&gpt_hdr->signature[4] != GPTSIG_HI) {
81         return 0;
82     }
83
84     u32_t crc = gpt_hdr->hdr_cksum;
85     gpt_hdr->hdr_cksum = 0;
86     if (crc32b((void*)gpt_hdr, sizeof(*gpt_hdr)) != crc) {
87         WARN("checksum failed");
88         // FUTURE check the backup header
89         return EINVAL;
90     }
91
92     errno = blkpart_parse(master, gpt_hdr);
93 done:
94     vfree(gpt_hdr);
95     return errno;
96 }