Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 105 additions & 16 deletions src/ptgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <inttypes.h>
#include <fcntl.h>
#include <stdint.h>
#include <getopt.h>
#include "cyg_crc.h"

#if __BYTE_ORDER == __BIG_ENDIAN
Expand Down Expand Up @@ -131,6 +132,7 @@ struct partinfo {
bool has_guid;
guid_t guid;
uint64_t gattr; /* GPT partition attributes */
unsigned part_index; /* index of GPT entry to be used */
};

/* GPT Partition table header */
Expand Down Expand Up @@ -169,7 +171,9 @@ int sectors = -1;
int kb_align = 0;
bool ignore_null_sized_partition = false;
bool use_guid_partition_table = false;
bool allow_stub_partition = true;
struct partinfo parts[GPT_ENTRY_MAX];
bool entry_used[GPT_ENTRY_MAX] = { false };
char *filename = NULL;

int gpt_split_image = false;
Expand Down Expand Up @@ -422,7 +426,7 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
uint64_t start, end;
uint64_t sect = GPT_SIZE + gpt_first_entry_sector;
int fd, ret = -1;
unsigned i, pmbr = 1;
unsigned i, index, pmbr = 1;
char img_name[strlen(filename) + 20];

memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX);
Expand Down Expand Up @@ -452,13 +456,15 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
return ret;
}
parts[i].actual_start = start;
gpte[i].start = cpu_to_le64(start);

index = parts[i].part_index;
gpte[index].start = cpu_to_le64(start);

sect = start + parts[i].size * 2;
gpte[i].end = cpu_to_le64(sect -1);
gpte[i].guid = guid;
gpte[i].guid.b[sizeof(guid_t) -1] += i + 1;
gpte[i].type = parts[i].guid;
gpte[index].end = cpu_to_le64(sect -1);
gpte[index].guid = guid;
gpte[index].guid.b[sizeof(guid_t) -1] += i + 1;
gpte[index].type = parts[i].guid;

if (parts[i].hybrid && pmbr < MBR_ENTRY_MAX) {
pte[pmbr].active = ((i + 1) == active) ? 0x80 : 0;
Expand All @@ -469,16 +475,16 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
to_chs(sect - 1, pte[1].chs_end);
pmbr++;
}
gpte[i].attr = parts[i].gattr;
gpte[index].attr = parts[i].gattr;

if (parts[i].name)
init_utf16(parts[i].name, (uint16_t *)gpte[i].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t));
init_utf16(parts[i].name, (uint16_t *)gpte[index].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t));

if ((i + 1) == (unsigned)active)
gpte[i].attr |= GPT_ATTR_LEGACY_BOOT;
gpte[index].attr |= GPT_ATTR_LEGACY_BOOT;

if (parts[i].required)
gpte[i].attr |= GPT_ATTR_PLAT_REQUIRED;
gpte[index].attr |= GPT_ATTR_PLAT_REQUIRED;

if (verbose)
fprintf(stderr, "Partition %d: start=%" PRIu64 ", end=%" PRIu64 ", size=%" PRIu64 "\n",
Expand All @@ -489,7 +495,8 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
printf("%" PRIu64 "\n", (sect - start) * DISK_SECTOR_SIZE);
}

if (parts[0].actual_start > GPT_FIRST_ENTRY_SECTOR + GPT_SIZE) {
if (parts[0].actual_start > gpt_first_entry_sector + GPT_SIZE &&
allow_stub_partition && !entry_used[GPT_ENTRY_MAX - 1]) {
gpte[GPT_ENTRY_MAX - 1].start = cpu_to_le64(gpt_first_entry_sector + GPT_SIZE);
gpte[GPT_ENTRY_MAX - 1].end = cpu_to_le64(parts[0].actual_start - 1);
gpte[GPT_ENTRY_MAX - 1].type = GUID_PARTITION_BIOS_BOOT;
Expand Down Expand Up @@ -618,10 +625,35 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)

static void usage(char *prog)
{
fprintf(stderr, "Usage: %s [-v] [-n] [-b] [-g] -h <heads> -s <sectors> -o <outputfile>\n"
" [-a <part number>] [-l <align kB>] [-G <guid>]\n"
" [-e <gpt_entry_offset>] [-d <gpt_disk_size>]\n"
" [[-t <type> | -T <GPT part type>] [-r] [-N <name>] -p <size>[@<start>]...] \n", prog);
fprintf(stderr, "Usage: %s [OPTION]...\n"
"Generate hard drive image with predefined partitions\n"
"\n"
"Mandatory arguments to long options are mandatory for short options too.\n"
" -?, --help display this help and exit\n"
" -v, --verbose enable vervose output\n"
" -l, --alignment=SIZE align partition boundaries to SIZE Kbytes\n"
" -n, --ignore-null-sized-parts do not create null sized partitions\n"
" -D, --disable-gpt-stub-part do not fill a gap before 1-st GPT partition\n"
" -o, --output=FILENAME write an image to a file FILENAME\n"
" -h, --heads=COUNT use CHS scheme, defines heads number\n"
" -s, --sectors=COUNT use CHS scheme, defines sectors count\n"
" -S, --mbr-disk-signature=VALUE defines MBR disk signature [default: 0x5452574F ('OWRT')]\n"
" -a, --active-part=PART_NUMBER defines active (boot) partition\n"
" -g, --gpt use GPT instead of MBR\n"
" -G, --gpt-guid=GUID defines custom GPT GUID\n"
" -e, --gpt-entry-offset=OFFSET defines custom placement of GPT Entry table (default: 1K)\n"
" -d, --gpt-disk-size=SIZE defines total size of disk image (used for ALT GPT headers)\n"
" -b, --gpt-split-images generate 2 or 3 images (depends on entry table placement):\n"
" GPT header + GPT Entry Table, Alt Entry Table + ALT Header\n"
" GPT header, GPT Entry Table, Alt Entry Table + ALT Header\n"
" -p, --part=SIZE[@START] defines partition of size SIZE, started at offset START\n"
" -t, --mbr-part-type=TYPE defines partition type by MBR partition type\n"
" -T, --gpt-part-type=TYPE_NAME defines partinion type by GPT type name\n"
" -N, --gpt-part-name=NAME defines GPT partition name\n"
" -r, --gpt-part-attr-required mark partition with GPT required attribute\n"
" -H, --gpt-part-hybrid put GPT partition to the MBR as well\n"
" -i, --gpt-part-index=INDEX use custom INDEX for the partition in the GPT Entry Table\n",
prog);

exit(EXIT_FAILURE);
}
Expand Down Expand Up @@ -653,21 +685,57 @@ int main (int argc, char **argv)
char *p;
int ch;
int part = 0;
unsigned part_index = 0;
char *name = NULL;
unsigned short int hybrid = 0, required = 0;
uint64_t total_sectors;
uint32_t signature = 0x5452574F; /* 'OWRT' */
guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \
0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00);

