Skip to content

Commit 4fe428f

Browse files
committed
image-hd: add support for overridding optional fields of the MBR
The 'holes' property allows to describe holes in an image, for example to allow writing an image that spans accross the MBR partition table. The image-hd code creates a fake partition spanning from 440 bytes to 512 bytes to protect the area used by the partition table. However, it turns out that the Amlogic SoCs have a bootloader that is precisely written accross the partition table, with some bits before the partition table and some bits after. But those Amlogic SoCs use the first 444 bytes, instead of just the first 440 bytes (see [1]). This is possible because the first 2 fields of the MBR are optional fields (see [2]). The first optional field is the disk signature (4 bytes), the second optional field is the "copy protect" field (2 bytes). Therefore, to write a bootloader image for the Amlogic SoCs, we need to write something like: image fip/u-boot.bin.sd.bin { file { holes = {"(444; 512)"} } } But that isn't accepted because it overlaps with the fake MBR partition that starts at offset 440. In order to allow this, the present commit adds a new 'mbr-skip-optionals' property, which tells genimage that we would like to skip writing those optional fields, allowing the full 446 bytes to be used, as is needed for Amlogic SoC bootloader images. Implementation note: we would have preferred to write: mbr_data += sizeof(struct mbr_tail_optionals); but genimage has chosen to not allow arithmetic on void* pointers, so instead we have chosen to use: mbr_data = &mbr.part_entry[0]; when adjusting the start of the MBR data that have to be inserted into the image. This commit also adds two test cases for this new feature: - One positive test case, where we verify that we can write an image where the hole is (444, 512) and the mbr-skip-optionals = "true" option is passed - One negative test case, where we verify that we are not allowed to write an image where the hole is (444, 512) when mbr-skip-optionals = "false". [1] http://docs.khadas.com/products/sbc/vim3/development/create-bootable-tf-card [2] https://wiki.osdev.org/MBR_(x86) Co-Developed-by: Romain Naour <[email protected]> Signed-off-by: Thomas Petazzoni <[email protected]>
1 parent 00009af commit 4fe428f

File tree

5 files changed

+71
-5
lines changed

5 files changed

+71
-5
lines changed

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ EXTRA_DIST += \
100100
test/hdimage7.config \
101101
test/hdimage7.fdisk \
102102
test/hole.config \
103+
test/hole-skip-optionals.config \
103104
test/hdimage-hybrid.config \
104105
test/hdimage-hybrid.fdisk \
105106
test/hdimage-fail1.config \

README.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,9 @@ Options:
425425
up to the end of the last partition. This might make the file
426426
bigger. This is necessary if the image will be processed by
427427
such tools as libvirt, libguestfs or parted.
428+
:mbr-skip-optionals: Boolean. If true, then the 6 bytes of optional fields in the MBR
429+
are skipped, allowing an image occupying the first 446 bytes
430+
instead of just the first 440 bytes to be written.
428431

429432
iso
430433
***

image-hd.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct hdimage {
4747
unsigned long long gpt_location;
4848
cfg_bool_t gpt_no_backup;
4949
cfg_bool_t fill;
50+
cfg_bool_t mbr_skip_optionals;
5051
unsigned long long file_size;
5152
};
5253

@@ -64,9 +65,14 @@ struct mbr_partition_entry {
6465
} __attribute__((packed));
6566
ct_assert(sizeof(struct mbr_partition_entry) == 16);
6667

