| 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # VM testing aarch64 library |
| 4 | # |
| 5 | # Copyright 2020 Linaro |
| 6 | # |
| 7 | # Authors: |
| 8 | # Robert Foley <robert.foley@linaro.org> |
| 9 | # |
| 10 | # This code is licensed under the GPL version 2 or later. See |
| 11 | # the COPYING file in the top-level directory. |
| 12 | # |
| 13 | import os |
| 14 | import sys |
| 15 | import subprocess |
| 16 | import basevm |
| 17 | from qemu.utils import kvm_available |
| 18 | |
| 19 | # This is the config needed for current version of QEMU. |
| 20 | # This works for both kvm and tcg. |
| 21 | CURRENT_CONFIG = { |
| 22 | 'cpu' : "max", |
| 23 | 'machine' : "virt,gic-version=max", |
| 24 | } |
| 25 | |
| 26 | # The minimum minor version of QEMU we will support with aarch64 VMs is 3. |
| 27 | # QEMU versions less than 3 have various issues running these VMs. |
| 28 | QEMU_AARCH64_MIN_VERSION = 3 |
| 29 | |
| 30 | # The DEFAULT_CONFIG will default to a version of |
| 31 | # parameters that works for backwards compatibility. |
| 32 | DEFAULT_CONFIG = {'kvm' : {'cpu' : "host", |
| 33 | 'machine' : "virt,gic-version=host"}, |
| 34 | 'tcg' : {'cpu' : "cortex-a57", |
| 35 | 'machine' : "virt"}, |
| 36 | } |
| 37 | |
| 38 | def get_config_defaults(vmcls, default_config): |
| 39 | """Fetch the configuration defaults for this VM, |
| 40 | taking into consideration the defaults for |
| 41 | aarch64 first, followed by the defaults for this VM.""" |
| 42 | config = default_config |
| 43 | config.update(aarch_get_config_defaults(vmcls)) |
| 44 | return config |
| 45 | |
| 46 | def aarch_get_config_defaults(vmcls): |
| 47 | """Set the defaults for current version of QEMU.""" |
| 48 | config = CURRENT_CONFIG |
| 49 | args = basevm.parse_args(vmcls) |
| 50 | qemu_path = basevm.get_qemu_path(vmcls.arch, args.build_path) |
| 51 | qemu_version = basevm.get_qemu_version(qemu_path) |
| 52 | if qemu_version < QEMU_AARCH64_MIN_VERSION: |
| 53 | error = "\nThis major version of QEMU {} is to old for aarch64 VMs.\n"\ |
| 54 | "The major version must be at least {}.\n"\ |
| 55 | "To continue with the current build of QEMU, "\ |
| 56 | "please restart with QEMU_LOCAL=1 .\n" |
| 57 | print(error.format(qemu_version, QEMU_AARCH64_MIN_VERSION)) |
| 58 | exit(1) |
| 59 | if qemu_version == QEMU_AARCH64_MIN_VERSION: |
| 60 | # We have an older version of QEMU, |
| 61 | # set the config values for backwards compatibility. |
| 62 | if kvm_available('aarch64'): |
| 63 | config.update(DEFAULT_CONFIG['kvm']) |
| 64 | else: |
| 65 | config.update(DEFAULT_CONFIG['tcg']) |
| 66 | return config |
| 67 | |
| 68 | def create_flash_images(flash_dir="./", efi_img=""): |
| 69 | """Creates the appropriate pflash files |
| 70 | for an aarch64 VM.""" |
| 71 | flash0_path = get_flash_path(flash_dir, "flash0") |
| 72 | flash1_path = get_flash_path(flash_dir, "flash1") |
| 73 | fd_null = open(os.devnull, 'w') |
| 74 | subprocess.check_call(["dd", "if=/dev/zero", "of={}".format(flash0_path), |
| 75 | "bs=1M", "count=64"], |
| 76 | stdout=fd_null, stderr=subprocess.STDOUT) |
| 77 | # A reliable way to get the QEMU EFI image is via an installed package or |
| 78 | # via the bios included with qemu. |
| 79 | if not os.path.exists(efi_img): |
| 80 | sys.stderr.write("*** efi argument is invalid ({})\n".format(efi_img)) |
| 81 | sys.stderr.write("*** please check --efi-aarch64 argument or "\ |
| 82 | "install qemu-efi-aarch64 package\n") |
| 83 | exit(3) |
| 84 | subprocess.check_call(["dd", "if={}".format(efi_img), |
| 85 | "of={}".format(flash0_path), |
| 86 | "conv=notrunc"], |
| 87 | stdout=fd_null, stderr=subprocess.STDOUT) |
| 88 | subprocess.check_call(["dd", "if=/dev/zero", |
| 89 | "of={}".format(flash1_path), |
| 90 | "bs=1M", "count=64"], |
| 91 | stdout=fd_null, stderr=subprocess.STDOUT) |
| 92 | fd_null.close() |
| 93 | |
| 94 | def get_pflash_args(flash_dir="./"): |
| 95 | """Returns a string that can be used to |
| 96 | boot qemu using the appropriate pflash files |
| 97 | for aarch64.""" |
| 98 | flash0_path = get_flash_path(flash_dir, "flash0") |
| 99 | flash1_path = get_flash_path(flash_dir, "flash1") |
| 100 | pflash_args_str = "-drive file={},format=raw,if=pflash "\ |
| 101 | "-drive file={},format=raw,if=pflash" |
| 102 | pflash_args = pflash_args_str.format(flash0_path, flash1_path) |
| 103 | return pflash_args.split(" ") |
| 104 | |
| 105 | def get_flash_path(flash_dir, name): |
| 106 | return os.path.join(flash_dir, "{}.img".format(name)) |