:: commit 8680f99eaa9fa5a860d00279ca4bcddab4649c00

mintsuki <mintsuki@protonmail.com> — 2020-04-15 11:21

parents: 98086e3829

Add GPT support

diff --git a/Makefile b/Makefile
index 89405e6a..09441bb5 100644
--- a/Makefile
+++ b/Makefile
@@ -10,12 +10,13 @@ echfs-test: all
 	$(MAKE) -C test
 	rm -f test.img
 	dd if=/dev/zero bs=1M count=0 seek=64 of=test.img
-	parted -s test.img mklabel msdos
-	parted -s test.img mkpart primary 1 100%
-	echfs-utils -m -p0 test.img quick-format 32768
-	echfs-utils -m -p0 test.img import test/test.elf test.elf
-	echfs-utils -m -p0 test.img import test/qloader2.cfg qloader2.cfg
-	./qloader2-install src/qloader2.bin test.img
+	parted -s test.img mklabel gpt
+	parted -s test.img mkpart primary 2048s 6143s
+	parted -s test.img mkpart primary 6144s 131038s
+	echfs-utils -g -p1 test.img quick-format 512
+	echfs-utils -g -p1 test.img import test/test.elf test.elf
+	echfs-utils -g -p1 test.img import test/qloader2.cfg qloader2.cfg
+	./qloader2-install src/qloader2.bin test.img 2048
 	qemu-system-x86_64 -hda test.img -monitor stdio
 
 ext2-test:
@@ -35,4 +36,4 @@ ext2-test:
 	sudo losetup -d `cat loopback_dev`
 	rm -rf test_image loopback_dev
 	./qloader2-install src/qloader2.bin test.img
-	qemu-system-x86_64 -hda test.img -monitor stdio
\ No newline at end of file
+	qemu-system-x86_64 -hda test.img -monitor stdio
diff --git a/src/drivers/disk.c b/src/drivers/disk.c
index 0aebbab1..8fb85bfc 100644
--- a/src/drivers/disk.c
+++ b/src/drivers/disk.c
@@ -4,7 +4,7 @@
 #include <drivers/disk.h>
 #include <lib/real.h>
 #include <lib/blib.h>
-#include <lib/mbr.h>
+#include <lib/part.h>
 
 #define SECTOR_SIZE 512
 #define BLOCK_SIZE_IN_SECTORS 16
@@ -74,6 +74,6 @@ int read(int drive, void *buffer, uint64_t loc, uint64_t count) {
     return 0;
 }
 
