Skip to content

Commit 17e7a62

Browse files
author
Chanj Wons
committed
firmware-utils/ptgen: add support for EBR (MBR extended partition)
Adding -e option to enable MBR extended partition automatically. MBR with EBR is important in some cases. For example Raspberry4B SD card A/B boot solution needs extended partition to enable 5 available partitions at least. Signed-off-by: Chanj Wons <wangchangqi@kylinos.cn>
1 parent bd7fcc7 commit 17e7a62

1 file changed

Lines changed: 94 additions & 7 deletions

File tree

src/ptgen.c

Lines changed: 94 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ typedef struct {
107107
#define MBR_DISK_SIGNATURE_OFFSET 440
108108
#define MBR_PARTITION_ENTRY_OFFSET 446
109109
#define MBR_BOOT_SIGNATURE_OFFSET 510
110+
#define MBR_MSDOS_SYSTYPE_EXTENDED 5
110111

111112
#define DISK_SECTOR_SIZE 512
112113

@@ -169,6 +170,12 @@ int sectors = -1;
169170
int kb_align = 0;
170171
bool ignore_null_sized_partition = false;
171172
bool use_guid_partition_table = false;
173+
bool use_mbr_extended_partition = false;
174+
/**
175+
* If only MBR: 4 primary partitions is enough, or use 3 primary partitions and 1 extended partition.
176+
* If MBR with EBR: At least 5 are needed, 3 primary, 1 extended, 1 logic.
177+
* If GPT: At most 128 can be used under Windows.
178+
*/
172179
struct partinfo parts[GPT_ENTRY_MAX];
173180
char *filename = NULL;
174181

@@ -324,7 +331,7 @@ static inline void init_utf16(char *str, uint16_t *buf, unsigned bufsize)
324331
}
325332

