From 814cb4eb801d313c7bc1b73cc0b15417261b9cd6 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Fri, 27 Dec 2019 18:25:09 +0100 Subject: [PATCH] assembler/qemu: gpt support for grub legacy The GRUB2 bootloader in legacy mode, i.e. non-EFI mode, consists of several stages. The fist one place in the in the Master Boot Record of the disk will load and execute the next, second stage, consisting of core modules and the grub kernel. The first bit is also known as 'boot' and the second as 'core'. When the 'MBR' partition layout is being used, there is a gap between the Master Boot Record (MBR) and the first partition (for historical and performance reasons). The core image normally is placed into this gap (call the MBR gap). When the partition layout is 'gpt' there is no standard gap that can be used, instead a special partition ("BIOS boot" [1]) needs to be created that can store the grub2 core image. Additionally, the 'boot' image need to modified to point the sector of that partition. The core image itself also needs to be modified with the information of the location its own second sector. The location of the pointers were taken from the grub2 source ([2] at commit [3]). For the 'boot' image it is 'GRUB_BOOT_MACHINE_KERNEL_SECTOR' (0x5c) from 'pc/boot.h' and for the core image "0x200 - GRUB_BOOT_MACHINE_LIST_SIZE (12)" to be found in 'pc/diskboot.S'. [1] https://en.wikipedia.org/wiki/BIOS_boot_partition [2] https://github.com/rhboot/grub2 [3] 2a2e10c1b39672de3d5da037a50d5c371f49b40d --- assemblers/org.osbuild.qemu | 68 ++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/assemblers/org.osbuild.qemu b/assemblers/org.osbuild.qemu index f105775d..99e772f0 100755 --- a/assemblers/org.osbuild.qemu +++ b/assemblers/org.osbuild.qemu @@ -5,6 +5,7 @@ import json import os import socket import shutil +import struct import subprocess import sys import tempfile @@ -269,6 +270,14 @@ class PartitionTable: return part return None + def find_bios_boot_partition(self) -> Partition: + """Find the BIOS-boot Partition""" + bb_type = "21686148-6449-6E6F-744E-656564454649" + for part in self.partitions: + if part.type.upper() == bb_type: + return part + return None + def write_to(self, target, sync=True): """Write the partition table to disk""" # generate the command for sfdisk to create the table @@ -394,6 +403,51 @@ def grub2_write_core_prep_part(core_f: BinaryIO, shutil.copyfileobj(core_f, image_f) +def grub2_write_core_bios_boot(core_f: BinaryIO, + image_f: BinaryIO, + pt: PartitionTable): + """Write the core to the bios boot partition""" + bb = pt.find_bios_boot_partition() + if bb is None: + raise ValueError("BIOS-boot partition missing") + core_size = os.fstat(core_f.fileno()).st_size + if bb.size_in_bytes < core_size: + raise ValueError("BIOS-boot partition too small") + + image_f.seek(bb.start_in_bytes) + shutil.copyfileobj(core_f, image_f) + + # The core image needs to know from where to load its + # second sector so that information needs to be embedded + # into the image itself at the right location, i.e. + # the "sector start parameter" ("size .long 2, 0"): + # 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE (12) = 0x1F4 = 500 + image_f.seek(bb.start_in_bytes + 500) + image_f.write(struct.pack("