-int read_partition(int drive, struct mbr_part *part, void *buffer, uint64_t loc, uint64_t count) {
+int read_partition(int drive, struct part *part, void *buffer, uint64_t loc, uint64_t count) {
     return read(drive, buffer, loc + (part->first_sect * 512), count);
 }
diff --git a/src/drivers/disk.h b/src/drivers/disk.h
index e6ed913a..daacbf56 100644
--- a/src/drivers/disk.h
+++ b/src/drivers/disk.h
@@ -3,9 +3,9 @@
 
 #include <stddef.h>
 #include <stdint.h>
-#include <lib/mbr.h>
+#include <lib/part.h>
 
 int read(int drive, void *buffer, uint64_t loc, uint64_t count);
-int read_partition(int drive, struct mbr_part *part, void *buffer, uint64_t loc, uint64_t count);
+int read_partition(int drive, struct part *part, void *buffer, uint64_t loc, uint64_t count);
 
 #endif
diff --git a/src/fs/echfs.c b/src/fs/echfs.c
index 6a077a99..bd63c625 100644
--- a/src/fs/echfs.c
+++ b/src/fs/echfs.c
@@ -24,14 +24,14 @@ static int read_block(struct echfs_file_handle *file, void *buf, uint64_t block,
             return -1;
 
         // Read the next block.
-        read_partition(file->disk, &file->mbr_part, &block_val, file->alloc_table_offset + block_val * sizeof(uint64_t),
+        read_partition(file->disk, &file->part, &block_val, file->alloc_table_offset + block_val * sizeof(uint64_t),
 sizeof(uint64_t));
     }
 
     if (block_val == END_OF_CHAIN)
         return -1;
 
-    return read_partition(file->disk, &file->mbr_part, buf, (block_val * file->block_size) + offset, count);
+    return read_partition(file->disk, &file->part, buf, (block_val * file->block_size) + offset, count);
 }
 
 int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
@@ -51,11 +51,11 @@ int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t
 }
 
 int echfs_check_signature(int disk, int partition) {
-    struct mbr_part mbr_part;
-    mbr_get_part(&mbr_part, disk, partition);
+    struct part part;
+    get_part(&part, disk, partition);
 
     struct echfs_identity_table id_table;
-    read_partition(disk, &mbr_part, &id_table, 0, sizeof(struct echfs_identity_table));
+    read_partition(disk, &part, &id_table, 0, sizeof(struct echfs_identity_table));
 
     if (strncmp(id_table.signature, "_ECH_FS_", 8)) {
         return 0;
@@ -67,10 +67,10 @@ int echfs_check_signature(int disk, int partition) {
 int echfs_open(struct echfs_file_handle *ret, int disk, int partition, const char *filename) {
     ret->disk = disk;
 
-    mbr_get_part(&ret->mbr_part, disk, partition);
+    get_part(&ret->part, disk, partition);
 
     struct echfs_identity_table id_table;
-    read_partition(disk, &ret->mbr_part, &id_table, 0, sizeof(struct echfs_identity_table));
+    read_partition(disk, &ret->part, &id_table, 0, sizeof(struct echfs_identity_table));
 
     if (strncmp(id_table.signature, "_ECH_FS_", 8)) {
         print("echfs: signature invalid\n", filename);
@@ -86,7 +86,7 @@ int echfs_open(struct echfs_file_handle *ret, int disk, int partition, const cha
 
     // Find the file in the root dir.
     for (uint64_t i = 0; i < ret->dir_length; i += sizeof(struct echfs_dir_entry)) {
-        read_partition(disk, &ret->mbr_part, &ret->dir_entry, i + ret->dir_offset, sizeof(struct echfs_dir_entry));
+        read_partition(disk, &ret->part, &ret->dir_entry, i + ret->dir_offset, sizeof(struct echfs_dir_entry));
 
         if (!ret->dir_entry.parent_id) {
             break;
@@ -101,4 +101,4 @@ int echfs_open(struct echfs_file_handle *ret, int disk, int partition, const cha
 
     print("echfs: file %s not found\n", filename);
     return -1;
-}
\ No newline at end of file
+}
diff --git a/src/fs/echfs.h b/src/fs/echfs.h
index fe096612..87a47e6c 100644
--- a/src/fs/echfs.h
+++ b/src/fs/echfs.h
@@ -2,7 +2,7 @@
 #define __FS__ECHFS_H__
 
 #include <stdint.h>
-#include <lib/mbr.h>
+#include <lib/part.h>
 
 struct echfs_dir_entry {
     uint64_t parent_id;
@@ -20,7 +20,7 @@ struct echfs_dir_entry {
 
 struct echfs_file_handle {
     int disk;
-    struct mbr_part mbr_part;
+    struct part part;
     uint64_t block_size;
     uint64_t block_count;
     uint64_t dir_length;
diff --git a/src/fs/ext2fs.c b/src/fs/ext2fs.c
index 462bdc8b..60523da9 100644
--- a/src/fs/ext2fs.c
+++ b/src/fs/ext2fs.c
@@ -66,7 +66,7 @@ struct ext2fs_superblock {
     uint16_t s_state;               // state of the filesystem

     uint16_t s_errors;              // what to do incase of an error

     uint16_t s_minor_rev_level;     // combine with major portion to get full version

-    

+

     uint32_t s_lastcheck;           // timestamp of last consistency check

     uint32_t s_checkinterval;       // amount of time between required consistency checks

     uint32_t s_creator_os;          // operating system ID

@@ -104,7 +104,7 @@ struct ext2fs_superblock {
     uint32_t s_journal_dev;         // Journal device

     uint32_t s_last_orphan;         // Head of orphan inode list

     uint32_t s_hash_seed[4];        // Seeds used for hashing algo for dir indexing

-    

+

     uint8_t s_def_hash_version;     // Default hash versrion used for dir indexing

 

     uint32_t s_default_mnt_opts;    // Default mount options

@@ -122,7 +122,7 @@ struct ext2fs_bgd {
     uint16_t bg_free_blocks_count;  // Number of unallocated blocks in group

     uint16_t bg_free_inodes_count;  // Number of unallocated blocks in inode

     uint16_t bg_dirs_count;         // Number of directories in group

-    

+

     uint16_t reserved[7];

 } __attribute__((packed));

 

@@ -184,7 +184,7 @@ struct ext2fs_inode {
     uint32_t i_ctime;           // Time of creation

     uint32_t i_mtime;           // Time of last modification

     uint32_t i_dtime;           // Time of last deletion

-    

+

     uint16_t i_gid;             // Block group ID this inode belongs to

     uint16_t i_links_count;     // Number of directory entries in this inode

 

@@ -193,7 +193,7 @@ struct ext2fs_inode {
     uint32_t i_osd1;            // OS specific value #1 (linux support only) (unused)

     uint32_t i_blocks[15];      // Block Pointers

     uint32_t i_generation;      // Generation number

-    

+

     /* EXT2 v >= 1.0 */

     uint32_t i_eab;             // Extended Attribute Block

     uint32_t i_maj;             // If feature bit set, upper 32 bit of file size. Directory ACL if inode is directory

@@ -227,10 +227,10 @@ static struct ext2fs_inode *root_inode;
 static int num_entries = 0;

 

 // parse an inode given the partition base and inode number

-static struct ext2fs_inode *ext2fs_get_inode(uint64_t drive, struct mbr_part *part, uint64_t inode) {

+static struct ext2fs_inode *ext2fs_get_inode(uint64_t drive, struct part *part, uint64_t inode) {

     uint64_t base = part->first_sect * 512;

     uint64_t bgdt_loc = base + EXT2_BLOCK_SIZE;

-    

+

     uint64_t ino_blk_grp = (inode - 1) / superblock->s_inodes_per_group;

     uint64_t ino_tbl_idx = (inode - 1) % superblock->s_inodes_per_group;

 

@@ -243,7 +243,7 @@ static struct ext2fs_inode *ext2fs_get_inode(uint64_t drive, struct mbr_part *pa
     return target;

 }

 

-static struct ext2fs_dir_entry *ext2fs_parse_dirent(int drive, struct mbr_part *part, const char* filename) {

+static struct ext2fs_dir_entry *ext2fs_parse_dirent(int drive, struct part *part, const char* filename) {

     if (root_inode == NULL)

         return NULL;

 

@@ -271,9 +271,9 @@ static struct ext2fs_dir_entry *ext2fs_parse_dirent(int drive, struct mbr_part *
 }

 

 int ext2fs_open(struct ext2fs_file_handle *ret, int drive, int partition, const char* filename) {

-    struct mbr_part part;

-    mbr_get_part(&part, drive, partition);

-    

+    struct part part;

+    get_part(&part, drive, partition);

+

     struct ext2fs_dir_entry *entry = ext2fs_parse_dirent(drive, &part, filename);

 

     ret->drive = drive;

@@ -307,8 +307,8 @@ static int first_run = 0;
 

 // attempts to initialize the ext2 filesystem

 int ext2fs_check_signature(int drive, int partition) {

-    struct mbr_part part;

-    mbr_get_part(&part, drive, partition);

+    struct part part;

+    get_part(&part, drive, partition);

 

     uint64_t base = part.first_sect * 512;

 

@@ -335,4 +335,4 @@ int ext2fs_check_signature(int drive, int partition) {
     }

 

     return 0;

-}
\ No newline at end of file
+}

diff --git a/src/fs/ext2fs.h b/src/fs/ext2fs.h
index 2c94edb8..1231cb95 100644
--- a/src/fs/ext2fs.h
+++ b/src/fs/ext2fs.h
@@ -6,11 +6,11 @@
 #include <drivers/disk.h>

 #include <lib/libc.h>

 #include <lib/blib.h>

-#include <lib/mbr.h>

+#include <lib/part.h>

 

 struct ext2fs_file_handle {

     int drive;

-    struct mbr_part part;

+    struct part part;

     int inode_num;

     int size;

 };

@@ -20,4 +20,4 @@ int ext2fs_check_signature(int drive, int partition);
 int ext2fs_open(struct ext2fs_file_handle *ret, int drive, int partition, const char* filename);

 int ext2fs_read(struct ext2fs_file_handle *file, void* buf, uint64_t loc, uint64_t count);

 

-#endif
\ No newline at end of file
+#endif

diff --git a/src/fs/file.c b/src/fs/file.c
index 4cdf9343..33ca3204 100644
--- a/src/fs/file.c
+++ b/src/fs/file.c
@@ -38,7 +38,7 @@ int fopen(struct file_handle *ret, int disk, int partition, const char *filename
         return 0;
     }
 
-    print("fs: Could not determine the file system of disk %u partition %u",
+    print("fs: Could not determine the file system of disk %u partition %u\n",
           disk, partition);
 
     return -1;
diff --git a/src/lib/blib.c b/src/lib/blib.c
index 684ecda4..7ce15d0c 100644
--- a/src/lib/blib.c
+++ b/src/lib/blib.c
@@ -2,6 +2,7 @@
 #include <stddef.h>
 #include <stdarg.h>
 #include <lib/blib.h>
+#include <lib/libc.h>
 #include <drivers/vga_textmode.h>
 #include <lib/real.h>
 #include <sys/interrupt.h>
diff --git a/src/lib/mbr.c b/src/lib/mbr.c
deleted file mode 100644
index 13cd429d..00000000
--- a/src/lib/mbr.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <lib/mbr.h>
-#include <drivers/disk.h>
-#include <stddef.h>
-
-struct mbr_entry {
-	uint8_t status;
-	uint8_t chs_first_sect[3];
-	uint8_t type;
-	uint8_t chs_last_sect[3];
-	uint32_t first_sect;
-	uint32_t sect_count;
-} __attribute__((packed));
-
-int mbr_get_part(struct mbr_part *part, int drive, int partition) {
-    // Variables.
-    struct mbr_entry entry;
-    const size_t entry_address = 0x1be + sizeof(struct mbr_entry) * partition;
-    
-    // Read the entry of the MBR.
-    int ret;
-    if ((ret = read(drive, &entry, entry_address, sizeof(struct mbr_entry)))) {
-        return ret;
-    }
-
-    // Check if the partition exists, fail if it doesnt.
-    if (entry.type == 0) {
-        return -1;
-    }
-
-    // Assign the final fields and return.
-    part->first_sect = entry.first_sect;
-    part->sect_count = entry.sect_count;
-    return 0;
-}
diff --git a/src/lib/mbr.h b/src/lib/mbr.h
deleted file mode 100644
index 72ac8b19..00000000
--- a/src/lib/mbr.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __MBR_H__
-#define __MBR_H__
-
-#include <stdint.h>
-
-struct mbr_part {
-	uint64_t first_sect;
-	uint64_t sect_count;
-};
-
-int mbr_get_part(struct mbr_part *part, int drive, int partition);
-
-#endif
diff --git a/src/lib/part.c b/src/lib/part.c
new file mode 100644
index 00000000..799dbfcf
--- /dev/null
+++ b/src/lib/part.c
@@ -0,0 +1,128 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <lib/part.h>
+#include <drivers/disk.h>
+#include <lib/libc.h>
+#include <lib/blib.h>
+
+#define NO_PARTITION  (-1)
+#define INVALID_TABLE (-2)
+
+struct gpt_table_header {
+    // the head
+    char     signature[8];
+    uint32_t revision;
+    uint32_t header_size;
+    uint32_t crc32;
+    uint32_t _reserved0;
+
+    // the partitioning info
+    uint64_t my_lba;
+    uint64_t alternate_lba;
+    uint64_t first_usable_lba;
+    uint64_t last_usable_lba;
+
+    // the guid
+    struct {
+        uint64_t low;
+        uint64_t high;
+    } disk_guid;
+
+    // entries related
+    uint64_t partition_entry_lba;
+    uint32_t number_of_partition_entries;
+    uint32_t size_of_partition_entry;
+    uint32_t partition_entry_array_crc32;
+} __attribute__((packed));
+
+struct gpt_entry {
+    struct {
+        uint64_t low;
+        uint64_t high;
+    } partition_type_guid;
+
+    struct {
+        uint64_t low;
+        uint64_t high;
+    } unique_partition_guid;
+
+    uint64_t starting_lba;
+    uint64_t ending_lba;
+
+    uint64_t attributes;
+
+    uint16_t partition_name[36];
+} __attribute__((packed));
+
+static int gpt_get_part(struct part *ret, int drive, int partition) {
+    struct gpt_table_header header = {0};
+
+    // read header, located after the first block
+    read(drive, &header, 512, sizeof(header));
+
+    // check the header
+    // 'EFI PART'
+    if (strncmp(header.signature, "EFI PART", 8)) return INVALID_TABLE;
+    if (header.revision != 0x00010000) return NO_PARTITION;
+
+    // parse the entries if reached here
+    if (partition >= header.number_of_partition_entries) return NO_PARTITION;
+
+    struct gpt_entry entry = {0};
+    read(drive, &entry,
+         (header.partition_entry_lba * 512) + (partition * sizeof(entry)),
+         sizeof(entry));
+
+    if (entry.unique_partition_guid.low  == 0 &&
+        entry.unique_partition_guid.high == 0) return NO_PARTITION;
+
+    ret->first_sect = entry.starting_lba;
+    ret->sect_count = (entry.ending_lba - entry.starting_lba) + 1;
+
+    return 0;
+}
+
+struct mbr_entry {
+	uint8_t status;
+	uint8_t chs_first_sect[3];
+	uint8_t type;
+	uint8_t chs_last_sect[3];
+	uint32_t first_sect;
+	uint32_t sect_count;
+} __attribute__((packed));
+
+static int mbr_get_part(struct part *ret, int drive, int partition) {
+    // Variables.
+    struct mbr_entry entry;
+    const size_t entry_address = 0x1be + sizeof(struct mbr_entry) * partition;
+
+    // Read the entry of the MBR.
+    int r;
+    if ((r = read(drive, &entry, entry_address, sizeof(struct mbr_entry)))) {
+        return r;
+    }
+
+    // Check if the partition exists, fail if it doesnt.
+    if (entry.type == 0) {
+        return NO_PARTITION;
+    }
+
+    // Assign the final fields and return.
+    ret->first_sect = entry.first_sect;
+    ret->sect_count = entry.sect_count;
+    return 0;
+}
+
+int get_part(struct part *part, int drive, int partition) {
+    int ret;
+
+    ret = gpt_get_part(part, drive, partition);
+    if (ret != INVALID_TABLE)
+        return ret;
+
+    ret = mbr_get_part(part, drive, partition);
+    if (ret != INVALID_TABLE)
+        return ret;
+
+    return -1;
+}
diff --git a/src/lib/part.h b/src/lib/part.h
new file mode 100644
index 00000000..ad142af5
--- /dev/null
+++ b/src/lib/part.h
@@ -0,0 +1,13 @@
+#ifndef __LIB__PART_H__
+#define __LIB__PART_H__
+
+#include <stdint.h>
+
+struct part {
+	uint64_t first_sect;
+	uint64_t sect_count;
+};
+
+int get_part(struct part *part, int drive, int partition);
+
+#endif
diff --git a/src/main.c b/src/main.c
index a74a93c6..c1fd277a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -9,7 +9,7 @@ asm (
 #include <lib/real.h>
 #include <lib/blib.h>
 #include <lib/libc.h>
-#include <lib/mbr.h>
+#include <lib/part.h>
 #include <lib/config.h>
 #include <fs/file.h>
 #include <sys/interrupt.h>
@@ -19,8 +19,6 @@ asm (
 extern symbol bss_begin;
 extern symbol bss_end;
 
-static int config_loaded = 0;
-
 void main(int boot_drive) {
     struct file_handle f;
 
@@ -34,53 +32,49 @@ void main(int boot_drive) {
     init_idt();
 
     print("qLoader 2\n\n");
-    print("=> Boot drive: %x\n", boot_drive);
+    print("Boot drive: %x\n", boot_drive);
 
-    // Enumerate partitions.
-    struct mbr_part parts[4];
-    for (int i = 0; i < 4; i++) {
-        print("=> Checking for partition %d...\n", i);
-        int ret = mbr_get_part(&parts[i], boot_drive, i);
+    // Look for config file.
+    print("Searching for config file...\n");
+    struct part parts[4];
+    for (int i = 0; ; i++) {
+        if (i == 4) {
+            panic("Config file not found.");
+        }
+        print("Checking partition %d...\n", i);
+        int ret = get_part(&parts[i], boot_drive, i);
         if (ret) {
-            print("   Not found!\n");
+            print("Partition not found.\n");
         } else {
-            print("   Found!\n");
-            if (!config_loaded) {
-                if (!init_config(boot_drive, i)) {
-                    config_loaded = 1;
-                    print("   Config file found and loaded!\n");
-                }
+            print("Partition found.\n");
+            if (!init_config(boot_drive, i)) {
+                print("Config file found and loaded.\n");
+                break;
             }
         }
     }
 
     int drive, part, timeout;
-    char path[128], cmdline[128], proto[64];
+    char path[128], cmdline[128], proto[64], buf[32];
 
-    if (config_loaded) {
-        char buf[32];
-        if (!config_get_value(buf, 0, 32, "KERNEL_DRIVE")) {
-            print("KERNEL_DRIVE not specified, using boot drive (%x)", boot_drive);
-            drive = boot_drive;
-        } else {
-            drive = (int)strtoui(buf);
-        }
-        if (!config_get_value(buf, 0, 64, "TIMEOUT")) {
-            timeout = 5;
-        } else {
-            timeout = (int)strtoui(buf);
-        }
-        config_get_value(buf, 0, 32, "KERNEL_PARTITION");
-        part = (int)strtoui(buf);
-        config_get_value(path, 0, 128, "KERNEL_PATH");
-        config_get_value(cmdline, 0, 128, "KERNEL_CMDLINE");
-        config_get_value(proto, 0, 64, "KERNEL_PROTO");
+    if (!config_get_value(buf, 0, 32, "KERNEL_DRIVE")) {
+        print("KERNEL_DRIVE not specified, using boot drive (%x)", boot_drive);
+        drive = boot_drive;
     } else {
-        print("   !! NO CONFIG FILE FOUND ON BOOT DRIVE !!");
-        for (;;);
+        drive = (int)strtoui(buf);
+    }
+    if (!config_get_value(buf, 0, 64, "TIMEOUT")) {
+        timeout = 5;
+    } else {
+        timeout = (int)strtoui(buf);
     }
+    config_get_value(buf, 0, 32, "KERNEL_PARTITION");
+    part = (int)strtoui(buf);
+    config_get_value(path, 0, 128, "KERNEL_PATH");
+    config_get_value(cmdline, 0, 128, "KERNEL_CMDLINE");
+    config_get_value(proto, 0, 64, "KERNEL_PROTO");
 
-    print("\n");
+    print("\n\n");
     for (int i = timeout; i; i--) {
         print("\rBooting in %d (press any key to edit command line)...", i);
         if (pit_sleep_and_quit_on_keypress(18)) {
@@ -89,7 +83,7 @@ void main(int boot_drive) {
             break;
         }
     }
-    print("\n");
+    print("\n\n");
 
     fopen(&f, drive, part, path);
 
@@ -109,4 +103,4 @@ void main(int boot_drive) {
         print("Invalid protocol specified: `%s`.\n", proto);
         for (;;);
     }
-}
\ No newline at end of file
+}
diff --git a/test/qloader2.cfg b/test/qloader2.cfg
index 9afddf1b..d5799bcd 100644
--- a/test/qloader2.cfg
+++ b/test/qloader2.cfg
@@ -1,14 +1,14 @@
 TIMEOUT=3
 
-KERNEL_PARTITION=0
+KERNEL_PARTITION=1
 KERNEL_PATH=test.elf
 KERNEL_PROTO=stivale
 KERNEL_CMDLINE=none
 
-MODULE_PARTITION=0
+MODULE_PARTITION=1
 MODULE_PATH=qloader2.cfg
 MODULE_STRING=something here
 
-MODULE_PARTITION=0
+MODULE_PARTITION=1
 MODULE_PATH=qloader2.cfg
 MODULE_STRING=second module
tab: 248 wrap: offon