summaryrefslogtreecommitdiff
path: root/gpt/gpt.ha
diff options
context:
space:
mode:
authorAlejandro Sior <aho@sior.be>2022-06-17 14:43:27 +0200
committerAlejandro Sior <aho@sior.be>2022-06-17 14:43:27 +0200
commit12577f3445df86023ba0cbe2462d55ea5dcafe20 (patch)
treee72d03b6339084760d4c781cbbb5e7e4dd71385d /gpt/gpt.ha
parent3c8602ee9f04991e1d60b8d6504e12296ca671d9 (diff)
gptman: now can allocate partitions
Diffstat (limited to 'gpt/gpt.ha')
-rw-r--r--gpt/gpt.ha248
1 files changed, 157 insertions, 91 deletions
diff --git a/gpt/gpt.ha b/gpt/gpt.ha
index e1ebcfd..53ca37f 100644
--- a/gpt/gpt.ha
+++ b/gpt/gpt.ha
@@ -23,28 +23,14 @@ export type block = struct {
entries: *[128]entry
};
-fn block_getheader(self: *block) *header = {
- return self.header_sec.buf: *[*]u8: *header;
+fn block_commit(self: *block) (void | io::error) = {
+ sector::commit(&self.header_sec)?;
+ sector::commit(&self.entries_sec)?;
};
-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_fetch(self: *block) (void | io::error) = {
+ sector::fetch(&self.header_sec)?;
+ sector::fetch(&self.entries_sec)?;
};
fn block_drop(self: *block) void = {
@@ -69,6 +55,10 @@ export type header = struct {
@offset(88) entries_crc32: u32
};
+fn header_validate(self: *header) bool = {
+ return self.signature == 0x5452415020494645;
+};
+
export type entry = struct {
@offset(0) part_type: [2]u64,
@offset(16) part: [2]u64,
@@ -78,66 +68,159 @@ export type entry = struct {
@offset(56) name: [72]u8
};
-export fn validate(self: *gpt) bool = {
- if (getheader(self).signature != 0x5452415020494645) {
- return false;
- };
+export fn from(fd: io::file) (*gpt | nogpt | io::error) = {
+ // Get the primary header
+ const prim_header_sec = sector::map(fd, 1, 1);
+ sector::fetch(&prim_header_sec)?;
- return true;
-};
+ const prim_header = prim_header_sec.buf: *[*]u8: *header;
+ if (!header_validate(prim_header)) {
+ sector::finish(&prim_header_sec);
+ return nogpt;
+ };
-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
+ // Get the primary entries
+ const prim_entries_sec = sector::map(fd, prim_header.entries_lba, 128*128/512);
+ sector::fetch(&prim_entries_sec)?;
- const prim_table_sector = sector::map(fd, prim_header.entries_lba, prim_header.entries_lba + 128*128/512 - 1);
- sector::fetch(&prim_table_sector);
+ // Get the backup header
+ const back_header_sec = sector::map(fd, prim_header.backup_header_lba, 1);
+ sector::fetch(&back_header_sec)?;
- // 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 = back_header_sec.buf: *[*]u8: *header;
+ if (!header_validate(back_header)) {
+ sector::finish(&prim_header_sec);
+ sector::finish(&back_header_sec);
+ return nogpt;
};
+ // Get the backup entries
+ const back_entries_sec = sector::map(fd, back_header.entries_lba, 128*128/512);
+ sector::fetch(&back_entries_sec)?;
- 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 mbr_sec = sector::map(fd, 0, 1);
+ sector::fetch(&mbr_sec)?;
- const back_table_sector = sector::map(fd, back_header.entries_lba, back_header.entries_lba + 128*128/512 - 1);
+ // Allocate the GPT structure
+ let self = alloc(gpt {
+ mbr_sec = mbr_sec,
+ mbr = mbr_sec.buf: *[*]u8: *mbr::mbr,
+ primary = block {
+ header_sec = prim_header_sec,
+ entries_sec = prim_entries_sec,
+ header = prim_header,
+ entries = prim_entries_sec.buf: *[*]u8: *[128]entry
+ },
+ backup = block {
+ header_sec = back_header_sec,
+ entries_sec = back_entries_sec,
+ header = back_header,
+ entries = back_entries_sec.buf: *[*]u8: *[128]entry
+ }
+ });
- sector::fetch(&back_table_sector);
+ return self;
+};
- // 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
+export fn create(fd: io::file, freeno: size) *gpt = {
+ const entries_begin = 2z;
+ const free_begin = entries_begin + 128*128/512;
+ const bentries_begin = free_begin + freeno + 1;
+ const bheader_begin = bentries_begin + 128*128/512;
+
+ const mbr_sec = sector::map(fd, 0, 1);
+ const mbr = mbr_sec.buf: *[*]u8: *mbr::mbr;
+
+ const prim_header_sec = sector::map(fd, 1, 1);
+ const prim_header = prim_header_sec.buf: *[*]u8: *header;
+ *prim_header = header {
+ signature = 0x5452415020494645,
+ revision = 0x10000,
+ header_size = 92,
+ header_crc32 = 0,
+ reserved0 = 0,
+ header_lba = 1,
+ backup_header_lba = bheader_begin,
+ first_lba = free_begin,
+ last_lba = bentries_begin - 1,
+ disk_guid = [0xCAFEBABE, 0xCAFEBABE],
+ entries_lba = entries_begin,
+ entries_len = 128,
+ entry_size = 128,
+ entries_crc32 = 0,
};
+ const prim_entries_sec = sector::map(fd, entries_begin, 128*128/512);
+ const prim_entries = prim_entries_sec.buf: *[*]u8: *[128]entry;
- const mbr_sec = sector::map(fd, 0, 0);
+ const back_header_sec = sector::map(fd, bheader_begin, 1);
+ const back_header = back_header_sec.buf: *[*]u8: *header;
- // Allocate the GPT structure
+ const back_entries_sec = sector::map(fd, bentries_begin, 128*128/512);
+ const back_entries = back_entries_sec.buf: *[*]u8: *[128]entry;
+
let self = alloc(gpt {
mbr_sec = mbr_sec,
- mbr = mbr_sec.buf: *[*]u8: *mbr::mbr,
- primary = primary,
- backup = backup
+ mbr = mbr,
+ primary = block {
+ header_sec = prim_header_sec,
+ entries_sec = prim_entries_sec,
+ header = prim_header,
+ entries = prim_entries
+ },
+ backup = block {
+ header_sec = back_header_sec,
+ entries_sec = back_entries_sec,
+ header = back_header,
+ entries = back_entries
+ }
});
-
- // Fetch the MBR
- sector::fetch(&self.mbr_sec);
+
+ mkbackup(self);
return self;
};
+// Finds an lba for a new partition that fits the desired length
+export fn findfree(self: *gpt, length: u64) u64 = {
+ const header = self.primary.header;
+ const entries = self.primary.entries;
+
+ let cur = header.first_lba;
+
+ for (cur >= header.first_lba && cur + length <= header.last_lba) {
+ let i = 0z;
+ for (i < header.entries_len) {
+ defer i += 1;
+ if (entries[i].part_type[0] == 0 && entries[i].part_type[1] == 0)
+ continue;
+ if (overlap((cur, length), (entries[i].lba_begin, entries[i].lba_end - entries[i].lba_begin))) {
+ cur = entries[i].lba_end + 1;
+ break;
+ };
+ };
+
+ if (i == header.entries_len)
+ return cur;
+ };
+
+ return 0;
+};
+
+// Finds a GPT entry that is currently not used
+// The entry pointer returned is borrowed from the arguments
+export fn findfreeentry(self: *gpt) nullable *entry = {
+ const header = self.primary.header;
+ const entries = self.primary.entries;
+
+ for (let i = 0z; i < header.entries_len; i += 1) {
+ if (entries[i].part_type[0] == 0 && entries[i].part_type[1] == 0)
+ return &entries[i];
+ };
+
+ return null;
+};
+
// Frees the resources associated with the GPT structure.
export fn finish(self: *gpt) void = {
sector::finish(&self.mbr_sec);
@@ -147,51 +230,34 @@ export fn finish(self: *gpt) void = {
};
// 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 fetch(self: *gpt) (void | io::error) = {
+ sector::fetch(&self.mbr_sec)?;
+ block_fetch(&self.primary)?;
+ block_fetch(&self.backup)?;
};
+// Copies the current primary block into its backup
+// Note: does not compute the checksums (see chksums())
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;
+ self.backup.header.header_lba = self.backup.header_sec.offs;
+ self.backup.header.backup_header_lba = self.primary.header_sec.offs;
+ self.backup.header.entries_lba = self.backup.entries_sec.offs;
};
// 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);
+export fn commit(self: *gpt) (void | io::error) = {
+ sector::commit(&self.mbr_sec)?;
+ block_commit(&self.primary)?;
+ block_commit(&self.backup)?;
};
// Updates the CRC32 checksums of the different blocks
export fn chksums(self: *gpt) void = {
+ self.primary.header.entries_crc32 = entries_crc32(self.primary.entries);
+ self.backup.header.entries_crc32 = entries_crc32(self.backup.entries);
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);
-};