diff mbox series

[v6,6/9] tests/vm: Added a new script for ubuntu.aarch64.

Message ID 20200512193340.265-7-robert.foley@linaro.org
State New
Headers show
Series tests/vm: Add support for aarch64 VMs | expand

Commit Message

Robert Foley May 12, 2020, 7:33 p.m. UTC
ubuntu.aarch64 provides a script to create an Ubuntu 18.04 VM.
Another new file is also added aarch64vm.py, which is a module with
common methods used by aarch64 VMs, such as how to create the
flash images.

Signed-off-by: Robert Foley <robert.foley@linaro.org>

Reviewed-by: Peter Puhov <peter.puhov@linaro.org>

---
 configure                 |  16 ++++++
 tests/vm/Makefile.include |   8 +++
 tests/vm/aarch64vm.py     | 105 ++++++++++++++++++++++++++++++++++
 tests/vm/basevm.py        |   8 +++
 tests/vm/ubuntu.aarch64   | 117 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 254 insertions(+)
 create mode 100644 tests/vm/aarch64vm.py
 create mode 100755 tests/vm/ubuntu.aarch64

-- 
2.17.1

Comments

Alex Bennée May 15, 2020, 3:42 p.m. UTC | #1
Robert Foley <robert.foley@linaro.org> writes:

> ubuntu.aarch64 provides a script to create an Ubuntu 18.04 VM.

> Another new file is also added aarch64vm.py, which is a module with

> common methods used by aarch64 VMs, such as how to create the

> flash images.

>

> Signed-off-by: Robert Foley <robert.foley@linaro.org>

> Reviewed-by: Peter Puhov <peter.puhov@linaro.org>

> ---

>  configure                 |  16 ++++++

>  tests/vm/Makefile.include |   8 +++

>  tests/vm/aarch64vm.py     | 105 ++++++++++++++++++++++++++++++++++

>  tests/vm/basevm.py        |   8 +++

>  tests/vm/ubuntu.aarch64   | 117 ++++++++++++++++++++++++++++++++++++++

>  5 files changed, 254 insertions(+)

>  create mode 100644 tests/vm/aarch64vm.py

>  create mode 100755 tests/vm/ubuntu.aarch64

>

> diff --git a/configure b/configure

> index b3cf32f556..26f8561557 100755

> --- a/configure

> +++ b/configure

> @@ -950,6 +950,20 @@ do

>      fi

>  done

>  

> +# Check for files needed by aarch64 VMs.

> +# Allow user to override the path for efi also.

> +qemu_efi_aarch64=

> +for fd in $QEMU_EFI_PATH /usr/share/qemu-efi-aarch64/QEMU_EFI.fd

> +do


I don't think we should be using an unset QEMU_EFI_PATH here - we only
really preserve the environment for compiler related things. Everything
else we pass with an --option so in this case we need to wire in a
--efi-aarch64.

Also we now have a copy of an EFI bios in the pc-bios blobs directory so
we could fall back to that. The minor wrinkle is something in the build
process bunzip2's the pc-bios/edk2-aarch64-code.fd.bz2 into the build
directory. I guess we can assume it will be there if we fail to find
another copy with the above.

> +    if has $fd


The "has" test fails to fire for me as that only cares if the thing is
executable. We can just do a -f test.

> +    then

> +        if [ -f  $fd ]; then


test -f without the []'s

> +            qemu_efi_aarch64=$fd

> +        fi

> +        break


break the loop if we find what we are looking for.

> +    fi

> +done

> +

>  # Check for existence of python3 yaml, needed to

>  # import yaml config files into vm-build.

>  python_yaml="no"

> @@ -6588,6 +6602,7 @@ if test "$docs" != "no"; then

>      echo "sphinx-build      $sphinx_build"

>  fi

>  echo "genisoimage       $genisoimage"

> +echo "qemu_efi_aarch64  $qemu_efi_aarch64"

>  echo "python_yaml       $python_yaml"

>  echo "slirp support     $slirp $(echo_version $slirp $slirp_version)"

>  if test "$slirp" != "no" ; then

> @@ -7650,6 +7665,7 @@ echo "PYTHON=$python" >> $config_host_mak

>  echo "SPHINX_BUILD=$sphinx_build" >> $config_host_mak

