Browse Source

config: detect support for various features

Unify the code for generating default settings with the code for generating
QEMU arguments. The list of supported archs/targets is incomplete and
should be filled out with more testing.

Also addresses the issue where "virtio-serial" device is generated for
SPARC virtual machines.

Fixes #4575
osy 2 years ago
parent
commit
82b4ad4e99

+ 48 - 0
Configuration/QEMUConstant.swift

@@ -390,3 +390,51 @@ enum QEMUPackageFileName: String {
     case debugLog = "debug.log"
     case efiVariables = "efi_vars.fd"
 }
+
+// MARK: Supported features
+
+extension QEMUArchitecture {
+    var hasAgentSupport: Bool {
+        switch self {
+        case .sparc, .sparc64: return false
+        default: return true
+        }
+    }
+    
+    var hasSharingSupport: Bool {
+        switch self {
+        case .sparc, .sparc64: return false
+        default: return true
+        }
+    }
+    
+    var hasUsbSupport: Bool {
+        switch self {
+        case .s390x: return false
+        case .sparc, .sparc64: return false
+        default: return true
+        }
+    }
+    
+    var hasHypervisorSupport: Bool {
+        guard jb_has_hypervisor() else {
+            return false
+        }
+        #if arch(arm64)
+        return self == .aarch64
+        #elseif arch(x86_64)
+        return self == .x86_64
+        #else
+        return false
+        #endif
+    }
+}
+
+extension QEMUTarget {
+    var hasUsbSupport: Bool {
+        switch self.rawValue {
+        case "isapc": return false
+        default: return true
+        }
+    }
+}

+ 11 - 30
Configuration/UTMQemuConfiguration+Arguments.swift

@@ -269,38 +269,12 @@ import Foundation
         #endif
     }
     
-    private var isHypervisorSupported: Bool {
-        guard jb_has_hypervisor() else {
-            return false
-        }
-        #if arch(arm64)
-        return system.architecture == .aarch64
-        #elseif arch(x86_64)
-        return system.architecture == .x86_64
-        #else
-        return false
-        #endif
-    }
-    
     private var isHypervisorUsed: Bool {
-        isHypervisorSupported && qemu.hasHypervisor
-    }
-    
-    private var isUsbSupported: Bool {
-        if system.target.rawValue == QEMUTarget_x86_64.isapc.rawValue {
-            return false
-        }
-        if system.architecture == .s390x {
-            return false
-        }
-        if system.architecture == .sparc || system.architecture == .sparc64 {
-            return false
-        }
-        return true
+        system.architecture.hasHypervisorSupport && qemu.hasHypervisor
     }
     
     private var isUsbUsed: Bool {
-        isUsbSupported && input.usbBusSupport != .disabled
+        system.architecture.hasUsbSupport && system.target.hasUsbSupport && input.usbBusSupport != .disabled
     }
     
     @QEMUArgumentBuilder private var machineArguments: [QEMUArgument] {
@@ -721,8 +695,15 @@ import Foundation
         }
     }
     
+    private var isAgentUsed: Bool {
+        guard system.architecture.hasAgentSupport else {
+            return false
+        }
+        return sharing.hasClipboardSharing || sharing.directoryShareMode == .webdav || displays.contains(where: { $0.isDynamicResolution })
+    }
+    
     @QEMUArgumentBuilder private var sharingArguments: [QEMUArgument] {
-        if sharing.hasClipboardSharing || sharing.directoryShareMode == .webdav || displays.contains(where: { $0.isDynamicResolution }) {
+        if isAgentUsed {
             f("-device")
             f("virtio-serial")
             f("-device")
@@ -736,7 +717,7 @@ import Foundation
                 f("spiceport,name=org.spice-space.webdav.0,id=charchannel1")
             }
         }
-        if sharing.directoryShareMode == .virtfs, let url = sharing.directoryShareUrl {
+        if system.architecture.hasSharingSupport && sharing.directoryShareMode == .virtfs, let url = sharing.directoryShareUrl {
             f("-fsdev")
             "local"
             "id=virtfs0"

+ 3 - 0
Configuration/UTMQemuConfigurationDisplay.swift

@@ -76,6 +76,9 @@ struct UTMQemuConfigurationDisplay: Codable, Identifiable {
 extension UTMQemuConfigurationDisplay {
     init?(forArchitecture architecture: QEMUArchitecture, target: any QEMUTarget) {
         self.init()
+        if !architecture.hasAgentSupport {
+            isDynamicResolution = false
+        }
         let rawTarget = target.rawValue
         if rawTarget.hasPrefix("pc") || rawTarget.hasPrefix("q35") {
             hardware = QEMUDisplayDevice_x86_64.virtio_vga

+ 3 - 3
Configuration/UTMQemuConfigurationInput.swift

@@ -57,12 +57,12 @@ extension UTMQemuConfigurationInput {
     init(forArchitecture architecture: QEMUArchitecture, target: any QEMUTarget) {
         self.init()
         let rawTarget = target.rawValue
-        if rawTarget.hasPrefix("pc") || rawTarget.hasPrefix("q35") {
+        if !architecture.hasUsbSupport || !target.hasUsbSupport {
+            usbBusSupport = .disabled
+        } else if rawTarget.hasPrefix("pc") || rawTarget.hasPrefix("q35") {
             usbBusSupport = .usb3_0
         } else if (architecture == .arm || architecture == .aarch64) && (rawTarget.hasPrefix("virt-") || rawTarget == "virt") {
             usbBusSupport = .usb3_0
-        } else if rawTarget == "isapc" {
-            usbBusSupport = .disabled
         }
     }
 }

+ 1 - 9
Configuration/UTMQemuConfigurationQEMU.swift

@@ -122,15 +122,7 @@ extension UTMQemuConfigurationQEMU {
             hasUefiBoot = true
             hasRNGDevice = true
         }
-        #if arch(arm64)
-        if architecture == .aarch64 {
-            hasHypervisor = jb_has_hypervisor()
-        }
-        #elseif arch(x86_64)
-        if architecture == .x86_64 {
-            hasHypervisor = jb_has_hypervisor()
-        }
-        #endif
+        hasHypervisor = architecture.hasHypervisorSupport
     }
 }
 

+ 7 - 0
Configuration/UTMQemuConfigurationSharing.swift

@@ -60,6 +60,13 @@ extension UTMQemuConfigurationSharing {
     init(forArchitecture architecture: QEMUArchitecture, target: any QEMUTarget) {
         self.init()
         let rawTarget = target.rawValue
+        if !architecture.hasAgentSupport {
+            hasClipboardSharing = false
+        }
+        if !architecture.hasSharingSupport {
+            directoryShareMode = .none
+        }
+        // overrides for specific configurations
         if rawTarget.hasPrefix("pc") || rawTarget.hasPrefix("q35") {
             directoryShareMode = .webdav
             hasClipboardSharing = true