326333
/* check the partition sizes and write the partition table */
327-
static int gen_ptable(uint32_t signature, int nr)
334+
static int gen_ptable(uint32_t signature, int nr, int realnr)
328335
{
329336
struct pte pte[MBR_ENTRY_MAX];
330337
unsigned long start, len, sect = 0;
@@ -364,7 +371,7 @@ static int gen_ptable(uint32_t signature, int nr)
364371
to_chs(start + len - 1, pte[i].chs_end);
365372

366373
if (verbose)
367-
fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n",
374+
fprintf(stderr, "MBR Partition %d: start=%ld, end=%ld, size=%ld\n",
368375
i,
369376
(long)start * DISK_SECTOR_SIZE,
370377
(long)(start + len) * DISK_SECTOR_SIZE,
@@ -395,6 +402,70 @@ static int gen_ptable(uint32_t signature, int nr)
395402
goto fail;
396403
}
397404

405+
if (use_mbr_extended_partition) {
406+
int _start = 0;
407+
int offset = pte[3].start * 512;
408+
409+
for (i = nr; i < realnr; i++) {
410+
unsigned long sect = 0;
411+
int start = sectors, len;
412+
struct pte ebrpte[2];
413+
memset(ebrpte, 0, sizeof(ebrpte));
414+
415+
if (!parts[i].size) {
416+
if (ignore_null_sized_partition)
417+
continue;
418+
fprintf(stderr, "Invalid size in partition %d!\n", i);
419+
return -1;
420+
}
421+
422+
ebrpte[0].active = 0;
423+
ebrpte[0].type = parts[i].type;
424+
425+
if (kb_align != 0)
426+
start = round_to_kb(start);
427+
ebrpte[0].start = cpu_to_le32(start);
428+
429+
sect = start + parts[i].size * 2;
430+
if (kb_align == 0)
431+
sect = round_to_cyl(sect);
432+
ebrpte[0].length = cpu_to_le32(len = sect - start);
433+
434+
to_chs(start, ebrpte[0].chs_start);
435+
to_chs(start + len - 1, ebrpte[0].chs_end);
436+
437+
/* ebrpte[1] -> point next EBR */
438+
if (realnr - i > 1) {
439+
_start += sect;
440+
ebrpte[1].active = 0;
441+
ebrpte[1].type = MBR_MSDOS_SYSTYPE_EXTENDED;
442+
ebrpte[1].start = cpu_to_le32(_start);
443+
ebrpte[1].length = 512;
444+
to_chs(_start, ebrpte[1].chs_start);
445+
to_chs(_start + 511, ebrpte[1].chs_end);
446+
}
447+
448+
if (verbose)
449+
fprintf(stderr, "EBR Partition %d: start=%ld, end=%ld, size=%ld\n", i - nr, (long)start * 512, ((long)start + (long)len) * 512, (long)len * 512);
450+
printf("%ld\n", (long)start * 512);
451+
printf("%ld\n", (long)len * 512);
452+
453+
lseek(fd, offset + 446, SEEK_SET);
454+
if (write(fd, ebrpte, sizeof(struct pte) * 2) != sizeof(struct pte) * 2) {
455+
fprintf(stderr, "write failed.\n");
456+
goto fail;
457+
}
458+
459+
lseek(fd, offset + 510, SEEK_SET);
460+
if (write(fd, "\x55\xaa", 2) != 2) {
461+
fprintf(stderr, "write failed.\n");
462+
goto fail;
463+
}
464+
465+
offset += sect * 512;
466+
}
467+
}
468+
398469
ret = 0;
399470
fail:
400471
close(fd);
@@ -568,7 +639,7 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
568639

569640
static void usage(char *prog)
570641
{
571-
fprintf(stderr, "Usage: %s [-v] [-n] [-g] -h <heads> -s <sectors> -o <outputfile>\n"
642+
fprintf(stderr, "Usage: %s [-v] [-n] [-g] [-e] -h <heads> -s <sectors> -o <outputfile>\n"
572643
" [-a <part number>] [-l <align kB>] [-G <guid>]\n"
573644
" [[-t <type> | -T <GPT part type>] [-r] [-N <name>] -p <size>[@<start>]...] \n", prog);
574645
exit(EXIT_FAILURE);
@@ -607,7 +678,7 @@ int main (int argc, char **argv)
607678
guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \
608679
0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00);
609680

610-
while ((ch = getopt(argc, argv, "h:s:p:a:t:T:o:vnHN:gl:rS:G:")) != -1) {
681+
while ((ch = getopt(argc, argv, "h:s:p:a:t:T:o:evnHN:gl:rS:G:")) != -1) {
611682
switch (ch) {
612683
case 'o':
613684
filename = optarg;
@@ -624,17 +695,26 @@ int main (int argc, char **argv)
624695
case 'H':
625696
hybrid = 1;
626697
break;
698+
case 'e':
699+
use_mbr_extended_partition = 1;
700+
break;
627701
case 'h':
628702
heads = (int)strtoul(optarg, NULL, 0);
629703
break;
630704
case 's':
631705
sectors = (int)strtoul(optarg, NULL, 0);
632706
break;
633707
case 'p':
634-
if (part > GPT_ENTRY_MAX - 1 || (!use_guid_partition_table && part > 3)) {
635-
fputs("Too many partitions\n", stderr);
708+
if (part > GPT_ENTRY_MAX - 1 || ((!use_guid_partition_table && !use_mbr_extended_partition) && part > 3)) {
709+
fputs("Too many partitions, please add the -e parameter to automatically enable MBR extended partition\n", stderr);
636710
exit(EXIT_FAILURE);
637711
}
712+
if (part == 3 && use_mbr_extended_partition) {
713+
parts[part++].type = MBR_MSDOS_SYSTYPE_EXTENDED;
714+
parts[part].size = to_kbytes(optarg);
715+
parts[part++].type = type;
716+
break;
717+
}
638718
p = strchr(optarg, '@');
639719
if (p) {
640720
*(p++) = 0;
@@ -709,5 +789,12 @@ int main (int argc, char **argv)
709789
return gen_gptable(signature, guid, part) ? EXIT_FAILURE : EXIT_SUCCESS;
710790
}
711791

712-
return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS;
792+
if (part > 4) {
793+
int logic_parts_sizes = 0;
794+
for (int i = 4; i < part; i++)
795+
logic_parts_sizes += kb_align / 2 + parts[i].size;
796+
parts[3].size = logic_parts_sizes;
797+
}
798+
799+
return gen_ptable(signature, part > 3 ? 4 : part, part) ? EXIT_FAILURE : EXIT_SUCCESS;
713800
}

0 commit comments

Comments
 (0)