>  echo "SPHINX_WERROR=$sphinx_werror" >> $config_host_mak

>  echo "GENISOIMAGE=$genisoimage" >> $config_host_mak

> +echo "QEMU_EFI_AARCH64=$qemu_efi_aarch64" >> $config_host_mak

>  echo "PYTHON_YAML=$python_yaml" >> $config_host_mak

>  echo "CC=$cc" >> $config_host_mak

>  if $iasl -h > /dev/null 2>&1; then

> diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include

> index 99c06832ac..d918d13f50 100644

> --- a/tests/vm/Makefile.include

> +++ b/tests/vm/Makefile.include

> @@ -5,6 +5,9 @@

>  IMAGES := freebsd netbsd openbsd centos fedora

>  ifneq ($(GENISOIMAGE),)

>  IMAGES += ubuntu.i386 centos

> +ifneq ($(QEMU_EFI_AARCH64),)

> +IMAGES += ubuntu.aarch64

> +endif

>  endif

>  

>  IMAGES_DIR := $(HOME)/.cache/qemu-vm/images

> @@ -23,6 +26,11 @@ vm-help vm-test:

>  ifneq ($(GENISOIMAGE),)

>  	@echo "  vm-build-centos                 - Build QEMU in CentOS VM, with Docker"

>  	@echo "  vm-build-ubuntu.i386            - Build QEMU in ubuntu i386 VM"

> +ifneq ($(QEMU_EFI_AARCH64),)

> +	@echo "  vm-build-ubuntu.aarch64         - Build QEMU in ubuntu aarch64 VM"

> +else

> +	@echo "  (install qemu-efi-aarch64 to build centos/ubuntu aarch64 images.)"

> +endif

>  else

>  	@echo "  (install genisoimage to build centos/ubuntu images)"

>  endif

> diff --git a/tests/vm/aarch64vm.py b/tests/vm/aarch64vm.py

> new file mode 100644

> index 0000000000..3a9807cd43

> --- /dev/null

> +++ b/tests/vm/aarch64vm.py

> @@ -0,0 +1,105 @@

> +#!/usr/bin/env python3

> +#

> +# VM testing aarch64 library

> +#

> +# Copyright 2020 Linaro

> +#

> +# Authors:

> +#  Robert Foley <robert.foley@linaro.org>

> +#

> +# This code is licensed under the GPL version 2 or later.  See

> +# the COPYING file in the top-level directory.

> +#

> +import os

> +import sys

> +import subprocess

> +import basevm

> +from qemu.accel import kvm_available

> +

> +# This is the config needed for current version of QEMU.

> +# This works for both kvm and tcg.

> +CURRENT_CONFIG = {

> +    'cpu'          : "max",

> +    'machine'      : "virt,gic-version=max",

> +}

> +

> +# The minimum minor version of QEMU we will support with aarch64 VMs is 3.

> +# QEMU versions less than 3 have various issues running these VMs.

> +QEMU_AARCH64_MIN_VERSION = 3

> +

> +# The DEFAULT_CONFIG will default to a version of

> +# parameters that works for backwards compatibility.

> +DEFAULT_CONFIG = {'kvm' : {'cpu'          : "host",

> +                           'machine'      : "virt,gic-version=host"},

> +                  'tcg' : {'cpu'          : "cortex-a57",

> +                           'machine'      : "virt"},

> +}

> +

> +def get_config_defaults(vmcls, default_config):

> +    """Fetch the configuration defaults for this VM,

> +       taking into consideration the defaults for

> +       aarch64 first, followed by the defaults for this VM."""

> +    config = default_config

> +    config.update(aarch_get_config_defaults(vmcls))

> +    return config

> +

> +def aarch_get_config_defaults(vmcls):

> +    """Set the defaults for current version of QEMU."""

> +    config = CURRENT_CONFIG

> +    args, argv = basevm.parse_args(vmcls)

> +    qemu_path = basevm.get_qemu_path(vmcls.arch, args.build_path)

> +    qemu_version = basevm.get_qemu_version(qemu_path)

> +    if qemu_version < QEMU_AARCH64_MIN_VERSION:

> +        error = "\nThis major version of QEMU {} is to old for aarch64 VMs.\n"\