67-
struct mbr_tail {
68+
struct mbr_tail_optionals {
6869
uint32_t disk_signature;
6970
uint16_t copy_protect;
71+
} __attribute__((packed));
72+
ct_assert(sizeof(struct mbr_tail_optionals) == 6);
73+
74+
struct mbr_tail {
75+
struct mbr_tail_optionals optionals;
7076
struct mbr_partition_entry part_entry[4];
7177
uint16_t boot_signature;
7278
} __attribute__((packed));
@@ -141,6 +147,9 @@ static int hdimage_insert_mbr(struct image *image, struct list_head *partitions)
141147
struct hdimage *hd = image->handler_priv;
142148
struct mbr_tail mbr;
143149
struct partition *part;
150+
unsigned long long mbr_offset;
151+
const void *mbr_data;
152+
size_t mbr_size;
144153
int ret, i = 0;
145154

146155
if (hd->table_type == TYPE_HYBRID) {
@@ -150,7 +159,7 @@ static int hdimage_insert_mbr(struct image *image, struct list_head *partitions)
150159
}
151160

152161
memset(&mbr, 0, sizeof(mbr));
153-
memcpy(&mbr.disk_signature, &hd->disksig, sizeof(hd->disksig));
162+
memcpy(&mbr.optionals.disk_signature, &hd->disksig, sizeof(hd->disksig));
154163

155164
list_for_each_entry(part, partitions, list) {
156165
struct mbr_partition_entry *entry;
@@ -192,7 +201,16 @@ static int hdimage_insert_mbr(struct image *image, struct list_head *partitions)
192201

193202
mbr.boot_signature = htole16(0xaa55);
194203

195-
ret = insert_data(image, &mbr, imageoutfile(image), sizeof(mbr), 440);
204+
mbr_offset = 440;
205+
mbr_size = sizeof(mbr);
206+
mbr_data = &mbr;
207+
if (hd->mbr_skip_optionals) {
208+
mbr_offset += sizeof(struct mbr_tail_optionals);
209+
mbr_size -= sizeof(struct mbr_tail_optionals);
210+
mbr_data = &mbr.part_entry[0];
211+
}
212+
213+
ret = insert_data(image, mbr_data, imageoutfile(image), mbr_size, mbr_offset);
196214
if (ret) {
197215
if (hd->table_type == TYPE_HYBRID) {
198216
image_error(image, "failed to write hybrid MBR\n");
@@ -968,6 +986,7 @@ static int hdimage_setup(struct image *image, cfg_t *cfg)
968986
hd->gpt_location = cfg_getint_suffix(cfg, "gpt-location");
969987
hd->gpt_no_backup = cfg_getbool(cfg, "gpt-no-backup");
970988
hd->fill = cfg_getbool(cfg, "fill");
989+
hd->mbr_skip_optionals = cfg_getbool(cfg, "mbr-skip-optionals");
971990

972991
if (is_block_device(imageoutfile(image))) {
973992
if (image->size) {
@@ -1029,8 +1048,19 @@ static int hdimage_setup(struct image *image, cfg_t *cfg)
10291048
}
10301049

10311050
if (hd->table_type != TYPE_NONE) {
1032-
struct partition *mbr = fake_partition("[MBR]", 512 - sizeof(struct mbr_tail),
1033-
sizeof(struct mbr_tail));
1051+
struct partition *mbr;
1052+
unsigned long long mbr_offset;
1053+
unsigned long long mbr_size;
1054+
1055+
mbr_offset = 512 - sizeof(struct mbr_tail);
1056+
mbr_size = sizeof(struct mbr_tail);
1057+
1058+
if (hd->mbr_skip_optionals) {
1059+
mbr_offset += sizeof(struct mbr_tail_optionals);
1060+
mbr_size -= sizeof(struct mbr_tail_optionals);
1061+
}
1062+
1063+
mbr = fake_partition("[MBR]", mbr_offset, mbr_size);
10341064

10351065
list_add_tail(&mbr->list, &image->partitions);
10361066
now = partition_end(mbr);
@@ -1215,6 +1245,7 @@ static cfg_opt_t hdimage_opts[] = {
12151245
CFG_STR("gpt-location", NULL, CFGF_NONE),
12161246
CFG_BOOL("gpt-no-backup", cfg_false, CFGF_NONE),
12171247
CFG_BOOL("fill", cfg_false, CFGF_NONE),
1248+
CFG_BOOL("mbr-skip-optionals", cfg_false, CFGF_NONE),
12181249
CFG_END()
12191250
};
12201251

test/hdimage.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,20 @@ test_expect_success "bootloader-hole5" "
159159
setup_gpt_files &&
160160
OFFSET=128K run_genimage hole.config"
161161

162+
# Test the mbr-skip-optionals
163+
test_expect_success "bootloader-hole6" "
164+
rm -rf input &&
165+
mkdir input &&
166+
truncate -s 100K input/bootloader.img &&
167+
MBR_SKIP_OPTIONALS=true run_genimage hole-skip-optionals.config"
168+
169+
# Test the mbr-skip-optionals
170+
test_expect_success "bootloader-hole7" "
171+
rm -rf input &&
172+
mkdir input &&
173+
truncate -s 100K input/bootloader.img &&
174+
MBR_SKIP_OPTIONALS=false test_must_fail run_genimage hole-skip-optionals.config"
175+
162176
test_expect_success hexdump "hdimage no-partition" "
163177
dd if=/dev/zero bs=1 count=100 | tr '\000' '\377' > input/block1.img &&
164178
dd if=/dev/zero bs=1 count=50 | tr '\000' '\252' > input/block2.img &&

test/hole-skip-optionals.config

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
image test.hole {
2+
hdimage {
3+
mbr-skip-optionals = "${MBR_SKIP_OPTIONALS}"
4+
}
5+
6+
partition bootloader {
7+
in-partition-table = false
8+
offset = 0
9+
image = "bootloader.img"
10+
}
11+
}
12+
13+
image bootloader.img {
14+
file {
15+
holes = "(444; 512)"
16+
}
17+
}

0 commit comments

Comments
 (0)