firmware-utils/ptgen: add support for hybrid MBR

Adding -H option copies partition to MBR after pmbr entry.
Max 3 partitions can be copied to MBR.

Hybrid MBR is needed only in special cases.
For example mt7622 SD card boot needs MBR entry with boot
flag enabled.

Signed-off-by: Oskari Lemmela <oskari@lemmela.net>
This commit is contained in:
Oskari Lemmela 2021-03-02 21:42:08 +02:00 committed by Daniel Golle
parent 4a078bd135
commit 460dd2fe28
1 changed files with 28 additions and 11 deletions

View File

@ -123,6 +123,7 @@ struct partinfo {
unsigned long start; unsigned long start;
unsigned long size; unsigned long size;
int type; int type;
int hybrid;
char *name; char *name;
short int required; short int required;
guid_t guid; guid_t guid;
@ -369,7 +370,7 @@ fail:
/* check the partition sizes and write the guid partition table */ /* check the partition sizes and write the guid partition table */
static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
{ {
struct pte pte; struct pte pte[MBR_ENTRY_MAX];
struct gpth gpth = { struct gpth gpth = {
.signature = cpu_to_le64(GPT_SIGNATURE), .signature = cpu_to_le64(GPT_SIGNATURE),
.revision = cpu_to_le32(GPT_REVISION), .revision = cpu_to_le32(GPT_REVISION),
@ -384,8 +385,9 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
struct gpte gpte[GPT_ENTRY_MAX]; struct gpte gpte[GPT_ENTRY_MAX];
uint64_t start, end, sect = 0; uint64_t start, end, sect = 0;
int fd, ret = -1; int fd, ret = -1;
unsigned i; unsigned i, pmbr = 1;
memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX);
memset(gpte, 0, GPT_ENTRY_SIZE * GPT_ENTRY_MAX); memset(gpte, 0, GPT_ENTRY_SIZE * GPT_ENTRY_MAX);
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
if (!parts[i].size) { if (!parts[i].size) {
@ -415,6 +417,16 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
gpte[i].guid.b[sizeof(guid_t) -1] += i + 1; gpte[i].guid.b[sizeof(guid_t) -1] += i + 1;
gpte[i].type = parts[i].guid; gpte[i].type = parts[i].guid;
if (parts[i].hybrid && pmbr < MBR_ENTRY_MAX) {
pte[pmbr].active = ((i + 1) == active) ? 0x80 : 0;
pte[pmbr].type = parts[i].type;
pte[pmbr].start = cpu_to_le32(start);
pte[pmbr].length = cpu_to_le32(sect - start);
to_chs(start, pte[1].chs_start);
to_chs(sect - 1, pte[1].chs_end);
pmbr++;
}
if (parts[i].name) 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[i].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t));
@ -441,11 +453,11 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
end = sect + sectors - 1; end = sect + sectors - 1;
pte.type = 0xEE; pte[0].type = 0xEE;
pte.start = cpu_to_le32(GPT_HEADER_SECTOR); pte[0].start = cpu_to_le32(GPT_HEADER_SECTOR);
pte.length = cpu_to_le32(end); pte[0].length = cpu_to_le32(end - GPT_HEADER_SECTOR);
to_chs(GPT_HEADER_SECTOR, pte.chs_start); to_chs(GPT_HEADER_SECTOR, pte[0].chs_start);
to_chs(end, pte.chs_end); to_chs(end, pte[0].chs_end);
gpth.last_usable = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE - 1); gpth.last_usable = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE - 1);
gpth.alternate = cpu_to_le64(end); gpth.alternate = cpu_to_le64(end);
@ -464,7 +476,7 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
} }
lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET); lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET);
if (write(fd, &pte, sizeof(struct pte)) != sizeof(struct pte)) { if (write(fd, pte, sizeof(struct pte) * MBR_ENTRY_MAX) != sizeof(struct pte) * MBR_ENTRY_MAX) {
fputs("write failed.\n", stderr); fputs("write failed.\n", stderr);
goto fail; goto fail;
} }
@ -551,13 +563,13 @@ int main (int argc, char **argv)
int ch; int ch;
int part = 0; int part = 0;
char *name = NULL; char *name = NULL;
unsigned short int required = 0; unsigned short int hybrid = 0, required = 0;
uint32_t signature = 0x5452574F; /* 'OWRT' */ uint32_t signature = 0x5452574F; /* 'OWRT' */
guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \ guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \
0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00); 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00);
guid_t part_guid = GUID_PARTITION_BASIC_DATA; guid_t part_guid = GUID_PARTITION_BASIC_DATA;
while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vnN:gl:rS:G:")) != -1) { while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vnHN:gl:rS:G:")) != -1) {
switch (ch) { switch (ch) {
case 'o': case 'o':
filename = optarg; filename = optarg;
@ -571,6 +583,9 @@ int main (int argc, char **argv)
case 'g': case 'g':
use_guid_partition_table = 1; use_guid_partition_table = 1;
break; break;
case 'H':
hybrid = 1;
break;
case 'h': case 'h':
heads = (int)strtoul(optarg, NULL, 0); heads = (int)strtoul(optarg, NULL, 0);
break; break;
@ -591,15 +606,17 @@ int main (int argc, char **argv)
parts[part].size = to_kbytes(optarg); parts[part].size = to_kbytes(optarg);
parts[part].required = required; parts[part].required = required;
parts[part].name = name; parts[part].name = name;
parts[part].hybrid = hybrid;
parts[part].guid = part_guid; parts[part].guid = part_guid;
fprintf(stderr, "part %ld %ld\n", parts[part].start, parts[part].size); fprintf(stderr, "part %ld %ld\n", parts[part].start, parts[part].size);
parts[part++].type = type; parts[part++].type = type;
/* /*
* reset 'name' and 'required' * reset 'name','required' and 'hybrid'
* 'type' is deliberately inherited from the previous delcaration * 'type' is deliberately inherited from the previous delcaration
*/ */
name = NULL; name = NULL;
required = 0; required = 0;
hybrid = 0;
break; break;
case 'N': case 'N':
name = optarg; name = optarg;