> +                "The major version must be at least {}.\n"\

> +                "To continue with the current build of QEMU, "\

> +                "please restart with QEMU_LOCAL=1 .\n"

> +        print(error.format(qemu_version, QEMU_AARCH64_MIN_VERSION))

> +        exit(1)

> +    if qemu_version == QEMU_AARCH64_MIN_VERSION:

> +        # We have an older version of QEMU,

> +        # set the config values for backwards compatibility.

> +        if kvm_available('aarch64'):

> +            config.update(DEFAULT_CONFIG['kvm'])

> +        else:

> +            config.update(DEFAULT_CONFIG['tcg'])

> +    return config

> +

> +def create_flash_images(flash_dir="./"):

> +    """Creates the appropriate pflash files

> +       for an aarch64 VM."""

> +    flash0_path = get_flash_path(flash_dir, "flash0")

> +    flash1_path = get_flash_path(flash_dir, "flash1")

> +    fd_null = open(os.devnull, 'w')

> +    subprocess.check_call(["dd", "if=/dev/zero", "of={}".format(flash0_path),

> +                           "bs=1M", "count=64"],

> +                           stdout=fd_null, stderr=subprocess.STDOUT)

> +    # A reliable way to get the QEMU EFI image is via an installed package.

> +    efi_img = "/usr/share/qemu-efi-aarch64/QEMU_EFI.fd"

> +    if not os.path.exists(efi_img):

> +        sys.stderr.write("*** {} is missing\n".format(efi_img))

> +        sys.stderr.write("*** please install qemu-efi-aarch64 package\n")

> +        exit(3)


This is hardcoded when we have just probed for it.

<snip>

Otherwise it looks ok to me.

-- 
Alex Bennée
Robert Foley May 15, 2020, 6:05 p.m. UTC | #2
Hi Alex,

These are all good points.  I will make these changes.

Thanks & Regards,
-Rob

On Fri, 15 May 2020 at 11:42, Alex Bennée <alex.bennee@linaro.org> wrote:
>

>

> Robert Foley <robert.foley@linaro.org> writes:

>

> > ubuntu.aarch64 provides a script to create an Ubuntu 18.04 VM.

> > Another new file is also added aarch64vm.py, which is a module with

> > common methods used by aarch64 VMs, such as how to create the

> > flash images.

> >

> > Signed-off-by: Robert Foley <robert.foley@linaro.org>

> > Reviewed-by: Peter Puhov <peter.puhov@linaro.org>

> > ---

> >  configure                 |  16 ++++++

> >  tests/vm/Makefile.include |   8 +++

> >  tests/vm/aarch64vm.py     | 105 ++++++++++++++++++++++++++++++++++

> >  tests/vm/basevm.py        |   8 +++

> >  tests/vm/ubuntu.aarch64   | 117 ++++++++++++++++++++++++++++++++++++++

> >  5 files changed, 254 insertions(+)

> >  create mode 100644 tests/vm/aarch64vm.py

> >  create mode 100755 tests/vm/ubuntu.aarch64

> >

> > diff --git a/configure b/configure

> > index b3cf32f556..26f8561557 100755

> > --- a/configure

> > +++ b/configure

> > @@ -950,6 +950,20 @@ do

> >      fi

> >  done

> >

> > +# Check for files needed by aarch64 VMs.

> > +# Allow user to override the path for efi also.

> > +qemu_efi_aarch64=

> > +for fd in $QEMU_EFI_PATH /usr/share/qemu-efi-aarch64/QEMU_EFI.fd

> > +do

>

> I don't think we should be using an unset QEMU_EFI_PATH here - we only

> really preserve the environment for compiler related things. Everything

> else we pass with an --option so in this case we need to wire in a

> --efi-aarch64.

>

> Also we now have a copy of an EFI bios in the pc-bios blobs directory so

> we could fall back to that. The minor wrinkle is something in the build

> process bunzip2's the pc-bios/edk2-aarch64-code.fd.bz2 into the build

> directory. I guess we can assume it will be there if we fail to find

> another copy with the above.

>

> > +    if has $fd

>

> The "has" test fails to fire for me as that only cares if the thing is

> executable. We can just do a -f test.

>

> > +    then

> > +        if [ -f  $fd ]; then

>

> test -f without the []'s

