]> git.proxmox.com Git - pve-edk2-firmware.git/blobdiff - debian/python/UEFI/Qemu.py
debian: update build and packaging from Debian upstream
[pve-edk2-firmware.git] / debian / python / UEFI / Qemu.py
diff --git a/debian/python/UEFI/Qemu.py b/debian/python/UEFI/Qemu.py
new file mode 100644 (file)
index 0000000..d8aaf23
--- /dev/null
@@ -0,0 +1,181 @@
+#
+# Copyright 2019-2021 Canonical Ltd.
+# Authors:
+# - dann frazier <dann.frazier@canonical.com>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 3, as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
+# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import enum
+import os
+import shutil
+import tempfile
+
+
+class QemuEfiMachine(enum.Enum):
+    OVMF_PC = enum.auto()
+    OVMF_Q35 = enum.auto()
+    OVMF32 = enum.auto()
+    AAVMF = enum.auto()
+    AAVMF32 = enum.auto()
+
+
+class QemuEfiVariant(enum.Enum):
+    MS = enum.auto()
+    SECBOOT = enum.auto()
+    SNAKEOIL = enum.auto()
+
+
+class QemuEfiFlashSize(enum.Enum):
+    DEFAULT = enum.auto
+    SIZE_2MB = enum.auto()
+    SIZE_4MB = enum.auto()
+
+
+class QemuCommand:
+    # Based on the args used by ovmf-vars-generator
+    Qemu_Common_Params = [
+        '-no-user-config', '-nodefaults',
+        '-m', '256',
+        '-smp', '2,sockets=2,cores=1,threads=1',
+        '-display', 'none',
+        '-serial', 'stdio',
+    ]
+    Ovmf_Common_Params = Qemu_Common_Params + [
+        '-chardev', 'pty,id=charserial1',
+        '-device', 'isa-serial,chardev=charserial1,id=serial1',
+    ]
+    Aavmf_Common_Params = Qemu_Common_Params + [
+        '-machine', 'virt', '-device', 'virtio-serial-device',
+    ]
+    Machine_Base_Command = {
+        QemuEfiMachine.AAVMF: [
+            'qemu-system-aarch64', '-cpu', 'cortex-a57',
+        ] + Aavmf_Common_Params,
+        QemuEfiMachine.AAVMF32: [
+            'qemu-system-aarch64', '-cpu', 'cortex-a15',
+        ] + Aavmf_Common_Params,
+        QemuEfiMachine.OVMF_PC: [
+            'qemu-system-x86_64', '-machine', 'pc,accel=tcg',
+        ] + Ovmf_Common_Params,
+        QemuEfiMachine.OVMF_Q35: [
+            'qemu-system-x86_64', '-machine', 'q35,accel=tcg',
+        ] + Ovmf_Common_Params,
+        QemuEfiMachine.OVMF32: [
+            'qemu-system-i386', '-machine', 'q35,accel=tcg',
+        ] + Ovmf_Common_Params,
+    }
+
+    def _get_default_flash_paths(self, machine, variant, flash_size):
+        assert(machine in QemuEfiMachine)
+        assert(variant is None or variant in QemuEfiVariant)
+        assert(flash_size in QemuEfiFlashSize)
+
+        code_ext = vars_ext = ''
+        if variant == QemuEfiVariant.MS:
+            code_ext = vars_ext = '.ms'
+        elif variant == QemuEfiVariant.SECBOOT:
+            code_ext = '.secboot'
+        elif variant == QemuEfiVariant.SNAKEOIL:
+            vars_ext = '.snakeoil'
+
+        if machine == QemuEfiMachine.AAVMF:
+            assert(flash_size == QemuEfiFlashSize.DEFAULT)
+            return (
+                f'/usr/share/AAVMF/AAVMF_CODE{code_ext}.fd',
+                f'/usr/share/AAVMF/AAVMF_VARS{code_ext}.fd',
+            )
+        if machine == QemuEfiMachine.AAVMF32:
+            assert(variant is None)
+            assert(flash_size == QemuEfiFlashSize.DEFAULT)
+            return (
+                '/usr/share/AAVMF/AAVMF32_CODE.fd',
+                '/usr/share/AAVMF/AAVMF32_VARS.fd'
+            )
+        if machine == QemuEfiMachine.OVMF32:
+            assert(variant is None or variant in [QemuEfiVariant.SECBOOT])
+            assert(
+                flash_size in [
+                    QemuEfiFlashSize.DEFAULT, QemuEfiFlashSize.SIZE_4MB
+                ]
+            )
+            return (
+                '/usr/share/OVMF/OVMF32_CODE_4M.secboot.fd',
+                '/usr/share/OVMF/OVMF32_VARS_4M.fd',
+            )
+        # Remaining possibilities are OVMF variants
+        if machine == QemuEfiMachine.OVMF_PC:
+            assert(variant is None)
+        if variant == QemuEfiVariant.SNAKEOIL:
+            # We provide one size - you don't get to pick.
+            assert(flash_size == QemuEfiFlashSize.DEFAULT)
+        size_ext = '' if flash_size == QemuEfiFlashSize.SIZE_2MB else '_4M'
+        return (
+            f'/usr/share/OVMF/OVMF_CODE{size_ext}{code_ext}.fd',
+            f'/usr/share/OVMF/OVMF_VARS{size_ext}{vars_ext}.fd'
+        )
+
+    def __init__(
+            self, machine, variant=None,
+            code_path=None, vars_template_path=None,
+            flash_size=QemuEfiFlashSize.DEFAULT,
+    ):
+        assert(
+            (code_path and vars_template_path) or
+            (not code_path and not vars_template_path)
+        )
+
+        if not code_path:
+            (code_path, vars_template_path) = self._get_default_flash_paths(
+                machine, variant, flash_size)
+
+        self.pflash = self.PflashParams(code_path, vars_template_path)
+        self.command = self.Machine_Base_Command[machine] + self.pflash.params
+        if variant in [QemuEfiVariant.MS, QemuEfiVariant.SECBOOT] and \
+           flash_size == QemuEfiFlashSize.SIZE_2MB:
+            # 2MB images have 64-bit PEI that does not support S3 w/ SMM
+            self.command.extend(['-global', 'ICH9-LPC.disable_s3=1'])
+
+    def add_disk(self, path):
+        self.command = self.command + [
+            '-drive', 'file=%s,format=raw' % (path)
+        ]
+
+    def add_oem_string(self, type, string):
+        string = string.replace(",", ",,")
+        self.command = self.command + [
+            '-smbios', f'type={type},value={string}'
+        ]
+
+    class PflashParams:
+        '''
+        Used to generate the appropriate -pflash arguments for QEMU. Mostly
+        used as a fancy way to generate a per-instance vars file and have it
+        be automatically cleaned up when the object is destroyed.
+        '''
+        def __init__(self, code_path, vars_template_path):
+            with tempfile.NamedTemporaryFile(delete=False) as varfile:
+                self.varfile_path = varfile.name
+                with open(vars_template_path, 'rb') as template:
+                    shutil.copyfileobj(template, varfile)
+                self.params = [
+                    '-drive',
+                    'file=%s,if=pflash,format=raw,unit=0,readonly=on' %
+                    (code_path),
+                    '-drive',
+                    'file=%s,if=pflash,format=raw,unit=1,readonly=off' %
+                    (varfile.name)
+                ]
+
+        def __del__(self):
+            os.unlink(self.varfile_path)