Skip to content

Commit 5f85f63

Browse files
committed
config(qemu): add experimental Raspberry Pi support
1 parent 30c8202 commit 5f85f63

29 files changed

Lines changed: 165 additions & 35 deletions

Configuration/QEMUConstant.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,9 +478,24 @@ extension QEMUTarget {
478478
}
479479
}
480480

481+
var hasUsbSharingSupport: Bool {
482+
switch self.rawValue {
483+
case let x where x.hasPrefix("raspi"): return false
484+
default: return true
485+
}
486+
}
487+
481488
var hasAgentSupport: Bool {
482489
switch self.rawValue {
483490
case "isapc": return false
491+
case let x where x.hasPrefix("raspi"): return false
492+
default: return true
493+
}
494+
}
495+
496+
var hasUefiSupport: Bool {
497+
switch self.rawValue {
498+
case let x where x.hasPrefix("raspi"): return false
484499
default: return true
485500
}
486501
}
@@ -491,6 +506,29 @@ extension QEMUTarget {
491506
default: return true
492507
}
493508
}
509+
510+
var hasHypervisorSupport: Bool {
511+
switch self.rawValue {
512+
case let x where x.hasPrefix("raspi"): return false
513+
default: return true
514+
}
515+
}
516+
517+
var hasBuiltinFramebuffer: Bool {
518+
switch self.rawValue {
519+
case let x where x.hasPrefix("raspi"): return true
520+
default: return false
521+
}
522+
}
523+
524+
var fixedMemorySize: Int? {
525+
switch self.rawValue {
526+
case "raspi0", "raspi1ap", "raspi3ap": return 512
527+
case "raspi2b", "raspi3b": return 1024
528+
case "raspi4b": return 2048
529+
default: return nil
530+
}
531+
}
494532
}
495533

496534
#if WITH_QEMU_TCI