>

> > +            qemu_efi_aarch64=$fd

> > +        fi

> > +        break

>

> break the loop if we find what we are looking for.

>

> > +    fi

> > +done

> > +

> >  # Check for existence of python3 yaml, needed to

> >  # import yaml config files into vm-build.

> >  python_yaml="no"

> > @@ -6588,6 +6602,7 @@ if test "$docs" != "no"; then

> >      echo "sphinx-build      $sphinx_build"

> >  fi

> >  echo "genisoimage       $genisoimage"

> > +echo "qemu_efi_aarch64  $qemu_efi_aarch64"

> >  echo "python_yaml       $python_yaml"

> >  echo "slirp support     $slirp $(echo_version $slirp $slirp_version)"

> >  if test "$slirp" != "no" ; then

> > @@ -7650,6 +7665,7 @@ echo "PYTHON=$python" >> $config_host_mak

> >  echo "SPHINX_BUILD=$sphinx_build" >> $config_host_mak

> >  echo "SPHINX_WERROR=$sphinx_werror" >> $config_host_mak

> >  echo "GENISOIMAGE=$genisoimage" >> $config_host_mak

> > +echo "QEMU_EFI_AARCH64=$qemu_efi_aarch64" >> $config_host_mak

> >  echo "PYTHON_YAML=$python_yaml" >> $config_host_mak

> >  echo "CC=$cc" >> $config_host_mak

> >  if $iasl -h > /dev/null 2>&1; then

> > diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include

> > index 99c06832ac..d918d13f50 100644

> > --- a/tests/vm/Makefile.include

> > +++ b/tests/vm/Makefile.include

> > @@ -5,6 +5,9 @@

> >  IMAGES := freebsd netbsd openbsd centos fedora

> >  ifneq ($(GENISOIMAGE),)

> >  IMAGES += ubuntu.i386 centos

> > +ifneq ($(QEMU_EFI_AARCH64),)

> > +IMAGES += ubuntu.aarch64

> > +endif

> >  endif

> >

> >  IMAGES_DIR := $(HOME)/.cache/qemu-vm/images

> > @@ -23,6 +26,11 @@ vm-help vm-test:

> >  ifneq ($(GENISOIMAGE),)

> >       @echo "  vm-build-centos                 - Build QEMU in CentOS VM, with Docker"

> >       @echo "  vm-build-ubuntu.i386            - Build QEMU in ubuntu i386 VM"

> > +ifneq ($(QEMU_EFI_AARCH64),)

> > +     @echo "  vm-build-ubuntu.aarch64         - Build QEMU in ubuntu aarch64 VM"

> > +else

> > +     @echo "  (install qemu-efi-aarch64 to build centos/ubuntu aarch64 images.)"

> > +endif

> >  else

> >       @echo "  (install genisoimage to build centos/ubuntu images)"

> >  endif

> > diff --git a/tests/vm/aarch64vm.py b/tests/vm/aarch64vm.py

> > new file mode 100644

> > index 0000000000..3a9807cd43

> > --- /dev/null

> > +++ b/tests/vm/aarch64vm.py

> > @@ -0,0 +1,105 @@

> > +#!/usr/bin/env python3

> > +#

> > +# VM testing aarch64 library

> > +#

> > +# Copyright 2020 Linaro

> > +#

> > +# Authors:

> > +#  Robert Foley <robert.foley@linaro.org>

> > +#

> > +# This code is licensed under the GPL version 2 or later.  See

> > +# the COPYING file in the top-level directory.

> > +#

> > +import os

> > +import sys

> > +import subprocess

> > +import basevm

> > +from qemu.accel import kvm_available

> > +

> > +# This is the config needed for current version of QEMU.

> > +# This works for both kvm and tcg.

> > +CURRENT_CONFIG = {

> > +    'cpu'          : "max",

> > +    'machine'      : "virt,gic-version=max",

> > +}

> > +

> > +# The minimum minor version of QEMU we will support with aarch64 VMs is 3.

> > +# QEMU versions less than 3 have various issues running these VMs.

> > +QEMU_AARCH64_MIN_VERSION = 3

> > +

> > +# The DEFAULT_CONFIG will default to a version of

> > +# parameters that works for backwards compatibility.

