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 5663b1ba..4ed50dc9 100644 Binary files a/limine.bin and b/limine.bin differ diff --git a/stage2/fs/echfs.c b/stage2/fs/echfs.c index 258be885..806f6370 100644 --- a/stage2/fs/echfs.c +++ b/stage2/fs/echfs.c @@ -13,6 +13,8 @@ struct echfs_identity_table { uint64_t block_count; uint64_t dir_length; uint64_t block_size; + uint32_t reserved; + struct guid guid; } __attribute__((packed)); #define ROOT_DIR_ID (~((uint64_t)0)) @@ -40,14 +42,9 @@ int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t return 0; } -int echfs_check_signature(int disk, int partition) { - struct part part; - if (get_part(&part, disk, partition)) { - panic("Invalid partition"); - } - +int echfs_check_signature(struct part *part) { struct echfs_identity_table id_table; - read_partition(disk, &part, &id_table, 0, sizeof(struct echfs_identity_table)); + read_partition(part->drive, 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