pve-edk2-firmware/debian/python/UEFI/Qemu.py
Thomas Lamprecht d7274593bf debian: sync tests with packaging upstream
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2023-03-07 10:01:59 +01:00

181 lines
6.3 KiB
Python

#
# 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:
Qemu_Common_Params = [
'-no-user-config', '-nodefaults',
'-m', '256',
'-smp', '1,sockets=1,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)