> > +DEFAULT_CONFIG = {'kvm' : {'cpu'          : "host",

> > +                           'machine'      : "virt,gic-version=host"},

> > +                  'tcg' : {'cpu'          : "cortex-a57",

> > +                           'machine'      : "virt"},

> > +}

> > +

> > +def get_config_defaults(vmcls, default_config):

> > +    """Fetch the configuration defaults for this VM,

> > +       taking into consideration the defaults for

> > +       aarch64 first, followed by the defaults for this VM."""

> > +    config = default_config

> > +    config.update(aarch_get_config_defaults(vmcls))

> > +    return config

> > +

> > +def aarch_get_config_defaults(vmcls):

> > +    """Set the defaults for current version of QEMU."""

> > +    config = CURRENT_CONFIG

> > +    args, argv = basevm.parse_args(vmcls)

> > +    qemu_path = basevm.get_qemu_path(vmcls.arch, args.build_path)

> > +    qemu_version = basevm.get_qemu_version(qemu_path)

> > +    if qemu_version < QEMU_AARCH64_MIN_VERSION:

> > +        error = "\nThis major version of QEMU {} is to old for aarch64 VMs.\n"\

> > +                "The major version must be at least {}.\n"\

> > +                "To continue with the current build of QEMU, "\

> > +                "please restart with QEMU_LOCAL=1 .\n"

> > +        print(error.format(qemu_version, QEMU_AARCH64_MIN_VERSION))

> > +        exit(1)

> > +    if qemu_version == QEMU_AARCH64_MIN_VERSION:

> > +        # We have an older version of QEMU,

> > +        # set the config values for backwards compatibility.

> > +        if kvm_available('aarch64'):

> > +            config.update(DEFAULT_CONFIG['kvm'])

> > +        else:

> > +            config.update(DEFAULT_CONFIG['tcg'])

> > +    return config

> > +

> > +def create_flash_images(flash_dir="./"):

> > +    """Creates the appropriate pflash files

> > +       for an aarch64 VM."""

> > +    flash0_path = get_flash_path(flash_dir, "flash0")

> > +    flash1_path = get_flash_path(flash_dir, "flash1")

> > +    fd_null = open(os.devnull, 'w')

> > +    subprocess.check_call(["dd", "if=/dev/zero", "of={}".format(flash0_path),

> > +                           "bs=1M", "count=64"],

> > +                           stdout=fd_null, stderr=subprocess.STDOUT)

> > +    # A reliable way to get the QEMU EFI image is via an installed package.

> > +    efi_img = "/usr/share/qemu-efi-aarch64/QEMU_EFI.fd"

> > +    if not os.path.exists(efi_img):

> > +        sys.stderr.write("*** {} is missing\n".format(efi_img))

> > +        sys.stderr.write("*** please install qemu-efi-aarch64 package\n")

> > +        exit(3)

>

> This is hardcoded when we have just probed for it.

>

> <snip>

>

> Otherwise it looks ok to me.

>

> --

> Alex Bennée
diff mbox series

Patch

diff --git a/configure b/configure
index b3cf32f556..26f8561557 100755
--- a/configure
+++ b/configure
@@ -950,6 +950,20 @@  do
     fi
 done
 
+# Check for files needed by aarch64 VMs.
+# Allow user to override the path for efi also.
+qemu_efi_aarch64=
+for fd in $QEMU_EFI_PATH /usr/share/qemu-efi-aarch64/QEMU_EFI.fd
+do
+    if has $fd
+    then
+        if [ -f  $fd ]; then
+            qemu_efi_aarch64=$fd
+        fi
+        break
+    fi
+done
+
 # Check for existence of python3 yaml, needed to
 # import yaml config files into vm-build.
 python_yaml="no"
@@ -6588,6 +6602,7 @@  if test "$docs" != "no"; then
     echo "sphinx-build      $sphinx_build"
 fi
 echo "genisoimage       $genisoimage"
+echo "qemu_efi_aarch64  $qemu_efi_aarch64"
 echo "python_yaml       $python_yaml"
 echo "slirp support     $slirp $(echo_version $slirp $slirp_version)"
 if test "$slirp" != "no" ; then
