[dts] [PATCH v2] framework: enable AArch64 and add more options for libvirt

Herbert Guan herbert.guan at arm.com
Wed Jan 3 05:40:04 CET 2018


1) Add the libvirt support on AArch64 platforms
2) Add 'loader' and 'nvram' option support in 'os' section
3) Add 'opt_bus', 'opt_dev' and 'opt_controller' option support in
   'disk' section.  Change 'type' to 'opt_format' to get aligined
   with option naming in qemu_kvm.
4) Add serial 'serial_option' option support for serial console
5) Add domain parsing in __parse_pci()
6) Function add_vm_device() uses 'opt_host' to specify PCI address

Signed-off-by: Herbert Guan <herbert.guan at arm.com>
---
 conf/vm_power_manager.cfg |  11 +++-
 framework/qemu_libvirt.py | 144 +++++++++++++++++++++++++++++++++++++---------
 2 files changed, 125 insertions(+), 30 deletions(-)

diff --git a/conf/vm_power_manager.cfg b/conf/vm_power_manager.cfg
index 9c8f87a..e2c8fc7 100644
--- a/conf/vm_power_manager.cfg
+++ b/conf/vm_power_manager.cfg
@@ -1,5 +1,8 @@
 # libvirtd options:
 # [VM name] section value is the name for VM
+# os
+#   loader:  /path/to/loader/file.fd
+#   nvram:   /path/to/nvram/file.fd
 # cpu       # hard code type to host-passthrough
 #   number: number of vcpus
 #   cpupin: host cpu list
@@ -7,7 +10,7 @@
 #   size: 4096
 # disk
 #   file: absolute path to disk image
-#   type: disk image format
+#   opt_format: [ raw | qcow2 | ... ]  #disk image format
 # login
 #   user: user name to login into VM
 #   password: passwork to login into VM
@@ -20,18 +23,20 @@
 
 # vm configuration for vm power management case
 [vm0]
+#os =
+#    loader=/usr/share/AAVMF/AAVMF_CODE.fd,nvram=/var/lib/libvirt/qemu/nvram/vm0_VARS.fd;
 cpu =
     number=4,cpupin=5 6 7 8;
 mem =
     size=4096;
 disk =
-    file=/storage/vm-image/vm0.img,type=raw;
+    file=/storage/vm-image/vm0.img,opt_format=raw;
 login =
     user=root,password=tester;
 [vm1]
 mem =
     size=4096;
 disk =
-    file=/storage/vm-image/vm1.img,type=raw;
+    file=/storage/vm-image/vm1.img,opt_format=raw;
 login =
     user=root,password=tester;
diff --git a/framework/qemu_libvirt.py b/framework/qemu_libvirt.py
index ed8e0e6..59a0c9e 100644
--- a/framework/qemu_libvirt.py
+++ b/framework/qemu_libvirt.py
@@ -57,6 +57,7 @@ class LibvirtKvm(VirtBase):
 
         # disk and pci device default index
         self.diskindex = 'a'
+        self.controllerindex = 0
         self.pciindex = 10
 
         # configure root element
@@ -79,6 +80,7 @@ class LibvirtKvm(VirtBase):
 
         # internal variable to track whether default nic has been added
         self.__default_nic = False
+        self.__default_nic_pci = ''
 
         # set some default values for vm,
         # if there is not the values of the specified options
@@ -98,6 +100,13 @@ class LibvirtKvm(VirtBase):
         """
         check and setup host virtual ability
         """
+        arch = self.host_session.send_expect('uname -m', '# ')
+        if arch == 'aarch64':
+            out = self.host_session.send_expect('service libvirtd status', "# ")
+            if 'active (running)' not in out:
+                return False
+            return True
+
         out = self.host_session.send_expect('cat /proc/cpuinfo | grep flags',
                                             '# ')
         rgx = re.search(' vmx ', out)
@@ -201,7 +210,31 @@ class LibvirtKvm(VirtBase):
                                 ',name=org.qemu.guest_agent.0'})
         self.qga_sock_path = '/tmp/%s_qga0.sock' % self.vm_name
 
