mirror of
https://git.yoctoproject.org/poky
synced 2026-09-19 09:49:33 +02:00
wic: Add gpt-hybrid partition layout
Add support for formatting a disk with a hybrid MBR & GPT partition scheme. In this scheme, the primary partitioning method is GPT, but a valid MBR header is also written than can point to a subset of the GPT partitions on the disk (any partitions marked with the `--mbr` flag will be included in this MBR). The primary purpose of this method is to allow for SoCs that can only find a bootloader in an MBR partition to use GPT once the bootloader is running. As an example, older versions of the Raspberry Pi firmware can only parse MBR partitions to find a kernel (or other bootloader like u-boot), but once those have booted GPT partitions can be used. In addition to the partitions annotated with the `--mbr`, a "protective" GPT partition of type 0xEE is added, as the existence of such a partition is the indication to tooling that this a hybrid MBR and that the GPT partition table should be parsed instead. (From OE-Core rev: e50e4c2a5ada6947b3503ca4d8e9c30d359e8a5d) Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
9d9c7d4b0b
commit
93388921ab
@@ -188,11 +188,12 @@ class KickStart():
|
|||||||
part.add_argument('--uuid')
|
part.add_argument('--uuid')
|
||||||
part.add_argument('--fsuuid')
|
part.add_argument('--fsuuid')
|
||||||
part.add_argument('--no-fstab-update', action='store_true')
|
part.add_argument('--no-fstab-update', action='store_true')
|
||||||
|
part.add_argument('--mbr', action='store_true')
|
||||||
|
|
||||||
bootloader = subparsers.add_parser('bootloader')
|
bootloader = subparsers.add_parser('bootloader')
|
||||||
bootloader.add_argument('--append')
|
bootloader.add_argument('--append')
|
||||||
bootloader.add_argument('--configfile')
|
bootloader.add_argument('--configfile')
|
||||||
bootloader.add_argument('--ptable', choices=('msdos', 'gpt'),
|
bootloader.add_argument('--ptable', choices=('msdos', 'gpt', 'gpt-hybrid'),
|
||||||
default='msdos')
|
default='msdos')
|
||||||
bootloader.add_argument('--timeout', type=int)
|
bootloader.add_argument('--timeout', type=int)
|
||||||
bootloader.add_argument('--source')
|
bootloader.add_argument('--source')
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class Partition():
|
|||||||
self.has_fstab = False
|
self.has_fstab = False
|
||||||
self.update_fstab_in_rootfs = False
|
self.update_fstab_in_rootfs = False
|
||||||
self.hidden = args.hidden
|
self.hidden = args.hidden
|
||||||
|
self.mbr = args.mbr
|
||||||
|
|
||||||
self.lineno = lineno
|
self.lineno = lineno
|
||||||
self.source_file = ""
|
self.source_file = ""
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ class PartitionedImage():
|
|||||||
# generate parition and filesystem UUIDs
|
# generate parition and filesystem UUIDs
|
||||||
for part in self.partitions:
|
for part in self.partitions:
|
||||||
if not part.uuid and part.use_uuid:
|
if not part.uuid and part.use_uuid:
|
||||||
if self.ptable_format == 'gpt':
|
if self.ptable_format in ('gpt', 'gpt-hybrid'):
|
||||||
part.uuid = str(uuid.uuid4())
|
part.uuid = str(uuid.uuid4())
|
||||||
else: # msdos partition table
|
else: # msdos partition table
|
||||||
part.uuid = '%08x-%02d' % (self.identifier, part.realnum)
|
part.uuid = '%08x-%02d' % (self.identifier, part.realnum)
|
||||||
@@ -398,6 +398,10 @@ class PartitionedImage():
|
|||||||
raise WicError("setting custom partition type is not " \
|
raise WicError("setting custom partition type is not " \
|
||||||
"implemented for msdos partitions")
|
"implemented for msdos partitions")
|
||||||
|
|
||||||
|
if part.mbr and self.ptable_format != 'gpt-hybrid':
|
||||||
|
raise WicError("Partition may only be included in MBR with " \
|
||||||
|
"a gpt-hybrid partition table")
|
||||||
|
|
||||||
# Get the disk where the partition is located
|
# Get the disk where the partition is located
|
||||||
self.numpart += 1
|
self.numpart += 1
|
||||||
if not part.no_table:
|
if not part.no_table:
|
||||||
@@ -406,7 +410,7 @@ class PartitionedImage():
|
|||||||
if self.numpart == 1:
|
if self.numpart == 1:
|
||||||
if self.ptable_format == "msdos":
|
if self.ptable_format == "msdos":
|
||||||
overhead = MBR_OVERHEAD
|
overhead = MBR_OVERHEAD
|
||||||
elif self.ptable_format == "gpt":
|
elif self.ptable_format in ("gpt", "gpt-hybrid"):
|
||||||
overhead = GPT_OVERHEAD
|
overhead = GPT_OVERHEAD
|
||||||
|
|
||||||
# Skip one sector required for the partitioning scheme overhead
|
# Skip one sector required for the partitioning scheme overhead
|
||||||
@@ -490,7 +494,7 @@ class PartitionedImage():
|
|||||||
# Once all the partitions have been layed out, we can calculate the
|
# Once all the partitions have been layed out, we can calculate the
|
||||||
# minumim disk size
|
# minumim disk size
|
||||||
self.min_size = self.offset
|
self.min_size = self.offset
|
||||||
if self.ptable_format == "gpt":
|
if self.ptable_format in ("gpt", "gpt-hybrid"):
|
||||||
self.min_size += GPT_OVERHEAD
|
self.min_size += GPT_OVERHEAD
|
||||||
|
|
||||||
self.min_size *= self.sector_size
|
self.min_size *= self.sector_size
|
||||||
@@ -511,22 +515,38 @@ class PartitionedImage():
|
|||||||
|
|
||||||
return exec_native_cmd(cmd, self.native_sysroot)
|
return exec_native_cmd(cmd, self.native_sysroot)
|
||||||
|
|
||||||
def create(self):
|
def _write_identifier(self, device, identifier):
|
||||||
logger.debug("Creating sparse file %s", self.path)
|
logger.debug("Set disk identifier %x", identifier)
|
||||||
with open(self.path, 'w') as sparse:
|
with open(device, 'r+b') as img:
|
||||||
os.ftruncate(sparse.fileno(), self.min_size)
|
|
||||||
|
|
||||||
logger.debug("Initializing partition table for %s", self.path)
|
|
||||||
exec_native_cmd("parted -s %s mklabel %s" %
|
|
||||||
(self.path, self.ptable_format), self.native_sysroot)
|
|
||||||
|
|
||||||
logger.debug("Set disk identifier %x", self.identifier)
|
|
||||||
with open(self.path, 'r+b') as img:
|
|
||||||
img.seek(0x1B8)
|
img.seek(0x1B8)
|
||||||
img.write(self.identifier.to_bytes(4, 'little'))
|
img.write(identifier.to_bytes(4, 'little'))
|
||||||
|
|
||||||
|
def _make_disk(self, device, ptable_format, min_size):
|
||||||
|
logger.debug("Creating sparse file %s", device)
|
||||||
|
with open(device, 'w') as sparse:
|
||||||
|
os.ftruncate(sparse.fileno(), min_size)
|
||||||
|
|
||||||
|
logger.debug("Initializing partition table for %s", device)
|
||||||
|
exec_native_cmd("parted -s %s mklabel %s" % (device, ptable_format),
|
||||||
|
self.native_sysroot)
|
||||||
|
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
self._make_disk(self.path,
|
||||||
|
"gpt" if self.ptable_format == "gpt-hybrid" else self.ptable_format,
|
||||||
|
self.min_size)
|
||||||
|
|
||||||
|
self._write_identifier(self.path, self.identifier)
|
||||||
|
|
||||||
|
if self.ptable_format == "gpt-hybrid":
|
||||||
|
mbr_path = self.path + ".mbr"
|
||||||
|
self._make_disk(mbr_path, "msdos", self.min_size)
|
||||||
|
self._write_identifier(mbr_path, self.identifier)
|
||||||
|
|
||||||
logger.debug("Creating partitions")
|
logger.debug("Creating partitions")
|
||||||
|
|
||||||
|
hybrid_mbr_part_num = 0
|
||||||
|
|
||||||
for part in self.partitions:
|
for part in self.partitions:
|
||||||
if part.num == 0:
|
if part.num == 0:
|
||||||
continue
|
continue
|
||||||
@@ -571,7 +591,14 @@ class PartitionedImage():
|
|||||||
self._create_partition(self.path, part.type,
|
self._create_partition(self.path, part.type,
|
||||||
parted_fs_type, part.start, part.size_sec)
|
parted_fs_type, part.start, part.size_sec)
|
||||||
|
|
||||||
if self.ptable_format == "gpt" and (part.part_name or part.label):
|
if self.ptable_format == "gpt-hybrid" and part.mbr:
|
||||||
|
hybrid_mbr_part_num += 1
|
||||||
|
if hybrid_mbr_part_num > 4:
|
||||||
|
raise WicError("Extended MBR partitions are not supported in hybrid MBR")
|
||||||
|
self._create_partition(mbr_path, "primary",
|
||||||
|
parted_fs_type, part.start, part.size_sec)
|
||||||
|
|
||||||
|
if self.ptable_format in ("gpt", "gpt-hybrid") and (part.part_name or part.label):
|
||||||
partition_label = part.part_name if part.part_name else part.label
|
partition_label = part.part_name if part.part_name else part.label
|
||||||
logger.debug("partition %d: set name to %s",
|
logger.debug("partition %d: set name to %s",
|
||||||
part.num, partition_label)
|
part.num, partition_label)
|
||||||
@@ -586,7 +613,7 @@ class PartitionedImage():
|
|||||||
(part.num, part.part_type,
|
(part.num, part.part_type,
|
||||||
self.path), self.native_sysroot)
|
self.path), self.native_sysroot)
|
||||||
|
|
||||||
if part.uuid and self.ptable_format == "gpt":
|
if part.uuid and self.ptable_format in ("gpt", "gpt-hybrid"):
|
||||||
logger.debug("partition %d: set UUID to %s",
|
logger.debug("partition %d: set UUID to %s",
|
||||||
part.num, part.uuid)
|
part.num, part.uuid)
|
||||||
exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \
|
exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \
|
||||||
@@ -594,12 +621,16 @@ class PartitionedImage():
|
|||||||
self.native_sysroot)
|
self.native_sysroot)
|
||||||
|
|
||||||
if part.active:
|
if part.active:
|
||||||
flag_name = "legacy_boot" if self.ptable_format == 'gpt' else "boot"
|
flag_name = "legacy_boot" if self.ptable_format in ('gpt', 'gpt-hybrid') else "boot"
|
||||||
logger.debug("Set '%s' flag for partition '%s' on disk '%s'",
|
logger.debug("Set '%s' flag for partition '%s' on disk '%s'",
|
||||||
flag_name, part.num, self.path)
|
flag_name, part.num, self.path)
|
||||||
exec_native_cmd("parted -s %s set %d %s on" % \
|
exec_native_cmd("parted -s %s set %d %s on" % \
|
||||||
(self.path, part.num, flag_name),
|
(self.path, part.num, flag_name),
|
||||||
self.native_sysroot)
|
self.native_sysroot)
|
||||||
|
if self.ptable_format == 'gpt-hybrid' and part.mbr:
|
||||||
|
exec_native_cmd("parted -s %s set %d %s on" % \
|
||||||
|
(mbr_path, hybrid_mbr_part_num, "boot"),
|
||||||
|
self.native_sysroot)
|
||||||
if part.system_id:
|
if part.system_id:
|
||||||
exec_native_cmd("sfdisk --part-type %s %s %s" % \
|
exec_native_cmd("sfdisk --part-type %s %s %s" % \
|
||||||
(self.path, part.num, part.system_id),
|
(self.path, part.num, part.system_id),
|
||||||
@@ -612,6 +643,25 @@ class PartitionedImage():
|
|||||||
(self.path, part.num),
|
(self.path, part.num),
|
||||||
self.native_sysroot)
|
self.native_sysroot)
|
||||||
|
|
||||||
|
if self.ptable_format == "gpt-hybrid":
|
||||||
|
# Write a protective GPT partition
|
||||||
|
hybrid_mbr_part_num += 1
|
||||||
|
if hybrid_mbr_part_num > 4:
|
||||||
|
raise WicError("Extended MBR partitions are not supported in hybrid MBR")
|
||||||
|
|
||||||
|
# parted cannot directly create a protective GPT partition, so
|
||||||
|
# create with an arbitrary type, then change it to the correct type
|
||||||
|
# with sfdisk
|
||||||
|
self._create_partition(mbr_path, "primary", "fat32", 1, GPT_OVERHEAD)
|
||||||
|
exec_native_cmd("sfdisk --part-type %s %d 0xee" % (mbr_path, hybrid_mbr_part_num),
|
||||||
|
self.native_sysroot)
|
||||||
|
|
||||||
|
# Copy hybrid MBR
|
||||||
|
with open(mbr_path, "rb") as mbr_file:
|
||||||
|
with open(self.path, "r+b") as image_file:
|
||||||
|
mbr = mbr_file.read(512)
|
||||||
|
image_file.write(mbr)
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user