diff options
| author | Alejandro Sior <aho@sior.be> | 2022-06-17 14:43:27 +0200 |
|---|---|---|
| committer | Alejandro Sior <aho@sior.be> | 2022-06-17 14:43:27 +0200 |
| commit | 12577f3445df86023ba0cbe2462d55ea5dcafe20 (patch) | |
| tree | e72d03b6339084760d4c781cbbb5e7e4dd71385d /gpt/gpt.ha | |
| parent | 3c8602ee9f04991e1d60b8d6504e12296ca671d9 (diff) | |
gptman: now can allocate partitions
Diffstat (limited to 'gpt/gpt.ha')
| -rw-r--r-- | gpt/gpt.ha | 248 |
1 files changed, 157 insertions, 91 deletions
@@ -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); -}; |