-    def set_vm_default(self):
+    def add_vm_os(self, **options):
+        os = self.domain.find('os')
+        if 'loader' in options.keys():
+            loader = ET.SubElement(
+            os, 'loader', {'readonly': 'yes', 'type': 'pflash'})
+            loader.text = options['loader']
+        if 'nvram' in options.keys():
+            nvram = ET.SubElement(os, 'nvram')
+            nvram.text = options['nvram']
+
+
+    def set_vm_default_aarch64(self):
+        os = ET.SubElement(self.domain, 'os')
+        type = ET.SubElement(
+            os, 'type', {'arch': 'aarch64', 'machine': 'virt'})
+        type.text = 'hvm'
+        ET.SubElement(os, 'boot', {'dev': 'hd'})
+        features = ET.SubElement(self.domain, 'features')
+        ET.SubElement(features, 'acpi')
+        ET.SubElement(features, 'gic', {'version': '3'})
+
+        ET.SubElement(self.domain, 'cpu',
+            {'mode': 'host-passthrough', 'check': 'none'})
+
+    def set_vm_default_x86_64(self):
         os = ET.SubElement(self.domain, 'os')
         type = ET.SubElement(
             os, 'type', {'arch': 'x86_64', 'machine': 'pc-i440fx-1.6'})
@@ -213,6 +246,14 @@ class LibvirtKvm(VirtBase):
         ET.SubElement(features, 'pae')
 
         ET.SubElement(self.domain, 'cpu', {'mode': 'host-passthrough'})
+        self.__default_nic_pci = '00:1f.0'
+
+    def set_vm_default(self):
+        arch = self.host_session.send_expect('uname -m', '# ')
+        set_default_func = getattr(self, 'set_vm_default_' + arch)
+        if callable(set_default_func):
+            set_default_func()
+            
 
         # qemu-kvm for emulator
         device = ET.SubElement(self.domain, 'devices')
@@ -226,7 +267,11 @@ class LibvirtKvm(VirtBase):
 
         # add default control interface
         if not self.__default_nic:
-            def_nic = {'type': 'nic', 'opt_hostfwd': '', 'opt_addr': '00:1f.0'}
+            if len(self.__default_nic_pci) > 0:
+                def_nic = {'type': 'nic', 'opt_hostfwd': '',
+                           'opt_addr': self.__default_nic_pci}
+            else:
+                def_nic = {'type': 'nic', 'opt_hostfwd': ''}
             self.add_vm_net(**def_nic)
             self.__default_nic = True
 
@@ -273,17 +318,57 @@ class LibvirtKvm(VirtBase):
             return False
 
         ET.SubElement(disk, 'source', {'file': options['file']})
-        if 'type' not in options:
+        if 'opt_format' not in options:
             disk_type = 'raw'
         else:
-            disk_type = options['type']
+            disk_type = options['opt_format']
 
         ET.SubElement(disk, 'driver', {'name': 'qemu', 'type': disk_type})
 
+        if 'opt_bus' not in options:
+            bus = 'virtio'
+        else:
+            bus = options['opt_bus']
+        if 'opt_dev' not in options:
+            dev = 'vd%c' % self.diskindex
+            self.diskindex = chr(ord(self.diskindex) + 1)
+        else:
+            dev = options['opt_dev']
         ET.SubElement(
-            disk, 'target', {'dev': 'vd%c' % self.diskindex, 'bus': 'virtio'})
+            disk, 'target', {'dev': dev, 'bus': bus})
+
+        if 'opt_controller' in options:
+            controller = ET.SubElement(devices, 'controller',
+                {'type': bus,
+                'index': hex(self.controllerindex)[2:],
+                'model': options['opt_controller']})
+            self.controllerindex += 1
+            ET.SubElement(controller, 'address',
+                {'type': 'pci', 'domain': '0x0000', 'bus': hex(self.pciindex),
+                'slot': '0x00', 'function': '0x00'})
+            self.pciindex += 1
 
