Michal Soltys
2010-Aug-08 00:10 UTC
[syslinux] PATCH/RFC chain.c: update iterator code, yank from chain.c, move both to separate directory
1) code split and move Iterator related functionality is yanked from chain.c and moved to iterator.{c,h}. Both are moved to com32/chain and this way chain.c is ready for further splitting. Alternatively, partiter could be moved to com32/lib at any time in the future. It's potentially useful for other modules (e.g. if someone wanted to code partition dumper or editor). 2) Iterator updates This part is actually pretty large: 2a) sanity checks - potential add/mul overflows are detected - partition related checks handled by notsane_{primary,logical,extended,gpt}() family of functions. They can be easily extended in the future. - additional checks in main pi_{gpt,dos}_next() functions and subfunctions 2b) EBR+MBR iterator merge They function now simply as 'dos' iterator (to keep naming consistent with disklib). Code is split into smaller functions, everything should look pretty logical. 2c) GPT iterator Core remained similar to previous version. Additional functionality includes: - extra small sanity check - empty partition is characterized by type guid == 0, not lba_first == 0 - automatic label rewrite from UCS2-LE to asciiz (to separate buffer) - export of partition guid (also to separate buffer) 2d) iterators *include* disk during iteration Right after creation, pi_begin() (previously get_first_partition()) does not iterate to first partition. 2e) available data at any time - disk guid or disk signature (sub.gpt.disk_guid or sub.dos_disk_sig) - parition guid (sub.gpt.part_guid) - parition label, asciiz (sub.gpt.part_label) - pointer to record holding unaltered partition entry (record) - iterator type (type) - lba beginning of partition (start_lba) - disk (0) / partition (1+) index (index) See partiter.h for details. 2f) pi_begin() It does sanity checks - including gpt's primary+backup+array crc checks - and allocates proper iterator. Some additional checks (mbr protective id, gpt revision, general sanity) are also performed. 2g) other stuff As previously, iterators self-destroy after finishing. They can be explicitly allocated through pi_new() (although this was exported mostly thinking about com32/lib) and removed through pi_del(); pi_next() moves iterator further. Partiter compiles cleanly with -Wextra -Wconversion -pedantic 2h) chain.c changes - find_by_guid() had small bug (took address of address of struct holding disk guid to compare) - find_by_{guid,label,disk} greately simplified due to extra data available from iterators - in main() - lba_fs takes clear precedence over regular partition number - changes necessary to include new iterator code - mbr/sect/hand/file's areas proper deallocation (from earlier patches) Code has been tested a lot with both gpt and legacy partitions, including holes (also logical ones) and partitions "not in disk" order (compared to the sample I sent offlist, it got one small bug fixed - the rest of changes are usually cosmetics/shuffling). Numbering is consistent with what linux kernel does. Michal Soltys (1): [RFC/PATCH] split chain into chain+iterator, expand iterators' code Makefile | 2 +- com32/Makefile | 2 +- com32/chain/Makefile | 39 ++ com32/{modules => chain}/chain.c | 568 +++++++----------------------- com32/chain/partiter.c | 714 ++++++++++++++++++++++++++++++++++++++ com32/chain/partiter.h | 94 +++++ com32/modules/Makefile | 2 +- 7 files changed, 985 insertions(+), 436 deletions(-) create mode 100644 com32/chain/Makefile rename com32/{modules => chain}/chain.c (68%) create mode 100644 com32/chain/partiter.c create mode 100644 com32/chain/partiter.h -- 1.7.2.1
Michal Soltys
2010-Aug-08 00:10 UTC
[syslinux] [RFC/PATCH] split chain into chain+iterator, expand iterators' code
Patch: - splits chain into chain and iterator parts and moves them into their own com32/chain directory - extensively updates iterators' code - adjusts chain.c to use new iterators - fixes mbr/sect/hand/file allocation Signed-off-by: Michal Soltys <soltys at ziu.info> --- Makefile | 2 +- com32/Makefile | 2 +- com32/chain/Makefile | 39 ++ com32/{modules => chain}/chain.c | 568 +++++++----------------------- com32/chain/partiter.c | 714 ++++++++++++++++++++++++++++++++++++++ com32/chain/partiter.h | 94 +++++ com32/modules/Makefile | 2 +- 7 files changed, 985 insertions(+), 436 deletions(-) create mode 100644 com32/chain/Makefile rename com32/{modules => chain}/chain.c (68%) create mode 100644 com32/chain/partiter.c create mode 100644 com32/chain/partiter.h diff --git a/Makefile b/Makefile index da90cdc..9ab401b 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ include $(topdir)/MCONFIG MODULES = memdisk/memdisk memdump/memdump.com modules/*.com \ com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \ com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \ - com32/sysdump/*.c32 com32/lua/src/*.c32 + com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 # syslinux.exe is BTARGET so as to not require everyone to have the # mingw suite installed diff --git a/com32/Makefile b/com32/Makefile index b090c40..43847bd 100644 --- a/com32/Makefile +++ b/com32/Makefile @@ -1,5 +1,5 @@ SUBDIRS = tools lib gpllib libutil modules mboot menu samples rosh cmenu \ - hdt gfxboot sysdump lua/src + hdt gfxboot sysdump lua/src chain all tidy dist clean spotless install: set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done diff --git a/com32/chain/Makefile b/com32/chain/Makefile new file mode 100644 index 0000000..16086ba --- /dev/null +++ b/com32/chain/Makefile @@ -0,0 +1,39 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2010 H. Peter Anvin - All Rights Reserved +## Copyright 2010 Michal Soltys +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + + +topdir = ../.. +include ../MCONFIG + +OBJS = chain.o partiter.o +#GCCWARN += -Wextra -Wconversion -pedantic -Wno-error + +all: chain.c32 + +chain.elf: $(OBJS) $(LIBS) $(C_LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +tidy dist: + rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp + +clean: tidy + rm -f *.lnx + +spotless: clean + rm -f *.lss *.c32 *.com + rm -f *~ \#* + +install: + + +-include .*.d diff --git a/com32/modules/chain.c b/com32/chain/chain.c similarity index 68% rename from com32/modules/chain.c rename to com32/chain/chain.c index 60e3abc..68c2476 100644 --- a/com32/modules/chain.c +++ b/com32/chain/chain.c @@ -119,6 +119,7 @@ #include <syslinux/config.h> #include <syslinux/disk.h> #include <syslinux/video.h> +#include "partiter.h" static struct options { const char *loadfile; @@ -148,319 +149,28 @@ static inline void error(const char *msg) static struct disk_info diskinfo; /* Search for a specific drive, based on the MBR signature; bytes 440-443 */ -static int find_disk(uint32_t mbr_sig) +static int find_by_sig(uint32_t mbr_sig) { + struct part_iter *boot_part = NULL; int drive; - bool is_me; - struct disk_dos_mbr *mbr; for (drive = 0x80; drive <= 0xff; drive++) { if (disk_get_params(drive, &diskinfo)) continue; /* Drive doesn't exist */ - if (!(mbr = disk_read_sectors(&diskinfo, 0, 1))) - continue; /* Cannot read sector */ - is_me = (mbr->disk_sig == mbr_sig); - free(mbr); - if (is_me) - return drive; - } - return -1; -} - -/* Forward declaration */ -struct disk_part_iter; - -/* Partition-/scheme-specific routine returning the next partition */ -typedef struct disk_part_iter *(*disk_part_iter_func) (struct disk_part_iter * - part); - -/* Contains details for a partition under examination */ -struct disk_part_iter { - /* The block holding the table we are part of */ - char *block; - /* The LBA for the beginning of data */ - uint64_t lba_data; - /* The partition number, as determined by our heuristic */ - int index; - /* The DOS partition record to pass, if applicable */ - const struct disk_dos_part_entry *record; - /* Function returning the next available partition */ - disk_part_iter_func next; - /* Partition-/scheme-specific details */ - union { - /* MBR specifics */ - int mbr_index; - /* EBR specifics */ - struct { - /* The first extended partition's start LBA */ - uint64_t lba_extended; - /* Any applicable parent, or NULL */ - struct disk_part_iter *parent; - /* The parent extended partition index */ - int parent_index; - } ebr; - /* GPT specifics */ - struct { - /* Real (not effective) index in the partition table */ - int index; - /* Current partition GUID */ - const struct guid *part_guid; - /* Current partition label */ - const char *part_label; - /* Count of entries in GPT */ - int parts; - /* Partition record size */ - uint32_t size; - } gpt; - } private; -}; - -static struct disk_part_iter *next_ebr_part(struct disk_part_iter *part) -{ - const struct disk_dos_part_entry *ebr_table; - const struct disk_dos_part_entry *parent_table - ((const struct disk_dos_mbr *)part->private.ebr.parent->block)->table; - static const struct disk_dos_part_entry phony = {.start_lba = 0 }; - uint64_t ebr_lba; - - /* Don't look for a "next EBR" the first time around */ - if (part->private.ebr.parent_index >= 0) - /* Look at the linked list */ - ebr_table = ((const struct disk_dos_mbr *)part->block)->table + 1; - /* Do we need to look for an extended partition? */ - if (part->private.ebr.parent_index < 0 || !ebr_table->start_lba) { - /* Start looking for an extended partition in the MBR */ - while (++part->private.ebr.parent_index < 4) { - uint8_t type = parent_table[part->private.ebr.parent_index].ostype; - - if ((type == 0x05) || (type == 0x0F) || (type == 0x85)) - break; - } - if (part->private.ebr.parent_index == 4) - /* No extended partitions found */ - goto out_finished; - part->private.ebr.lba_extended - parent_table[part->private.ebr.parent_index].start_lba; - ebr_table = &phony; - } - /* Load next EBR */ - ebr_lba = ebr_table->start_lba + part->private.ebr.lba_extended; - free(part->block); - part->block = disk_read_sectors(&diskinfo, ebr_lba, 1); - if (!part->block) { - error("Could not load EBR!\n"); - goto err_ebr; - } - ebr_table = ((const struct disk_dos_mbr *)part->block)->table; - dprintf("next_ebr_part:\n"); - disk_dos_part_dump(ebr_table); - - /* - * Sanity check entry: must not extend outside the - * extended partition. This is necessary since some OSes - * put crap in some entries. - */ - { - const struct disk_dos_mbr *mbr - (const struct disk_dos_mbr *)part->private.ebr.parent->block; - const struct disk_dos_part_entry *extended - mbr->table + part->private.ebr.parent_index; - - if (ebr_table[0].start_lba >= extended->start_lba + extended->length) { - dprintf("Insane logical partition!\n"); - goto err_insane; - } - } - /* Success */ - part->lba_data = ebr_table[0].start_lba + ebr_lba; - dprintf("Partition %d logical lba %u\n", part->index, part->lba_data); - part->index++; - part->record = ebr_table; - return part; - -err_insane: - - free(part->block); - part->block = NULL; -err_ebr: - -out_finished: - free(part->private.ebr.parent->block); - free(part->private.ebr.parent); - free(part->block); - free(part); - return NULL; -} - -static struct disk_part_iter *next_mbr_part(struct disk_part_iter *part) -{ - struct disk_part_iter *ebr_part; - /* Look at the partition table */ - struct disk_dos_part_entry *table - ((struct disk_dos_mbr *)part->block)->table; - - /* Look for data partitions */ - while (++part->private.mbr_index < 4) { - uint8_t type = table[part->private.mbr_index].ostype; - - if (type == 0x00 || type == 0x05 || type == 0x0F || type == 0x85) - /* Skip empty or extended partitions */ + /* Check for a MBR disk */ + boot_part = pi_begin(&diskinfo); + if (boot_part->type != typedos) { + pi_del(&boot_part); continue; - if (!table[part->private.mbr_index].length) - /* Empty */ - continue; - break; - } - /* If we're currently the last partition, it's time for EBR processing */ - if (part->private.mbr_index == 4) { - /* Allocate another iterator for extended partitions */ - ebr_part = malloc(sizeof(*ebr_part)); - if (!ebr_part) { - error("Could not allocate extended partition iterator!\n"); - goto err_alloc; } - /* Setup EBR iterator parameters */ - ebr_part->block = NULL; - ebr_part->index = 4; - ebr_part->record = NULL; - ebr_part->next = next_ebr_part; - ebr_part->private.ebr.parent = part; - /* Trigger an initial EBR load */ - ebr_part->private.ebr.parent_index = -1; - /* The EBR iterator is responsible for freeing us */ - return next_ebr_part(ebr_part); - } - dprintf("next_mbr_part:\n"); - disk_dos_part_dump(table + part->private.mbr_index); - - /* Update parameters to reflect this new partition. Re-use iterator */ - part->lba_data = table[part->private.mbr_index].start_lba; - dprintf("Partition %d primary lba %u\n", part->private.mbr_index, part->lba_data); - part->index = part->private.mbr_index + 1; - part->record = table + part->private.mbr_index; - return part; - - free(ebr_part); -err_alloc: - - free(part->block); - free(part); - return NULL; -} - -static struct disk_part_iter *next_gpt_part(struct disk_part_iter *part) -{ - const struct disk_gpt_part_entry *gpt_part = NULL; - - while (++part->private.gpt.index < part->private.gpt.parts) { - gpt_part - (const struct disk_gpt_part_entry *)(part->block + - (part->private.gpt.index * - part->private.gpt.size)); - if (!gpt_part->lba_first) - continue; - break; - } - /* Were we the last partition? */ - if (part->private.gpt.index == part->private.gpt.parts) { - goto err_last; - } - part->lba_data = gpt_part->lba_first; - part->private.gpt.part_guid = &gpt_part->uid; - part->private.gpt.part_label = gpt_part->name; - /* Update our index */ - part->index = part->private.gpt.index + 1; -#ifdef DEBUG - disk_gpt_part_dump(gpt_part); -#endif - - /* In a GPT scheme, we re-use the iterator */ - return part; - -err_last: - free(part->block); - free(part); - - return NULL; -} - -static struct disk_part_iter *get_first_partition(struct disk_part_iter *part) -{ - const struct disk_gpt_header *gpt_candidate; - - /* - * Ignore any passed partition iterator. The caller should - * have passed NULL. Allocate a new partition iterator - */ - part = malloc(sizeof(*part)); - if (!part) { - error("Count not allocate partition iterator!\n"); - goto err_alloc_iter; - } - /* Read MBR */ - part->block = disk_read_sectors(&diskinfo, 0, 2); - if (!part->block) { - error("Could not read two sectors!\n"); - goto err_read_mbr; - } - /* Check for an MBR */ - if (((struct disk_dos_mbr *)part->block)->sig != disk_mbr_sig_magic) { - error("No MBR magic!\n"); - goto err_mbr; - } - /* Establish a pseudo-partition for the MBR (index 0) */ - part->index = 0; - part->record = NULL; - part->private.mbr_index = -1; - part->next = next_mbr_part; - /* Check for a GPT disk */ - gpt_candidate = (const struct disk_gpt_header *)(part->block + SECTOR); - if (!memcmp - (gpt_candidate->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) { - /* LBA for partition table */ - uint64_t lba_table; - - /* It looks like one */ - /* TODO: Check checksum. Possibly try alternative GPT */ -#if DEBUG - puts("Looks like a GPT disk."); - disk_gpt_header_dump(gpt_candidate); -#endif - /* TODO: Check table checksum (maybe) */ - /* Note relevant GPT details */ - part->next = next_gpt_part; - part->private.gpt.index = -1; - part->private.gpt.parts = gpt_candidate->part_count; - part->private.gpt.size = gpt_candidate->part_size; - lba_table = gpt_candidate->lba_table; - gpt_candidate = NULL; - /* Load the partition table */ - free(part->block); - part->block - disk_read_sectors(&diskinfo, lba_table, - ((part->private.gpt.size * - part->private.gpt.parts) + SECTOR - - 1) / SECTOR); - if (!part->block) { - error("Could not read GPT partition list!\n"); - goto err_gpt_table; + if (boot_part->sub.dos.disk_sig == mbr_sig) { + pi_del(&boot_part); + goto ok; } } - /* Return the pseudo-partition's next partition, which is real */ - return part->next(part); - -err_gpt_table: - -err_mbr: - - free(part->block); - part->block = NULL; -err_read_mbr: - - free(part); -err_alloc_iter: - - return NULL; + drive = -1; +ok: + return drive; } /* @@ -472,45 +182,35 @@ err_alloc_iter: * found, we return -1. */ static int find_by_guid(const struct guid *gpt_guid, - struct disk_part_iter **boot_part) + struct part_iter **_boot_part) { + struct part_iter *boot_part = NULL; int drive; - bool is_me; - struct disk_gpt_header *header; for (drive = 0x80; drive <= 0xff; drive++) { if (disk_get_params(drive, &diskinfo)) continue; /* Drive doesn't exist */ - if (!(header = disk_read_sectors(&diskinfo, 1, 1))) - continue; /* Cannot read sector */ - if (memcmp - (&header->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) { - /* Not a GPT disk */ - free(header); + /* Check for a GPT disk */ + boot_part = pi_begin(&diskinfo); + if (boot_part->type != typegpt) { + pi_del(&boot_part); continue; } -#if DEBUG - disk_gpt_header_dump(header); -#endif - is_me = !memcmp(&header->disk_guid, &gpt_guid, sizeof(*gpt_guid)); - free(header); - if (!is_me) { - /* Check for a matching partition */ - boot_part[0] = get_first_partition(NULL); - while (boot_part[0]) { - is_me - !memcmp(boot_part[0]->private.gpt.part_guid, gpt_guid, - sizeof(*gpt_guid)); - if (is_me) - break; - boot_part[0] = boot_part[0]->next(boot_part[0]); - } - } else - boot_part[0] = NULL; - if (is_me) - return drive; + /* Check for a matching GPT disk guid */ + if(!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) { + pi_del(&boot_part); + goto ok; + } + /* disk guid doesn't match, maybe partition guid will */ + while (pi_next(&boot_part)) { + if(!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid))) + goto ok; + } } - return -1; + drive = -1; +ok: + *_boot_part = boot_part; + return drive; } /* @@ -520,47 +220,30 @@ static int find_by_guid(const struct guid *gpt_guid, * If no matching partition is found, boot_part will be populated with * NULL and we return -1. */ -static int find_by_label(const char *label, struct disk_part_iter **boot_part) +static int find_by_label(const char *label, struct part_iter **_boot_part) { + struct part_iter *boot_part = NULL; int drive; - bool is_me; for (drive = 0x80; drive <= 0xff; drive++) { if (disk_get_params(drive, &diskinfo)) continue; /* Drive doesn't exist */ /* Check for a GPT disk */ - boot_part[0] = get_first_partition(NULL); - if (!(boot_part[0]->next == next_gpt_part)) { - /* Not a GPT disk */ - while (boot_part[0]) { - /* Run through until the end */ - boot_part[0] = boot_part[0]->next(boot_part[0]); - } + boot_part = pi_begin(&diskinfo); + if (!(boot_part->type == typegpt)) { + pi_del(&boot_part); continue; } /* Check for a matching partition */ - while (boot_part[0]) { - char gpt_label[sizeof(((struct disk_gpt_part_entry *) NULL)->name)]; - const char *gpt_label_scanner - boot_part[0]->private.gpt.part_label; - int j = 0; - - /* Re-write the GPT partition label as ASCII */ - while (gpt_label_scanner < - boot_part[0]->private.gpt.part_label + sizeof(gpt_label)) { - if ((gpt_label[j] = *gpt_label_scanner)) - j++; - gpt_label_scanner++; - } - if ((is_me = !strcmp(label, gpt_label))) - break; - boot_part[0] = boot_part[0]->next(boot_part[0]); + while (pi_next(&boot_part)) { + if (!strcmp(label, boot_part->sub.gpt.part_label)) + goto ok; } - if (is_me) - return drive; } - - return -1; + drive = -1; +ok: + *_boot_part = boot_part; + return drive; } static void do_boot(struct data_area *data, int ndata, @@ -698,10 +381,8 @@ static int hide_unhide(struct disk_dos_mbr *mbr, int part) int i; struct disk_dos_part_entry *pt; const uint16_t mask - (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | (1 << 0x07) | (1 << 0x0b) | (1 - << - 0x0c) - | (1 << 0x0e); + (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | + (1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e); uint8_t t; bool write_back = false; @@ -802,7 +483,12 @@ int main(int argc, char *argv[]) { struct disk_dos_mbr *mbr = NULL; char *p; - struct disk_part_iter *cur_part = NULL; + struct part_iter *cur_part = NULL; + + void *sect_area = NULL; + void *file_area = NULL; + struct disk_dos_part_entry *hand_area = NULL; + struct syslinux_rm_regs regs; char *drivename, *partition; int hd, drive, whichpart = 0; /* MBR by default */ @@ -918,7 +604,7 @@ int main(int argc, char *argv[]) hd = 0; if (!strncmp(drivename, "mbr", 3)) { - drive = find_disk(strtoul(drivename + 4, NULL, 0)); + drive = find_by_sig(strtoul(drivename + 4, NULL, 0)); if (drive == -1) { error("Unable to find requested MBR signature\n"); goto bail; @@ -982,33 +668,45 @@ int main(int argc, char *argv[]) if (partition) whichpart = strtoul(partition, NULL, 0); - /* "guid:" or "label:" might have specified a partition */ + + /* "guid:" or "label:" might have specified a partition. In such case, + * this overrides explicit partition number specification. cur-part->index + * can't be 0 at this stage as find_by* won't export iterator at such + * position. + */ if (cur_part) whichpart = cur_part->index; - /* Boot the MBR by default */ - if (!cur_part && (whichpart || fs_lba)) { - /* Boot a partition, possibly the Syslinux partition itself */ - cur_part = get_first_partition(NULL); - while (cur_part) { - if ((cur_part->index == whichpart) - || (cur_part->lba_data == fs_lba)) - /* Found the partition to boot */ + /* If nothing was found, try fs/boot first */ + if (!cur_part && fs_lba) { + cur_part = pi_begin(&diskinfo); + /* search for matching fs_lba, must be partition */ + while (pi_next(&cur_part)) { + if (cur_part->start_lba == fs_lba) break; - cur_part = cur_part->next(cur_part); - } - if (!cur_part) { - error("Requested partition not found!\n"); - goto bail; } - whichpart = cur_part->index; } + /* If still nothing found, do standard search */ + if (!cur_part) { + cur_part = pi_begin(&diskinfo); + /* search for matching part#, including disk */ + do { + if (cur_part->index == whichpart) + break; + } while (pi_next(&cur_part)); + } + if (!cur_part) { + error("Requested disk / partition not found!\n"); + goto bail; + } + + whichpart = cur_part->index; if (!(drive & 0x80) && whichpart) { error("Warning: Partitions of floppy devices may not work\n"); } - /* + /* * GRLDR of GRUB4DOS wants the partition number in DH: * -1: whole drive (default) * 0-3: primary partitions @@ -1034,6 +732,7 @@ int main(int argc, char *argv[]) goto bail; } data[ndata].base = load_base; + file_area = (void *)data[ndata].data; load_base = 0x7c00; /* If we also load a boot sector */ /* Create boot info table: needed when you want to chainload @@ -1058,7 +757,7 @@ int main(int argc, char *argv[]) boot file starting at byte offset 64. All linear block addresses (LBAs) are given in CD sectors (normally 2048 bytes). - LBA of primary volume descriptor should already be set to 16. + LBA of primary volume descriptor should already be set to 16. */ isolinux_bin = (unsigned char *)data[ndata].data; @@ -1176,7 +875,7 @@ int main(int argc, char *argv[]) * another location. * * Partition numbers always start from zero. - * Unused partition bytes must be set to 0xFF. + * Unused partition bytes must be set to 0xFF. * * We only care about top-level partition, so we only need to change * "part1" to the appropriate value: @@ -1207,15 +906,15 @@ int main(int argc, char *argv[]) if (!opt.loadfile || data[0].base >= 0x7c00 + SECTOR) { /* Actually read the boot sector */ - if (!cur_part) { + if (!cur_part->index) { data[ndata].data = mbr; } else - if (! - (data[ndata].data - disk_read_sectors(&diskinfo, cur_part->lba_data, 1))) { + if (!(data[ndata].data + disk_read_sectors(&diskinfo, cur_part->start_lba, 1))) { error("Cannot read boot sector\n"); goto bail; - } + } else + sect_area = (void *)data[ndata].data; data[ndata].size = SECTOR; data[ndata].base = load_base; @@ -1235,7 +934,7 @@ int main(int argc, char *argv[]) * the string "cmdcons\0" to memory location 0000:7C03. * Memory location 0000:7C00 contains the bootsector of the partition. */ - if (cur_part && opt.cmldr) { + if (cur_part->index && opt.cmldr) { memcpy((char *)data[ndata].data + 3, cmldr_signature, sizeof cmldr_signature); } @@ -1245,94 +944,97 @@ int main(int argc, char *argv[]) * this modifies the field used by FAT and NTFS filesystems, and * possibly other boot loaders which use the same format. */ - if (cur_part && opt.sethidden) { - *(uint32_t *) ((char *)data[ndata].data + 28) = cur_part->lba_data; + if (cur_part->index && opt.sethidden) { + *(uint32_t *) ((char *)data[ndata].data + 28) = cur_part->start_lba; } ndata++; } - if (cur_part) { - if (cur_part->next == next_gpt_part) { + if (cur_part->index) { + if (cur_part->type == typegpt) { /* Do GPT hand-over, if applicable (as per syslinux/doc/gpt.txt) */ - struct disk_dos_part_entry *record; /* Look at the GPT partition */ const struct disk_gpt_part_entry *gp - (const struct disk_gpt_part_entry *) - (cur_part->block + - (cur_part->private.gpt.size * cur_part->private.gpt.index)); + (const struct disk_gpt_part_entry *)cur_part->record; /* Note the partition length */ uint64_t lba_count = gp->lba_last - gp->lba_first + 1; /* The length of the hand-over */ - int synth_size + uint32_t synth_size sizeof(struct disk_dos_part_entry) + sizeof(uint32_t) + - cur_part->private.gpt.size; + cur_part->sub.gpt.pe_size; /* Will point to the partition record length in the hand-over */ uint32_t *plen; /* Allocate the hand-over record */ - record = malloc(synth_size); - if (!record) { + hand_area = malloc(synth_size); + if (!hand_area) { error("Could not build GPT hand-over record!\n"); goto bail; } /* Synthesize the record */ - memset(record, 0, synth_size); - record->active_flag = 0x80; - record->ostype = 0xED; + memset(hand_area, 0, synth_size); + hand_area->active_flag = 0x80; + hand_area->ostype = 0xED; /* All bits set by default */ - record->start_lba = ~(uint32_t) 0; - record->length = ~(uint32_t) 0; + hand_area->start_lba = ~(uint32_t) 0; + hand_area->length = ~(uint32_t) 0; /* If these fit the precision, pass them on */ - if (cur_part->lba_data < record->start_lba) - record->start_lba = cur_part->lba_data; - if (lba_count < record->length) - record->length = lba_count; + if (cur_part->start_lba < hand_area->start_lba) + hand_area->start_lba = cur_part->start_lba; + if (lba_count < hand_area->length) + hand_area->length = lba_count; /* Next comes the GPT partition record length */ - plen = (uint32_t *) (record + 1); - plen[0] = cur_part->private.gpt.size; + plen = (uint32_t *) (hand_area + 1); + plen[0] = cur_part->sub.gpt.pe_size; /* Next comes the GPT partition record copy */ memcpy(plen + 1, gp, plen[0]); - cur_part->record = record; regs.eax.l = 0x54504721; /* '!GPT' */ data[ndata].base = 0x7be; data[ndata].size = synth_size; - data[ndata].data = (void *)record; + data[ndata].data = (void *)hand_area; ndata++; regs.esi.w[0] = 0x7be; - - dprintf("GPT handover:\n"); - disk_dos_part_dump(record); #ifdef DEBUG + dprintf("GPT handover:\n"); + disk_dos_part_dump(hand_area); disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1)); #endif - } else if (cur_part->record) { + } else { /* MBR handover protocol */ - static struct disk_dos_part_entry handover_record; + /* Allocate the hand-over record */ + hand_area = malloc(sizeof(struct disk_dos_part_entry)); + if (!hand_area) { + error("Could not build MBR hand-over record!\n"); + goto bail; + } - handover_record = *cur_part->record; - handover_record.start_lba = cur_part->lba_data; + memcpy(hand_area, cur_part->record, sizeof(struct disk_dos_part_entry)); + hand_area->start_lba = cur_part->start_lba; data[ndata].base = 0x7be; - data[ndata].size = sizeof handover_record; - data[ndata].data = &handover_record; + data[ndata].size = sizeof(struct disk_dos_part_entry); + data[ndata].data = (void *)hand_area; ndata++; regs.esi.w[0] = 0x7be; - +#ifdef DEBUG dprintf("MBR handover:\n"); - disk_dos_part_dump(&handover_record); + disk_dos_part_dump(hand_area); +#endif } } do_boot(data, ndata, ®s); bail: - if (cur_part) { - free(cur_part->block); - free((void *)cur_part->record); - } - free(cur_part); + pi_del(&cur_part); + /* Free allocated areas */ free(mbr); + free(file_area); + free(sect_area); + free(hand_area); return 255; } + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c new file mode 100644 index 0000000..4b76e22 --- /dev/null +++ b/com32/chain/partiter.c @@ -0,0 +1,714 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved + * Copyright 2010 Shao Miller + * Copyright 2010 Michal Soltys + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * partiter.c + * + * Provides disk / partition iteration. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <zlib.h> +#include <syslinux/disk.h> +#include "partiter.h" + +#define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85) +#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00) +#define sane(s,l) ((s)+(l) > (s)) + +/* this is chosen to follow how many sectors disklib can read at once */ +#define MAXGPTPTSIZE (255u*SECTOR) + +static void error(const char *msg) +{ + fputs(msg, stderr); +} + +/* forwards */ + +static int iter_dos_ctor(struct part_iter *, va_list *); +static int iter_gpt_ctor(struct part_iter *, va_list *); +static void iter_dtor(struct part_iter *); +static struct part_iter *pi_dos_next(struct part_iter *); +static struct part_iter *pi_gpt_next(struct part_iter *); + +static struct itertype types[] = { + [0] = { + .ctor = &iter_dos_ctor, + .dtor = &iter_dtor, + .next = &pi_dos_next, +}, [1] = { + .ctor = &iter_gpt_ctor, + .dtor = &iter_dtor, + .next = &pi_gpt_next, +}}; + +const struct itertype * const typedos = types; +const struct itertype * const typegpt = types+1; + +static int inv_type(const void *type) +{ + int i, cnt = sizeof(types)/sizeof(types[0]); + for (i = 0; i < cnt; i++) { + if (type == types + i) + return 0; + } + return -1; +} + +static int guid_is0(const struct guid *guid) +{ + return !*(const uint64_t *)guid && !*((const uint64_t *)guid+1); +} + +/** + * iter_ctor() - common iterator initialization + * @iter: iterator pointer + * @args(0): disk_info structure used for disk functions + * + * Second and further arguments are passed as a pointer to va_list + **/ +static int iter_ctor(struct part_iter *iter, va_list *args) +{ + const struct disk_info *di = va_arg(*args, const struct disk_info *); + + if (!di) + return -1; + + memcpy(&iter->di, di, sizeof(struct disk_info)); + + return 0; +} + +/** + * iter_dtor() - common iterator cleanup + * @iter: iterator pointer + * + **/ +static void iter_dtor(struct part_iter *iter) +{ + free(iter->data); +} + +/** + * iter_dos_ctor() - MBR/EBR iterator specific initialization + * @iter: iterator pointer + * @args(0): disk_info structure used for disk functions + * @args(1): pointer to buffer with loaded valid MBR + * + * Second and further arguments are passed as a pointer to va_list. + * This function only makes rudimentary checks. If user uses + * pi_new(), he/she is responsible for doing proper sanity checks. + **/ +static int iter_dos_ctor(struct part_iter *iter, va_list *args) +{ + const struct disk_dos_mbr *mbr; + + /* uses args(0) */ + if (iter_ctor(iter, args)) + return -1; + + mbr = va_arg(*args, const struct disk_dos_mbr *); + + if (!mbr) + goto out; + + if (!(iter->data = malloc(sizeof(struct disk_dos_mbr)))) + goto out; + + memcpy(iter->data, mbr, sizeof(struct disk_dos_mbr)); + + iter->sub.dos.index0 = -1; + iter->sub.dos.bebr_index0 = -1; + iter->sub.dos.disk_sig = mbr->disk_sig; + + return 0; +out: + iter->type->dtor(iter); + return -1; +} + +/** + * iter_gpt_ctor() - GPT iterator specific initialization + * @iter: iterator pointer + * @args(0): ptr to disk_info structure + * @args(1): ptr to buffer with GPT header + * @args(2): ptr to buffer with GPT partition list + * + * Second and further arguments are passed as a pointer to va_list. + * This function only makes rudimentary checks. If user uses + * pi_new(), he/she is responsible for doing proper sanity checks. + **/ +static int iter_gpt_ctor(struct part_iter *iter, va_list *args) +{ + uint64_t siz; + const struct disk_gpt_header *gpth; + const struct disk_gpt_part_entry *gptl; + + /* uses args(0) */ + if (iter_ctor(iter, args)) + return -1; + + gpth = va_arg(*args, const struct disk_gpt_header *); + gptl = va_arg(*args, const struct disk_gpt_part_entry *); + + if (!gpth || !gptl) + goto out; + + siz = (uint64_t)gpth->part_count * (uint64_t)gpth->part_size; + + if (!siz || siz > MAXGPTPTSIZE || + gpth->part_size < sizeof(struct disk_gpt_part_entry)) { + goto out; + } + + if (!(iter->data = malloc((size_t)siz))) + goto out; + + memcpy(iter->data, gptl, (size_t)siz); + + iter->sub.gpt.index0 = -1; + iter->sub.gpt.pe_count = (int)gpth->part_count; + iter->sub.gpt.pe_size = (int)gpth->part_size; + memcpy(&iter->sub.gpt.disk_guid, &gpth->disk_guid, sizeof(struct guid)); + + return 0; + +out: + iter->type->dtor(iter); + return -1; +} + +/* Logical partition must be sane, meaning: + * - must be data or empty + * - must have non-0 start and length + * - values must not wrap around 32bit + * - must be inside current EBR frame + */ + +static int notsane_logical(const struct part_iter *iter) +{ + const struct disk_dos_part_entry *dp; + uint32_t end_log; + + dp = ((struct disk_dos_mbr *)iter->data)->table; + + if (!dp[0].ostype) + return 0; + + if (ost_is_ext(dp[0].ostype)) { + error("1st EBR entry must be data or empty.\n"); + return -1; + } + + end_log = dp[0].start_lba + dp[0].length; + + if (!dp[0].start_lba || + !dp[0].length || + !sane(dp[0].start_lba, dp[0].length) || + end_log > iter->sub.dos.ebr_size) { + + error("Insane logical partition.\n"); + return -1; + } + + return 0; +} + +/* Extended partition must be sane, meaning: + * - must be extended or empty + * - must have non-0 start and length + * - values must not wrap around 32bit + * - must be inside base EBR frame + */ + +static int notsane_extended(const struct part_iter *iter) +{ + const struct disk_dos_part_entry *dp; + uint32_t end_ebr; + + dp = ((struct disk_dos_mbr *)iter->data)->table; + + if (!dp[1].ostype) + return 0; + + if (!ost_is_nondata(dp[1].ostype)) { + error("2nd EBR entry must be extended or empty.\n"); + return -1; + } + + end_ebr = dp[1].start_lba + dp[1].length; + + if (!dp[1].start_lba || + !dp[1].length || + !sane(dp[1].start_lba, dp[1].length) || + end_ebr > iter->sub.dos.bebr_size) { + + error("Insane extended partition.\n"); + return -1; + } + + return 0; +} + +/* Primary partition must be sane, meaning: + * - must have non-0 start and length + * - values must not wrap around 32bit + */ + +static int notsane_primary(const struct disk_dos_part_entry *dp) +{ + if (!dp->ostype) + return 0; + + if (!dp->start_lba || + !dp->length || + !sane(dp->start_lba, dp->length)) { + error("Insane primary (MBR) partition.\n"); + return -1; + } + + return 0; +} + +static int notsane_gpt(const struct disk_gpt_part_entry *gp) +{ + if (guid_is0(&gp->type)) + return 0; + + if (!gp->lba_first || + !gp->lba_last || + gp->lba_first > gp->lba_last) { + error("Insane GPT partition.\n"); + return -1; + } + + return 0; +} + +static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba, + struct disk_dos_part_entry **_dp) +{ + struct disk_dos_part_entry *dp; + + while (++iter->sub.dos.index0 < 4) { + dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.index0; + + if (notsane_primary(dp)) + return -1; + + if (ost_is_ext(dp->ostype)) { + if (iter->sub.dos.bebr_index0 >= 0) { + error("You have more than 1 extended partition.\n"); + return -1; + } + /* record base EBR index */ + iter->sub.dos.bebr_index0 = iter->sub.dos.index0; + } + if (ost_is_nondata(dp->ostype)) + continue; + + break; + } + + *lba = dp->start_lba; + *_dp = dp; + return 0; +} + +static int prep_base_ebr(struct part_iter *iter) +{ + struct disk_dos_part_entry *dp; + + if (iter->sub.dos.bebr_index0 < 0) + return -1; + else if (!iter->sub.dos.bebr_start) { + dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.bebr_index0; + + iter->sub.dos.bebr_start = dp->start_lba; + iter->sub.dos.bebr_size = dp->length; + + iter->sub.dos.ebr_start = 0; + iter->sub.dos.ebr_size = iter->sub.dos.bebr_size; + + iter->sub.dos.index0--; + } + return 0; +} + +static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba, + struct disk_dos_part_entry **_dp) +{ + struct disk_dos_part_entry *dp; + uint32_t abs_ebr; + + if (prep_base_ebr(iter)) + return -1; + + if(++iter->sub.dos.index0 >= 1024) + /* that's one paranoid upper bound */ + return -1; + + while (iter->sub.dos.ebr_size) { + + abs_ebr = iter->sub.dos.bebr_start + iter->sub.dos.ebr_start; + + /* load ebr for current iteration */ + free(iter->data); + if (!(iter->data = disk_read_sectors(&iter->di, abs_ebr, 1))) { + error("Couldn't load EBR.\n"); + break; + } + + if (notsane_logical(iter) || notsane_extended(iter)) + break; + + dp = ((struct disk_dos_mbr *)iter->data)->table; + abs_ebr += dp[0].start_lba; + + /* setup next frame values */ + if (dp[1].ostype) { + iter->sub.dos.ebr_start = dp[1].start_lba; + iter->sub.dos.ebr_size = dp[1].length; + } else { + iter->sub.dos.ebr_size = 0; + } + + if (dp[0].ostype) { + *lba = abs_ebr; + *_dp = dp; + return 0; + } + /* + * This way it's possible to continue, if some crazy soft left a "hole" + * - EBR with a valid extended partition without a logical one. In + * such case, linux will not reserve a number for such hole - so we + * don't increase index0. + */ + } + return -1; +} + +static struct part_iter *pi_dos_next(struct part_iter *iter) +{ + uint32_t start_lba = 0; + struct disk_dos_part_entry *dos_part = NULL; + + /* look for primary partitions */ + if (iter->sub.dos.index0 < 4 && + pi_dos_next_mbr(iter, &start_lba, &dos_part)) + return pi_del(&iter); + + /* look for logical partitions */ + if (iter->sub.dos.index0 >= 4 && + pi_dos_next_ebr(iter, &start_lba, &dos_part)) + return pi_del(&iter); + + /* dos_part and start_lba are guaranteed to be valid here */ + + iter->index = iter->sub.dos.index0 + 1; + iter->start_lba = start_lba; + iter->record = (char *)dos_part; + +#ifdef DEBUG + disk_dos_part_dump(dos_part); +#endif + + return iter; +} + +static void gpt_conv_label(struct part_iter *iter) +{ + const struct disk_gpt_part_entry *gp; + const int16_t *orig_lab; + + gp = (const struct disk_gpt_part_entry *) + (iter->data + iter->sub.gpt.index0 * iter->sub.gpt.pe_size); + orig_lab = (const int16_t *)gp->name; + + /* caveat: this is very crude conversion */ + for (int i = 0; i < PI_GPTLABSIZE/2; i++) { + iter->sub.gpt.part_label[i] = (char)orig_lab[i]; + } + iter->sub.gpt.part_label[PI_GPTLABSIZE/2] = 0; +} + +static struct part_iter *pi_gpt_next(struct part_iter *iter) +{ + const struct disk_gpt_part_entry *gpt_part = NULL; + + while (++iter->sub.gpt.index0 < iter->sub.gpt.pe_count) { + gpt_part = (const struct disk_gpt_part_entry *) + (iter->data + iter->sub.gpt.index0 * iter->sub.gpt.pe_size); + + if (notsane_gpt(gpt_part)) + goto out; + + if (guid_is0(&gpt_part->type)) + continue; + break; + } + /* no more partitions ? */ + if (iter->sub.gpt.index0 == iter->sub.gpt.pe_count) { + goto out; + } + /* gpt_part is guaranteed to be valid here */ + iter->index = iter->sub.gpt.index0 + 1; + iter->start_lba = gpt_part->lba_first; + iter->record = (char *)gpt_part; + memcpy(&iter->sub.gpt.part_guid, &gpt_part->uid, sizeof(struct guid)); + gpt_conv_label(iter); + +#ifdef DEBUG + disk_gpt_part_dump(gpt_part); +#endif + + return iter; +out: + return pi_del(&iter); +} + +static int check_crc(uint32_t crc_match, const uint8_t *buf, unsigned int siz) +{ + uint32_t crc; + + crc = crc32(0, NULL, 0); + crc = crc32(crc, buf, siz); + + return crc_match != crc; +} + +static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh) +{ + struct disk_gpt_header *gh = *_gh; + uint64_t lba_alt; + uint32_t hold_crc32; + + hold_crc32 = gh->chksum; + gh->chksum = 0; + if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) { + error("WARNING: Primary GPT header checksum invalid.\n"); + /* retry with backup */ + lba_alt = gh->lba_alt; + free(gh); + if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) { + error("Couldn't read backup GPT header.\n"); + return -1; + } + hold_crc32 = gh->chksum; + gh->chksum = 0; + if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) { + error("Secondary GPT header checksum invalid.\n"); + return -1; + } + } + /* restore old checksum */ + gh->chksum = hold_crc32; + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * Following functions are for users to call. + * ---------------------------------------------------------------------------- + */ + + +struct part_iter *pi_next(struct part_iter **_iter) +{ + struct part_iter *iter = *_iter; + if (!iter) + return NULL; + if (inv_type(iter->type)) { + error("This is not a valid iterator.\n"); + return NULL; + } + *_iter = iter->type->next(iter); + return *_iter; +} + +/** + * pi_new() - get new iterator + * @itertype: iterator type + * @...: variable arguments passed to ctors + * + * Variable arguments depend on the type. Please see functions: + * iter_gpt_ctor() and iter_dos_ctor() for details. + **/ +struct part_iter *pi_new(const struct itertype *type, ...) +{ + int badctor = 0; + struct part_iter *iter = NULL; + va_list ap; + + if (inv_type(type)) { + error("Unknown iterator requested.\n"); + return NULL; + } + + if (!(iter = malloc(sizeof(struct part_iter)))) { + error("Couldn't allocate memory for the iterator.\n"); + return NULL; + } + + memset(iter, 0, sizeof(struct part_iter)); + iter->type = type; + + va_start(ap, type); + + if ((badctor = type->ctor(iter, &ap))) { + error("Cannot initialize the iterator.\n"); + goto out; + } + +out: + va_end(ap); + if (badctor) { + free(iter); + iter = NULL; + } + return iter; +} + +/** + * pi_del() - delete iterator + * @iter: iterator double pointer + * + **/ + +void *pi_del(struct part_iter **_iter) +{ + struct part_iter *iter; + + if(!_iter || !*_iter) + return NULL; + iter = *_iter; + + if (inv_type(iter->type)) { + error("This is not a valid iterator.\n"); + return NULL; + } + iter->type->dtor(iter); + free(iter); + *_iter = NULL; + return NULL; +} + +/** + * pi_begin() - check disk, validate, and get proper iterator + * @di: diskinfo struct pointer + * + * This function checks the disk for GPT or legacy partition table and allocates + * an appropriate iterator. + **/ +struct part_iter *pi_begin(const struct disk_info *di) +{ + struct part_iter *iter = NULL; + struct disk_dos_mbr *mbr = NULL; + struct disk_gpt_header *gpth = NULL; + struct disk_gpt_part_entry *gptl = NULL; + + /* Read MBR */ + if (!(mbr = disk_read_sectors(di, 0, 1))) { + error("Couldn't read MBR sector."); + goto out; + } + + /* Check for MBR magic*/ + if (mbr->sig != disk_mbr_sig_magic) { + error("No MBR magic.\n"); + goto out; + } + + /* Check for GPT protective MBR */ + if (mbr->table[0].ostype == 0xEE) { + if (!(gpth = disk_read_sectors(di, 1, 1))) { + error("Couldn't read GPT header."); + goto out; + } + } + + if (gpth && gpth->rev.uint32 == 0x00010000 && + !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) { + /* looks like GPT v1.0 */ + uint64_t gpt_loff; /* offset to GPT partition list in sectors */ + uint64_t gpt_lsiz; /* size of GPT partition list in bytes */ +#if DEBUG + puts("Looks like a GPT v1.0 disk."); + disk_gpt_header_dump(gpth); +#endif + /* Verify checksum, fallback to backup, then bail if invalid */ + if (gpt_check_hdr_crc(di, &gpth)) + goto out; + + gpt_loff = gpth->lba_table; + gpt_lsiz = (uint64_t)gpth->part_size*gpth->part_count; + + /* + * disk_read_sectors allows reading of max 255 sectors, so we use + * it as a sanity check base. EFI doesn't specify max. + */ + if (!gpt_loff || !gpt_lsiz || gpt_lsiz > MAXGPTPTSIZE || + gpth->part_size < sizeof(struct disk_gpt_part_entry)) { + error("Invalid GPT header's lba_table/part_count/part_size values.\n"); + goto out; + } + if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)((gpt_lsiz+SECTOR-1)/SECTOR)))) { + error("Couldn't read GPT partition list.\n"); + goto out; + } + /* Check array checksum. */ + if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { + error("GPT partition list checksum invalid.\n"); + goto out; + } + /* allocate iterator and exit */ + if (!(iter = pi_new(typegpt, di, gpth, gptl))) + goto out; + } else { + /* looks like MBR */ + if (!(iter = pi_new(typedos, di, mbr))) + goto out; + } + + /* we do not do first iteration ! */ + +out: + free(mbr); + free(gpth); + free(gptl); + + return iter; +} + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h new file mode 100644 index 0000000..c2bbb44 --- /dev/null +++ b/com32/chain/partiter.h @@ -0,0 +1,94 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved + * Copyright 2010 Shao Miller + * Copyright 2010 Michal Soltys + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * partiter.h + * + * Provides disk / partition iteration. + */ + +#ifndef _SYSLINUX_PARTITER_H +#define _SYSLINUX_PARTITER_H + +#include <stdint.h> +#include <syslinux/disk.h> + +struct itertype; +struct part_iter; + +struct itertype { + int (*ctor)(struct part_iter *, va_list *); + void (*dtor)(struct part_iter *); + struct part_iter *(*next) (struct part_iter *); +}; + +#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name)) + +struct part_iter { + const struct itertype *type; + char *record; + uint64_t start_lba; + int index; + /* internal */ + char *data; + struct disk_info di; + union _sub { + struct _dos { + uint32_t disk_sig; + /* internal */ + uint32_t ebr_start; + uint32_t ebr_size; + uint32_t bebr_start; + uint32_t bebr_size; + int index0; + int bebr_index0; + } dos; + struct _gpt { + struct guid disk_guid; + struct guid part_guid; + char part_label[PI_GPTLABSIZE/2+1]; + /* internal */ + int pe_count; + int pe_size; + int index0; + } gpt; + } sub; +}; + +extern const struct itertype * const typedos; +extern const struct itertype * const typegpt; + +struct part_iter *pi_begin(const struct disk_info *); +struct part_iter *pi_new(const struct itertype *, ...); +void *pi_del(struct part_iter **); +struct part_iter *pi_next(struct part_iter **); + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/modules/Makefile b/com32/modules/Makefile index 2d47913..e1b62b5 100644 --- a/com32/modules/Makefile +++ b/com32/modules/Makefile @@ -18,7 +18,7 @@ topdir = ../.. include ../MCONFIG -MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ +MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \ meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \ kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \ -- 1.7.2.1