diff --git a/qubes/ext/pci.py b/qubes/ext/pci.py index 92ad4cf3..8ebb72b8 100644 --- a/qubes/ext/pci.py +++ b/qubes/ext/pci.py @@ -224,6 +224,10 @@ class PCIDeviceExtension(qubes.ext.Extension): raise qubes.exc.QubesException( 'Invalid PCI device: {}'.format(device.ident)) + if vm.virt_mode == 'pvh': + raise qubes.exc.QubesException( + "Can't attach PCI device to VM in pvh mode") + if not vm.is_running(): return diff --git a/qubes/tests/vm/qubesvm.py b/qubes/tests/vm/qubesvm.py index 1092fe63..65572f9d 100644 --- a/qubes/tests/vm/qubesvm.py +++ b/qubes/tests/vm/qubesvm.py @@ -47,6 +47,13 @@ class TestProp(object): # pylint: disable=too-few-public-methods __name__ = 'testprop' +class TestDeviceCollection(object): + def __init__(self): + self._list = [] + + def persistent(self): + return self._list + class TestVM(object): # pylint: disable=too-few-public-methods app = TestApp() @@ -56,6 +63,7 @@ class TestVM(object): self.installed_by_rpm = False for k, v in kwargs.items(): setattr(self, k, v) + self.devices = {'pci': TestDeviceCollection()} def is_running(self): return self.running @@ -108,6 +116,12 @@ class TC_00_setters(qubes.tests.QubesTestCase): self.assertEqual( qubes.vm.qubesvm._setter_virt_mode(self.vm, self.prop, 'PV'), 'pv') + self.assertEqual( + qubes.vm.qubesvm._setter_virt_mode(self.vm, self.prop, 'pvh'), + 'pvh') + self.vm.devices['pci']._list.append(object()) + with self.assertRaises(ValueError): + qubes.vm.qubesvm._setter_virt_mode(self.vm, self.prop, 'pvh') with self.assertRaises(ValueError): qubes.vm.qubesvm._setter_virt_mode(self.vm, self.prop, 'True') @@ -608,3 +622,66 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase): libvirt_xml = vm.create_config_file() self.assertXMLEqual(lxml.etree.XML(libvirt_xml), lxml.etree.XML(expected)) + + def test_600_libvirt_xml_pvh(self): + expected = ''' + test-inst-test + 7db78950-c467-4863-94d1-af59806384ea + 500 + 400 + 2 + + + + + + + + + hvm + /tmp/kernel/vmlinuz + /tmp/kernel/initramfs + root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH rd.plymouth.enable=0 plymouth.enable=0 nopat + + + + + + + + + + + destroy + destroy + destroy + + + + + + + + + + + + + + ''' + my_uuid = '7db78950-c467-4863-94d1-af59806384ea' + vm = self.get_vm(uuid=my_uuid) + vm.netvm = None + vm.virt_mode = 'pvh' + # tests for storage are later + vm.volumes['kernel'] = unittest.mock.Mock(**{ + 'kernels_dir': '/tmp/kernel', + 'block_device.return_value.domain': 'dom0', + 'block_device.return_value.script': None, + 'block_device.return_value.path': '/tmp/kernel/modules.img', + 'block_device.return_value.devtype': 'disk', + 'block_device.return_value.name': 'kernel', + }) + libvirt_xml = vm.create_config_file() + self.assertXMLEqual(lxml.etree.XML(libvirt_xml), + lxml.etree.XML(expected)) diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index 241aaf87..2e5cca65 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -95,6 +95,9 @@ def _setter_virt_mode(self, prop, value): if value not in ('hvm', 'pv', 'pvh'): raise qubes.exc.QubesPropertyValueError(self, prop, value, 'Invalid virtualization mode, supported values: hvm, pv, pvh') + if value == 'pvh' and list(self.devices['pci'].persistent()): + raise qubes.exc.QubesPropertyValueError(self, prop, value, + "pvh mode can't be set if pci devices are attached") return value