@@ -7650,6 +7665,7 @@  echo "PYTHON=$python" >> $config_host_mak
 echo "SPHINX_BUILD=$sphinx_build" >> $config_host_mak
 echo "SPHINX_WERROR=$sphinx_werror" >> $config_host_mak
 echo "GENISOIMAGE=$genisoimage" >> $config_host_mak
+echo "QEMU_EFI_AARCH64=$qemu_efi_aarch64" >> $config_host_mak
 echo "PYTHON_YAML=$python_yaml" >> $config_host_mak
 echo "CC=$cc" >> $config_host_mak
 if $iasl -h > /dev/null 2>&1; then
diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include
index 99c06832ac..d918d13f50 100644
--- a/tests/vm/Makefile.include
+++ b/tests/vm/Makefile.include
@@ -5,6 +5,9 @@ 
 IMAGES := freebsd netbsd openbsd centos fedora
 ifneq ($(GENISOIMAGE),)
 IMAGES += ubuntu.i386 centos
+ifneq ($(QEMU_EFI_AARCH64),)
+IMAGES += ubuntu.aarch64
+endif
 endif
 
 IMAGES_DIR := $(HOME)/.cache/qemu-vm/images
@@ -23,6 +26,11 @@  vm-help vm-test:
 ifneq ($(GENISOIMAGE),)
 	@echo "  vm-build-centos                 - Build QEMU in CentOS VM, with Docker"
 	@echo "  vm-build-ubuntu.i386            - Build QEMU in ubuntu i386 VM"
+ifneq ($(QEMU_EFI_AARCH64),)
+	@echo "  vm-build-ubuntu.aarch64         - Build QEMU in ubuntu aarch64 VM"
+else
+	@echo "  (install qemu-efi-aarch64 to build centos/ubuntu aarch64 images.)"
+endif
 else
 	@echo "  (install genisoimage to build centos/ubuntu images)"
 endif