Configuration/UTMQemuConfiguration+Arguments.swift

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ import Virtualization // for getting network interfaces
264264
"vgamem_mb=\(vgaRamSize)"
265265
}
266266
f()
267+
} else if system.target.hasBuiltinFramebuffer {
268+
// Use the board's built-in framebuffer (no arguments)
267269
} else {
268270
for display in displays {
269271
if !shouldSkipDisplay(display) {
@@ -951,36 +953,38 @@ import Virtualization // for getting network interfaces
951953
f("usb-kbd,bus=usb-bus.0")
952954
}
953955
#if WITH_USB
954-
let maxDevices = input.maximumUsbShare
955-
let buses = (maxDevices + 2) / 3
956-
if input.usbBusSupport == .usb3_0 {
957-
var controller = "qemu-xhci"
958-
if isPcCompatible {
959-
controller = "nec-usb-xhci"
960-
}
961-
for i in 0..<buses {
962-
f("-device")
963-
f("\(controller),id=usb-controller-\(i)")
956+
if system.target.hasUsbSharingSupport {
957+
let maxDevices = input.maximumUsbShare
958+
let buses = (maxDevices + 2) / 3
959+
if input.usbBusSupport == .usb3_0 {
960+
var controller = "qemu-xhci"
961+
if isPcCompatible {
962+
controller = "nec-usb-xhci"
963+
}
964+
for i in 0..<buses {
965+
f("-device")
966+
f("\(controller),id=usb-controller-\(i)")
967+
}
968+
} else {
969+
for i in 0..<buses {
970+
f("-device")
971+
f("ich9-usb-ehci1,id=usb-controller-\(i)")
972+
f("-device")
973+
f("ich9-usb-uhci1,masterbus=usb-controller-\(i).0,firstport=0,multifunction=on")
974+
f("-device")
975+
f("ich9-usb-uhci2,masterbus=usb-controller-\(i).0,firstport=2,multifunction=on")
976+
f("-device")
977+
f("ich9-usb-uhci3,masterbus=usb-controller-\(i).0,firstport=4,multifunction=on")
978+
}
964979
}
965-
} else {
966-
for i in 0..<buses {
967-
f("-device")
968-
f("ich9-usb-ehci1,id=usb-controller-\(i)")
969-
f("-device")
970-
f("ich9-usb-uhci1,masterbus=usb-controller-\(i).0,firstport=0,multifunction=on")
971-
f("-device")
972-
f("ich9-usb-uhci2,masterbus=usb-controller-\(i).0,firstport=2,multifunction=on")
980+
// set up usb forwarding
981+
for i in 0..<maxDevices {
982+
f("-chardev")
983+
f("spicevmc,name=usbredir,id=usbredirchardev\(i)")
973984
f("-device")
974-
f("ich9-usb-uhci3,masterbus=usb-controller-\(i).0,firstport=4,multifunction=on")
985+
f("usb-redir,chardev=usbredirchardev\(i),id=usbredirdev\(i),bus=usb-controller-\(i/3).0")
975986
}
976987
}
977-
// set up usb forwarding
978-
for i in 0..<maxDevices {
979-
f("-chardev")
980-
f("spicevmc,name=usbredir,id=usbredirchardev\(i)")
981-
f("-device")
982-
f("usb-redir,chardev=usbredirchardev\(i),id=usbredirdev\(i),bus=usb-controller-\(i/3).0")
983-
}
984988
#endif
985989
}
986990

Configuration/UTMQemuConfiguration.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ extension UTMQemuConfiguration {
260260
input = .init(forArchitecture: architecture, target: target)
261261
sharing = .init(forArchitecture: architecture, target: target)
262262
system.cpu = architecture.cpuType.default
263+
if let fixedMemorySize = target.fixedMemorySize {
264+
system.memorySize = fixedMemorySize
265+
}
263266
if let display = UTMQemuConfigurationDisplay(forArchitecture: architecture, target: target) {
264267
displays = [display]
265268
} else {

Configuration/UTMQemuConfigurationNetwork.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ extension UTMQemuConfigurationNetwork {
180180
hardware = QEMUNetworkDevice_ppc.sungem
181181
} else if architecture == .m68k && rawTarget == QEMUTarget_m68k.q800.rawValue {
182182
hardware = QEMUNetworkDevice_m68k.dp8393x
183+
} else if rawTarget.hasPrefix("raspi") {
184+
return nil
183185
} else {
184186
let cards = architecture.networkDeviceType.allRawValues
185187
if let first = cards.first {

Configuration/UTMQemuConfigurationQEMU.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ extension UTMQemuConfigurationQEMU {
157157
hasUefiBoot = true
158158
hasRNGDevice = true
159159
}
160-
hasHypervisor = architecture.hasHypervisorSupport
160+
hasHypervisor = architecture.hasHypervisorSupport && target.hasHypervisorSupport
161161
}
162162
}
163163

Configuration/UTMQemuConfigurationSound.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ extension UTMQemuConfigurationSound {
5757
hardware = QEMUSoundDevice_ppc.screamer
5858
} else if architecture == .m68k && rawTarget == QEMUTarget_m68k.q800.rawValue {
5959
hardware = QEMUSoundDevice_m68k.asc
60+
} else if rawTarget.hasPrefix("raspi") {
61+
return nil
6062
} else {
6163
let cards = architecture.soundDeviceType.allRawValues
6264
if let first = cards.first {

Platform/Shared/VMConfigDisplayView.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,16 @@ struct VMConfigDisplayView: View {
2828
VStack {
2929
Form {
3030
Section(header: Text("Hardware")) {
31-
VMConfigConstantPicker("Emulated Display Card", selection: $config.hardware, type: system.architecture.displayDeviceType)
31+
if system.target.hasBuiltinFramebuffer {
32+
HStack {
33+
Text("Emulated Display Card")
34+
Spacer()
35+
Text("Built-in Framebuffer")
36+
.foregroundColor(.secondary)
37+
}
38+
} else {
39+
VMConfigConstantPicker("Emulated Display Card", selection: $config.hardware, type: system.architecture.displayDeviceType)
40+
}
3241

3342
Toggle("GPU Acceleration Supported", isOn: .constant(isGLSupported)).disabled(true)
3443
if isGLSupported {

Platform/Shared/VMConfigInputView.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import SwiftUI
1919
struct VMConfigInputView: View {
2020
@Binding var config: UTMQemuConfigurationInput
2121
let hasUsbSupport: Bool
22+
let hasUsbSharingSupport: Bool
2223

2324
var body: some View {
2425
VStack {
@@ -29,7 +30,7 @@ struct VMConfigInputView: View {
2930
}
3031

3132
#if WITH_USB
32-
if config.usbBusSupport != .disabled {
33+
if config.usbBusSupport != .disabled && hasUsbSharingSupport {
3334
Section(header: Text("USB Sharing")) {
3435
if !jb_has_usb_entitlement() {
3536
Text("USB sharing not supported in this build of UTM.")
@@ -101,7 +102,7 @@ struct VMConfigInputView_Previews: PreviewProvider {
101102
@State static private var config = UTMQemuConfigurationInput()
102103

103104
static var previews: some View {
104-
VMConfigInputView(config: $config, hasUsbSupport: true)
105+
VMConfigInputView(config: $config, hasUsbSupport: true, hasUsbSharingSupport: true)
105106
#if os(macOS)
106107
.scrollable()
107108
#endif

Platform/Shared/VMConfigQEMUView.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct VMConfigQEMUView: View {
3838

3939
private var supportsUefi: Bool {
4040
UTMQemuConfigurationQEMU.uefiImagePrefix(forArchitecture: system.architecture) != nil
41+
&& system.target.hasUefiSupport
4142
}
4243

4344
private var supportsPs2: Bool {
@@ -80,7 +81,7 @@ struct VMConfigQEMUView: View {
8081
}
8182
Toggle("Use Hypervisor", isOn: $config.hasHypervisor)
8283
.help("Only available if host architecture matches the target. Otherwise, TCG emulation is used.")
83-
.disabled(!system.architecture.hasHypervisorSupport)
84+
.disabled(!system.architecture.hasHypervisorSupport || !system.target.hasHypervisorSupport)
8485
if config.hasHypervisor {
8586
Toggle("Use TSO", isOn: $config.hasTSO)
8687
.help("Only available when Hypervisor is used on supported hardware. TSO speeds up Intel emulation in the guest at the cost of decreased performance in general.")

Platform/Shared/VMConfigSystemView.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct VMConfigSystemView: View {
3434
Form {
3535
HardwareOptions(config: $config, architecture: $architecture, target: $target, warningMessage: $warningMessage)
3636
RAMSlider(systemMemory: $config.memorySize, onValidate: validateMemorySize)
37+
.disabled(target.fixedMemorySize != nil)
3738
Section(header: Text("CPU")) {
3839
VMConfigConstantPicker(selection: $config.cpu, type: config.architecture.cpuType)
3940
}
@@ -201,6 +202,9 @@ private struct HardwareOptions: View {
201202
.onChange(of: config.target.rawValue) { newValue in
202203
if newValue != target.rawValue {
203204
target = AnyQEMUConstant(rawValue: newValue)!
205+
if let fixedMemorySize = target.fixedMemorySize {
206+
config.memorySize = fixedMemorySize
207+
}
204208
}
205209
}
206210
}

0 commit comments

Comments
 (0)