while ((ch = getopt(argc, argv, "h:s:p:a:t:T:o:vnbHN:gl:rS:G:e:d:")) != -1) {
while (1) {
int option_index = 0;
static struct option long_options[] = {
{"help", no_argument, 0, '?'},
{"verbose", no_argument, 0, 'v'},
{"kb_alignment", required_argument, 0, 'l'},
{"ignore-null-sized-parts", no_argument, 0, 'n'},
{"disable-gpt-stub-part", no_argument, 0, 'D'},
{"output", required_argument, 0, 'o'},
{"heads", required_argument, 0, 'h'},
{"sectors", required_argument, 0, 's'},
{"mbr-disk-signature", required_argument, 0, 'S'},
{"active-part", required_argument, 0, 'a'},
{"gpt", no_argument, 0, 'g'},
{"gpt-guid", required_argument, 0, 'G'},
{"gpt-entry-offset", required_argument, 0, 'e'},
{"gpt-disk-size", required_argument, 0, 'd'},
{"gpt-split-images", no_argument, 0, 'b'},
{"part", required_argument, 0, 'p'},
{"mbr-part-type", required_argument, 0, 't'},
{"gpt-part-type", required_argument, 0, 'T'},
{"gpt-part-name", required_argument, 0, 'N'},
{"gpt-part-attr-required", no_argument, 0, 'r'},
{"gpt-part-hybrid", no_argument, 0, 'H'},
{"gpt-part-index", required_argument, 0, 'i'},
{NULL, 0, 0, 0 },
};

ch = getopt_long(argc, argv, "?h:s:p:a:t:T:o:DvnbHN:gl:rS:G:e:d:i:",
long_options, &option_index);
if (ch == -1)
break;

switch (ch) {
case 'o':
filename = optarg;
break;
case 'v':
verbose++;
break;
case 'D':
allow_stub_partition = false;
break;
case 'n':
ignore_null_sized_partition = true;
break;
Expand Down Expand Up @@ -719,6 +787,11 @@ int main (int argc, char **argv)
fputs("Too many partitions\n", stderr);
exit(EXIT_FAILURE);
}
if (entry_used[part_index]) {
fprintf(stderr, "Partition entry with index %d already defined\n", part_index);
exit(EXIT_FAILURE);
}

p = strchr(optarg, '@');
if (p) {
*(p++) = 0;
Expand All @@ -731,6 +804,7 @@ int main (int argc, char **argv)
parts[part].required = required;
parts[part].name = name;
parts[part].hybrid = hybrid;
parts[part].part_index = part_index;
fprintf(stderr, "part %lld %lld\n", parts[part].start, parts[part].size);
parts[part++].type = type;
/*
Expand All @@ -740,13 +814,28 @@ int main (int argc, char **argv)
name = NULL;
required = 0;
hybrid = 0;

/* mark index as used, switch to next index */
entry_used[part_index++] = true;
if (part_index > GPT_ENTRY_MAX - 1 ||
(!use_guid_partition_table && part_index > 3))
part_index = 0;

break;
case 'N':
name = optarg;
break;
case 'r':
required = 1;
break;
case 'i':
part_index = (int)strtoul(optarg, NULL, 0);
if (part_index > GPT_ENTRY_MAX - 1 ||
(!use_guid_partition_table && part_index > 3)) {
fprintf(stderr, "Too big GPT/MBR entry index %d\n", part_index);
exit(EXIT_FAILURE);
}
break;
case 't':
type = (char)strtoul(optarg, NULL, 16);
break;
Expand Down