diff --git a/tests/vm/aarch64vm.py b/tests/vm/aarch64vm.py
new file mode 100644
index 0000000000..3a9807cd43
--- /dev/null
+++ b/tests/vm/aarch64vm.py
@@ -0,0 +1,105 @@ 
+#!/usr/bin/env python3
+#
+# VM testing aarch64 library
+#
+# Copyright 2020 Linaro
+#
+# Authors:
+#  Robert Foley <robert.foley@linaro.org>
+#
+# This code is licensed under the GPL version 2 or later.  See
+# the COPYING file in the top-level directory.
+#
+import os
+import sys
+import subprocess
+import basevm
+from qemu.accel import kvm_available
+
+# This is the config needed for current version of QEMU.
+# This works for both kvm and tcg.
+CURRENT_CONFIG = {
+    'cpu'          : "max",
+    'machine'      : "virt,gic-version=max",
+}
+
+# The minimum minor version of QEMU we will support with aarch64 VMs is 3.
+# QEMU versions less than 3 have various issues running these VMs.
+QEMU_AARCH64_MIN_VERSION = 3
+
+# The DEFAULT_CONFIG will default to a version of
+# parameters that works for backwards compatibility.
+DEFAULT_CONFIG = {'kvm' : {'cpu'          : "host",
+                           'machine'      : "virt,gic-version=host"},
+                  'tcg' : {'cpu'          : "cortex-a57",
+                           'machine'      : "virt"},
+}
+
+def get_config_defaults(vmcls, default_config):
+    """Fetch the configuration defaults for this VM,
+       taking into consideration the defaults for
+       aarch64 first, followed by the defaults for this VM."""
+    config = default_config
+    config.update(aarch_get_config_defaults(vmcls))
+    return config
+
+def aarch_get_config_defaults(vmcls):
+    """Set the defaults for current version of QEMU."""
+    config = CURRENT_CONFIG
+    args, argv = basevm.parse_args(vmcls)
+    qemu_path = basevm.get_qemu_path(vmcls.arch, args.build_path)
+    qemu_version = basevm.get_qemu_version(qemu_path)
+    if qemu_version < QEMU_AARCH64_MIN_VERSION:
+        error = "\nThis major version of QEMU {} is to old for aarch64 VMs.\n"\
+                "The major version must be at least {}.\n"\
+                "To continue with the current build of QEMU, "\
+                "please restart with QEMU_LOCAL=1 .\n"
+        print(error.format(qemu_version, QEMU_AARCH64_MIN_VERSION))
+        exit(1)
+    if qemu_version == QEMU_AARCH64_MIN_VERSION:
+        # We have an older version of QEMU,
+        # set the config values for backwards compatibility.
+        if kvm_available('aarch64'):
+            config.update(DEFAULT_CONFIG['kvm'])
+        else:
+            config.update(DEFAULT_CONFIG['tcg'])
+    return config
+
+def create_flash_images(flash_dir="./"):
+    """Creates the appropriate pflash files
+       for an aarch64 VM."""
+    flash0_path = get_flash_path(flash_dir, "flash0")
+    flash1_path = get_flash_path(flash_dir, "flash1")
+    fd_null = open(os.devnull, 'w')
+    subprocess.check_call(["dd", "if=/dev/zero", "of={}".format(flash0_path),
+                           "bs=1M", "count=64"],
+                           stdout=fd_null, stderr=subprocess.STDOUT)
+    # A reliable way to get the QEMU EFI image is via an installed package.
+    efi_img = "/usr/share/qemu-efi-aarch64/QEMU_EFI.fd"
+    if not os.path.exists(efi_img):
+        sys.stderr.write("*** {} is missing\n".format(efi_img))
+        sys.stderr.write("*** please install qemu-efi-aarch64 package\n")
+        exit(3)
+    subprocess.check_call(["dd", "if={}".format(efi_img),
+                           "of={}".format(flash0_path),
+                           "conv=notrunc"],
+                           stdout=fd_null, stderr=subprocess.STDOUT)
+    subprocess.check_call(["dd", "if=/dev/zero",
+                           "of={}".format(flash1_path),
+                           "bs=1M", "count=64"],
+                           stdout=fd_null, stderr=subprocess.STDOUT)
+    fd_null.close()
+
+def get_pflash_args(flash_dir="./"):
+    """Returns a string that can be used to
+       boot qemu using the appropriate pflash files
+       for aarch64."""
+    flash0_path = get_flash_path(flash_dir, "flash0")
+    flash1_path = get_flash_path(flash_dir, "flash1")
+    pflash_args_str = "-drive file={},format=raw,if=pflash "\
+                      "-drive file={},format=raw,if=pflash"
+    pflash_args = pflash_args_str.format(flash0_path, flash1_path)
+    return pflash_args.split(" ")
+
+def get_flash_path(flash_dir, name):
+    return os.path.join(flash_dir, "{}.img".format(name))
diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
index 4fa1ea8fde..e94b2d0356 100644
--- a/tests/vm/basevm.py
+++ b/tests/vm/basevm.py
@@ -497,6 +497,14 @@  def get_qemu_path(arch, build_path=None):
         qemu_path = "qemu-system-" + arch
     return qemu_path
 
