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