-        self.diskindex = chr(ord(self.diskindex) + 1)
+    def add_vm_serial_port(self, **options):
+        if 'enable' in options.keys():
+            if options['enable'].lower() == 'yes':
+                devices = self.domain.find('devices')
+                if 'opt_type' in options.keys():
+                    serial_type = options['opt_type']
+                else:
+                    serial_type = 'unix'
+                if serial_type == 'pty':
+                    serial = ET.SubElement(devices, 'serial', {'type': serial_type})
+                    ET.SubElement(serial, 'target', {'port': '0'})
+                elif serial_type == 'unix':
+                    serial = ET.SubElement(devices, 'serial', {'type': serial_type})
+                    self.serial_path = "/tmp/%s_serial.sock" % self.vm_name
+                    ET.SubElement(serial, 'source', {'mode': 'bind', 'path': self.serial_path})
+                    ET.SubElement(serial, 'target', {'port': '0'})
+                else:
+                    print utils.RED("Serial type %s is not supported!" % serial_type)
+                    return False
+                console = ET.SubElement(devices, 'console', {'type': serial_type})
+                ET.SubElement(console, 'target', {'type': 'serial', 'port': '0'})
 
     def add_vm_login(self, **options):
         """
@@ -305,14 +390,23 @@ class LibvirtKvm(VirtBase):
     def __parse_pci(self, pci_address):
         pci_regex = r"([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2})" + \
             ".([0-9a-fA-F]{1,2})"
+        pci_regex_domain = r"([0-9a-fA-F]{1,4}):([0-9a-fA-F]{1,2}):" + \
+            "([0-9a-fA-F]{1,2}).([0-9a-fA-F]{1,2})"
         m = re.match(pci_regex, pci_address)
-        if m is None:
-            return None
-        bus = m.group(1)
-        slot = m.group(2)
-        func = m.group(3)
-
-        return (bus, slot, func)
+        if m is not None:
+            bus = m.group(1)
+            slot = m.group(2)
+            func = m.group(3)
+            dom  = '0'
+            return (bus, slot, func, dom)
+        m = re.match(pci_regex_domain, pci_address)
+        if m is not None:
+            bus = m.group(2)
+            slot = m.group(3)
+            func = m.group(4)
+            dom  = m.group(1)
+            return (bus, slot, func, dom)
+        return None
 
     def add_vm_device(self, **options):
         """
@@ -325,35 +419,31 @@ class LibvirtKvm(VirtBase):
                                    'mode': 'subsystem', 'type': 'pci',
                                    'managed': 'yes'})
 
-        if 'pf_idx' not in options.keys():
-            print utils.RED("Missing device index for device option!!!")
-            return False
-
-        pf = int(options['pf_idx'])
-        if pf > len(self.host_dut.ports_info):
-            print utils.RED("PF device index over size!!!")
+        if 'opt_host' in options.keys():
+            pci_addr = options['opt_host']
+        else:
+            print utils.RED("Missing opt_host for device option!!!")
             return False
 
-        pci_addr = self.host_dut.ports_info[pf]['pci']
 
         pci = self.__parse_pci(pci_addr)
         if pci is None:
             return False
-        bus, slot, func = pci
+        bus, slot, func, dom = pci
 
         source = ET.SubElement(hostdevice, 'source')
         ET.SubElement(source, 'address', {
-                      'domain': '0x0', 'bus': '0x%s' % bus,
+                      'domain': '0x%s' % dom, 'bus': '0x%s' % bus,
                       'slot': '0x%s' % slot,
                       'function': '0x%s' % func})
         if 'guestpci' in options.keys():
             pci = self.__parse_pci(options['guestpci'])
             if pci is None:
                 return False
-            bus, slot, func = pci
+            bus, slot, func, dom = pci
             ET.SubElement(hostdevice, 'address', {
-                          'type': 'pci', 'domain': '0x0', 'bus': '0x%s' % bus,
-                          'slot': '0x%s' % slot, 'function': '0x%s' % func})
+                  'type': 'pci', 'domain': '0x%s' % dom, 'bus': '0x%s' % bus,
+                  'slot': '0x%s' % slot, 'function': '0x%s' % func})
             # save host and guest pci address mapping
             pci_map = {}
             pci_map['hostpci'] = pci_addr
@@ -397,7 +487,7 @@ class LibvirtKvm(VirtBase):
             pci = self.__parse_pci(options['opt_addr'])
             if pci is None:
                 return False
-            bus, slot, func = pci
+            bus, slot, func, dom = pci
             ET.SubElement(qemu, 'qemu:arg',
                           {'value': 'nic,model=e1000,addr=0x%s' % slot})
         else:
-- 
1.8.3.1



More information about the dts mailing list