+def get_qemu_version(qemu_path):
+    """Get the version number from the current QEMU,
+       and return the major number."""
+    output = subprocess.check_output([qemu_path, '--version'])
+    version_line = output.decode("utf-8")
+    version_num = re.split(' |\(', version_line)[3].split('.')[0]
+    return int(version_num)
+
 def parse_config(config, args):
     """ Parse yaml config and populate our config structure.
         The yaml config allows the user to override the
diff --git a/tests/vm/ubuntu.aarch64 b/tests/vm/ubuntu.aarch64
new file mode 100755
index 0000000000..81d3b2f5ed
--- /dev/null
+++ b/tests/vm/ubuntu.aarch64
@@ -0,0 +1,117 @@ 
+#!/usr/bin/env python3
+#
+# Ubuntu aarch64 image
+#
+# Copyright 2020 Linaro
+#
+# Authors:
+#  Robert Foley <robert.foley@linaro.org>
+#  Originally based on ubuntu.i386 Fam Zheng <famz@redhat.com>
+#
+# This code is licensed under the GPL version 2 or later.  See
+# the COPYING file in the top-level directory.
+#
+
+import os
+import sys
+import subprocess
+import basevm
+from qemu.accel import kvm_available
+import time
+import aarch64vm
+
+DEFAULT_CONFIG = {
+    'cpu'          : "cortex-a57",
+    'machine'      : "virt,gic-version=3",
+    'install_cmds' : "apt-get update,"\
+                     "apt-get build-dep -y --arch-only qemu,"\
+                     "apt-get install -y libfdt-dev flex bison pkg-config",
+    # We increase beyond the default time since during boot
+    # it can take some time (many seconds) to log into the VM
+    # especially using softmmu.
+    'ssh_timeout'  : 60,
+}
+
+class UbuntuAarch64VM(basevm.BaseVM):
+    name = "ubuntu.aarch64"
+    arch = "aarch64"
+    image_name = "ubuntu-18.04-server-cloudimg-arm64.img"
+    image_link = "https://cloud-images.ubuntu.com/releases/18.04/release/" + image_name
+    login_prompt = "ubuntu-aarch64-guest login:"
+    BUILD_SCRIPT = """
+        set -e;
+        cd $(mktemp -d);
+        sudo chmod a+r /dev/vdb;
+        tar --checkpoint=.10 -xf /dev/vdb;
+        ./configure {configure_opts};
+        make --output-sync {target} -j{jobs} {verbose};
+    """
+    def boot(self, img, extra_args=None):
+        aarch64vm.create_flash_images(self._tmpdir)
+        default_args = aarch64vm.get_pflash_args(self._tmpdir)
+        if extra_args:
+            extra_args.extend(default_args)
+        else:
+            extra_args = default_args
+        # We always add these performance tweaks
+        # because without them, we boot so slowly that we
+        # can time out finding the boot efi device.
+        if '-smp' not in extra_args and \
+           '-smp' not in self._config['extra_args'] and \
+           '-smp' not in self._args:
+            # Only add if not already there to give caller option to change it.
+            extra_args.extend(["-smp", "8"])
+
+        # We have overridden boot() since aarch64 has additional parameters.
+        # Call down to the base class method.
+        super(UbuntuAarch64VM, self).boot(img, extra_args=extra_args)
+
+    def build_image(self, img):
+        os_img = self._download_with_cache(self.image_link)
+        img_tmp = img + ".tmp"
+        subprocess.check_call(["cp", "-f", os_img, img_tmp])
+        subprocess.check_call(["qemu-img", "resize", img_tmp, "+50G"])
+        ci_img = self.gen_cloud_init_iso()
+
+        self.boot(img_tmp, extra_args = ["-cdrom", ci_img])
+        if self.debug:
+            self.wait_boot()
+        # First command we issue is fix for slow ssh login.
+        self.wait_ssh(wait_root=True,
+                      cmd="chmod -x /etc/update-motd.d/*")
+        # Wait for cloud init to finish
+        self.wait_ssh(wait_root=True,
+                      cmd="ls /var/lib/cloud/instance/boot-finished")
+        self.ssh_root("touch /etc/cloud/cloud-init.disabled")
+        # Disable auto upgrades.
+        # We want to keep the VM system state stable.
+        self.ssh_root('sed -ie \'s/"1"/"0"/g\' /etc/apt/apt.conf.d/20auto-upgrades')
+        # If the user chooses *not* to do the second phase,
+        # then we will jump right to the graceful shutdown
+        if self._config['install_cmds'] != "":
+            self.ssh_root("sync")
+            # Shutdown and then boot it again.
+            # Allows us to know for sure it is booting (not shutting down)
+            # before we call wait_ssh().
+            self.graceful_shutdown()
+            self.boot(img_tmp)
+            if self.debug:
+                self.wait_boot()
+            self.wait_ssh(wait_root=True)
+            self.wait_ssh(wait_root=True, cmd="locale")
+            # The previous update sometimes doesn't survive a reboot, so do it again
+            self.ssh_root("sed -ie s/^#\ deb-src/deb-src/g /etc/apt/sources.list")
+
+            # Issue the install commands.
+            # This can be overriden by the user in the config .yml.
+            install_cmds = self._config['install_cmds'].split(',')
+            for cmd in install_cmds:
+                self.ssh_root(cmd)
+        self.graceful_shutdown()
+        self.wait()
+        os.rename(img_tmp, img)
+        return 0
+
+if __name__ == "__main__":
+    defaults = aarch64vm.get_config_defaults(UbuntuAarch64VM, DEFAULT_CONFIG)
+    sys.exit(basevm.main(UbuntuAarch64VM, defaults))