Blob Blame Raw
diff --git a/oz.cfg b/oz.cfg
index 5be1cb0..8913f9d 100644
--- a/oz.cfg
+++ b/oz.cfg
@@ -19,3 +19,9 @@ jeos = no
 
 [icicle]
 safe_generation = no
+
+[timeouts]
+install = 1200
+inactivity = 300
+boot = 300
+shutdown = 90
diff --git a/oz/Guest.py b/oz/Guest.py
index 54a0e8c..22c93c4 100644
--- a/oz/Guest.py
+++ b/oz/Guest.py
@@ -203,6 +203,16 @@ class Guest(object):
                                                                 'safe_generation',
                                                                 False)
 
+        # configuration of 'timeouts' section
+        self.default_install_timeout = int(oz.ozutil.config_get_key(config, 'timeouts',
+                                                                            'install', 1200))
+        self.inactivity_timeout = int(oz.ozutil.config_get_key(config, 'timeouts',
+                                                               'inactivity', 300))
+        self.boot_timeout = int(oz.ozutil.config_get_key(config, 'timeouts',
+                                                                 'boot', 300))
+        self.shutdown_timeout = int(oz.ozutil.config_get_key(config, 'timeouts',
+                                                                     'shutdown', 90))
+
         # only pull a cached JEOS if it was built with the correct image type
         jeos_extension = self.image_type
         if self.image_type == 'raw':
@@ -471,6 +481,10 @@ class Guest(object):
             if self.tdl.arch == "armv7l":
                 cmdline += " console=ttyAMA0"
             self.lxml_subelement(osNode, "cmdline", cmdline)
+        if self.tdl.arch == "aarch64":
+            loader,nvram = oz.ozutil.find_uefi_firmware(self.tdl.arch)
+            self.lxml_subelement(osNode, "loader", loader, {'readonly': 'yes', 'type': 'pflash'})
+            self.lxml_subelement(osNode, "nvram", None, {'template': nvram})
         # poweroff, reboot, crash
         self.lxml_subelement(domain, "on_poweroff", "destroy")
         self.lxml_subelement(domain, "on_reboot", "destroy")
@@ -761,8 +775,7 @@ class Guest(object):
                 # the passed in exception was None, just raise a generic error
                 raise oz.OzException.OzException("Unknown libvirt error")
 
