assembler/qemu: refactor grub2 boot image patching
As noted in earlier commits the grub2 boot image needs to be patched to contain the position of the grub2 core. By default, the location in the boot image is hard-coded to be the mbr gap (sector 1) but for GPT partition schemes a separate BIOS boot partition is used that is located at a "random" location. Refactor the code to generalize the boot image patching, where the default mbr gap location is just a special case of the general.
This commit is contained in:
parent
814cb4eb80
commit
9e929d3db6
1 changed files with 28 additions and 18 deletions
|
|
@ -360,15 +360,25 @@ def partition_table_from_options(options) -> PartitionTable:
|
|||
|
||||
|
||||
def grub2_write_boot_image(boot_f: BinaryIO,
|
||||
image_f: BinaryIO):
|
||||
image_f: BinaryIO,
|
||||
core_location: int):
|
||||
"""Write the boot image (grub2 stage 1) to the MBR"""
|
||||
|
||||
# The boot.img file is 512 bytes, but we must only copy the first 440
|
||||
# bytes, as these contain the bootstrapping code. The rest of the
|
||||
# first sector contains the partition table, and must not be
|
||||
# overwritten.
|
||||
image_f.seek(0)
|
||||
image_f.write(boot_f.read(440))
|
||||
|
||||
# Additionally, write the location (in sectors) of
|
||||
# the grub core image, into the boot image, so the
|
||||
# latter can find the former. To exact location is
|
||||
# taken from grub2's "boot.S":
|
||||
# GRUB_BOOT_MACHINE_KERNEL_SECTOR 0x5c (= 92)
|
||||
image_f.seek(0x5c)
|
||||
image_f.write(struct.pack("<Q", core_location))
|
||||
|
||||
|
||||
def grub2_write_core_mbrgap(core_f: BinaryIO,
|
||||
image_f: BinaryIO,
|
||||
|
|
@ -384,6 +394,8 @@ def grub2_write_core_mbrgap(core_f: BinaryIO,
|
|||
image_f.seek(512)
|
||||
shutil.copyfileobj(core_f, image_f)
|
||||
|
||||
return 1 # the location of the core image in sectors
|
||||
|
||||
|
||||
def grub2_write_core_prep_part(core_f: BinaryIO,
|
||||
image_f: BinaryIO,
|
||||
|
|
@ -402,6 +414,8 @@ def grub2_write_core_prep_part(core_f: BinaryIO,
|
|||
image_f.seek(prep_part.start_in_bytes)
|
||||
shutil.copyfileobj(core_f, image_f)
|
||||
|
||||
return prep_part.start
|
||||
|
||||
|
||||
def grub2_write_core_bios_boot(core_f: BinaryIO,
|
||||
image_f: BinaryIO,
|
||||
|
|
@ -425,13 +439,7 @@ def grub2_write_core_bios_boot(core_f: BinaryIO,
|
|||
image_f.seek(bb.start_in_bytes + 500)
|
||||
image_f.write(struct.pack("<Q", bb.start + 1))
|
||||
|
||||
# Additionally, write the location (in sectors) of
|
||||
# the grub core image, into the boot image, so the
|
||||
# latter can find the former. To exact location is
|
||||
# taken from grub2's "boot.S"":
|
||||
# GRUB_BOOT_MACHINE_KERNEL_SECTOR 0x5c (= 92)
|
||||
image_f.seek(0x5c)
|
||||
image_f.write(struct.pack("<Q", bb.start))
|
||||
return bb.start
|
||||
|
||||
|
||||
def grub2_partition_id(pt: PartitionTable):
|
||||
|
|
@ -506,23 +514,25 @@ def install_grub2(image: str, pt: PartitionTable, options):
|
|||
check=True)
|
||||
|
||||
with open(image, "rb+") as image_f:
|
||||
if platform == "i386-pc":
|
||||
# On x86, install the level-1 bootloader into the start of the MBR
|
||||
# The purpose of this is simply to jump into the stage-2 bootloader.
|
||||
# On ppc64le & Open Firmware stage-2 is loaded by the firmware
|
||||
with open(boot_path, "rb") as boot_f:
|
||||
grub2_write_boot_image(boot_f, image_f)
|
||||
|
||||
# Write the newly created grub2 core to the image
|
||||
with open(core_path, "rb") as core_f:
|
||||
if platform == "powerpc-ieee1275":
|
||||
# write the core to the PrEP partition
|
||||
grub2_write_core_prep_part(core_f, image_f, pt)
|
||||
core_loc = grub2_write_core_prep_part(core_f, image_f, pt)
|
||||
elif pt.label == "gpt":
|
||||
# gpt requires a bios-boot partition
|
||||
grub2_write_core_bios_boot(core_f, image_f, pt)
|
||||
core_loc = grub2_write_core_bios_boot(core_f, image_f, pt)
|
||||
else:
|
||||
# embed the core in the MBR gap
|
||||
grub2_write_core_mbrgap(core_f, image_f, pt)
|
||||
core_loc = grub2_write_core_mbrgap(core_f, image_f, pt)
|
||||
|
||||
# On certain platforms (x86) a level 1 boot loader is required
|
||||
# to load to the core image (on ppc64le & Open Firmware this is
|
||||
# done by the firmware itself)
|
||||
if platform == "i386-pc":
|
||||
# On x86, the boot image just jumps to core image
|
||||
with open(boot_path, "rb") as boot_f:
|
||||
grub2_write_boot_image(boot_f, image_f, core_loc)
|
||||
|
||||
|
||||
def main(tree, output_dir, options, loop_client):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue