From 038c0412085a66a286561ffa2e5fe8b9aedd74a7 Mon Sep 17 00:00:00 2001 From: mintsuki Date: Sun, 1 Nov 2020 21:25:35 +0100 Subject: [PATCH] Add GUID resource type --- CONFIG.md | 1 + Makefile | 6 ++++-- limine.bin | Bin 32768 -> 32768 bytes stage2/fs/echfs.c | 24 +++++++++++++++++------- stage2/fs/echfs.h | 5 ++++- stage2/fs/ext2.c | 21 +++++++++++++++------ stage2/fs/ext2.h | 5 ++++- stage2/fs/fat32.c | 21 ++++++++++++--------- stage2/fs/fat32.h | 2 +- stage2/fs/file.c | 23 ++++++++++++++++++++--- stage2/fs/file.h | 6 ++++++ stage2/lib/blib.c | 31 +++++++++++++++++++++++++------ stage2/lib/config.c | 3 ++- stage2/lib/part.c | 44 ++++++++++++++++++++++++++++++++++++++------ stage2/lib/part.h | 4 ++++ test/limine.cfg | 2 +- 16 files changed, 154 insertions(+), 44 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 5a4e2fd7..8c7a1397 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -63,3 +63,4 @@ The format for `root` changes depending on the resource used. A resource can be one of the following: * `bios` - The `root` takes the form of `drive:partition`; for example: `bios://3:1/...` would use BIOS drive 3, partition 1. Partitions and BIOS drives are both 1-based. Omitting the drive is possible; for example: `bios://:2/...`. Omitting the drive makes Limine use the boot drive. +* `guid` - The `root` takes the form of a GUID/UUID, such as `736b5698-5ae1-4dff-be2c-ef8f44a61c52`. It is a filesystem GUID and not a partition GUID. diff --git a/Makefile b/Makefile index 82c7b262..d921cbfe 100644 --- a/Makefile +++ b/Makefile @@ -43,9 +43,11 @@ test.img: echfs-test: limine-install test.img $(MAKE) -C test - echfs-utils -m -p0 test.img quick-format 512 + echfs-utils -m -p0 test.img quick-format 512 > part_guid + sed "s/@GUID@/`cat part_guid`/g" < test/limine.cfg > limine.cfg.tmp + echfs-utils -m -p0 test.img import limine.cfg.tmp limine.cfg + rm -f limine.cfg.tmp part_guid echfs-utils -m -p0 test.img import test/test.elf boot/test.elf - echfs-utils -m -p0 test.img import test/limine.cfg limine.cfg echfs-utils -m -p0 test.img import test/bg.bmp bg.bmp ./limine-install limine.bin test.img qemu-system-x86_64 -net none -smp 4 -enable-kvm -cpu host -hda test.img -debugcon stdio diff --git a/limine.bin b/limine.bin index 5663b1baceb9d393b20468eb4b0bd5b9bf85127b..4ed50dc937cfca00d9e3e762998d9b6b189d502c 100644 GIT binary patch delta 23028 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 H;b2G|*az}s delta 22559 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, part, &id_table, 0, sizeof(struct echfs_identity_table)); if (strncmp(id_table.signature, "_ECH_FS_", 8)) { return 0; @@ -56,6 +53,19 @@ int echfs_check_signature(int disk, int partition) { return 1; } +bool echfs_get_guid(struct guid *guid, struct part *part) { + struct echfs_identity_table id_table; + read_partition(part->drive, part, &id_table, 0, sizeof(struct echfs_identity_table)); + + if (strncmp(id_table.signature, "_ECH_FS_", 8)) { + return false; + } + + *guid = id_table.guid; + + return true; +} + int echfs_open(struct echfs_file_handle *ret, int disk, int partition, const char *path) { const char *fullpath = path; diff --git a/stage2/fs/echfs.h b/stage2/fs/echfs.h index 5899afd7..a3eb7b3e 100644 --- a/stage2/fs/echfs.h +++ b/stage2/fs/echfs.h @@ -2,7 +2,9 @@ #define __FS__ECHFS_H__ #include +#include #include +#include struct echfs_dir_entry { uint64_t parent_id; @@ -31,7 +33,8 @@ struct echfs_file_handle { struct echfs_dir_entry dir_entry; }; -int echfs_check_signature(int disk, int partition); +int echfs_check_signature(struct part *part); +bool echfs_get_guid(struct guid *guid, struct part *part); int echfs_open(struct echfs_file_handle *ret, int disk, int partition, const char *filename); int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count); diff --git a/stage2/fs/ext2.c b/stage2/fs/ext2.c index 87885fd7..ef29d1da 100644 --- a/stage2/fs/ext2.c +++ b/stage2/fs/ext2.c @@ -411,13 +411,9 @@ static int inode_read(void *buf, uint64_t loc, uint64_t count, // attempts to initialize the ext2 filesystem // and checks if all features are supported -int ext2_check_signature(int drive, int partition) { - struct part part; - if (get_part(&part, drive, partition)) - panic("Invalid partition"); - +int ext2_check_signature(struct part *part) { struct ext2_superblock sb; - read_partition(drive, &part, &sb, 1024, sizeof(struct ext2_superblock)); + read_partition(part->drive, part, &sb, 1024, sizeof(struct ext2_superblock)); if (sb.s_magic != EXT2_S_MAGIC) return 0; @@ -434,3 +430,16 @@ int ext2_check_signature(int drive, int partition) { return 1; } + +bool ext2_get_guid(struct guid *guid, struct part *part) { + struct ext2_superblock sb; + read_partition(part->drive, part, &sb, 1024, sizeof(struct ext2_superblock)); + + if (sb.s_magic != EXT2_S_MAGIC) + return false; + + ((uint64_t *)guid)[0] = sb.s_uuid[0]; + ((uint64_t *)guid)[1] = sb.s_uuid[1]; + + return true; +} diff --git a/stage2/fs/ext2.h b/stage2/fs/ext2.h index 0fbc1f8f..c59b8c10 100644 --- a/stage2/fs/ext2.h +++ b/stage2/fs/ext2.h @@ -3,7 +3,9 @@ #include #include +#include #include +#include struct ext2_linux { uint8_t frag_num; @@ -54,7 +56,8 @@ struct ext2_file_handle { uint64_t block_size; }; -int ext2_check_signature(int drive, int partition); +int ext2_check_signature(struct part *part); +bool ext2_get_guid(struct guid *guid, struct part *part); int ext2_open(struct ext2_file_handle *ret, int drive, int partition, const char *path); int ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count); diff --git a/stage2/fs/fat32.c b/stage2/fs/fat32.c index 1f3c3690..7361d50e 100644 --- a/stage2/fs/fat32.c +++ b/stage2/fs/fat32.c @@ -66,14 +66,12 @@ struct fat32_lfn_entry { char name3[4]; } __attribute__((packed)); -static int fat32_init_context(struct fat32_context* context, int disk, int partition) { - context->drive = disk; - if (get_part(&context->part, disk, partition)) { - panic("Invalid partition"); - } +static int fat32_init_context(struct fat32_context* context, struct part *part) { + context->part = *part; + context->drive = part->drive; struct fat32_bpb bpb; - read_partition(disk, &context->part, &bpb, 0, sizeof(struct fat32_bpb)); + read_partition(part->drive, &context->part, &bpb, 0, sizeof(struct fat32_bpb)); if (bpb.signature != FAT32_VALID_SIGNATURE_1 && bpb.signature != FAT32_VALID_SIGNATURE_2) { return 1; @@ -223,14 +221,19 @@ static int fat32_open_in(struct fat32_context* context, struct fat32_directory_e return -1; } -int fat32_check_signature(int disk, int partition) { +int fat32_check_signature(struct part *part) { struct fat32_context context; - return fat32_init_context(&context, disk, partition) == 0; + return fat32_init_context(&context, part) == 0; } int fat32_open(struct fat32_file_handle* ret, int disk, int partition, const char* path) { + struct part part; + if (get_part(&part, disk, partition)) { + panic("Invalid partition"); + } + struct fat32_context context; - int r = fat32_init_context(&context, disk, partition); + int r = fat32_init_context(&context, &part); if (r) { print("fat32: context init failure (%d)\n", r); diff --git a/stage2/fs/fat32.h b/stage2/fs/fat32.h index 145a1728..8697a40f 100644 --- a/stage2/fs/fat32.h +++ b/stage2/fs/fat32.h @@ -24,7 +24,7 @@ struct fat32_file_handle { uint32_t size_clusters; }; -int fat32_check_signature(int disk, int partition); +int fat32_check_signature(struct part *part); int fat32_open(struct fat32_file_handle *ret, int disk, int partition, const char *path); int fat32_read(struct fat32_file_handle *file, void *buf, uint64_t loc, uint64_t count); diff --git a/stage2/fs/file.c b/stage2/fs/file.c index a125cf50..4dec2d9e 100644 --- a/stage2/fs/file.c +++ b/stage2/fs/file.c @@ -6,9 +6,26 @@ #include #include #include +#include + +bool fs_get_guid(struct guid *guid, struct part *part) { + if (echfs_check_signature(part)) { + return echfs_get_guid(guid, part); + } + if (ext2_check_signature(part)) { + return ext2_get_guid(guid, part); + } + + return false; +} int fopen(struct file_handle *ret, int disk, int partition, const char *filename) { - if (echfs_check_signature(disk, partition)) { + struct part part; + if (get_part(&part, disk, partition)) { + panic("Invalid partition"); + } + + if (echfs_check_signature(&part)) { struct echfs_file_handle *fd = conv_mem_alloc(sizeof(struct echfs_file_handle)); int r = echfs_open(fd, disk, partition, filename); @@ -24,7 +41,7 @@ int fopen(struct file_handle *ret, int disk, int partition, const char *filename return 0; } - if (ext2_check_signature(disk, partition)) { + if (ext2_check_signature(&part)) { struct ext2_file_handle *fd = conv_mem_alloc(sizeof(struct ext2_file_handle)); int r = ext2_open(fd, disk, partition, filename); @@ -40,7 +57,7 @@ int fopen(struct file_handle *ret, int disk, int partition, const char *filename return 0; } - if (fat32_check_signature(disk, partition)) { + if (fat32_check_signature(&part)) { struct fat32_file_handle *fd = conv_mem_alloc(sizeof(struct fat32_file_handle)); int r = fat32_open(fd, disk, partition, filename); diff --git a/stage2/fs/file.h b/stage2/fs/file.h index d39ec2a9..dfea68b3 100644 --- a/stage2/fs/file.h +++ b/stage2/fs/file.h @@ -2,6 +2,12 @@ #define __FS__FILE_H__ #include +#include + +struct part; +struct guid; + +bool fs_get_guid(struct guid *guid, struct part *part); struct file_handle { int disk; diff --git a/stage2/lib/blib.c b/stage2/lib/blib.c index 3f48c23d..ea4b0eef 100644 --- a/stage2/lib/blib.c +++ b/stage2/lib/blib.c @@ -10,6 +10,7 @@ #include #include #include +#include #include uint8_t boot_drive; @@ -59,14 +60,32 @@ static bool uri_bios_dispatch(struct file_handle *fd, char *loc, char *path) { return true; } +static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path) { + struct guid guid; + + if (!string_to_guid(&guid, guid_str)) + panic("Invalid GUID format"); + + int drive, partition; + if (!part_get_by_guid(&drive, &partition, &guid)) + panic("No partition found for GUID: %s", guid_str); + + if (fopen(fd, drive, partition, path)) + return false; + + return true; +} + bool uri_open(struct file_handle *fd, char *uri) { char *resource, *root, *path; config_resolve_uri(uri, &resource, &root, &path); if (!strcmp(resource, "bios")) { return uri_bios_dispatch(fd, root, path); + } else if (!strcmp(resource, "guid")) { + return uri_guid_dispatch(fd, root, path); } else { - panic("Resource `%s` not valid."); + panic("Resource `%s` not valid.", resource); } } @@ -148,7 +167,7 @@ static bool is_valid_guid(const char *s) { } } } - +/* static void guid_convert_le_cluster(uint8_t *dest, const char *s, int len) { size_t p = 0; for (int i = len - 1; i >= 0; i--) { @@ -157,7 +176,7 @@ static void guid_convert_le_cluster(uint8_t *dest, const char *s, int len) { i % 2 ? (dest[p] = val) : (dest[p++] |= val << 4); } } - +*/ static void guid_convert_be_cluster(uint8_t *dest, const char *s, int len) { size_t p = 0; for (int i = 0; i < len; i++) { @@ -171,9 +190,9 @@ bool string_to_guid(struct guid *guid, const char *s) { if (!is_valid_guid(s)) return false; - guid_convert_le_cluster((uint8_t *)guid + 0, s + 0, 8); - guid_convert_le_cluster((uint8_t *)guid + 4, s + 9, 4); - guid_convert_le_cluster((uint8_t *)guid + 6, s + 14, 4); + guid_convert_be_cluster((uint8_t *)guid + 0, s + 0, 8); + guid_convert_be_cluster((uint8_t *)guid + 4, s + 9, 4); + guid_convert_be_cluster((uint8_t *)guid + 6, s + 14, 4); guid_convert_be_cluster((uint8_t *)guid + 8, s + 19, 4); guid_convert_be_cluster((uint8_t *)guid + 10, s + 24, 12); diff --git a/stage2/lib/config.c b/stage2/lib/config.c index 8f07660a..d81b4633 100644 --- a/stage2/lib/config.c +++ b/stage2/lib/config.c @@ -140,6 +140,7 @@ bool config_resolve_uri(char *uri, char **resource, char **root, char **path) { } } + // Get root for (size_t i = 0; ; i++) { if (uri[i] == 0) return false; @@ -152,9 +153,9 @@ bool config_resolve_uri(char *uri, char **resource, char **root, char **path) { } } + // Get path if (*uri == 0) return false; - *path = uri; return true; diff --git a/stage2/lib/part.c b/stage2/lib/part.c index da7dccdf..12070ee4 100644 --- a/stage2/lib/part.c +++ b/stage2/lib/part.c @@ -75,9 +75,18 @@ static int gpt_get_part(struct part *ret, int drive, int partition) { if (!memcmp(&entry.unique_partition_guid, &empty_guid, sizeof(struct guid))) return NO_PARTITION; + ret->drive = drive; + ret->partition = partition; ret->first_sect = entry.starting_lba; ret->sect_count = (entry.ending_lba - entry.starting_lba) + 1; - ret->guid = entry.unique_partition_guid; + + struct guid guid; + if (!fs_get_guid(&guid, ret)) { + ret->guid_valid = false; + } else { + ret->guid_valid = true; + ret->guid = guid; + } return 0; } @@ -114,14 +123,18 @@ static int mbr_get_part(struct part *ret, int drive, int partition) { if (entry.type == 0) return NO_PARTITION; + ret->drive = drive; + ret->partition = partition; ret->first_sect = entry.first_sect; ret->sect_count = entry.sect_count; - // We use the same method of generating GUIDs for MBR partitions as Linux - struct guid empty_guid = {0}; - ret->guid = empty_guid; - ret->guid.a = disk_signature; - ret->guid.b = (partition + 1) << 8; + struct guid guid; + if (!fs_get_guid(&guid, ret)) { + ret->guid_valid = false; + } else { + ret->guid_valid = true; + ret->guid = guid; + } return 0; } @@ -189,3 +202,22 @@ load_up: goto load_up; } } + +bool part_get_by_guid(int *drive, int *part, struct guid *guid) { + for (size_t i = 0; i < part_index_i; i++) { + if (!part_index[i].guid_valid) + continue; + print("%X %X\n", + ((uint64_t*)&part_index[i].guid)[0], + ((uint64_t*)&part_index[i].guid)[1]); + print("%X %X\n", + ((uint64_t*)guid)[0], + ((uint64_t*)guid)[1]); + if (!memcmp(&part_index[i].guid, guid, 16)) { + *drive = part_index[i].drive; + *part = part_index[i].partition; + return true; + } + } + return false; +} diff --git a/stage2/lib/part.h b/stage2/lib/part.h index 135c32f5..e7304b10 100644 --- a/stage2/lib/part.h +++ b/stage2/lib/part.h @@ -6,12 +6,16 @@ #include struct part { + int drive; + int partition; uint64_t first_sect; uint64_t sect_count; + bool guid_valid; struct guid guid; }; int get_part(struct part *part, int drive, int partition); +bool part_get_by_guid(int *drive, int *part, struct guid *guid); void part_create_index(void); diff --git a/test/limine.cfg b/test/limine.cfg index e1d7cf7a..05ed74c4 100644 --- a/test/limine.cfg +++ b/test/limine.cfg @@ -20,7 +20,7 @@ BACKGROUND_PATH=bg.bmp :Stivale Test PROTOCOL=stivale -KERNEL_PATH=bios://:1/boot/test.elf +KERNEL_PATH=guid://@GUID@/boot/test.elf KERNEL_CMDLINE=Hi! This is an example! :Stivale2 Test