-    def _wait_for_install_finish(self, libvirt_dom, count,
-                                 inactivity_timeout=300):
+    def _wait_for_install_finish(self, libvirt_dom, count):
         """
         Method to wait for an installation to finish.  This will wait around
         until either the VM has gone away (at which point it is assumed the
@@ -774,7 +787,7 @@ class Guest(object):
 
         last_disk_activity = 0
         last_network_activity = 0
-        inactivity_countdown = inactivity_timeout
+        inactivity_countdown = self.inactivity_timeout
         origcount = count
         saved_exception = None
         while count > 0 and inactivity_countdown > 0:
@@ -809,7 +822,7 @@ class Guest(object):
                 inactivity_countdown -= 1
             else:
                 # if we did see some activity, then we can reset the timer
-                inactivity_countdown = inactivity_timeout
+                inactivity_countdown = self.inactivity_timeout
 
             last_disk_activity = total_disk_req
             last_network_activity = total_net_bytes
@@ -826,18 +839,19 @@ class Guest(object):
             # if we saw no disk or network activity in the countdown window,
             # we presume the install has hung.  Fail here
             screenshot_text = self._capture_screenshot(libvirt_dom)
-            raise oz.OzException.OzException("No disk activity in %d seconds, failing.  %s" % (inactivity_timeout, screenshot_text))
+            raise oz.OzException.OzException("No disk activity in %d seconds, failing.  %s" % (self.inactivity_timeout, screenshot_text))
 
         # We get here only if we got a libvirt exception
         self._wait_for_clean_shutdown(libvirt_dom, saved_exception)
 
         self.log.info("Install of %s succeeded", self.tdl.name)
 
-    def _wait_for_guest_shutdown(self, libvirt_dom, count=90):
+    def _wait_for_guest_shutdown(self, libvirt_dom):
         """
         Method to wait around for orderly shutdown of a running guest.  Returns
         True if the guest shutdown in the specified time, False otherwise.
         """
+        count = self.shutdown_timeout
         origcount = count
         saved_exception = None
         while count > 0:
@@ -1235,12 +1249,12 @@ class Guest(object):
             sock.connect(('127.0.0.1', self.listen_port))
 
             addr = None
-            count = 300
+            count = self.boot_timeout
             data = ''
             while count > 0:
                 do_sleep = True
                 if count % 10 == 0:
-                    self.log.debug("Waiting for guest %s to boot, %d/300", self.tdl.name, count)
+                    self.log.debug("Waiting for guest %s to boot, %d/%d", self.tdl.name, count, self.boot_timeout)
                 try:
                     # note that we have to build the data up here, since there
                     # is no guarantee that we will get the whole write in one go
diff --git a/oz/RedHat.py b/oz/RedHat.py
index aaa102c..896edb7 100644
--- a/oz/RedHat.py
+++ b/oz/RedHat.py
@@ -334,6 +334,11 @@ label customiso
         # part 4; make sure the guest announces itself
         self.log.debug("Step 4: Guest announcement")
 
+        if self.tdl.arch in [ 'ppc64', 'ppc64le' ]:
+            announce_device = '/dev/hvc1'
+        else:
+            announce_device = '/dev/ttyS1'
+
         scriptfile = os.path.join(self.icicle_tmp, "script")
 
         if g_handle.exists("/etc/NetworkManager/dispatcher.d"):
@@ -342,9 +347,9 @@ label customiso
 #!/bin/bash
 
 if [ "$1" = "eth0" -a "$2" = "up" ]; then
-    echo -n "!$DHCP4_IP_ADDRESS,%s!" > /dev/ttyS1
+    echo -n "!$DHCP4_IP_ADDRESS,%s!" > %s
 fi
-""" % (self.uuid))
+""" % (self.uuid, announce_device))
 
             try:
                 g_handle.upload(scriptfile,
@@ -364,8 +369,8 @@ DEV=$(/bin/awk '{if ($2 == 0) print $1}' /proc/net/route) &&
 [ -z "$DEV" ] && exit 0
 ADDR=$(/sbin/ip -4 -o addr show dev $DEV | /bin/awk '{print $4}' | /bin/cut -d/ -f1) &&
 [ -z "$ADDR" ] && exit 0
-echo -n "!$ADDR,%s!" > /dev/ttyS1
-""" % (self.uuid))
+echo -n "!$ADDR,%s!" > %s
+""" % (self.uuid, announce_device))
 
         try:
             g_handle.upload(scriptfile, '/root/reportip')
diff --git a/oz/ozutil.py b/oz/ozutil.py
index eb4cd6f..775576b 100644
--- a/oz/ozutil.py
+++ b/oz/ozutil.py
@@ -970,3 +970,45 @@ def recursively_add_write_bit(inputdir):
             except OSError as err:
                 if err.errno != errno.ENOENT:
                     raise
+
+def find_uefi_firmware(arch):
+    # Yuck.  Finding the UEFI firmware to start certain guests (like aarch64)
+    # is a really nasty process.  While slightly out of date, this blog post
+    # describes the mess: http://blog.wikichoon.com/2016/01/uefi-support-in-virt-install-and-virt.html
+    # Here, we replicate what libguestfs is doing here, which is to essentially
+    # hardcode paths where UEFI firmware can be found on popular distributions.
+    # I verified that these files exist on both Fedora/RHEL and Ubuntu.
+    # Hopefully there will be a nicer way to do this in the future.
+    class UEFI(object):
+        def __init__(self, loader, nvram):
+            self.loader = loader
+            self.nvram = nvram
+
+        def exists(self):
+            if os.path.exists(self.loader) and os.path.exists(self.nvram):
+                return True
+            return False
+
+    if arch in ['i386', 'i486', 'i586', 'i686']:
+        uefi_list = [UEFI('/usr/share/edk2.git/ovmf-ia32/OVMF_CODE-pure-efi.fd',
+                          '/usr/share/edk2.git/ovmf-ia32/OVMF_VARS-pure-efi.fd')]
+    elif arch in ['x86_64']:
+        uefi_list = [UEFI('/usr/share/OVMF/OVMF_CODE.fd',
+                          '/usr/share/OVMF/OVMF_VARS.fd'),
+                     UEFI('/usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd',
+                          '/usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd')]
+    elif arch in ['aarch64']:
+        uefi_list = [UEFI('/usr/share/AAVMF/AAVMF_CODE.fd',
+                          '/usr/share/AAVMF/AAVMF_VARS.fd'),
+                     UEFI('/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw',
+                          '/usr/share/edk2/aarch64/vars-template-pflash.raw'),
+                     UEFI('/usr/share/edk2.git/aarch64/QEMU_EFI-pflash.raw',
+                          '/usr/share/edk2.git/aarch64/vars-template-pflash.raw')]
+    else:
+        raise Exception("Invalid arch for UEFI firmware")
+
+    for uefi in uefi_list:
+        if uefi.exists():
+            return uefi.loader,uefi.nvram
+
+    raise Exception("UEFI firmware is not installed!")