summaryrefslogtreecommitdiff
path: root/gpt/gpt.ha
diff options
context:
space:
mode:
authorAlejandro Sior <aho@sior.be>2022-06-15 17:42:40 +0200
committerAlejandro Sior <aho@sior.be>2022-06-15 17:42:40 +0200
commit3c8602ee9f04991e1d60b8d6504e12296ca671d9 (patch)
tree1be941405e224be61ce1f2c9116cc5f05bc13e01 /gpt/gpt.ha
gptman: add files
Diffstat (limited to 'gpt/gpt.ha')
-rw-r--r--gpt/gpt.ha197
1 files changed, 197 insertions, 0 deletions
diff --git a/gpt/gpt.ha b/gpt/gpt.ha
new file mode 100644
index 0000000..e1ebcfd
--- /dev/null
+++ b/gpt/gpt.ha
@@ -0,0 +1,197 @@
+use errors;
+use io;
+use types;
+use rt;
+use fmt;
+
+use mbr;
+use sector;
+
+export type nogpt = !void;
+
+export type gpt = struct {
+ mbr_sec: sector::sector,
+ mbr: *mbr::mbr,
+ primary: block,
+ backup: block
+};
+
+export type block = struct {
+ header_sec: sector::sector,
+ entries_sec: sector::sector,
+ header: *header,
+ entries: *[128]entry
+};
+
+fn block_getheader(self: *block) *header = {
+ return self.header_sec.buf: *[*]u8: *header;
+};
+
+fn block_getentries(self: *block) []entry = {
+ const e = types::slice {
+ data = self.entries_sec.buf: *[*]u8,
+ length = 128,
+ capacity = 128
+ };
+
+ return *(&e: *const []entry);
+};
+
+fn block_commit(self: *block) void = {
+ sector::commit(&self.header_sec);
+ //sector::commit(&self.entries_sec);
+};
+
+fn block_fetch(self: *block) void = {
+ sector::fetch(&self.header_sec);
+ sector::fetch(&self.entries_sec);
+};
+
+fn block_drop(self: *block) void = {
+ sector::finish(&self.header_sec);
+ sector::finish(&self.entries_sec);
+};
+
+export type header = struct {
+ @offset(0) signature: u64,
+ @offset(8) revision: u32,
+ @offset(12) header_size: u32,
+ @offset(16) header_crc32: u32,
+ @offset(20) reserved0: u32,
+ @offset(24) header_lba: u64,
+ @offset(32) backup_header_lba: u64,
+ @offset(40) first_lba: u64,
+ @offset(48) last_lba: u64,
+ @offset(56) disk_guid: [2]u64,
+ @offset(72) entries_lba: u64,
+ @offset(80) entries_len: u32,
+ @offset(84) entry_size: u32,
+ @offset(88) entries_crc32: u32
+};
+
+export type entry = struct {
+ @offset(0) part_type: [2]u64,
+ @offset(16) part: [2]u64,
+ @offset(32) lba_begin: u64,
+ @offset(40) lba_end: u64,
+ @offset(48) attributes: u64,
+ @offset(56) name: [72]u8
+};
+
+export fn validate(self: *gpt) bool = {
+ if (getheader(self).signature != 0x5452415020494645) {
+ return false;
+ };
+
+ return true;
+};
+
+export fn from(fd: io::file) (*gpt | nogpt | errors::error) = {
+ const prim_header_sector = sector::map(fd, 1, 1);
+ sector::fetch(&prim_header_sector);
+ const prim_header = prim_header_sector.buf: *[*]u8: *header;
+ // XXX validate header
+
+ const prim_table_sector = sector::map(fd, prim_header.entries_lba, prim_header.entries_lba + 128*128/512 - 1);
+ sector::fetch(&prim_table_sector);
+
+ // Create the primary GPT copy
+ const primary = block {
+ header_sec = prim_header_sector,
+ entries_sec = prim_table_sector,
+ header = prim_header,
+ entries = prim_table_sector.buf: *[*]u8: *[128]entry
+ };
+
+
+ const back_header_sector = sector::map(fd, prim_header.backup_header_lba, prim_header.backup_header_lba);
+ sector::fetch(&back_header_sector);
+ const back_header = back_header_sector.buf: *[*]u8: *header;
+ //XXX validate header
+
+ const back_table_sector = sector::map(fd, back_header.entries_lba, back_header.entries_lba + 128*128/512 - 1);
+
+ sector::fetch(&back_table_sector);
+
+ // Create the backup block structure
+ let backup = block {
+ header_sec = back_header_sector,
+ entries_sec = back_table_sector,
+ header = back_header,
+ entries = back_table_sector.buf: *[*]u8: *[128]entry
+ };
+
+
+ const mbr_sec = sector::map(fd, 0, 0);
+
+ // Allocate the GPT structure
+ let self = alloc(gpt {
+ mbr_sec = mbr_sec,
+ mbr = mbr_sec.buf: *[*]u8: *mbr::mbr,
+ primary = primary,
+ backup = backup
+ });
+
+ // Fetch the MBR
+ sector::fetch(&self.mbr_sec);
+
+ return self;
+};
+
+// Frees the resources associated with the GPT structure.
+export fn finish(self: *gpt) void = {
+ sector::finish(&self.mbr_sec);
+ block_drop(&self.primary);
+ block_drop(&self.backup);
+ free(self);
+};
+
+// Updates the data structures from the disk
+export fn fetch(self: *gpt) void = {
+ sector::fetch(&self.mbr_sec);
+ block_fetch(&self.primary);
+ block_fetch(&self.backup);
+};
+
+export fn mkbackup(self: *gpt) void = {
+ rt::memcpy(self.backup.header, self.primary.header, size(header));
+ rt::memcpy(self.backup.entries, self.primary.entries, size([128]entry));
+
+ self.backup.header.header_lba = self.backup.header_sec.lba_begin;
+ self.backup.header.backup_header_lba = self.primary.header_sec.lba_begin;
+ self.backup.header.entries_lba = self.backup.entries_sec.lba_begin;
+};
+
+// Commits changed done on the data structure to the disk
+export fn commit(self: *gpt) void = {
+ // XXX: CRC32 checksum
+
+ sector::commit(&self.mbr_sec);
+ block_commit(&self.primary);
+ block_commit(&self.backup);
+ //const header = getheader(self);
+
+ // XXX: update copy
+ //sector::commit_at(self.mbr, self.mbr.fd, header.backup_header_lba);
+};
+
+// Updates the CRC32 checksums of the different blocks
+export fn chksums(self: *gpt) void = {
+ self.primary.header.header_crc32 = header_crc32(self.primary.header);
+ self.backup.header.header_crc32 = header_crc32(self.backup.header);
+};
+
+// Gets the MBR structure. Return value is borrowed from argument.
+export fn getmbr(self: *gpt) *mbr::mbr = {
+ return self.mbr_sec.buf: *[*]u8: *mbr::mbr;
+};
+
+// Gets the GPT primary header structure. Return value is borrowed from argument.
+export fn getheader(self: *gpt) *header = {
+ return block_getheader(&self.primary);
+};
+
+// Gets the GPT primary entries structures. Return value is borrowed from argument.
+export fn getentries(self: *gpt) []entry = {
+ return block_getentries(&self.primary);
+};