1
(Apologies to anyone who has received more than one version of this
1
<meta>
2
series of emails; my git-send-email was misconfigured and this is
2
This patch series has been through months of review and
3
a new attempt.)
3
refinement. It now has end-to-end Reviewed-by: tags and
4
all code patches but one have Tested-by: tags. No significant
5
issues have been found via review for some weeks.
6
7
The patch set creates two new subsystems:
8
hw/display/apple-gfx
9
hw/vmapple
10
so it doesn't fall within the responsibility of existing
11
maintainers. How do we proceed to get this merged now that
12
10.0 development is open?
13
</meta>
14
4
15
5
This patch set introduces a new ARM and macOS HVF specific machine type
16
This patch set introduces a new ARM and macOS HVF specific machine type
6
called "vmapple", as well as a family of display devices based on the
17
called "vmapple", as well as a family of display devices based on the
7
ParavirtualizedGraphics.framework in macOS. One of the display adapter
18
ParavirtualizedGraphics.framework in macOS. One of the display adapter
8
variants, apple-gfx-vmapple, is required for the new machine type, while
19
variants, apple-gfx-mmio, is required for the new machine type, while
9
apple-gfx-pci can be used to enable 3D graphics acceleration with x86-64
20
apple-gfx-pci can be used to enable 3D graphics acceleration with x86-64
10
macOS guest OSes.
21
macOS guest OSes.
11
22
12
Previous versions of this patch set were submitted semi-separately:
23
Previous versions of this patch set were submitted semi-separately:
13
the original vmapple patch set by Alexander Graf included a monolithic
24
the original vmapple patch set by Alexander Graf included a monolithic
14
implementation of apple-gfx-vmapple. I subsequently reviewed and reworked
25
implementation of apple-gfx-mmio. I subsequently reviewed and reworked
15
the latter to support the PCI variant of the device as well and submitted
26
the latter to support the PCI variant of the device as well and submitted
16
the result in isolation. As requested in subsequent review, I have now
27
the result in isolation. As requested in subsequent review, I have now
17
recombined this with the original vmapple patch set, which I have updated
28
recombined this with the original vmapple patch set, which I have updated
18
and improved in a few ways as well.
29
and improved in a few ways as well.
19
30
...
...
35
hosts only because ParavirtualizedGraphics.framework is a black box
46
hosts only because ParavirtualizedGraphics.framework is a black box
36
implementing most of the logic behind the apple-gfx device.)
47
implementing most of the logic behind the apple-gfx device.)
37
* PCI devices use legacy IRQs, not MSI/MSI-X. As far as I can tell,
48
* PCI devices use legacy IRQs, not MSI/MSI-X. As far as I can tell,
38
we'd need to include the GICv3 ITS, but it's unclear to me what
49
we'd need to include the GICv3 ITS, but it's unclear to me what
39
exactly needs wiring up.
50
exactly needs wiring up.
40
* Due to lack of MSI(-X), event delivery from USB devices to the guest
51
* Due to a quirk (bug?) in the macOS XHCI driver when MSI-X is not
41
macOS isn't working correctly. My current conclusion is that the
52
available, correct functioning of the USB controller (and thus
42
OS's XHCI driver simply was never designed to work with legacy IRQs.
53
keyboard/tablet) requires a small workaround in the XHCI controller
43
The upshot is that keyboard and mouse/tablet input is very laggy.
54
device. This is part of another patch series:
44
The solution would be to implement MSI(-X) support or figure out how
55
https://patchew.org/QEMU/20241208191646.64857-1-phil@philjordan.eu/
45
to make hcd-xhci-sysbus work with the macOS guest, if at all possible.
46
(EHCI and UHCI/OHCI controllers are not an option as the VMAPPLE
47
guest kernel does not include drivers for these.)
48
* The guest OS must first be provisioned using Virtualization.framework;
56
* The guest OS must first be provisioned using Virtualization.framework;
49
the disk images can subsequently be used in Qemu. (See docs.)
57
the disk images can subsequently be used in Qemu. (See docs.)
50
58
51
The apple-gfx device can be used independently from the vmapple machine
59
The apple-gfx device can be used independently from the vmapple machine
52
type, at least in the PCI variant. It mainly targets x86-64 macOS guests
60
type, at least in the PCI variant. It mainly targets x86-64 macOS guests
...
...
72
framebuffer is copied to system memory and uses Qemu's usual
80
framebuffer is copied to system memory and uses Qemu's usual
73
CPU-based drawing. For maximum efficiency, the Metal texture
81
CPU-based drawing. For maximum efficiency, the Metal texture
74
containing the guest framebuffer could be drawn directly to
82
containing the guest framebuffer could be drawn directly to
75
a Metal view in the host window, staying on the GPU. (Similar
83
a Metal view in the host window, staying on the GPU. (Similar
76
to the OpenGL/virgl render path on other platforms.)
84
to the OpenGL/virgl render path on other platforms.)
85
86
Some of my part of this work has been sponsored by Sauce Labs Inc.
77
87
78
---
88
---
79
89
80
v2 -> v3:
90
v2 -> v3:
81
91
...
...
96
virtio HID devices, at least not in version 12's vmapple kernel.
106
virtio HID devices, at least not in version 12's vmapple kernel.
97
So input now sort of works (interrupt issues) rather than not
107
So input now sort of works (interrupt issues) rather than not
98
at all. Use network-based remote access to the guest OS as a
108
at all. Use network-based remote access to the guest OS as a
99
work-around.
109
work-around.
100
110
111
v3 -> v4:
112
113
* Complete rework of the mechanism for handling runloop/libdispatch
114
events on the main thread. PV graphics now work with the SDL UI.
115
* Renamed 'apple-gfx-vmapple' device to 'apple-gfx-mmio'
116
* hw/display/apple-gfx: threading model overhaul to be more consistent,
117
safer, and more QEMU-idiomatic.
118
* display-modes property on the apple-gfx devices now uses the
119
native array property mechanism and works on both device variants.
120
* hw/vmapple/aes: Improvements to logging and error handling.
121
* hw/vmapple/cfg: Bug fixes around device property default values.
122
* hw/vmapple/{aes,cfg,virtio-blk/vmapple}: Most header code moved into
123
.c files, only a single vmapple.h now contains the #defines for the
124
vmapple machine model-specific device type names.
125
* hw/block/virtio-blk: New patch for replacing virtio_blk_free_request
126
with g_free. (Optional)
127
* Various smaller changes following comments in v3 code review in
128
apple-gfx, aes, cfg, bdif, virtio-blk-vmapple, and the vmapple
129
machine type itself. See patch-specific v4 change notes for details.
130
131
v4 -> v5:
132
133
* Simplified the main thread runloop mechanism. Back to setting
134
     qemu_main directly, but narrowing the scope of what it needs to do,
135
     and it can now be NULL. (Meaning run the QEMU main event loop on
136
     the main thread as is traditional.)
137
* hw/display/apple-gfx: Further improvements to the BH based job code bridging
138
the libdispatch & QEMU thread synchronisation impedance mismatch.
139
* hw/display/apple-gfx: Thread safety and object lifetime improvements.
140
* hw/display/apple-gfx-*: Better buffer and error handling in display mode
141
property setters and getters.
142
* hw/vmapple/aes: More consistent and safer logging/tracing
143
* hw/vmapple/cfg: Better error reporting on overlong property strings.
144
* hw/vmapple/virtio-blk: Fixed theoretically-unaligned write to config buffer.
145
* vmapple machine type: Moved ecam region into machine state, improved device
146
property setting error handling, improved ECID/UUID extraction script and
147
docs.
148
* Various smaller fixes in apple-gfx/-mmio, apple-gfx-pci, vmapple/aes,
149
vmapple/cfg, vmapple/virtio-blk, and vmapple machine type.
150
* Added SPDX license identifiers where they were missing.
151
152
v5 -> v6:
153
154
* 01/15 (main/Cocoa/runloop): Combined functions, fixed whitespace
155
* 02/15 (apple-gfx): Further refinement of PVG threading: reduced some callback
156
tasks from BHs to merely acquiring RCU read lock; replaced some libdispatch
157
tasks with BHs; last remaining synchronous BH now uses emphemeral
158
QemuSemaphore.
159
* 02/15 (apple-gfx): Readability improvements and other smaller tweaks
160
(see patch change notes for details)
161
* 04/15 (display modes): Replaced use of alloca() with NSMutableArray.
162
163
v6 -> v7:
164
165
* 02/15 (apple-gfx): Use g_ptr_array_find() helper function, coding style tweak
166
* 03/15 (apple-gfx-pci): Removed an unused function parameter
167
* 04/15 (apple-gfx display mode property): Simplified error handling in
168
property parsing.
169
* 10/15 (vmapple/aes): Coding style tweaks.
170
* 12/15 (vmapple/cfg): Changed error messages for overrun of properties with
171
fixed-length strings to be more useful to users than developers.
172
* 15/15 (vmapple machine type): Tiny error handling fix, un-inlined function
173
174
v7 -> v8:
175
176
* 02/15 (apple-gfx): Naming and type use improvements, fixes for a bug and a
177
leak.
178
* 04/15 (apple-gfx display mode property): Type use improvement
179
* 10/15 (vmapple/aes): Guest error logging tweaks.
180
* 11/15 (vmapple/bdif): Replaced uses of cpu_physical_memory_read with
181
dma_memory_read, and a g_free call with g_autofree.
182
* 12/15 (vmapple/cfg): Macro hygiene fix: consistently enclosing arguments in
183
parens.
184
* 15/15 (vmapple machine type): Use less verbose pattern for defining uuid
185
property.
186
187
v8 -> v9:
188
189
* 01/16 (ui & main loop): Set qemu_main to NULL for GTK UI as well.
190
* 02/16 (apple-gfx): Pass device pointer to graphic_console_init(), various
191
     non-functional changes.
192
* 03/16 (apple-gfx-pci): Fixup of changed common call, whitespace and comment
193
formatting tweaks.
194
* 04/16 (apple-gfx display modes): Re-ordered type definitions so we can drop
195
a 'struct' keyword.
196
* 10/16 (vmapple/aes): Replaced a use of cpu_physical_memory_write with
197
dma_memory_write, minor style tweak.
198
* 11/16 (vmapple/bdif): Replaced uses of cpu_physical_memory_write with
199
dma_memory_write.
200
* 13/16 (vmapple/virtio-blk): Correctly specify class_size for
201
VMAppleVirtIOBlkClass.
202
* 15/16 (vmapple machine type): Documentation improvements, fixed variable
203
name and struct field used during pvpanic device creation.
204
* 16/16 (NEW/RFC vmapple/virtio-blk): Proposed change to replace type hierarchy
205
with a variant property. This seems cleaner and less confusing than the
206
original approach to me, but I'm not sure if it warrants creation of a new
207
QAPI enum and property type definition.
208
209
v9 -> v10:
210
211
* 01/15 (ui & main loop): Added comments to qemu_main declaration and GTK.
212
* 02/15 (apple-gfx): Reworked the way frame rendering code is threaded to use
213
BHs for sections requiring BQL.
214
* 02/15 (apple-gfx): Fixed ./configure error on non-macOS platforms.
215
* 10/15 (vmapple/aes): Code style and comment improvements.
216
* 12/15 (vmapple/cfg): Slightly tidier error reporting for overlong property
217
values.
218
* 13/15 (vmapple/virtio-blk): Folded v9 patch 16/16 into this one, changing
219
the device type design to provide a single device type with a variant
220
     property instead of 2 different subtypes for aux and root volumes.
221
* 15/15 (vmapple machine type): Documentation fixup for changed virtio-blk
222
device type; small improvements to shell commands in documentation;
223
improved propagation of errors during cfg device instantiation.
224
225
v10 -> v11:
226
227
* 01/15 (ui & main loop): Simplified main.c, better comments & commit message
228
* 02/15 (apple-gfx): Give each PV display instance a unique serial number.
229
* 02 & 03/15 (apple-gfx, -pci): Formatting/style tweaks
230
* 15/15 (vmapple machine type): Improvements to shell code in docs
231
232
v11 -> v12:
233
234
* 01/15 (ui & main loop): More precise wording of code comments.
235
* 02/15 (apple-gfx): Fixed memory management regressions introduced in v10;
236
improved error handling; various more conmetic code adjustments
237
* 09/15 (GPEX): Fixed uses of deleted GPEX_NUM_IRQS constant that have been
238
added to QEMU since this patch was originally written.
239
240
v12 -> v13:
241
242
* 15/15 (vmapple machine type): Bumped the machine type version from 9.2
243
to 10.0.
244
* All patches in the series now have been positively reviewed and received
245
corresponding reviewed-by tags.
246
247
v13 -> v14:
248
249
* 6/15 (hw/vmapple directory): Changed myself from reviewer
250
to maintainer, as that seemed appropriate at this point.
251
* 15/15 (vmapple machine type): Gate creation of XHCI and
252
USB HID devices behind if (defaults_enabled()).
101
253
102
Alexander Graf (9):
254
Alexander Graf (9):
103
hw: Add vmapple subdir
255
hw: Add vmapple subdir
104
hw/misc/pvpanic: Add MMIO interface
256
hw/misc/pvpanic: Add MMIO interface
105
hvf: arm: Ignore writes to CNTP_CTL_EL0
257
hvf: arm: Ignore writes to CNTP_CTL_EL0
...
...
108
hw/vmapple/bdif: Introduce vmapple backdoor interface
260
hw/vmapple/bdif: Introduce vmapple backdoor interface
109
hw/vmapple/cfg: Introduce vmapple cfg region
261
hw/vmapple/cfg: Introduce vmapple cfg region
110
hw/vmapple/virtio-blk: Add support for apple virtio-blk
262
hw/vmapple/virtio-blk: Add support for apple virtio-blk
111
hw/vmapple/vmapple: Add vmapple machine type
263
hw/vmapple/vmapple: Add vmapple machine type
112
264
113
Phil Dennis-Jordan (5):
265
Phil Dennis-Jordan (6):
266
ui & main loop: Redesign of system-specific main thread event handling
114
hw/display/apple-gfx: Introduce ParavirtualizedGraphics.Framework
267
hw/display/apple-gfx: Introduce ParavirtualizedGraphics.Framework
115
support
268
support
116
hw/display/apple-gfx: Adds PCI implementation
269
hw/display/apple-gfx: Adds PCI implementation
117
ui/cocoa: Adds non-app runloop on main thread mode
118
hw/display/apple-gfx: Adds configurable mode list
270
hw/display/apple-gfx: Adds configurable mode list
119
MAINTAINERS: Add myself as maintainer for apple-gfx, reviewer for HVF
271
MAINTAINERS: Add myself as maintainer for apple-gfx, reviewer for HVF
120
272
hw/block/virtio-blk: Replaces request free function with g_free
121
MAINTAINERS | 15 +
273
122
docs/system/arm/vmapple.rst | 63 +++
274
MAINTAINERS | 15 +
123
docs/system/target-arm.rst | 1 +
275
contrib/vmapple/uuid.sh | 9 +
124
hw/Kconfig | 1 +
276
docs/system/arm/vmapple.rst | 63 ++
125
hw/arm/sbsa-ref.c | 2 +-
277
docs/system/target-arm.rst | 1 +
126
hw/arm/virt.c | 2 +-
278
hw/Kconfig | 1 +
127
hw/block/virtio-blk.c | 19 +-
279
hw/arm/sbsa-ref.c | 2 +-
128
hw/display/Kconfig | 14 +
280
hw/arm/virt.c | 2 +-
129
hw/display/apple-gfx-pci.m | 179 +++++++++
281
hw/block/virtio-blk.c | 58 +-
130
hw/display/apple-gfx-vmapple.m | 215 ++++++++++
282
hw/core/qdev-properties-system.c | 8 +
131
hw/display/apple-gfx.h | 72 ++++
283
hw/display/Kconfig | 13 +
132
hw/display/apple-gfx.m | 668 ++++++++++++++++++++++++++++++++
284
hw/display/apple-gfx-mmio.m | 289 +++++++++
133
hw/display/meson.build | 3 +
285
hw/display/apple-gfx-pci.m | 157 +++++
134
hw/display/trace-events | 26 ++
286
hw/display/apple-gfx.h | 77 +++
135
hw/i386/microvm.c | 2 +-
287
hw/display/apple-gfx.m | 880 ++++++++++++++++++++++++++++
136
hw/loongarch/virt.c | 2 +-
288
hw/display/meson.build | 7 +
137
hw/meson.build | 1 +
289
hw/display/trace-events | 30 +
138
hw/mips/loongson3_virt.c | 2 +-
290
hw/i386/microvm.c | 2 +-
139
hw/misc/Kconfig | 4 +
291
hw/loongarch/virt.c | 12 +-
140
hw/misc/meson.build | 1 +
292
hw/meson.build | 1 +
141
hw/misc/pvpanic-mmio.c | 61 +++
293
hw/mips/loongson3_virt.c | 2 +-
142
hw/openrisc/virt.c | 12 +-
294
hw/misc/Kconfig | 4 +
143
hw/pci-host/gpex.c | 36 +-
295
hw/misc/meson.build | 1 +
144
hw/riscv/virt.c | 12 +-
296
hw/misc/pvpanic-mmio.c | 61 ++
145
hw/vmapple/Kconfig | 32 ++
297
hw/openrisc/virt.c | 12 +-
146
hw/vmapple/aes.c | 584 ++++++++++++++++++++++++++++
298
hw/pci-host/gpex.c | 43 +-
147
hw/vmapple/bdif.c | 245 ++++++++++++
299
hw/riscv/virt.c | 12 +-
148
hw/vmapple/cfg.c | 106 +++++
300
hw/vmapple/Kconfig | 32 +
149
hw/vmapple/meson.build | 5 +
301
hw/vmapple/aes.c | 581 ++++++++++++++++++
150
hw/vmapple/trace-events | 26 ++
302
hw/vmapple/bdif.c | 275 +++++++++
151
hw/vmapple/trace.h | 1 +
303
hw/vmapple/cfg.c | 196 +++++++
152
hw/vmapple/virtio-blk.c | 212 ++++++++++
304
hw/vmapple/meson.build | 5 +
153
hw/vmapple/vmapple.c | 661 +++++++++++++++++++++++++++++++
305
hw/vmapple/trace-events | 21 +
154
hw/xtensa/virt.c | 2 +-
306
hw/vmapple/trace.h | 1 +
155
include/hw/misc/pvpanic.h | 1 +
307
hw/vmapple/virtio-blk.c | 205 +++++++
156
include/hw/pci-host/gpex.h | 7 +-
308
hw/vmapple/vmapple.c | 648 ++++++++++++++++++++
157
include/hw/pci/pci_ids.h | 1 +
309
hw/xen/xen-pvh-common.c | 2 +-
158
include/hw/virtio/virtio-blk.h | 12 +-
310
hw/xtensa/virt.c | 2 +-
159
include/hw/vmapple/bdif.h | 31 ++
311
include/hw/misc/pvpanic.h | 1 +
160
include/hw/vmapple/cfg.h | 68 ++++
312
include/hw/pci-host/gpex.h | 7 +-
161
include/hw/vmapple/virtio-blk.h | 39 ++
313
include/hw/pci/pci_ids.h | 1 +
162
include/qemu-main.h | 2 +
314
include/hw/qdev-properties-system.h | 5 +
163
meson.build | 5 +
315
include/hw/virtio/virtio-blk.h | 11 +-
164
target/arm/hvf/hvf.c | 9 +
316
include/hw/vmapple/vmapple.h | 23 +
165
ui/cocoa.m | 15 +-
317
include/qemu-main.h | 14 +-
166
45 files changed, 3443 insertions(+), 34 deletions(-)
318
include/qemu/cutils.h | 15 +
319
meson.build | 5 +
320
qapi/virtio.json | 14 +
321
system/main.c | 37 +-
322
target/arm/hvf/hvf.c | 9 +
323
ui/cocoa.m | 54 +-
324
ui/gtk.c | 4 +
325
ui/sdl2.c | 4 +
326
util/hexdump.c | 18 +
327
53 files changed, 3842 insertions(+), 110 deletions(-)
328
create mode 100755 contrib/vmapple/uuid.sh
167
create mode 100644 docs/system/arm/vmapple.rst
329
create mode 100644 docs/system/arm/vmapple.rst
330
create mode 100644 hw/display/apple-gfx-mmio.m
168
create mode 100644 hw/display/apple-gfx-pci.m
331
create mode 100644 hw/display/apple-gfx-pci.m
169
create mode 100644 hw/display/apple-gfx-vmapple.m
170
create mode 100644 hw/display/apple-gfx.h
332
create mode 100644 hw/display/apple-gfx.h
171
create mode 100644 hw/display/apple-gfx.m
333
create mode 100644 hw/display/apple-gfx.m
172
create mode 100644 hw/misc/pvpanic-mmio.c
334
create mode 100644 hw/misc/pvpanic-mmio.c
173
create mode 100644 hw/vmapple/Kconfig
335
create mode 100644 hw/vmapple/Kconfig
174
create mode 100644 hw/vmapple/aes.c
336
create mode 100644 hw/vmapple/aes.c
...
...
177
create mode 100644 hw/vmapple/meson.build
339
create mode 100644 hw/vmapple/meson.build
178
create mode 100644 hw/vmapple/trace-events
340
create mode 100644 hw/vmapple/trace-events
179
create mode 100644 hw/vmapple/trace.h
341
create mode 100644 hw/vmapple/trace.h
180
create mode 100644 hw/vmapple/virtio-blk.c
342
create mode 100644 hw/vmapple/virtio-blk.c
181
create mode 100644 hw/vmapple/vmapple.c
343
create mode 100644 hw/vmapple/vmapple.c
182
create mode 100644 include/hw/vmapple/bdif.h
344
create mode 100644 include/hw/vmapple/vmapple.h
183
create mode 100644 include/hw/vmapple/cfg.h
184
create mode 100644 include/hw/vmapple/virtio-blk.h
185
345
186
--
346
--
187
2.39.3 (Apple Git-145)
347
2.39.5 (Apple Git-154)
348
349
diff view generated by jsdifflib
Deleted patch
1
MacOS provides a framework (library) that allows any vmm to implement a
2
paravirtualized 3d graphics passthrough to the host metal stack called
3
ParavirtualizedGraphics.Framework (PVG). The library abstracts away
4
almost every aspect of the paravirtualized device model and only provides
5
and receives callbacks on MMIO access as well as to share memory address
6
space between the VM and PVG.
7
1
8
This patch implements a QEMU device that drives PVG for the VMApple
9
variant of it.
10
11
Signed-off-by: Alexander Graf <graf@amazon.com>
12
Co-authored-by: Alexander Graf <graf@amazon.com>
13
14
Subsequent changes:
15
16
* Cherry-pick/rebase conflict fixes
17
* BQL function renaming
18
* Moved from hw/vmapple/ (useful outside that machine type)
19
* Code review comments: Switched to DEFINE_TYPES macro & little endian
20
MMIO.
21
* Removed some dead/superfluous code
22
* Mad set_mode thread & memory safe
23
* Added migration blocker due to lack of (de-)serialisation.
24
* Fixes to ObjC refcounting and autorelease pool usage.
25
* Fixed ObjC new/init misuse
26
* Switched to ObjC category extension for private property.
27
* Simplified task memory mapping and made it thread safe.
28
* Refactoring to split generic and vmapple MMIO variant specific
29
code.
30
* Switched to asynchronous MMIO writes on x86-64
31
* Rendering and graphics update are now done asynchronously
32
* Fixed cursor handling
33
* Coding convention fixes
34
* Removed software cursor compositing
35
36
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
37
38
---
39
40
v3:
41
42
* Rebased on latest upstream, fixed breakages including switching to Resettable methods.
43
* Squashed patches dealing with dGPUs, MMIO area size, and GPU picking.
44
* Allow re-entrant MMIO; this simplifies the code and solves the divergence
45
between x86-64 and arm64 variants.
46
47
hw/display/Kconfig | 9 +
48
hw/display/apple-gfx-vmapple.m | 215 +++++++++++++
49
hw/display/apple-gfx.h | 57 ++++
50
hw/display/apple-gfx.m | 536 +++++++++++++++++++++++++++++++++
51
hw/display/meson.build | 2 +
52
hw/display/trace-events | 26 ++
53
meson.build | 4 +
54
7 files changed, 849 insertions(+)
55
create mode 100644 hw/display/apple-gfx-vmapple.m
56
create mode 100644 hw/display/apple-gfx.h
57
create mode 100644 hw/display/apple-gfx.m
58
59
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
60
index XXXXXXX..XXXXXXX 100644
61
--- a/hw/display/Kconfig
62
+++ b/hw/display/Kconfig
63
@@ -XXX,XX +XXX,XX @@ config XLNX_DISPLAYPORT
64
65
config DM163
66
bool
67
+
68
+config MAC_PVG
69
+ bool
70
+ default y
71
+
72
+config MAC_PVG_VMAPPLE
73
+ bool
74
+ depends on MAC_PVG
75
+ depends on ARM
76
diff --git a/hw/display/apple-gfx-vmapple.m b/hw/display/apple-gfx-vmapple.m
77
new file mode 100644
78
index XXXXXXX..XXXXXXX
79
--- /dev/null
80
+++ b/hw/display/apple-gfx-vmapple.m
81
@@ -XXX,XX +XXX,XX @@
82
+/*
83
+ * QEMU Apple ParavirtualizedGraphics.framework device, vmapple (arm64) variant
84
+ *
85
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
86
+ *
87
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
88
+ * See the COPYING file in the top-level directory.
89
+ *
90
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS provides
91
+ * which implements 3d graphics passthrough to the host as well as a
92
+ * proprietary guest communication channel to drive it. This device model
93
+ * implements support to drive that library from within QEMU as an MMIO-based
94
+ * system device for macOS on arm64 VMs.
95
+ */
96
+
97
+#include "apple-gfx.h"
98
+#include "monitor/monitor.h"
99
+#include "hw/sysbus.h"
100
+#include "hw/irq.h"
101
+#include "trace.h"
102
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
103
+
104
+_Static_assert(__aarch64__, "");
105
+
106
+/*
107
+ * ParavirtualizedGraphics.Framework only ships header files for the PCI
108
+ * variant which does not include IOSFC descriptors and host devices. We add
109
+ * their definitions here so that we can also work with the ARM version.
110
+ */
111
+typedef bool(^IOSFCRaiseInterrupt)(uint32_t vector);
112
+typedef bool(^IOSFCUnmapMemory)(
113
+ void *a, void *b, void *c, void *d, void *e, void *f);
114
+typedef bool(^IOSFCMapMemory)(
115
+ uint64_t phys, uint64_t len, bool ro, void **va, void *e, void *f);
116
+
117
+@interface PGDeviceDescriptor (IOSurfaceMapper)
118
+@property (readwrite, nonatomic) bool usingIOSurfaceMapper;
119
+@end
120
+
121
+@interface PGIOSurfaceHostDeviceDescriptor : NSObject
122
+-(PGIOSurfaceHostDeviceDescriptor *)init;
123
+@property (readwrite, nonatomic, copy, nullable) IOSFCMapMemory mapMemory;
124
+@property (readwrite, nonatomic, copy, nullable) IOSFCUnmapMemory unmapMemory;
125
+@property (readwrite, nonatomic, copy, nullable) IOSFCRaiseInterrupt raiseInterrupt;
126
+@end
127
+
128
+@interface PGIOSurfaceHostDevice : NSObject
129
+-(instancetype)initWithDescriptor:(PGIOSurfaceHostDeviceDescriptor *) desc;
130
+-(uint32_t)mmioReadAtOffset:(size_t) offset;
131
+-(void)mmioWriteAtOffset:(size_t) offset value:(uint32_t)value;
132
+@end
133
+
134
+typedef struct AppleGFXVmappleState {
135
+ SysBusDevice parent_obj;
136
+
137
+ AppleGFXState common;
138
+
139
+ qemu_irq irq_gfx;
140
+ qemu_irq irq_iosfc;
141
+ MemoryRegion iomem_iosfc;
142
+ PGIOSurfaceHostDevice *pgiosfc;
143
+} AppleGFXVmappleState;
144
+
145
+OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXVmappleState, APPLE_GFX_VMAPPLE)
146
+
147
+
148
+static uint64_t apple_iosfc_read(void *opaque, hwaddr offset, unsigned size)
149
+{
150
+ AppleGFXVmappleState *s = opaque;
151
+ uint64_t res = 0;
152
+
153
+ bql_unlock();
154
+ res = [s->pgiosfc mmioReadAtOffset:offset];
155
+ bql_lock();
156
+
157
+ trace_apple_iosfc_read(offset, res);
158
+
159
+ return res;
160
+}
161
+
162
+static void apple_iosfc_write(
163
+ void *opaque, hwaddr offset, uint64_t val, unsigned size)
164
+{
165
+ AppleGFXVmappleState *s = opaque;
166
+
167
+ trace_apple_iosfc_write(offset, val);
168
+
169
+ [s->pgiosfc mmioWriteAtOffset:offset value:val];
170
+}
171
+
172
+static const MemoryRegionOps apple_iosfc_ops = {
173
+ .read = apple_iosfc_read,
174
+ .write = apple_iosfc_write,
175
+ .endianness = DEVICE_LITTLE_ENDIAN,
176
+ .valid = {
177
+ .min_access_size = 4,
178
+ .max_access_size = 8,
179
+ },
180
+ .impl = {
181
+ .min_access_size = 4,
182
+ .max_access_size = 8,
183
+ },
184
+};
185
+
186
+static PGIOSurfaceHostDevice *apple_gfx_prepare_iosurface_host_device(
187
+ AppleGFXVmappleState *s)
188
+{
189
+ PGIOSurfaceHostDeviceDescriptor *iosfc_desc =
190
+ [PGIOSurfaceHostDeviceDescriptor new];
191
+ PGIOSurfaceHostDevice *iosfc_host_dev = nil;
192
+
193
+ iosfc_desc.mapMemory =
194
+ ^(uint64_t phys, uint64_t len, bool ro, void **va, void *e, void *f) {
195
+ trace_apple_iosfc_map_memory(phys, len, ro, va, e, f);
196
+ MemoryRegion *tmp_mr;
197
+ *va = gpa2hva(&tmp_mr, phys, len, NULL);
198
+ return (bool)true;
199
+ };
200
+
201
+ iosfc_desc.unmapMemory =
202
+ ^(void *a, void *b, void *c, void *d, void *e, void *f) {
203
+ trace_apple_iosfc_unmap_memory(a, b, c, d, e, f);
204
+ return (bool)true;
205
+ };
206
+
207
+ iosfc_desc.raiseInterrupt = ^(uint32_t vector) {
208
+ trace_apple_iosfc_raise_irq(vector);
209
+ bool locked = bql_locked();
210
+ if (!locked) {
211
+ bql_lock();
212
+ }
213
+ qemu_irq_pulse(s->irq_iosfc);
214
+ if (!locked) {
215
+ bql_unlock();
216
+ }
217
+ return (bool)true;
218
+ };
219
+
220
+ iosfc_host_dev =
221
+ [[PGIOSurfaceHostDevice alloc] initWithDescriptor:iosfc_desc];
222
+ [iosfc_desc release];
223
+ return iosfc_host_dev;
224
+}
225
+
226
+static void apple_gfx_vmapple_realize(DeviceState *dev, Error **errp)
227
+{
228
+ @autoreleasepool {
229
+ AppleGFXVmappleState *s = APPLE_GFX_VMAPPLE(dev);
230
+
231
+ PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
232
+ desc.usingIOSurfaceMapper = true;
233
+ desc.raiseInterrupt = ^(uint32_t vector) {
234
+ bool locked;
235
+
236
+ trace_apple_gfx_raise_irq(vector);
237
+ locked = bql_locked();
238
+ if (!locked) {
239
+ bql_lock();
240
+ }
241
+ qemu_irq_pulse(s->irq_gfx);
242
+ if (!locked) {
243
+ bql_unlock();
244
+ }
245
+ };
246
+
247
+ s->pgiosfc = apple_gfx_prepare_iosurface_host_device(s);
248
+
249
+ apple_gfx_common_realize(&s->common, desc);
250
+ [desc release];
251
+ desc = nil;
252
+ }
253
+}
254
+
255
+static void apple_gfx_vmapple_init(Object *obj)
256
+{
257
+ AppleGFXVmappleState *s = APPLE_GFX_VMAPPLE(obj);
258
+
259
+ apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_VMAPPLE);
260
+
261
+ memory_region_init_io(&s->iomem_iosfc, obj, &apple_iosfc_ops, s,
262
+ TYPE_APPLE_GFX_VMAPPLE, 0x10000);
263
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->common.iomem_gfx);
264
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem_iosfc);
265
+ sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_gfx);
266
+ sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_iosfc);
267
+}
268
+
269
+static void apple_gfx_vmapple_reset(Object *obj, ResetType type)
270
+{
271
+ AppleGFXVmappleState *s = APPLE_GFX_VMAPPLE(obj);
272
+ [s->common.pgdev reset];
273
+}
274
+
275
+
276
+static void apple_gfx_vmapple_class_init(ObjectClass *klass, void *data)
277
+{
278
+ DeviceClass *dc = DEVICE_CLASS(klass);
279
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
280
+
281
+ assert(rc->phases.hold == NULL);
282
+ rc->phases.hold = apple_gfx_vmapple_reset;
283
+
284
+ dc->realize = apple_gfx_vmapple_realize;
285
+}
286
+
287
+static TypeInfo apple_gfx_vmapple_types[] = {
288
+ {
289
+ .name = TYPE_APPLE_GFX_VMAPPLE,
290
+ .parent = TYPE_SYS_BUS_DEVICE,
291
+ .instance_size = sizeof(AppleGFXVmappleState),
292
+ .class_init = apple_gfx_vmapple_class_init,
293
+ .instance_init = apple_gfx_vmapple_init,
294
+ }
295
+};
296
+DEFINE_TYPES(apple_gfx_vmapple_types)
297
diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h
298
new file mode 100644
299
index XXXXXXX..XXXXXXX
300
--- /dev/null
301
+++ b/hw/display/apple-gfx.h
302
@@ -XXX,XX +XXX,XX @@
303
+#ifndef QEMU_APPLE_GFX_H
304
+#define QEMU_APPLE_GFX_H
305
+
306
+#define TYPE_APPLE_GFX_VMAPPLE "apple-gfx-vmapple"
307
+#define TYPE_APPLE_GFX_PCI "apple-gfx-pci"
308
+
309
+#include "qemu/typedefs.h"
310
+
311
+typedef struct AppleGFXState AppleGFXState;
312
+
313
+void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_name);
314
+
315
+#ifdef __OBJC__
316
+
317
+#include "qemu/osdep.h"
318
+#include "exec/memory.h"
319
+#include "ui/surface.h"
320
+#include <dispatch/dispatch.h>
321
+
322
+@class PGDeviceDescriptor;
323
+@protocol PGDevice;
324
+@protocol PGDisplay;
325
+@protocol MTLDevice;
326
+@protocol MTLTexture;
327
+@protocol MTLCommandQueue;
328
+
329
+typedef QTAILQ_HEAD(, PGTask_s) AppleGFXTaskList;
330
+
331
+struct AppleGFXState {
332
+ MemoryRegion iomem_gfx;
333
+ id<PGDevice> pgdev;
334
+ id<PGDisplay> pgdisp;
335
+ AppleGFXTaskList tasks;
336
+ QemuConsole *con;
337
+ id<MTLDevice> mtl;
338
+ id<MTLCommandQueue> mtl_queue;
339
+ bool handles_frames;
340
+ bool new_frame;
341
+ bool cursor_show;
342
+ QEMUCursor *cursor;
343
+
344
+ dispatch_queue_t render_queue;
345
+ /* The following fields should only be accessed from render_queue: */
346
+ bool gfx_update_requested;
347
+ bool new_frame_ready;
348
+ bool using_managed_texture_storage;
349
+ int32_t pending_frames;
350
+ void *vram;
351
+ DisplaySurface *surface;
352
+ id<MTLTexture> texture;
353
+};
354
+
355
+void apple_gfx_common_realize(AppleGFXState *s, PGDeviceDescriptor *desc);
356
+
357
+#endif /* __OBJC__ */
358
+
359
+#endif
360
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
361
new file mode 100644
362
index XXXXXXX..XXXXXXX
363
--- /dev/null
364
+++ b/hw/display/apple-gfx.m
365
@@ -XXX,XX +XXX,XX @@
366
+/*
367
+ * QEMU Apple ParavirtualizedGraphics.framework device
368
+ *
369
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
370
+ *
371
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
372
+ * See the COPYING file in the top-level directory.
373
+ *
374
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS provides
375
+ * which implements 3d graphics passthrough to the host as well as a
376
+ * proprietary guest communication channel to drive it. This device model
377
+ * implements support to drive that library from within QEMU.
378
+ */
379
+
380
+#include "apple-gfx.h"
381
+#include "trace.h"
382
+#include "qemu/main-loop.h"
383
+#include "ui/console.h"
384
+#include "monitor/monitor.h"
385
+#include "qapi/error.h"
386
+#include "migration/blocker.h"
387
+#include <mach/mach_vm.h>
388
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
389
+
390
+static const PGDisplayCoord_t apple_gfx_modes[] = {
391
+ { .x = 1440, .y = 1080 },
392
+ { .x = 1280, .y = 1024 },
393
+};
394
+
395
+typedef struct PGTask_s { // Name matches forward declaration in PG header
396
+ QTAILQ_ENTRY(PGTask_s) node;
397
+ mach_vm_address_t address;
398
+ uint64_t len;
399
+} AppleGFXTask;
400
+
401
+static Error *apple_gfx_mig_blocker;
402
+
403
+static void apple_gfx_render_frame_completed(AppleGFXState *s, void *vram,
404
+ id<MTLTexture> texture);
405
+
406
+static AppleGFXTask *apple_gfx_new_task(AppleGFXState *s, uint64_t len)
407
+{
408
+ mach_vm_address_t task_mem;
409
+ AppleGFXTask *task;
410
+ kern_return_t r;
411
+
412
+ r = mach_vm_allocate(mach_task_self(), &task_mem, len, VM_FLAGS_ANYWHERE);
413
+ if (r != KERN_SUCCESS || task_mem == 0) {
414
+ return NULL;
415
+ }
416
+
417
+ task = g_new0(AppleGFXTask, 1);
418
+
419
+ task->address = task_mem;
420
+ task->len = len;
421
+ QTAILQ_INSERT_TAIL(&s->tasks, task, node);
422
+
423
+ return task;
424
+}
425
+
426
+static uint64_t apple_gfx_read(void *opaque, hwaddr offset, unsigned size)
427
+{
428
+ AppleGFXState *s = opaque;
429
+ uint64_t res = 0;
430
+
431
+ bql_unlock();
432
+ res = [s->pgdev mmioReadAtOffset:offset];
433
+ bql_lock();
434
+
435
+ trace_apple_gfx_read(offset, res);
436
+
437
+ return res;
438
+}
439
+
440
+static void apple_gfx_write(void *opaque, hwaddr offset, uint64_t val,
441
+ unsigned size)
442
+{
443
+ AppleGFXState *s = opaque;
444
+
445
+ trace_apple_gfx_write(offset, val);
446
+
447
+ bql_unlock();
448
+ [s->pgdev mmioWriteAtOffset:offset value:val];
449
+ bql_lock();
450
+}
451
+
452
+static const MemoryRegionOps apple_gfx_ops = {
453
+ .read = apple_gfx_read,
454
+ .write = apple_gfx_write,
455
+ .endianness = DEVICE_LITTLE_ENDIAN,
456
+ .valid = {
457
+ .min_access_size = 4,
458
+ .max_access_size = 8,
459
+ },
460
+ .impl = {
461
+ .min_access_size = 4,
462
+ .max_access_size = 4,
463
+ },
464
+};
465
+
466
+static void apple_gfx_render_new_frame(AppleGFXState *s)
467
+{
468
+ BOOL r;
469
+ void *vram = s->vram;
470
+ uint32_t width = surface_width(s->surface);
471
+ uint32_t height = surface_height(s->surface);
472
+ MTLRegion region = MTLRegionMake2D(0, 0, width, height);
473
+ id<MTLCommandBuffer> command_buffer = [s->mtl_queue commandBuffer];
474
+ id<MTLTexture> texture = s->texture;
475
+ r = [s->pgdisp encodeCurrentFrameToCommandBuffer:command_buffer
476
+ texture:texture
477
+ region:region];
478
+ if (!r) {
479
+ return;
480
+ }
481
+ [texture retain];
482
+ if (s->using_managed_texture_storage) {
483
+ /* "Managed" textures exist in both VRAM and RAM and must be synced. */
484
+ id<MTLBlitCommandEncoder> blit = [command_buffer blitCommandEncoder];
485
+ [blit synchronizeResource:texture];
486
+ [blit endEncoding];
487
+ }
488
+ [command_buffer retain];
489
+ [command_buffer addCompletedHandler:
490
+ ^(id<MTLCommandBuffer> cb)
491
+ {
492
+ dispatch_async(s->render_queue, ^{
493
+ apple_gfx_render_frame_completed(s, vram, texture);
494
+ [texture release];
495
+ });
496
+ [command_buffer release];
497
+ }];
498
+ [command_buffer commit];
499
+}
500
+
501
+static void copy_mtl_texture_to_surface_mem(id<MTLTexture> texture, void *vram)
502
+{
503
+ /* TODO: Skip this entirely on a pure Metal or headless/guest-only
504
+ * rendering path, else use a blit command encoder? Needs careful
505
+ * (double?) buffering design. */
506
+ size_t width = texture.width, height = texture.height;
507
+ MTLRegion region = MTLRegionMake2D(0, 0, width, height);
508
+ [texture getBytes:vram
509
+ bytesPerRow:(width * 4)
510
+ bytesPerImage:(width * height * 4)
511
+ fromRegion:region
512
+ mipmapLevel:0
513
+ slice:0];
514
+}
515
+
516
+static void apple_gfx_render_frame_completed(AppleGFXState *s, void *vram,
517
+ id<MTLTexture> texture)
518
+{
519
+ --s->pending_frames;
520
+ assert(s->pending_frames >= 0);
521
+
522
+ if (vram != s->vram) {
523
+ /* Display mode has changed, drop this old frame. */
524
+ assert(texture != s->texture);
525
+ g_free(vram);
526
+ } else {
527
+ copy_mtl_texture_to_surface_mem(texture, vram);
528
+ if (s->gfx_update_requested) {
529
+ s->gfx_update_requested = false;
530
+ dpy_gfx_update_full(s->con);
531
+ graphic_hw_update_done(s->con);
532
+ s->new_frame_ready = false;
533
+ } else {
534
+ s->new_frame_ready = true;
535
+ }
536
+ }
537
+ if (s->pending_frames > 0) {
538
+ apple_gfx_render_new_frame(s);
539
+ }
540
+}
541
+
542
+static void apple_gfx_fb_update_display(void *opaque)
543
+{
544
+ AppleGFXState *s = opaque;
545
+
546
+ dispatch_async(s->render_queue, ^{
547
+ if (s->pending_frames > 0) {
548
+ s->gfx_update_requested = true;
549
+ } else {
550
+ if (s->new_frame_ready) {
551
+ dpy_gfx_update_full(s->con);
552
+ s->new_frame_ready = false;
553
+ }
554
+ graphic_hw_update_done(s->con);
555
+ }
556
+ });
557
+}
558
+
559
+static const GraphicHwOps apple_gfx_fb_ops = {
560
+ .gfx_update = apple_gfx_fb_update_display,
561
+ .gfx_update_async = true,
562
+};
563
+
564
+static void update_cursor(AppleGFXState *s)
565
+{
566
+ dpy_mouse_set(s->con, s->pgdisp.cursorPosition.x,
567
+ s->pgdisp.cursorPosition.y, s->cursor_show);
568
+}
569
+
570
+static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
571
+{
572
+ void *vram = NULL;
573
+ DisplaySurface *surface;
574
+ MTLTextureDescriptor *textureDescriptor;
575
+ id<MTLTexture> texture = nil;
576
+ __block bool no_change = false;
577
+
578
+ dispatch_sync(s->render_queue,
579
+ ^{
580
+ if (s->surface &&
581
+ width == surface_width(s->surface) &&
582
+ height == surface_height(s->surface)) {
583
+ no_change = true;
584
+ }
585
+ });
586
+
587
+ if (no_change) {
588
+ return;
589
+ }
590
+
591
+ vram = g_malloc0(width * height * 4);
592
+ surface = qemu_create_displaysurface_from(width, height, PIXMAN_LE_a8r8g8b8,
593
+ width * 4, vram);
594
+
595
+ @autoreleasepool {
596
+ textureDescriptor =
597
+ [MTLTextureDescriptor
598
+ texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
599
+ width:width
600
+ height:height
601
+ mipmapped:NO];
602
+ textureDescriptor.usage = s->pgdisp.minimumTextureUsage;
603
+ texture = [s->mtl newTextureWithDescriptor:textureDescriptor];
604
+ }
605
+
606
+ s->using_managed_texture_storage =
607
+ (texture.storageMode == MTLStorageModeManaged);
608
+
609
+ dispatch_sync(s->render_queue,
610
+ ^{
611
+ id<MTLTexture> old_texture = nil;
612
+ void *old_vram = s->vram;
613
+ s->vram = vram;
614
+ s->surface = surface;
615
+
616
+ dpy_gfx_replace_surface(s->con, surface);
617
+
618
+ old_texture = s->texture;
619
+ s->texture = texture;
620
+ [old_texture release];
621
+
622
+ if (s->pending_frames == 0) {
623
+ g_free(old_vram);
624
+ }
625
+ });
626
+}
627
+
628
+static void create_fb(AppleGFXState *s)
629
+{
630
+ s->con = graphic_console_init(NULL, 0, &apple_gfx_fb_ops, s);
631
+ set_mode(s, 1440, 1080);
632
+
633
+ s->cursor_show = true;
634
+}
635
+
636
+static size_t apple_gfx_get_default_mmio_range_size(void)
637
+{
638
+ size_t mmio_range_size;
639
+ @autoreleasepool {
640
+ PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
641
+ mmio_range_size = desc.mmioLength;
642
+ [desc release];
643
+ }
644
+ return mmio_range_size;
645
+}
646
+
647
+void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_name)
648
+{
649
+ Error *local_err = NULL;
650
+ int r;
651
+ size_t mmio_range_size = apple_gfx_get_default_mmio_range_size();
652
+
653
+ trace_apple_gfx_common_init(obj_name, mmio_range_size);
654
+ memory_region_init_io(&s->iomem_gfx, obj, &apple_gfx_ops, s, obj_name,
655
+ mmio_range_size);
656
+ s->iomem_gfx.disable_reentrancy_guard = true;
657
+
658
+ /* TODO: PVG framework supports serialising device state: integrate it! */
659
+ if (apple_gfx_mig_blocker == NULL) {
660
+ error_setg(&apple_gfx_mig_blocker,
661
+ "Migration state blocked by apple-gfx display device");
662
+ r = migrate_add_blocker(&apple_gfx_mig_blocker, &local_err);
663
+ if (r < 0) {
664
+ error_report_err(local_err);
665
+ }
666
+ }
667
+}
668
+
669
+static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
670
+ PGDeviceDescriptor *desc)
671
+{
672
+ desc.createTask = ^(uint64_t vmSize, void * _Nullable * _Nonnull baseAddress) {
673
+ AppleGFXTask *task = apple_gfx_new_task(s, vmSize);
674
+ *baseAddress = (void*)task->address;
675
+ trace_apple_gfx_create_task(vmSize, *baseAddress);
676
+ return task;
677
+ };
678
+
679
+ desc.destroyTask = ^(AppleGFXTask * _Nonnull task) {
680
+ trace_apple_gfx_destroy_task(task);
681
+ QTAILQ_REMOVE(&s->tasks, task, node);
682
+ mach_vm_deallocate(mach_task_self(), task->address, task->len);
683
+ g_free(task);
684
+ };
685
+
686
+ desc.mapMemory = ^(AppleGFXTask * _Nonnull task, uint32_t rangeCount,
687
+ uint64_t virtualOffset, bool readOnly,
688
+ PGPhysicalMemoryRange_t * _Nonnull ranges) {
689
+ kern_return_t r;
690
+ mach_vm_address_t target, source;
691
+ trace_apple_gfx_map_memory(task, rangeCount, virtualOffset, readOnly);
692
+ for (int i = 0; i < rangeCount; i++) {
693
+ PGPhysicalMemoryRange_t *range = &ranges[i];
694
+ MemoryRegion *tmp_mr;
695
+ /* TODO: Bounds checks? r/o? */
696
+ bql_lock();
697
+
698
+ trace_apple_gfx_map_memory_range(i, range->physicalAddress,
699
+ range->physicalLength);
700
+
701
+ target = task->address + virtualOffset;
702
+ source = (mach_vm_address_t)gpa2hva(&tmp_mr,
703
+ range->physicalAddress,
704
+ range->physicalLength, NULL);
705
+ vm_prot_t cur_protection = 0;
706
+ vm_prot_t max_protection = 0;
707
+ // Map guest RAM at range->physicalAddress into PG task memory range
708
+ r = mach_vm_remap(mach_task_self(),
709
+ &target, range->physicalLength, vm_page_size - 1,
710
+ VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
711
+ mach_task_self(),
712
+ source, false /* shared mapping, no copy */,
713
+ &cur_protection, &max_protection,
714
+ VM_INHERIT_COPY);
715
+ trace_apple_gfx_remap(r, source, target);
716
+ g_assert(r == KERN_SUCCESS);
717
+
718
+ bql_unlock();
719
+
720
+ virtualOffset += range->physicalLength;
721
+ }
722
+ return (bool)true;
723
+ };
724
+
725
+ desc.unmapMemory = ^(AppleGFXTask * _Nonnull task, uint64_t virtualOffset,
726
+ uint64_t length) {
727
+ kern_return_t r;
728
+ mach_vm_address_t range_address;
729
+
730
+ trace_apple_gfx_unmap_memory(task, virtualOffset, length);
731
+
732
+ /* Replace task memory range with fresh pages, undoing the mapping
733
+ * from guest RAM. */
734
+ range_address = task->address + virtualOffset;
735
+ r = mach_vm_allocate(mach_task_self(), &range_address, length,
736
+ VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
737
+ g_assert(r == KERN_SUCCESS);
738
+
739
+ return (bool)true;
740
+ };
741
+
742
+ desc.readMemory = ^(uint64_t physicalAddress, uint64_t length,
743
+ void * _Nonnull dst) {
744
+ trace_apple_gfx_read_memory(physicalAddress, length, dst);
745
+ cpu_physical_memory_read(physicalAddress, dst, length);
746
+ return (bool)true;
747
+ };
748
+
749
+}
750
+
751
+static PGDisplayDescriptor *apple_gfx_prepare_display_handlers(AppleGFXState *s)
752
+{
753
+ PGDisplayDescriptor *disp_desc = [PGDisplayDescriptor new];
754
+
755
+ disp_desc.name = @"QEMU display";
756
+ disp_desc.sizeInMillimeters = NSMakeSize(400., 300.); /* A 20" display */
757
+ disp_desc.queue = dispatch_get_main_queue();
758
+ disp_desc.newFrameEventHandler = ^(void) {
759
+ trace_apple_gfx_new_frame();
760
+ dispatch_async(s->render_queue, ^{
761
+ /* Drop frames if we get too far ahead. */
762
+ if (s->pending_frames >= 2)
763
+ return;
764
+ ++s->pending_frames;
765
+ if (s->pending_frames > 1) {
766
+ return;
767
+ }
768
+ @autoreleasepool {
769
+ apple_gfx_render_new_frame(s);
770
+ }
771
+ });
772
+ };
773
+ disp_desc.modeChangeHandler = ^(PGDisplayCoord_t sizeInPixels,
774
+ OSType pixelFormat) {
775
+ trace_apple_gfx_mode_change(sizeInPixels.x, sizeInPixels.y);
776
+ set_mode(s, sizeInPixels.x, sizeInPixels.y);
777
+ };
778
+ disp_desc.cursorGlyphHandler = ^(NSBitmapImageRep *glyph,
779
+ PGDisplayCoord_t hotSpot) {
780
+ uint32_t bpp = glyph.bitsPerPixel;
781
+ size_t width = glyph.pixelsWide;
782
+ size_t height = glyph.pixelsHigh;
783
+ size_t padding_bytes_per_row = glyph.bytesPerRow - width * 4;
784
+ const uint8_t* px_data = glyph.bitmapData;
785
+
786
+ trace_apple_gfx_cursor_set(bpp, width, height);
787
+
788
+ if (s->cursor) {
789
+ cursor_unref(s->cursor);
790
+ s->cursor = NULL;
791
+ }
792
+
793
+ if (bpp == 32) { /* Shouldn't be anything else, but just to be safe...*/
794
+ s->cursor = cursor_alloc(width, height);
795
+ s->cursor->hot_x = hotSpot.x;
796
+ s->cursor->hot_y = hotSpot.y;
797
+
798
+ uint32_t *dest_px = s->cursor->data;
799
+
800
+ for (size_t y = 0; y < height; ++y) {
801
+ for (size_t x = 0; x < width; ++x) {
802
+ /* NSBitmapImageRep's red & blue channels are swapped
803
+ * compared to QEMUCursor's. */
804
+ *dest_px =
805
+ (px_data[0] << 16u) |
806
+ (px_data[1] << 8u) |
807
+ (px_data[2] << 0u) |
808
+ (px_data[3] << 24u);
809
+ ++dest_px;
810
+ px_data += 4;
811
+ }
812
+ px_data += padding_bytes_per_row;
813
+ }
814
+ dpy_cursor_define(s->con, s->cursor);
815
+ update_cursor(s);
816
+ }
817
+ };
818
+ disp_desc.cursorShowHandler = ^(BOOL show) {
819
+ trace_apple_gfx_cursor_show(show);
820
+ s->cursor_show = show;
821
+ update_cursor(s);
822
+ };
823
+ disp_desc.cursorMoveHandler = ^(void) {
824
+ trace_apple_gfx_cursor_move();
825
+ update_cursor(s);
826
+ };
827
+
828
+ return disp_desc;
829
+}
830
+
831
+static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void)
832
+{
833
+ PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
834
+ NSArray<PGDisplayMode*>* mode_array = nil;
835
+ int i;
836
+
837
+ for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
838
+ modes[i] =
839
+ [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i] refreshRateInHz:60.];
840
+ }
841
+
842
+ mode_array = [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_gfx_modes)];
843
+
844
+ for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
845
+ [modes[i] release];
846
+ modes[i] = nil;
847
+ }
848
+
849
+ return mode_array;
850
+}
851
+
852
+static id<MTLDevice> copy_suitable_metal_device(void)
853
+{
854
+ id<MTLDevice> dev = nil;
855
+ NSArray<id<MTLDevice>> *devs = MTLCopyAllDevices();
856
+
857
+ /* Prefer a unified memory GPU. Failing that, pick a non-removable GPU. */
858
+ for (size_t i = 0; i < devs.count; ++i) {
859
+ if (devs[i].hasUnifiedMemory) {
860
+ dev = devs[i];
861
+ break;
862
+ }
863
+ if (!devs[i].removable) {
864
+ dev = devs[i];
865
+ }
866
+ }
867
+
868
+ if (dev != nil) {
869
+ [dev retain];
870
+ } else {
871
+ dev = MTLCreateSystemDefaultDevice();
872
+ }
873
+ [devs release];
874
+
875
+ return dev;
876
+}
877
+
878
+void apple_gfx_common_realize(AppleGFXState *s, PGDeviceDescriptor *desc)
879
+{
880
+ PGDisplayDescriptor *disp_desc = nil;
881
+
882
+ QTAILQ_INIT(&s->tasks);
883
+ s->render_queue = dispatch_queue_create("apple-gfx.render",
884
+ DISPATCH_QUEUE_SERIAL);
885
+ s->mtl = copy_suitable_metal_device();
886
+ s->mtl_queue = [s->mtl newCommandQueue];
887
+
888
+ desc.device = s->mtl;
889
+
890
+ apple_gfx_register_task_mapping_handlers(s, desc);
891
+
892
+ s->pgdev = PGNewDeviceWithDescriptor(desc);
893
+
894
+ disp_desc = apple_gfx_prepare_display_handlers(s);
895
+ s->pgdisp = [s->pgdev newDisplayWithDescriptor:disp_desc
896
+ port:0 serialNum:1234];
897
+ [disp_desc release];
898
+ s->pgdisp.modeList = apple_gfx_prepare_display_mode_array();
899
+
900
+ create_fb(s);
901
+}
902
diff --git a/hw/display/meson.build b/hw/display/meson.build
903
index XXXXXXX..XXXXXXX 100644
904
--- a/hw/display/meson.build
905
+++ b/hw/display/meson.build
906
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c'))
907
908
system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('ati.c', 'ati_2d.c', 'ati_dbg.c'), pixman])
909
910
+system_ss.add(when: 'CONFIG_MAC_PVG', if_true: [files('apple-gfx.m'), pvg, metal])
911
+system_ss.add(when: 'CONFIG_MAC_PVG_VMAPPLE', if_true: [files('apple-gfx-vmapple.m'), pvg, metal])
912
913
if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
914
virtio_gpu_ss = ss.source_set()
915
diff --git a/hw/display/trace-events b/hw/display/trace-events
916
index XXXXXXX..XXXXXXX 100644
917
--- a/hw/display/trace-events
918
+++ b/hw/display/trace-events
919
@@ -XXX,XX +XXX,XX @@ dm163_bits_ppi(unsigned dest_width) "dest_width : %u"
920
dm163_leds(int led, uint32_t value) "led %d: 0x%x"
921
dm163_channels(int channel, uint8_t value) "channel %d: 0x%x"
922
dm163_refresh_rate(uint32_t rr) "refresh rate %d"
923
+
924
+# apple-gfx.m
925
+apple_gfx_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
926
+apple_gfx_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
927
+apple_gfx_create_task(uint32_t vm_size, void *va) "vm_size=0x%x base_addr=%p"
928
+apple_gfx_destroy_task(void *task) "task=%p"
929
+apple_gfx_map_memory(void *task, uint32_t range_count, uint64_t virtual_offset, uint32_t read_only) "task=%p range_count=0x%x virtual_offset=0x%"PRIx64" read_only=%d"
930
+apple_gfx_map_memory_range(uint32_t i, uint64_t phys_addr, uint64_t phys_len) "[%d] phys_addr=0x%"PRIx64" phys_len=0x%"PRIx64
931
+apple_gfx_remap(uint64_t retval, uint64_t source, uint64_t target) "retval=%"PRId64" source=0x%"PRIx64" target=0x%"PRIx64
932
+apple_gfx_unmap_memory(void *task, uint64_t virtual_offset, uint64_t length) "task=%p virtual_offset=0x%"PRIx64" length=0x%"PRIx64
933
+apple_gfx_read_memory(uint64_t phys_address, uint64_t length, void *dst) "phys_addr=0x%"PRIx64" length=0x%"PRIx64" dest=%p"
934
+apple_gfx_raise_irq(uint32_t vector) "vector=0x%x"
935
+apple_gfx_new_frame(void) ""
936
+apple_gfx_mode_change(uint64_t x, uint64_t y) "x=%"PRId64" y=%"PRId64
937
+apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint64_t height) "bpp=%d width=%"PRId64" height=0x%"PRId64
938
+apple_gfx_cursor_show(uint32_t show) "show=%d"
939
+apple_gfx_cursor_move(void) ""
940
+apple_gfx_common_init(const char *device_name, size_t mmio_size) "device: %s; MMIO size: %zu bytes"
941
+
942
+# apple-gfx-vmapple.m
943
+apple_iosfc_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
944
+apple_iosfc_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
945
+apple_iosfc_map_memory(uint64_t phys, uint64_t len, uint32_t ro, void *va, void *e, void *f) "phys=0x%"PRIx64" len=0x%"PRIx64" ro=%d va=%p e=%p f=%p"
946
+apple_iosfc_unmap_memory(void *a, void *b, void *c, void *d, void *e, void *f) "a=%p b=%p c=%p d=%p e=%p f=%p"
947
+apple_iosfc_raise_irq(uint32_t vector) "vector=0x%x"
948
+
949
diff --git a/meson.build b/meson.build
950
index XXXXXXX..XXXXXXX 100644
951
--- a/meson.build
952
+++ b/meson.build
953
@@ -XXX,XX +XXX,XX @@ socket = []
954
version_res = []
955
coref = []
956
iokit = []
957
+pvg = []
958
+metal = []
959
emulator_link_args = []
960
midl = not_found
961
widl = not_found
962
@@ -XXX,XX +XXX,XX @@ elif host_os == 'darwin'
963
coref = dependency('appleframeworks', modules: 'CoreFoundation')
964
iokit = dependency('appleframeworks', modules: 'IOKit', required: false)
965
host_dsosuf = '.dylib'
966
+ pvg = dependency('appleframeworks', modules: 'ParavirtualizedGraphics')
967
+ metal = dependency('appleframeworks', modules: 'Metal')
968
elif host_os == 'sunos'
969
socket = [cc.find_library('socket'),
970
cc.find_library('nsl'),
971
--
972
2.39.3 (Apple Git-145)
973
974
diff view generated by jsdifflib
Deleted patch
1
This change wires up the PCI variant of the paravirtualised
2
graphics device, mainly useful for x86-64 macOS guests, implemented
3
by macOS's ParavirtualizedGraphics.framework. It builds on code
4
shared with the vmapple/mmio variant of the PVG device.
5
1
6
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
7
---
8
hw/display/Kconfig | 5 ++
9
hw/display/apple-gfx-pci.m | 138 +++++++++++++++++++++++++++++++++++++
10
hw/display/meson.build | 1 +
11
3 files changed, 144 insertions(+)
12
create mode 100644 hw/display/apple-gfx-pci.m
13
14
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/display/Kconfig
17
+++ b/hw/display/Kconfig
18
@@ -XXX,XX +XXX,XX @@ config MAC_PVG_VMAPPLE
19
bool
20
depends on MAC_PVG
21
depends on ARM
22
+
23
+config MAC_PVG_PCI
24
+ bool
25
+ depends on MAC_PVG && PCI
26
+ default y if PCI_DEVICES
27
diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m
28
new file mode 100644
29
index XXXXXXX..XXXXXXX
30
--- /dev/null
31
+++ b/hw/display/apple-gfx-pci.m
32
@@ -XXX,XX +XXX,XX @@
33
+/*
34
+ * QEMU Apple ParavirtualizedGraphics.framework device, PCI variant
35
+ *
36
+ * Copyright © 2023-2024 Phil Dennis-Jordan
37
+ *
38
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
39
+ * See the COPYING file in the top-level directory.
40
+ *
41
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS provides
42
+ * which implements 3d graphics passthrough to the host as well as a
43
+ * proprietary guest communication channel to drive it. This device model
44
+ * implements support to drive that library from within QEMU as a PCI device
45
+ * aimed primarily at x86-64 macOS VMs.
46
+ */
47
+
48
+#include "apple-gfx.h"
49
+#include "hw/pci/pci_device.h"
50
+#include "hw/pci/msi.h"
51
+#include "qapi/error.h"
52
+#include "trace.h"
53
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
54
+
55
+typedef struct AppleGFXPCIState {
56
+ PCIDevice parent_obj;
57
+
58
+ AppleGFXState common;
59
+} AppleGFXPCIState;
60
+
61
+OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXPCIState, APPLE_GFX_PCI)
62
+
63
+static const char* apple_gfx_pci_option_rom_path = NULL;
64
+
65
+static void apple_gfx_init_option_rom_path(void)
66
+{
67
+ NSURL *option_rom_url = PGCopyOptionROMURL();
68
+ const char *option_rom_path = option_rom_url.fileSystemRepresentation;
69
+ if (option_rom_url.fileURL && option_rom_path != NULL) {
70
+ apple_gfx_pci_option_rom_path = g_strdup(option_rom_path);
71
+ }
72
+ [option_rom_url release];
73
+}
74
+
75
+static void apple_gfx_pci_init(Object *obj)
76
+{
77
+ AppleGFXPCIState *s = APPLE_GFX_PCI(obj);
78
+
79
+ if (!apple_gfx_pci_option_rom_path) {
80
+ /* Done on device not class init to avoid -daemonize ObjC fork crash */
81
+ PCIDeviceClass *pci = PCI_DEVICE_CLASS(object_get_class(obj));
82
+ apple_gfx_init_option_rom_path();
83
+ pci->romfile = apple_gfx_pci_option_rom_path;
84
+ }
85
+
86
+ apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_PCI);
87
+}
88
+
89
+static void apple_gfx_pci_interrupt(PCIDevice *dev, AppleGFXPCIState *s,
90
+ uint32_t vector)
91
+{
92
+ bool msi_ok;
93
+ trace_apple_gfx_raise_irq(vector);
94
+
95
+ msi_ok = msi_enabled(dev);
96
+ if (msi_ok) {
97
+ msi_notify(dev, vector);
98
+ }
99
+}
100
+
101
+static void apple_gfx_pci_realize(PCIDevice *dev, Error **errp)
102
+{
103
+ AppleGFXPCIState *s = APPLE_GFX_PCI(dev);
104
+ Error *err = NULL;
105
+ int ret;
106
+
107
+ pci_register_bar(dev, PG_PCI_BAR_MMIO,
108
+ PCI_BASE_ADDRESS_SPACE_MEMORY, &s->common.iomem_gfx);
109
+
110
+ ret = msi_init(dev, 0x0 /* config offset; 0 = find space */,
111
+ PG_PCI_MAX_MSI_VECTORS, true /* msi64bit */,
112
+ false /*msi_per_vector_mask*/, &err);
113
+ if (ret != 0) {
114
+ error_propagate(errp, err);
115
+ return;
116
+ }
117
+
118
+ @autoreleasepool {
119
+ PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
120
+ desc.raiseInterrupt = ^(uint32_t vector) {
121
+ apple_gfx_pci_interrupt(dev, s, vector);
122
+ };
123
+
124
+ apple_gfx_common_realize(&s->common, desc);
125
+ [desc release];
126
+ desc = nil;
127
+ }
128
+}
129
+
130
+static void apple_gfx_pci_reset(Object *obj, ResetType type)
131
+{
132
+ AppleGFXPCIState *s = APPLE_GFX_PCI(obj);
133
+ [s->common.pgdev reset];
134
+}
135
+
136
+static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
137
+{
138
+ DeviceClass *dc = DEVICE_CLASS(klass);
139
+ PCIDeviceClass *pci = PCI_DEVICE_CLASS(klass);
140
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
141
+
142
+ assert(rc->phases.hold == NULL);
143
+ rc->phases.hold = apple_gfx_pci_reset;
144
+ dc->desc = "macOS Paravirtualized Graphics PCI Display Controller";
145
+ dc->hotpluggable = false;
146
+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
147
+
148
+ pci->vendor_id = PG_PCI_VENDOR_ID;
149
+ pci->device_id = PG_PCI_DEVICE_ID;
150
+ pci->class_id = PCI_CLASS_DISPLAY_OTHER;
151
+ pci->realize = apple_gfx_pci_realize;
152
+
153
+ // TODO: Property for setting mode list
154
+}
155
+
156
+static TypeInfo apple_gfx_pci_types[] = {
157
+ {
158
+ .name = TYPE_APPLE_GFX_PCI,
159
+ .parent = TYPE_PCI_DEVICE,
160
+ .instance_size = sizeof(AppleGFXPCIState),
161
+ .class_init = apple_gfx_pci_class_init,
162
+ .instance_init = apple_gfx_pci_init,
163
+ .interfaces = (InterfaceInfo[]) {
164
+ { INTERFACE_PCIE_DEVICE },
165
+ { },
166
+ },
167
+ }
168
+};
169
+DEFINE_TYPES(apple_gfx_pci_types)
170
+
171
diff --git a/hw/display/meson.build b/hw/display/meson.build
172
index XXXXXXX..XXXXXXX 100644
173
--- a/hw/display/meson.build
174
+++ b/hw/display/meson.build
175
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('ati.c', 'ati_2d.c', 'ati_
176
177
system_ss.add(when: 'CONFIG_MAC_PVG', if_true: [files('apple-gfx.m'), pvg, metal])
178
system_ss.add(when: 'CONFIG_MAC_PVG_VMAPPLE', if_true: [files('apple-gfx-vmapple.m'), pvg, metal])
179
+system_ss.add(when: 'CONFIG_MAC_PVG_PCI', if_true: [files('apple-gfx-pci.m'), pvg, metal])
180
181
if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
182
virtio_gpu_ss = ss.source_set()
183
--
184
2.39.3 (Apple Git-145)
185
186
diff view generated by jsdifflib
Deleted patch
1
Various system frameworks on macOS and other Apple platforms
2
require a main runloop to be processing events on the process’s
3
main thread. The Cocoa UI’s requirement to run the process as a
4
Cocoa application automatically enables this runloop, but it
5
can be useful to have the runloop handling events even without
6
the Cocoa UI active.
7
1
8
This change adds a non-app runloop mode to the cocoa_main
9
function. This can be requested by other code, while the Cocoa UI
10
additionally enables app mode. This arrangement ensures there is
11
only one qemu_main function switcheroo, and the Cocoa UI’s app
12
mode requirement and other subsystems’ runloop requests don’t
13
conflict with each other.
14
15
The main runloop is required for the AppleGFX PV graphics device,
16
so the runloop request call has been added to its initialisation.
17
18
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
19
---
20
hw/display/apple-gfx.m | 3 +++
21
include/qemu-main.h | 2 ++
22
ui/cocoa.m | 15 +++++++++++++--
23
3 files changed, 18 insertions(+), 2 deletions(-)
24
25
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
26
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/display/apple-gfx.m
28
+++ b/hw/display/apple-gfx.m
29
@@ -XXX,XX +XXX,XX @@
30
31
#include "apple-gfx.h"
32
#include "trace.h"
33
+#include "qemu-main.h"
34
#include "qemu/main-loop.h"
35
#include "ui/console.h"
36
#include "monitor/monitor.h"
37
@@ -XXX,XX +XXX,XX @@ void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_name)
38
error_report_err(local_err);
39
}
40
}
41
+
42
+ cocoa_enable_runloop_on_main_thread();
43
}
44
45
static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
46
diff --git a/include/qemu-main.h b/include/qemu-main.h
47
index XXXXXXX..XXXXXXX 100644
48
--- a/include/qemu-main.h
49
+++ b/include/qemu-main.h
50
@@ -XXX,XX +XXX,XX @@
51
int qemu_default_main(void);
52
extern int (*qemu_main)(void);
53
54
+void cocoa_enable_runloop_on_main_thread(void);
55
+
56
#endif /* QEMU_MAIN_H */
57
diff --git a/ui/cocoa.m b/ui/cocoa.m
58
index XXXXXXX..XXXXXXX 100644
59
--- a/ui/cocoa.m
60
+++ b/ui/cocoa.m
61
@@ -XXX,XX +XXX,XX @@ static void cocoa_clipboard_request(QemuClipboardInfo *info,
62
exit(status);
63
}
64
65
+static bool run_as_cocoa_app = false;
66
static int cocoa_main(void)
67
{
68
QemuThread thread;
69
@@ -XXX,XX +XXX,XX @@ static int cocoa_main(void)
70
71
// Start the main event loop
72
COCOA_DEBUG("Main thread: entering OSX run loop\n");
73
- [NSApp run];
74
+ if (run_as_cocoa_app) {
75
+ [NSApp run];
76
+ } else {
77
+ CFRunLoopRun();
78
+ }
79
COCOA_DEBUG("Main thread: left OSX run loop, which should never happen\n");
80
81
abort();
82
@@ -XXX,XX +XXX,XX @@ static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *cursor)
83
});
84
}
85
86
+void cocoa_enable_runloop_on_main_thread(void)
87
+{
88
+ qemu_main = cocoa_main;
89
+}
90
+
91
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
92
{
93
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
94
95
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
96
97
- qemu_main = cocoa_main;
98
+ run_as_cocoa_app = true;
99
+ cocoa_enable_runloop_on_main_thread();
100
101
// Pull this console process up to being a fully-fledged graphical
102
// app with a menubar and Dock icon
103
--
104
2.39.3 (Apple Git-145)
105
106
diff view generated by jsdifflib
Deleted patch
1
This change adds a property 'display_modes' on the graphics device
2
which permits specifying a list of display modes. (screen resolution
3
and refresh rate)
4
1
5
PCI variant of apple-gfx only for the moment.
6
7
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
8
---
9
hw/display/apple-gfx-pci.m | 43 ++++++++++-
10
hw/display/apple-gfx.h | 17 ++++-
11
hw/display/apple-gfx.m | 151 ++++++++++++++++++++++++++++++++++---
12
3 files changed, 198 insertions(+), 13 deletions(-)
13
14
diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/display/apple-gfx-pci.m
17
+++ b/hw/display/apple-gfx-pci.m
18
@@ -XXX,XX +XXX,XX @@
19
#include "apple-gfx.h"
20
#include "hw/pci/pci_device.h"
21
#include "hw/pci/msi.h"
22
+#include "hw/qdev-properties.h"
23
#include "qapi/error.h"
24
#include "trace.h"
25
#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
26
@@ -XXX,XX +XXX,XX @@ static void apple_gfx_pci_reset(Object *obj, ResetType type)
27
[s->common.pgdev reset];
28
}
29
30
+static void apple_gfx_pci_get_display_modes(Object *obj, Visitor *v,
31
+ const char *name, void *opaque,
32
+ Error **errp)
33
+{
34
+ Property *prop = opaque;
35
+ AppleGFXDisplayModeList *mode_list = object_field_prop_ptr(obj, prop);
36
+
37
+ apple_gfx_get_display_modes(mode_list, v, name, errp);
38
+}
39
+
40
+static void apple_gfx_pci_set_display_modes(Object *obj, Visitor *v,
41
+ const char *name, void *opaque,
42
+ Error **errp)
43
+{
44
+ Property *prop = opaque;
45
+ AppleGFXDisplayModeList *mode_list = object_field_prop_ptr(obj, prop);
46
+
47
+ apple_gfx_set_display_modes(mode_list, v, name, errp);
48
+}
49
+
50
+const PropertyInfo apple_gfx_pci_prop_display_modes = {
51
+ .name = "display_modes",
52
+ .description =
53
+ "Colon-separated list of display modes; "
54
+ "<width>x<height>@<refresh-rate>; the first mode is considered "
55
+ "'native'. Example: 3840x2160@60:2560x1440@60:1920x1080@60",
56
+ .get = apple_gfx_pci_get_display_modes,
57
+ .set = apple_gfx_pci_set_display_modes,
58
+};
59
+
60
+#define DEFINE_PROP_DISPLAY_MODES(_name, _state, _field) \
61
+ DEFINE_PROP(_name, _state, _field, apple_gfx_pci_prop_display_modes, \
62
+ AppleGFXDisplayModeList)
63
+
64
+static Property apple_gfx_pci_properties[] = {
65
+ DEFINE_PROP_DISPLAY_MODES("display-modes", AppleGFXPCIState,
66
+ common.display_modes),
67
+ DEFINE_PROP_END_OF_LIST(),
68
+};
69
+
70
static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
71
{
72
DeviceClass *dc = DEVICE_CLASS(klass);
73
@@ -XXX,XX +XXX,XX @@ static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
74
pci->class_id = PCI_CLASS_DISPLAY_OTHER;
75
pci->realize = apple_gfx_pci_realize;
76
77
- // TODO: Property for setting mode list
78
+ device_class_set_props(dc, apple_gfx_pci_properties);
79
}
80
81
static TypeInfo apple_gfx_pci_types[] = {
82
diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h
83
index XXXXXXX..XXXXXXX 100644
84
--- a/hw/display/apple-gfx.h
85
+++ b/hw/display/apple-gfx.h
86
@@ -XXX,XX +XXX,XX @@
87
#define TYPE_APPLE_GFX_PCI "apple-gfx-pci"
88
89
#include "qemu/typedefs.h"
90
+#include "qemu/osdep.h"
91
92
typedef struct AppleGFXState AppleGFXState;
93
94
+typedef struct AppleGFXDisplayMode {
95
+ uint16_t width_px;
96
+ uint16_t height_px;
97
+ uint16_t refresh_rate_hz;
98
+} AppleGFXDisplayMode;
99
+
100
+typedef struct AppleGFXDisplayModeList {
101
+ GArray *modes;
102
+} AppleGFXDisplayModeList;
103
+
104
void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_name);
105
+void apple_gfx_get_display_modes(AppleGFXDisplayModeList *mode_list, Visitor *v,
106
+ const char *name, Error **errp);
107
+void apple_gfx_set_display_modes(AppleGFXDisplayModeList *mode_list, Visitor *v,
108
+ const char *name, Error **errp);
109
110
#ifdef __OBJC__
111
112
-#include "qemu/osdep.h"
113
#include "exec/memory.h"
114
#include "ui/surface.h"
115
#include <dispatch/dispatch.h>
116
@@ -XXX,XX +XXX,XX @@ struct AppleGFXState {
117
bool new_frame;
118
bool cursor_show;
119
QEMUCursor *cursor;
120
+ AppleGFXDisplayModeList display_modes;
121
122
dispatch_queue_t render_queue;
123
/* The following fields should only be accessed from render_queue: */
124
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
125
index XXXXXXX..XXXXXXX 100644
126
--- a/hw/display/apple-gfx.m
127
+++ b/hw/display/apple-gfx.m
128
@@ -XXX,XX +XXX,XX @@
129
#include "trace.h"
130
#include "qemu-main.h"
131
#include "qemu/main-loop.h"
132
+#include "qemu/cutils.h"
133
+#include "qapi/visitor.h"
134
+#include "qapi/error.h"
135
#include "ui/console.h"
136
#include "monitor/monitor.h"
137
#include "qapi/error.h"
138
@@ -XXX,XX +XXX,XX @@
139
#include <mach/mach_vm.h>
140
#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
141
142
-static const PGDisplayCoord_t apple_gfx_modes[] = {
143
- { .x = 1440, .y = 1080 },
144
- { .x = 1280, .y = 1024 },
145
+static const AppleGFXDisplayMode apple_gfx_default_modes[] = {
146
+ { 1920, 1080, 60 },
147
+ { 1440, 1080, 60 },
148
+ { 1280, 1024, 60 },
149
};
150
151
typedef struct PGTask_s { // Name matches forward declaration in PG header
152
@@ -XXX,XX +XXX,XX @@ static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
153
static void create_fb(AppleGFXState *s)
154
{
155
s->con = graphic_console_init(NULL, 0, &apple_gfx_fb_ops, s);
156
- set_mode(s, 1440, 1080);
157
158
s->cursor_show = true;
159
}
160
@@ -XXX,XX +XXX,XX @@ static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
161
return disp_desc;
162
}
163
164
-static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void)
165
+static NSArray<PGDisplayMode*>* apple_gfx_create_display_mode_array(
166
+ const AppleGFXDisplayMode display_modes[], int display_mode_count)
167
{
168
- PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
169
+ PGDisplayMode **modes = alloca(sizeof(modes[0]) * display_mode_count);
170
NSArray<PGDisplayMode*>* mode_array = nil;
171
int i;
172
173
- for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
174
+ for (i = 0; i < display_mode_count; i++) {
175
+ const AppleGFXDisplayMode *mode = &display_modes[i];
176
+ PGDisplayCoord_t mode_size = { mode->width_px, mode->height_px };
177
modes[i] =
178
- [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i] refreshRateInHz:60.];
179
+ [[PGDisplayMode alloc] initWithSizeInPixels:mode_size
180
+ refreshRateInHz:mode->refresh_rate_hz];
181
}
182
183
- mode_array = [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_gfx_modes)];
184
+ mode_array = [NSArray arrayWithObjects:modes count:display_mode_count];
185
186
- for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
187
+ for (i = 0; i < display_mode_count; i++) {
188
[modes[i] release];
189
modes[i] = nil;
190
}
191
@@ -XXX,XX +XXX,XX @@ static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
192
void apple_gfx_common_realize(AppleGFXState *s, PGDeviceDescriptor *desc)
193
{
194
PGDisplayDescriptor *disp_desc = nil;
195
+ const AppleGFXDisplayMode *display_modes = apple_gfx_default_modes;
196
+ int num_display_modes = ARRAY_SIZE(apple_gfx_default_modes);
197
198
QTAILQ_INIT(&s->tasks);
199
s->render_queue = dispatch_queue_create("apple-gfx.render",
200
@@ -XXX,XX +XXX,XX @@ void apple_gfx_common_realize(AppleGFXState *s, PGDeviceDescriptor *desc)
201
s->pgdisp = [s->pgdev newDisplayWithDescriptor:disp_desc
202
port:0 serialNum:1234];
203
[disp_desc release];
204
- s->pgdisp.modeList = apple_gfx_prepare_display_mode_array();
205
+
206
+ if (s->display_modes.modes != NULL && s->display_modes.modes->len > 0) {
207
+ display_modes =
208
+ &g_array_index(s->display_modes.modes, AppleGFXDisplayMode, 0);
209
+ num_display_modes = s->display_modes.modes->len;
210
+ }
211
+ s->pgdisp.modeList =
212
+ apple_gfx_create_display_mode_array(display_modes, num_display_modes);
213
214
create_fb(s);
215
}
216
+
217
+void apple_gfx_get_display_modes(AppleGFXDisplayModeList *mode_list, Visitor *v,
218
+ const char *name, Error **errp)
219
+{
220
+ GArray *modes = mode_list->modes;
221
+ /* 3 uint16s (max 5 digits) and 3 separator characters per mode + nul. */
222
+ size_t buffer_size = (5 + 1) * 3 * modes->len + 1;
223
+
224
+ char *buffer = alloca(buffer_size);
225
+ char *pos = buffer;
226
+
227
+ unsigned used = 0;
228
+ buffer[0] = '\0';
229
+ for (guint i = 0; i < modes->len; ++i)
230
+ {
231
+ AppleGFXDisplayMode *mode =
232
+ &g_array_index(modes, AppleGFXDisplayMode, i);
233
+ int rc = snprintf(pos, buffer_size - used,
234
+ "%s%"PRIu16"x%"PRIu16"@%"PRIu16,
235
+ i > 0 ? ":" : "",
236
+ mode->width_px, mode->height_px,
237
+ mode->refresh_rate_hz);
238
+ used += rc;
239
+ pos += rc;
240
+ assert(used < buffer_size);
241
+ }
242
+
243
+ pos = buffer;
244
+ visit_type_str(v, name, &pos, errp);
245
+}
246
+
247
+void apple_gfx_set_display_modes(AppleGFXDisplayModeList *mode_list, Visitor *v,
248
+ const char *name, Error **errp)
249
+{
250
+ Error *local_err = NULL;
251
+ const char *endptr;
252
+ char *str;
253
+ int ret;
254
+ unsigned int val;
255
+ uint32_t num_modes;
256
+ GArray *modes;
257
+ uint32_t mode_idx;
258
+
259
+ visit_type_str(v, name, &str, &local_err);
260
+ if (local_err) {
261
+ error_propagate(errp, local_err);
262
+ return;
263
+ }
264
+
265
+ // Count colons to estimate modes. No leading/trailing colons so start at 1.
266
+ num_modes = 1;
267
+ for (size_t i = 0; str[i] != '\0'; ++i)
268
+ {
269
+ if (str[i] == ':') {
270
+ ++num_modes;
271
+ }
272
+ }
273
+
274
+ modes = g_array_sized_new(false, true, sizeof(AppleGFXDisplayMode), num_modes);
275
+
276
+ endptr = str;
277
+ for (mode_idx = 0; mode_idx < num_modes; ++mode_idx)
278
+ {
279
+ AppleGFXDisplayMode mode = {};
280
+ if (mode_idx > 0)
281
+ {
282
+ if (*endptr != ':') {
283
+ goto separator_error;
284
+ }
285
+ ++endptr;
286
+ }
287
+
288
+ ret = qemu_strtoui(endptr, &endptr, 10, &val);
289
+ if (ret || val > UINT16_MAX || val == 0) {
290
+ error_setg(errp, "width of '%s' must be a decimal integer number "
291
+ "of pixels in the range 1..65535", name);
292
+ goto out;
293
+ }
294
+ mode.width_px = val;
295
+ if (*endptr != 'x') {
296
+ goto separator_error;
297
+ }
298
+
299
+ ret = qemu_strtoui(endptr + 1, &endptr, 10, &val);
300
+ if (ret || val > UINT16_MAX || val == 0) {
301
+ error_setg(errp, "height of '%s' must be a decimal integer number "
302
+ "of pixels in the range 1..65535", name);
303
+ goto out;
304
+ }
305
+ mode.height_px = val;
306
+ if (*endptr != '@') {
307
+ goto separator_error;
308
+ }
309
+
310
+ ret = qemu_strtoui(endptr + 1, &endptr, 10, &val);
311
+ if (ret) {
312
+ error_setg(errp, "refresh rate of '%s'"
313
+ " must be a non-negative decimal integer (Hertz)", name);
314
+ }
315
+ mode.refresh_rate_hz = val;
316
+ g_array_append_val(modes, mode);
317
+ }
318
+
319
+ mode_list->modes = modes;
320
+ goto out;
321
+
322
+separator_error:
323
+ error_setg(errp, "Each display mode takes the format "
324
+ "'<width>x<height>@<rate>', modes are separated by colons. (:)");
325
+out:
326
+ g_free(str);
327
+ return;
328
+}
329
--
330
2.39.3 (Apple Git-145)
diff view generated by jsdifflib
Deleted patch
1
I'm happy to take responsibility for the macOS PV graphics code. As
2
HVF patches don't seem to get much attention at the moment, I'm also
3
adding myself as designated reviewer for HVF and x86 HVF to try and
4
improve that.
5
1
6
I anticipate that the resulting workload should be covered by the
7
funding I'm receiving for improving Qemu in combination with macOS. As
8
of right now this runs out at the end of 2024; I expect the workload on
9
apple-gfx should be relatively minor and manageable in my spare time
10
beyond that. I may have to remove myself from more general HVF duties
11
once the contract runs out if it's more than I can manage.
12
13
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
14
---
15
MAINTAINERS | 7 +++++++
16
1 file changed, 7 insertions(+)
17
18
diff --git a/MAINTAINERS b/MAINTAINERS
19
index XXXXXXX..XXXXXXX 100644
20
--- a/MAINTAINERS
21
+++ b/MAINTAINERS
22
@@ -XXX,XX +XXX,XX @@ F: target/arm/hvf/
23
X86 HVF CPUs
24
M: Cameron Esfahani <dirty@apple.com>
25
M: Roman Bolshakov <rbolshakov@ddn.com>
26
+R: Phil Dennis-Jordan <phil@philjordan.eu>
27
W: https://wiki.qemu.org/Features/HVF
28
S: Maintained
29
F: target/i386/hvf/
30
@@ -XXX,XX +XXX,XX @@ F: target/i386/hvf/
31
HVF
32
M: Cameron Esfahani <dirty@apple.com>
33
M: Roman Bolshakov <rbolshakov@ddn.com>
34
+R: Phil Dennis-Jordan <phil@philjordan.eu>
35
W: https://wiki.qemu.org/Features/HVF
36
S: Maintained
37
F: accel/hvf/
38
@@ -XXX,XX +XXX,XX @@ F: hw/display/edid*
39
F: include/hw/display/edid.h
40
F: qemu-edid.c
41
42
+macOS PV Graphics (apple-gfx)
43
+M: Phil Dennis-Jordan <phil@philjordan.eu>
44
+S: Maintained
45
+F: hw/display/apple-gfx*
46
+
47
PIIX4 South Bridge (i82371AB)
48
M: Hervé Poussineau <hpoussin@reactos.org>
49
M: Philippe Mathieu-Daudé <philmd@linaro.org>
50
--
51
2.39.3 (Apple Git-145)
52
53
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
We will introduce a number of devices that are specific to the vmapple
4
target machine. To keep them all tidily together, let's put them into
5
a single target directory.
6
7
Signed-off-by: Alexander Graf <graf@amazon.com>
8
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
9
---
10
MAINTAINERS | 7 +++++++
11
hw/Kconfig | 1 +
12
hw/meson.build | 1 +
13
hw/vmapple/Kconfig | 1 +
14
hw/vmapple/meson.build | 0
15
hw/vmapple/trace-events | 2 ++
16
hw/vmapple/trace.h | 1 +
17
meson.build | 1 +
18
8 files changed, 14 insertions(+)
19
create mode 100644 hw/vmapple/Kconfig
20
create mode 100644 hw/vmapple/meson.build
21
create mode 100644 hw/vmapple/trace-events
22
create mode 100644 hw/vmapple/trace.h
23
24
diff --git a/MAINTAINERS b/MAINTAINERS
25
index XXXXXXX..XXXXXXX 100644
26
--- a/MAINTAINERS
27
+++ b/MAINTAINERS
28
@@ -XXX,XX +XXX,XX @@ F: hw/hyperv/hv-balloon*.h
29
F: include/hw/hyperv/dynmem-proto.h
30
F: include/hw/hyperv/hv-balloon.h
31
32
+VMapple
33
+M: Alexander Graf <agraf@csgraf.de>
34
+R: Phil Dennis-Jordan <phil@philjordan.eu>
35
+S: Maintained
36
+F: hw/vmapple/*
37
+F: include/hw/vmapple/*
38
+
39
Subsystems
40
----------
41
Overall Audio backends
42
diff --git a/hw/Kconfig b/hw/Kconfig
43
index XXXXXXX..XXXXXXX 100644
44
--- a/hw/Kconfig
45
+++ b/hw/Kconfig
46
@@ -XXX,XX +XXX,XX @@ source ufs/Kconfig
47
source usb/Kconfig
48
source virtio/Kconfig
49
source vfio/Kconfig
50
+source vmapple/Kconfig
51
source xen/Kconfig
52
source watchdog/Kconfig
53
54
diff --git a/hw/meson.build b/hw/meson.build
55
index XXXXXXX..XXXXXXX 100644
56
--- a/hw/meson.build
57
+++ b/hw/meson.build
58
@@ -XXX,XX +XXX,XX @@ subdir('ufs')
59
subdir('usb')
60
subdir('vfio')
61
subdir('virtio')
62
+subdir('vmapple')
63
subdir('watchdog')
64
subdir('xen')
65
subdir('xenpv')
66
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
67
new file mode 100644
68
index XXXXXXX..XXXXXXX
69
--- /dev/null
70
+++ b/hw/vmapple/Kconfig
71
@@ -0,0 +1 @@
72
+
73
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
74
new file mode 100644
75
index XXXXXXX..XXXXXXX
76
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
77
new file mode 100644
78
index XXXXXXX..XXXXXXX
79
--- /dev/null
80
+++ b/hw/vmapple/trace-events
81
@@ -XXX,XX +XXX,XX @@
82
+# See docs/devel/tracing.rst for syntax documentation.
83
+
84
diff --git a/hw/vmapple/trace.h b/hw/vmapple/trace.h
85
new file mode 100644
86
index XXXXXXX..XXXXXXX
87
--- /dev/null
88
+++ b/hw/vmapple/trace.h
89
@@ -0,0 +1 @@
90
+#include "trace/trace-hw_vmapple.h"
91
diff --git a/meson.build b/meson.build
92
index XXXXXXX..XXXXXXX 100644
93
--- a/meson.build
94
+++ b/meson.build
95
@@ -XXX,XX +XXX,XX @@ if have_system
96
'hw/usb',
97
'hw/vfio',
98
'hw/virtio',
99
+ 'hw/vmapple',
100
'hw/watchdog',
101
'hw/xen',
102
'hw/gpio',
103
--
104
2.39.3 (Apple Git-145)
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
In addition to the ISA and PCI variants of pvpanic, let's add an MMIO
4
platform device that we can use in embedded arm environments.
5
6
Signed-off-by: Alexander Graf <graf@amazon.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
10
11
---
12
v3:
13
* Rebased on upstream, updated a header path
14
15
hw/misc/Kconfig | 4 +++
16
hw/misc/meson.build | 1 +
17
hw/misc/pvpanic-mmio.c | 61 +++++++++++++++++++++++++++++++++++++++
18
include/hw/misc/pvpanic.h | 1 +
19
4 files changed, 67 insertions(+)
20
create mode 100644 hw/misc/pvpanic-mmio.c
21
22
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
23
index XXXXXXX..XXXXXXX 100644
24
--- a/hw/misc/Kconfig
25
+++ b/hw/misc/Kconfig
26
@@ -XXX,XX +XXX,XX @@ config PVPANIC_ISA
27
depends on ISA_BUS
28
select PVPANIC_COMMON
29
30
+config PVPANIC_MMIO
31
+ bool
32
+ select PVPANIC_COMMON
33
+
34
config AUX
35
bool
36
select I2C
37
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
38
index XXXXXXX..XXXXXXX 100644
39
--- a/hw/misc/meson.build
40
+++ b/hw/misc/meson.build
41
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files('armsse-mhu.c'))
42
43
system_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
44
system_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
45
+system_ss.add(when: 'CONFIG_PVPANIC_MMIO', if_true: files('pvpanic-mmio.c'))
46
system_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
47
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
48
'aspeed_hace.c',
49
diff --git a/hw/misc/pvpanic-mmio.c b/hw/misc/pvpanic-mmio.c
50
new file mode 100644
51
index XXXXXXX..XXXXXXX
52
--- /dev/null
53
+++ b/hw/misc/pvpanic-mmio.c
54
@@ -XXX,XX +XXX,XX @@
55
+/*
56
+ * QEMU simulated pvpanic device (MMIO frontend)
57
+ *
58
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
59
+ *
60
+ * SPDX-License-Identifier: GPL-2.0-or-later
61
+ */
62
+
63
+#include "qemu/osdep.h"
64
+
65
+#include "hw/qdev-properties.h"
66
+#include "hw/misc/pvpanic.h"
67
+#include "hw/sysbus.h"
68
+#include "standard-headers/misc/pvpanic.h"
69
+
70
+OBJECT_DECLARE_SIMPLE_TYPE(PVPanicMMIOState, PVPANIC_MMIO_DEVICE)
71
+
72
+#define PVPANIC_MMIO_SIZE 0x2
73
+
74
+struct PVPanicMMIOState {
75
+ SysBusDevice parent_obj;
76
+
77
+ PVPanicState pvpanic;
78
+};
79
+
80
+static void pvpanic_mmio_initfn(Object *obj)
81
+{
82
+ PVPanicMMIOState *s = PVPANIC_MMIO_DEVICE(obj);
83
+
84
+ pvpanic_setup_io(&s->pvpanic, DEVICE(s), PVPANIC_MMIO_SIZE);
85
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->pvpanic.mr);
86
+}
87
+
88
+static Property pvpanic_mmio_properties[] = {
89
+ DEFINE_PROP_UINT8("events", PVPanicMMIOState, pvpanic.events,
90
+ PVPANIC_PANICKED | PVPANIC_CRASH_LOADED),
91
+ DEFINE_PROP_END_OF_LIST(),
92
+};
93
+
94
+static void pvpanic_mmio_class_init(ObjectClass *klass, void *data)
95
+{
96
+ DeviceClass *dc = DEVICE_CLASS(klass);
97
+
98
+ device_class_set_props(dc, pvpanic_mmio_properties);
99
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
100
+}
101
+
102
+static const TypeInfo pvpanic_mmio_info = {
103
+ .name = TYPE_PVPANIC_MMIO_DEVICE,
104
+ .parent = TYPE_SYS_BUS_DEVICE,
105
+ .instance_size = sizeof(PVPanicMMIOState),
106
+ .instance_init = pvpanic_mmio_initfn,
107
+ .class_init = pvpanic_mmio_class_init,
108
+};
109
+
110
+static void pvpanic_register_types(void)
111
+{
112
+ type_register_static(&pvpanic_mmio_info);
113
+}
114
+
115
+type_init(pvpanic_register_types)
116
diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h
117
index XXXXXXX..XXXXXXX 100644
118
--- a/include/hw/misc/pvpanic.h
119
+++ b/include/hw/misc/pvpanic.h
120
@@ -XXX,XX +XXX,XX @@
121
122
#define TYPE_PVPANIC_ISA_DEVICE "pvpanic"
123
#define TYPE_PVPANIC_PCI_DEVICE "pvpanic-pci"
124
+#define TYPE_PVPANIC_MMIO_DEVICE "pvpanic-mmio"
125
126
#define PVPANIC_IOPORT_PROP "ioport"
127
128
--
129
2.39.3 (Apple Git-145)
130
131
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
MacOS unconditionally disables interrupts of the physical timer on boot
4
and then continues to use the virtual one. We don't really want to support
5
a full physical timer emulation, so let's just ignore those writes.
6
7
Signed-off-by: Alexander Graf <graf@amazon.com>
8
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
9
---
10
target/arm/hvf/hvf.c | 9 +++++++++
11
1 file changed, 9 insertions(+)
12
13
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/hvf/hvf.c
16
+++ b/target/arm/hvf/hvf.c
17
@@ -XXX,XX +XXX,XX @@
18
19
#include "qemu/osdep.h"
20
#include "qemu/error-report.h"
21
+#include "qemu/log.h"
22
23
#include "sysemu/runstate.h"
24
#include "sysemu/hvf.h"
25
@@ -XXX,XX +XXX,XX @@ void hvf_arm_init_debug(void)
26
#define SYSREG_OSLSR_EL1 SYSREG(2, 0, 1, 1, 4)
27
#define SYSREG_OSDLR_EL1 SYSREG(2, 0, 1, 3, 4)
28
#define SYSREG_CNTPCT_EL0 SYSREG(3, 3, 14, 0, 1)
29
+#define SYSREG_CNTP_CTL_EL0 SYSREG(3, 3, 14, 2, 1)
30
#define SYSREG_PMCR_EL0 SYSREG(3, 3, 9, 12, 0)
31
#define SYSREG_PMUSERENR_EL0 SYSREG(3, 3, 9, 14, 0)
32
#define SYSREG_PMCNTENSET_EL0 SYSREG(3, 3, 9, 12, 1)
33
@@ -XXX,XX +XXX,XX @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
34
case SYSREG_OSLAR_EL1:
35
env->cp15.oslsr_el1 = val & 1;
36
return 0;
37
+ case SYSREG_CNTP_CTL_EL0:
38
+ /*
39
+ * Guests should not rely on the physical counter, but macOS emits
40
+ * disable writes to it. Let it do so, but ignore the requests.
41
+ */
42
+ qemu_log_mask(LOG_UNIMP, "Unsupported write to CNTP_CTL_EL0\n");
43
+ return 0;
44
case SYSREG_OSDLR_EL1:
45
/* Dummy register */
46
return 0;
47
--
48
2.39.3 (Apple Git-145)
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
Some boards such as vmapple don't do real legacy PCI IRQ swizzling.
4
Instead, they just keep allocating more board IRQ lines for each new
5
legacy IRQ. Let's support that mode by giving instantiators a new
6
"nr_irqs" property they can use to support more than 4 legacy IRQ lines.
7
In this mode, GPEX will export more IRQ lines, one for each device.
8
9
Signed-off-by: Alexander Graf <graf@amazon.com>
10
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
11
---
12
hw/arm/sbsa-ref.c | 2 +-
13
hw/arm/virt.c | 2 +-
14
hw/i386/microvm.c | 2 +-
15
hw/loongarch/virt.c | 2 +-
16
hw/mips/loongson3_virt.c | 2 +-
17
hw/openrisc/virt.c | 12 ++++++------
18
hw/pci-host/gpex.c | 36 +++++++++++++++++++++++++++++++-----
19
hw/riscv/virt.c | 12 ++++++------
20
hw/xtensa/virt.c | 2 +-
21
include/hw/pci-host/gpex.h | 7 +++----
22
10 files changed, 52 insertions(+), 27 deletions(-)
23
24
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/arm/sbsa-ref.c
27
+++ b/hw/arm/sbsa-ref.c
28
@@ -XXX,XX +XXX,XX @@ static void create_pcie(SBSAMachineState *sms)
29
/* Map IO port space */
30
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
31
32
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
33
+ for (i = 0; i < PCI_NUM_PINS; i++) {
34
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
35
qdev_get_gpio_in(sms->gic, irq + i));
36
gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
37
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/hw/arm/virt.c
40
+++ b/hw/arm/virt.c
41
@@ -XXX,XX +XXX,XX @@ static void create_pcie(VirtMachineState *vms)
42
/* Map IO port space */
43
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
44
45
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
46
+ for (i = 0; i < PCI_NUM_PINS; i++) {
47
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
48
qdev_get_gpio_in(vms->gic, irq + i));
49
gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
50
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/hw/i386/microvm.c
53
+++ b/hw/i386/microvm.c
54
@@ -XXX,XX +XXX,XX @@ static void create_gpex(MicrovmMachineState *mms)
55
mms->gpex.mmio64.base, mmio64_alias);
56
}
57
58
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
59
+ for (i = 0; i < PCI_NUM_PINS; i++) {
60
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
61
x86ms->gsi[mms->gpex.irq + i]);
62
}
63
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/hw/loongarch/virt.c
66
+++ b/hw/loongarch/virt.c
67
@@ -XXX,XX +XXX,XX @@ static void virt_devices_init(DeviceState *pch_pic,
68
memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE,
69
pio_alias);
70
71
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
72
+ for (i = 0; i < PCI_NUM_PINS; i++) {
73
sysbus_connect_irq(d, i,
74
qdev_get_gpio_in(pch_pic, 16 + i));
75
gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
76
diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/hw/mips/loongson3_virt.c
79
+++ b/hw/mips/loongson3_virt.c
80
@@ -XXX,XX +XXX,XX @@ static inline void loongson3_virt_devices_init(MachineState *machine,
81
virt_memmap[VIRT_PCIE_PIO].base, s->pio_alias);
82
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
83
84
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
85
+ for (i = 0; i < PCI_NUM_PINS; i++) {
86
irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
87
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
88
gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
89
diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/hw/openrisc/virt.c
92
+++ b/hw/openrisc/virt.c
93
@@ -XXX,XX +XXX,XX @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
94
{
95
int pin, dev;
96
uint32_t irq_map_stride = 0;
97
- uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {};
98
+ uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] = {};
99
uint32_t *irq_map = full_irq_map;
100
101
/*
102
@@ -XXX,XX +XXX,XX @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
103
* possible slot) seeing the interrupt-map-mask will allow the table
104
* to wrap to any number of devices.
105
*/
106
- for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
107
+ for (dev = 0; dev < PCI_NUM_PINS; dev++) {
108
int devfn = dev << 3;
109
110
- for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
111
- int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
112
+ for (pin = 0; pin < PCI_NUM_PINS; pin++) {
113
+ int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
114
int i = 0;
115
116
/* Fill PCI address cells */
117
@@ -XXX,XX +XXX,XX @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
118
}
119
120
qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
121
- GPEX_NUM_IRQS * GPEX_NUM_IRQS *
122
+ PCI_NUM_PINS * PCI_NUM_PINS *
123
irq_map_stride * sizeof(uint32_t));
124
125
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
126
@@ -XXX,XX +XXX,XX @@ static void openrisc_virt_pcie_init(OR1KVirtState *state,
127
memory_region_add_subregion(get_system_memory(), pio_base, alias);
128
129
/* Connect IRQ lines. */
130
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
131
+ for (i = 0; i < PCI_NUM_PINS; i++) {
132
pcie_irq = get_per_cpu_irq(cpus, num_cpus, irq_base + i);
133
134
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pcie_irq);
135
diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/hw/pci-host/gpex.c
138
+++ b/hw/pci-host/gpex.c
139
@@ -XXX,XX +XXX,XX @@
140
#include "qemu/osdep.h"
141
#include "qapi/error.h"
142
#include "hw/irq.h"
143
+#include "hw/pci/pci_bus.h"
144
#include "hw/pci-host/gpex.h"
145
#include "hw/qdev-properties.h"
146
#include "migration/vmstate.h"
147
@@ -XXX,XX +XXX,XX @@ static void gpex_set_irq(void *opaque, int irq_num, int level)
148
149
int gpex_set_irq_num(GPEXHost *s, int index, int gsi)
150
{
151
- if (index >= GPEX_NUM_IRQS) {
152
+ if (index >= s->nr_irqs) {
153
return -EINVAL;
154
}
155
156
@@ -XXX,XX +XXX,XX @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin)
157
return route;
158
}
159
160
+static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
161
+{
162
+ PCIBus *bus = pci_device_root_bus(pci_dev);
163
+
164
+ return (PCI_SLOT(pci_dev->devfn) + pin) % bus->nirq;
165
+}
166
+
167
static void gpex_host_realize(DeviceState *dev, Error **errp)
168
{
169
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
170
GPEXHost *s = GPEX_HOST(dev);
171
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
172
PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
173
+ pci_map_irq_fn map_irq_fn = pci_swizzle_map_irq_fn;
174
int i;
175
176
+ s->irq = g_malloc0(s->nr_irqs * sizeof(*s->irq));
177
+ s->irq_num = g_malloc0(s->nr_irqs * sizeof(*s->irq_num));
178
+
179
+ if (s->nr_irqs != PCI_NUM_PINS) {
180
+ map_irq_fn = gpex_swizzle_map_irq_fn;
181
+ }
182
+
183
pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
184
sysbus_init_mmio(sbd, &pex->mmio);
185
186
@@ -XXX,XX +XXX,XX @@ static void gpex_host_realize(DeviceState *dev, Error **errp)
187
sysbus_init_mmio(sbd, &s->io_ioport);
188
}
189
190
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
191
+ for (i = 0; i < s->nr_irqs; i++) {
192
sysbus_init_irq(sbd, &s->irq[i]);
193
s->irq_num[i] = -1;
194
}
195
196
- pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq,
197
- pci_swizzle_map_irq_fn, s, &s->io_mmio,
198
- &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
199
+ pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq, map_irq_fn,
200
+ s, &s->io_mmio, &s->io_ioport, 0,
201
+ s->nr_irqs, TYPE_PCIE_BUS);
202
203
pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq);
204
qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal);
205
}
206
207
+static void gpex_host_unrealize(DeviceState *dev)
208
+{
209
+ GPEXHost *s = GPEX_HOST(dev);
210
+
211
+ g_free(s->irq);
212
+ g_free(s->irq_num);
213
+}
214
+
215
static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
216
PCIBus *rootbus)
217
{
218
@@ -XXX,XX +XXX,XX @@ static Property gpex_host_properties[] = {
219
gpex_cfg.mmio64.base, 0),
220
DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost,
221
gpex_cfg.mmio64.size, 0),
222
+ DEFINE_PROP_UINT32("nr-irqs", GPEXHost, nr_irqs, PCI_NUM_PINS),
223
DEFINE_PROP_END_OF_LIST(),
224
};
225
226
@@ -XXX,XX +XXX,XX @@ static void gpex_host_class_init(ObjectClass *klass, void *data)
227
228
hc->root_bus_path = gpex_host_root_bus_path;
229
dc->realize = gpex_host_realize;
230
+ dc->unrealize = gpex_host_unrealize;
231
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
232
dc->fw_name = "pci";
233
device_class_set_props(dc, gpex_host_properties);
234
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
235
index XXXXXXX..XXXXXXX 100644
236
--- a/hw/riscv/virt.c
237
+++ b/hw/riscv/virt.c
238
@@ -XXX,XX +XXX,XX @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
239
{
240
int pin, dev;
241
uint32_t irq_map_stride = 0;
242
- uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS *
243
+ uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
244
FDT_MAX_INT_MAP_WIDTH] = {};
245
uint32_t *irq_map = full_irq_map;
246
247
@@ -XXX,XX +XXX,XX @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
248
* possible slot) seeing the interrupt-map-mask will allow the table
249
* to wrap to any number of devices.
250
*/
251
- for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
252
+ for (dev = 0; dev < PCI_NUM_PINS; dev++) {
253
int devfn = dev * 0x8;
254
255
- for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
256
- int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
257
+ for (pin = 0; pin < PCI_NUM_PINS; pin++) {
258
+ int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
259
int i = 0;
260
261
/* Fill PCI address cells */
262
@@ -XXX,XX +XXX,XX @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
263
}
264
265
qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
266
- GPEX_NUM_IRQS * GPEX_NUM_IRQS *
267
+ PCI_NUM_PINS * PCI_NUM_PINS *
268
irq_map_stride * sizeof(uint32_t));
269
270
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
271
@@ -XXX,XX +XXX,XX @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
272
273
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
274
275
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
276
+ for (i = 0; i < PCI_NUM_PINS; i++) {
277
irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
278
279
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
280
diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c
281
index XXXXXXX..XXXXXXX 100644
282
--- a/hw/xtensa/virt.c
283
+++ b/hw/xtensa/virt.c
284
@@ -XXX,XX +XXX,XX @@ static void create_pcie(MachineState *ms, CPUXtensaState *env, int irq_base,
285
/* Connect IRQ lines. */
286
extints = xtensa_get_extints(env);
287
288
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
289
+ for (i = 0; i < PCI_NUM_PINS; i++) {
290
void *q = extints[irq_base + i];
291
292
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, q);
293
diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h
294
index XXXXXXX..XXXXXXX 100644
295
--- a/include/hw/pci-host/gpex.h
296
+++ b/include/hw/pci-host/gpex.h
297
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(GPEXHost, GPEX_HOST)
298
#define TYPE_GPEX_ROOT_DEVICE "gpex-root"
299
OBJECT_DECLARE_SIMPLE_TYPE(GPEXRootState, GPEX_ROOT_DEVICE)
300
301
-#define GPEX_NUM_IRQS 4
302
-
303
struct GPEXRootState {
304
/*< private >*/
305
PCIDevice parent_obj;
306
@@ -XXX,XX +XXX,XX @@ struct GPEXHost {
307
MemoryRegion io_mmio;
308
MemoryRegion io_ioport_window;
309
MemoryRegion io_mmio_window;
310
- qemu_irq irq[GPEX_NUM_IRQS];
311
- int irq_num[GPEX_NUM_IRQS];
312
+ uint32_t nr_irqs;
313
+ qemu_irq *irq;
314
+ int *irq_num;
315
316
bool allow_unmapped_accesses;
317
318
--
319
2.39.3 (Apple Git-145)
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
VMApple contains an "aes" engine device that it uses to encrypt and
4
decrypt its nvram. It has trivial hard coded keys it uses for that
5
purpose.
6
7
Add device emulation for this device model.
8
9
Signed-off-by: Alexander Graf <graf@amazon.com>
10
Co-authored-by: Phil Dennis-Jordan <phil@philjordan.eu>
11
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
12
13
---
14
v3:
15
16
* Rebased on latest upstream and fixed minor breakages.
17
* Replaced legacy device reset method with Resettable method
18
19
hw/vmapple/Kconfig | 2 +
20
hw/vmapple/aes.c | 584 ++++++++++++++++++++++++++++++++++++++++
21
hw/vmapple/meson.build | 1 +
22
hw/vmapple/trace-events | 19 ++
23
4 files changed, 606 insertions(+)
24
create mode 100644 hw/vmapple/aes.c
25
26
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/vmapple/Kconfig
29
+++ b/hw/vmapple/Kconfig
30
@@ -1 +1,3 @@
31
+config VMAPPLE_AES
32
+ bool
33
34
diff --git a/hw/vmapple/aes.c b/hw/vmapple/aes.c
35
new file mode 100644
36
index XXXXXXX..XXXXXXX
37
--- /dev/null
38
+++ b/hw/vmapple/aes.c
39
@@ -XXX,XX +XXX,XX @@
40
+/*
41
+ * QEMU Apple AES device emulation
42
+ *
43
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
44
+ *
45
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
46
+ * See the COPYING file in the top-level directory.
47
+ */
48
+
49
+#include "qemu/osdep.h"
50
+#include "hw/irq.h"
51
+#include "migration/vmstate.h"
52
+#include "qemu/log.h"
53
+#include "qemu/module.h"
54
+#include "trace.h"
55
+#include "hw/sysbus.h"
56
+#include "crypto/hash.h"
57
+#include "crypto/aes.h"
58
+#include "crypto/cipher.h"
59
+
60
+#define TYPE_AES "apple-aes"
61
+#define MAX_FIFO_SIZE 9
62
+
63
+#define CMD_KEY 0x1
64
+#define CMD_KEY_CONTEXT_SHIFT 27
65
+#define CMD_KEY_CONTEXT_MASK (0x1 << CMD_KEY_CONTEXT_SHIFT)
66
+#define CMD_KEY_SELECT_SHIFT 24
67
+#define CMD_KEY_SELECT_MASK (0x7 << CMD_KEY_SELECT_SHIFT)
68
+#define CMD_KEY_KEY_LEN_SHIFT 22
69
+#define CMD_KEY_KEY_LEN_MASK (0x3 << CMD_KEY_KEY_LEN_SHIFT)
70
+#define CMD_KEY_ENCRYPT_SHIFT 20
71
+#define CMD_KEY_ENCRYPT_MASK (0x1 << CMD_KEY_ENCRYPT_SHIFT)
72
+#define CMD_KEY_BLOCK_MODE_SHIFT 16
73
+#define CMD_KEY_BLOCK_MODE_MASK (0x3 << CMD_KEY_BLOCK_MODE_SHIFT)
74
+#define CMD_IV 0x2
75
+#define CMD_IV_CONTEXT_SHIFT 26
76
+#define CMD_IV_CONTEXT_MASK (0x3 << CMD_KEY_CONTEXT_SHIFT)
77
+#define CMD_DSB 0x3
78
+#define CMD_SKG 0x4
79
+#define CMD_DATA 0x5
80
+#define CMD_DATA_KEY_CTX_SHIFT 27
81
+#define CMD_DATA_KEY_CTX_MASK (0x1 << CMD_DATA_KEY_CTX_SHIFT)
82
+#define CMD_DATA_IV_CTX_SHIFT 25
83
+#define CMD_DATA_IV_CTX_MASK (0x3 << CMD_DATA_IV_CTX_SHIFT)
84
+#define CMD_DATA_LEN_MASK 0xffffff
85
+#define CMD_STORE_IV 0x6
86
+#define CMD_STORE_IV_ADDR_MASK 0xffffff
87
+#define CMD_WRITE_REG 0x7
88
+#define CMD_FLAG 0x8
89
+#define CMD_FLAG_STOP_MASK BIT(26)
90
+#define CMD_FLAG_RAISE_IRQ_MASK BIT(27)
91
+#define CMD_FLAG_INFO_MASK 0xff
92
+#define CMD_MAX 0x10
93
+
94
+#define CMD_SHIFT 28
95
+
96
+#define REG_STATUS 0xc
97
+#define REG_STATUS_DMA_READ_RUNNING BIT(0)
98
+#define REG_STATUS_DMA_READ_PENDING BIT(1)
99
+#define REG_STATUS_DMA_WRITE_RUNNING BIT(2)
100
+#define REG_STATUS_DMA_WRITE_PENDING BIT(3)
101
+#define REG_STATUS_BUSY BIT(4)
102
+#define REG_STATUS_EXECUTING BIT(5)
103
+#define REG_STATUS_READY BIT(6)
104
+#define REG_STATUS_TEXT_DPA_SEEDED BIT(7)
105
+#define REG_STATUS_UNWRAP_DPA_SEEDED BIT(8)
106
+
107
+#define REG_IRQ_STATUS 0x18
108
+#define REG_IRQ_STATUS_INVALID_CMD BIT(2)
109
+#define REG_IRQ_STATUS_FLAG BIT(5)
110
+#define REG_IRQ_ENABLE 0x1c
111
+#define REG_WATERMARK 0x20
112
+#define REG_Q_STATUS 0x24
113
+#define REG_FLAG_INFO 0x30
114
+#define REG_FIFO 0x200
115
+
116
+static const uint32_t key_lens[4] = {
117
+ [0] = 16,
118
+ [1] = 24,
119
+ [2] = 32,
120
+ [3] = 64,
121
+};
122
+
123
+struct key {
124
+ uint32_t key_len;
125
+ uint32_t key[8];
126
+};
127
+
128
+struct iv {
129
+ uint32_t iv[4];
130
+};
131
+
132
+struct context {
133
+ struct key key;
134
+ struct iv iv;
135
+};
136
+
137
+static struct key builtin_keys[7] = {
138
+ [1] = {
139
+ .key_len = 32,
140
+ .key = { 0x1 },
141
+ },
142
+ [2] = {
143
+ .key_len = 32,
144
+ .key = { 0x2 },
145
+ },
146
+ [3] = {
147
+ .key_len = 32,
148
+ .key = { 0x3 },
149
+ }
150
+};
151
+
152
+typedef struct AESState {
153
+ /* Private */
154
+ SysBusDevice parent_obj;
155
+
156
+ /* Public */
157
+ qemu_irq irq;
158
+ MemoryRegion iomem1;
159
+ MemoryRegion iomem2;
160
+
161
+ uint32_t status;
162
+ uint32_t q_status;
163
+ uint32_t irq_status;
164
+ uint32_t irq_enable;
165
+ uint32_t watermark;
166
+ uint32_t flag_info;
167
+ uint32_t fifo[MAX_FIFO_SIZE];
168
+ uint32_t fifo_idx;
169
+ struct key key[2];
170
+ struct iv iv[4];
171
+ bool is_encrypt;
172
+ QCryptoCipherMode block_mode;
173
+} AESState;
174
+
175
+OBJECT_DECLARE_SIMPLE_TYPE(AESState, AES)
176
+
177
+static void aes_update_irq(AESState *s)
178
+{
179
+ qemu_set_irq(s->irq, !!(s->irq_status & s->irq_enable));
180
+}
181
+
182
+static uint64_t aes1_read(void *opaque, hwaddr offset, unsigned size)
183
+{
184
+ AESState *s = opaque;
185
+ uint64_t res = 0;
186
+
187
+ switch (offset) {
188
+ case REG_STATUS:
189
+ res = s->status;
190
+ break;
191
+ case REG_IRQ_STATUS:
192
+ res = s->irq_status;
193
+ break;
194
+ case REG_IRQ_ENABLE:
195
+ res = s->irq_enable;
196
+ break;
197
+ case REG_WATERMARK:
198
+ res = s->watermark;
199
+ break;
200
+ case REG_Q_STATUS:
201
+ res = s->q_status;
202
+ break;
203
+ case REG_FLAG_INFO:
204
+ res = s->flag_info;
205
+ break;
206
+
207
+ default:
208
+ trace_aes_read_unknown(offset);
209
+ break;
210
+ }
211
+
212
+ trace_aes_read(offset, res);
213
+
214
+ return res;
215
+}
216
+
217
+static void fifo_append(AESState *s, uint64_t val)
218
+{
219
+ if (s->fifo_idx == MAX_FIFO_SIZE) {
220
+ /* Exceeded the FIFO. Bail out */
221
+ return;
222
+ }
223
+
224
+ s->fifo[s->fifo_idx++] = val;
225
+}
226
+
227
+static bool has_payload(AESState *s, uint32_t elems)
228
+{
229
+ return s->fifo_idx >= (elems + 1);
230
+}
231
+
232
+static bool cmd_key(AESState *s)
233
+{
234
+ uint32_t cmd = s->fifo[0];
235
+ uint32_t key_select = (cmd & CMD_KEY_SELECT_MASK) >> CMD_KEY_SELECT_SHIFT;
236
+ uint32_t ctxt = (cmd & CMD_KEY_CONTEXT_MASK) >> CMD_KEY_CONTEXT_SHIFT;
237
+ uint32_t key_len;
238
+
239
+ switch ((cmd & CMD_KEY_BLOCK_MODE_MASK) >> CMD_KEY_BLOCK_MODE_SHIFT) {
240
+ case 0:
241
+ s->block_mode = QCRYPTO_CIPHER_MODE_ECB;
242
+ break;
243
+ case 1:
244
+ s->block_mode = QCRYPTO_CIPHER_MODE_CBC;
245
+ break;
246
+ default:
247
+ return false;
248
+ }
249
+
250
+ s->is_encrypt = !!((cmd & CMD_KEY_ENCRYPT_MASK) >> CMD_KEY_ENCRYPT_SHIFT);
251
+ key_len = key_lens[((cmd & CMD_KEY_KEY_LEN_MASK) >> CMD_KEY_KEY_LEN_SHIFT)];
252
+
253
+ if (key_select) {
254
+ trace_aes_cmd_key_select_builtin(ctxt, key_select,
255
+ s->is_encrypt ? "en" : "de",
256
+ QCryptoCipherMode_str(s->block_mode));
257
+ s->key[ctxt] = builtin_keys[key_select];
258
+ } else {
259
+ trace_aes_cmd_key_select_new(ctxt, key_len,
260
+ s->is_encrypt ? "en" : "de",
261
+ QCryptoCipherMode_str(s->block_mode));
262
+ if (key_len > sizeof(s->key[ctxt].key)) {
263
+ return false;
264
+ }
265
+ if (!has_payload(s, key_len / sizeof(uint32_t))) {
266
+ /* wait for payload */
267
+ return false;
268
+ }
269
+ memcpy(&s->key[ctxt].key, &s->fifo[1], key_len);
270
+ s->key[ctxt].key_len = key_len;
271
+ }
272
+
273
+ return true;
274
+}
275
+
276
+static bool cmd_iv(AESState *s)
277
+{
278
+ uint32_t cmd = s->fifo[0];
279
+ uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
280
+
281
+ if (!has_payload(s, 4)) {
282
+ /* wait for payload */
283
+ return false;
284
+ }
285
+ memcpy(&s->iv[ctxt].iv, &s->fifo[1], sizeof(s->iv[ctxt].iv));
286
+ trace_aes_cmd_iv(ctxt, s->fifo[1], s->fifo[2], s->fifo[3], s->fifo[4]);
287
+
288
+ return true;
289
+}
290
+
291
+static char hexdigit2str(uint8_t val)
292
+{
293
+ g_assert(val < 0x10);
294
+ if (val >= 0xa) {
295
+ return 'a' + (val - 0xa);
296
+ } else {
297
+ return '0' + val;
298
+ }
299
+}
300
+
301
+static void dump_data(const char *desc, const void *p, size_t len)
302
+{
303
+ char *hex = alloca((len * 2) + 1);
304
+ const uint8_t *data = p;
305
+ char *hexp = hex;
306
+ size_t i;
307
+
308
+ if (len > 0x1000) {
309
+ /* Too large buffer, let's bail out */
310
+ return;
311
+ }
312
+
313
+ for (i = 0; i < len; i++) {
314
+ uint8_t val = data[i];
315
+ *(hexp++) = hexdigit2str(val >> 4);
316
+ *(hexp++) = hexdigit2str(val & 0xf);
317
+ }
318
+ *hexp = '\0';
319
+
320
+ trace_aes_dump_data(desc, hex);
321
+}
322
+
323
+static bool cmd_data(AESState *s)
324
+{
325
+ uint32_t cmd = s->fifo[0];
326
+ uint32_t ctxt_iv = 0;
327
+ uint32_t ctxt_key = (cmd & CMD_DATA_KEY_CTX_MASK) >> CMD_DATA_KEY_CTX_SHIFT;
328
+ uint32_t len = cmd & CMD_DATA_LEN_MASK;
329
+ uint64_t src_addr = s->fifo[2];
330
+ uint64_t dst_addr = s->fifo[3];
331
+ QCryptoCipherAlgo alg;
332
+ QCryptoCipher *cipher;
333
+ char *src;
334
+ char *dst;
335
+
336
+ src_addr |= ((uint64_t)s->fifo[1] << 16) & 0xffff00000000ULL;
337
+ dst_addr |= ((uint64_t)s->fifo[1] << 32) & 0xffff00000000ULL;
338
+
339
+ trace_aes_cmd_data(ctxt_key, ctxt_iv, src_addr, dst_addr, len);
340
+
341
+ if (!has_payload(s, 3)) {
342
+ /* wait for payload */
343
+ trace_aes_cmd_data_error("No payload");
344
+ return false;
345
+ }
346
+
347
+ if (ctxt_key >= ARRAY_SIZE(s->key) ||
348
+ ctxt_iv >= ARRAY_SIZE(s->iv)) {
349
+ /* Invalid input */
350
+ trace_aes_cmd_data_error("Invalid key or iv");
351
+ return false;
352
+ }
353
+
354
+ src = g_malloc0(len);
355
+ dst = g_malloc0(len);
356
+
357
+ cpu_physical_memory_read(src_addr, src, len);
358
+
359
+ dump_data("cmd_data(): src_data=", src, len);
360
+
361
+ switch (s->key[ctxt_key].key_len) {
362
+ case 128 / 8:
363
+ alg = QCRYPTO_CIPHER_ALGO_AES_128;
364
+ break;
365
+ case 192 / 8:
366
+ alg = QCRYPTO_CIPHER_ALGO_AES_192;
367
+ break;
368
+ case 256 / 8:
369
+ alg = QCRYPTO_CIPHER_ALGO_AES_256;
370
+ break;
371
+ default:
372
+ trace_aes_cmd_data_error("Invalid key len");
373
+ goto err_free;
374
+ }
375
+ cipher = qcrypto_cipher_new(alg, s->block_mode,
376
+ (void *)s->key[ctxt_key].key,
377
+ s->key[ctxt_key].key_len, NULL);
378
+ g_assert(cipher != NULL);
379
+ if (s->block_mode != QCRYPTO_CIPHER_MODE_ECB) {
380
+ if (qcrypto_cipher_setiv(cipher, (void *)s->iv[ctxt_iv].iv,
381
+ sizeof(s->iv[ctxt_iv].iv), NULL) != 0) {
382
+ trace_aes_cmd_data_error("Failed to set IV");
383
+ goto err_free_cipher;
384
+ }
385
+ }
386
+ if (s->is_encrypt) {
387
+ if (qcrypto_cipher_encrypt(cipher, src, dst, len, NULL) != 0) {
388
+ trace_aes_cmd_data_error("Encrypt failed");
389
+ goto err_free_cipher;
390
+ }
391
+ } else {
392
+ if (qcrypto_cipher_decrypt(cipher, src, dst, len, NULL) != 0) {
393
+ trace_aes_cmd_data_error("Decrypt failed");
394
+ goto err_free_cipher;
395
+ }
396
+ }
397
+ qcrypto_cipher_free(cipher);
398
+
399
+ dump_data("cmd_data(): dst_data=", dst, len);
400
+ cpu_physical_memory_write(dst_addr, dst, len);
401
+ g_free(src);
402
+ g_free(dst);
403
+
404
+ return true;
405
+
406
+err_free_cipher:
407
+ qcrypto_cipher_free(cipher);
408
+err_free:
409
+ g_free(src);
410
+ g_free(dst);
411
+ return false;
412
+}
413
+
414
+static bool cmd_store_iv(AESState *s)
415
+{
416
+ uint32_t cmd = s->fifo[0];
417
+ uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
418
+ uint64_t addr = s->fifo[1];
419
+
420
+ if (!has_payload(s, 1)) {
421
+ /* wait for payload */
422
+ return false;
423
+ }
424
+
425
+ if (ctxt >= ARRAY_SIZE(s->iv)) {
426
+ /* Invalid context selected */
427
+ return false;
428
+ }
429
+
430
+ addr |= ((uint64_t)cmd << 32) & 0xff00000000ULL;
431
+ cpu_physical_memory_write(addr, &s->iv[ctxt].iv, sizeof(s->iv[ctxt].iv));
432
+
433
+ trace_aes_cmd_store_iv(ctxt, addr, s->iv[ctxt].iv[0], s->iv[ctxt].iv[1],
434
+ s->iv[ctxt].iv[2], s->iv[ctxt].iv[3]);
435
+
436
+ return true;
437
+}
438
+
439
+static bool cmd_flag(AESState *s)
440
+{
441
+ uint32_t cmd = s->fifo[0];
442
+ uint32_t raise_irq = cmd & CMD_FLAG_RAISE_IRQ_MASK;
443
+
444
+ /* We always process data when it's coming in, so fire an IRQ immediately */
445
+ if (raise_irq) {
446
+ s->irq_status |= REG_IRQ_STATUS_FLAG;
447
+ }
448
+
449
+ s->flag_info = cmd & CMD_FLAG_INFO_MASK;
450
+
451
+ trace_aes_cmd_flag(!!raise_irq, s->flag_info);
452
+
453
+ return true;
454
+}
455
+
456
+static void fifo_process(AESState *s)
457
+{
458
+ uint32_t cmd = s->fifo[0] >> CMD_SHIFT;
459
+ bool success = false;
460
+
461
+ if (!s->fifo_idx) {
462
+ return;
463
+ }
464
+
465
+ switch (cmd) {
466
+ case CMD_KEY:
467
+ success = cmd_key(s);
468
+ break;
469
+ case CMD_IV:
470
+ success = cmd_iv(s);
471
+ break;
472
+ case CMD_DATA:
473
+ success = cmd_data(s);
474
+ break;
475
+ case CMD_STORE_IV:
476
+ success = cmd_store_iv(s);
477
+ break;
478
+ case CMD_FLAG:
479
+ success = cmd_flag(s);
480
+ break;
481
+ default:
482
+ s->irq_status |= REG_IRQ_STATUS_INVALID_CMD;
483
+ break;
484
+ }
485
+
486
+ if (success) {
487
+ s->fifo_idx = 0;
488
+ }
489
+
490
+ trace_aes_fifo_process(cmd, success ? 1 : 0);
491
+}
492
+
493
+static void aes1_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
494
+{
495
+ AESState *s = opaque;
496
+
497
+ trace_aes_write(offset, val);
498
+
499
+ switch (offset) {
500
+ case REG_IRQ_STATUS:
501
+ s->irq_status &= ~val;
502
+ break;
503
+ case REG_IRQ_ENABLE:
504
+ s->irq_enable = val;
505
+ break;
506
+ case REG_FIFO:
507
+ fifo_append(s, val);
508
+ fifo_process(s);
509
+ break;
510
+ default:
511
+ trace_aes_write_unknown(offset);
512
+ return;
513
+ }
514
+
515
+ aes_update_irq(s);
516
+}
517
+
518
+static const MemoryRegionOps aes1_ops = {
519
+ .read = aes1_read,
520
+ .write = aes1_write,
521
+ .endianness = DEVICE_NATIVE_ENDIAN,
522
+ .valid = {
523
+ .min_access_size = 4,
524
+ .max_access_size = 8,
525
+ },
526
+ .impl = {
527
+ .min_access_size = 4,
528
+ .max_access_size = 4,
529
+ },
530
+};
531
+
532
+static uint64_t aes2_read(void *opaque, hwaddr offset, unsigned size)
533
+{
534
+ uint64_t res = 0;
535
+
536
+ switch (offset) {
537
+ case 0:
538
+ res = 0;
539
+ break;
540
+ default:
541
+ trace_aes_2_read_unknown(offset);
542
+ break;
543
+ }
544
+
545
+ trace_aes_2_read(offset, res);
546
+
547
+ return res;
548
+}
549
+
550
+static void aes2_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
551
+{
552
+ trace_aes_2_write(offset, val);
553
+
554
+ switch (offset) {
555
+ default:
556
+ trace_aes_2_write_unknown(offset);
557
+ return;
558
+ }
559
+}
560
+
561
+static const MemoryRegionOps aes2_ops = {
562
+ .read = aes2_read,
563
+ .write = aes2_write,
564
+ .endianness = DEVICE_NATIVE_ENDIAN,
565
+ .valid = {
566
+ .min_access_size = 4,
567
+ .max_access_size = 8,
568
+ },
569
+ .impl = {
570
+ .min_access_size = 4,
571
+ .max_access_size = 4,
572
+ },
573
+};
574
+
575
+static void aes_reset(Object *obj, ResetType type)
576
+{
577
+ AESState *s = AES(obj);
578
+
579
+ s->status = 0x3f80;
580
+ s->q_status = 2;
581
+ s->irq_status = 0;
582
+ s->irq_enable = 0;
583
+ s->watermark = 0;
584
+}
585
+
586
+static void aes_init(Object *obj)
587
+{
588
+ AESState *s = AES(obj);
589
+
590
+ memory_region_init_io(&s->iomem1, obj, &aes1_ops, s, TYPE_AES, 0x4000);
591
+ memory_region_init_io(&s->iomem2, obj, &aes2_ops, s, TYPE_AES, 0x4000);
592
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem1);
593
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem2);
594
+ sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
595
+}
596
+
597
+static void aes_realize(DeviceState *dev, Error **errp)
598
+{
599
+}
600
+
601
+static void aes_class_init(ObjectClass *klass, void *data)
602
+{
603
+ DeviceClass *dc = DEVICE_CLASS(klass);
604
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
605
+
606
+ rc->phases.hold = aes_reset;
607
+ dc->realize = aes_realize;
608
+}
609
+
610
+static const TypeInfo aes_info = {
611
+ .name = TYPE_AES,
612
+ .parent = TYPE_SYS_BUS_DEVICE,
613
+ .instance_size = sizeof(AESState),
614
+ .class_init = aes_class_init,
615
+ .instance_init = aes_init,
616
+};
617
+
618
+static void aes_register_types(void)
619
+{
620
+ type_register_static(&aes_info);
621
+}
622
+
623
+type_init(aes_register_types)
624
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
625
index XXXXXXX..XXXXXXX 100644
626
--- a/hw/vmapple/meson.build
627
+++ b/hw/vmapple/meson.build
628
@@ -0,0 +1 @@
629
+system_ss.add(when: 'CONFIG_VMAPPLE_AES', if_true: files('aes.c'))
630
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
631
index XXXXXXX..XXXXXXX 100644
632
--- a/hw/vmapple/trace-events
633
+++ b/hw/vmapple/trace-events
634
@@ -XXX,XX +XXX,XX @@
635
# See docs/devel/tracing.rst for syntax documentation.
636
637
+# aes.c
638
+aes_read_unknown(uint64_t offset) "offset=0x%"PRIx64
639
+aes_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
640
+aes_cmd_key_select_builtin(uint32_t ctx, uint32_t key_id, const char *direction, const char *cipher) "[%d] Selecting builtin key %d to %scrypt with %s"
641
+aes_cmd_key_select_new(uint32_t ctx, uint32_t key_len, const char *direction, const char *cipher) "[%d] Selecting new key size=%d to %scrypt with %s"
642
+aes_cmd_iv(uint32_t ctx, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3) "[%d] 0x%08x 0x%08x 0x%08x 0x%08x"
643
+aes_cmd_data(uint32_t key, uint32_t iv, uint64_t src, uint64_t dst, uint32_t len) "[key=%d iv=%d] src=0x%"PRIx64" dst=0x%"PRIx64" len=0x%x"
644
+aes_cmd_data_error(const char *reason) "reason=%s"
645
+aes_cmd_store_iv(uint32_t ctx, uint64_t addr, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3) "[%d] addr=0x%"PRIx64"x -> 0x%08x 0x%08x 0x%08x 0x%08x"
646
+aes_cmd_flag(uint32_t raise, uint32_t flag_info) "raise=%d flag_info=0x%x"
647
+aes_fifo_process(uint32_t cmd, uint32_t success) "cmd=%d success=%d"
648
+aes_write_unknown(uint64_t offset) "offset=0x%"PRIx64
649
+aes_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
650
+aes_2_read_unknown(uint64_t offset) "offset=0x%"PRIx64
651
+aes_2_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
652
+aes_2_write_unknown(uint64_t offset) "offset=0x%"PRIx64
653
+aes_2_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
654
+aes_dump_data(const char *desc, const char *hex) "%s%s"
655
+
656
--
657
2.39.3 (Apple Git-145)
658
659
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
The VMApple machine exposes AUX and ROOT block devices (as well as USB OTG
4
emulation) via virtio-pci as well as a special, simple backdoor platform
5
device.
6
7
This patch implements this backdoor platform device to the best of my
8
understanding. I left out any USB OTG parts; they're only needed for
9
guest recovery and I don't understand the protocol yet.
10
11
Signed-off-by: Alexander Graf <graf@amazon.com>
12
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
13
---
14
hw/vmapple/Kconfig | 3 +
15
hw/vmapple/bdif.c | 245 ++++++++++++++++++++++++++++++++++++++
16
hw/vmapple/meson.build | 1 +
17
hw/vmapple/trace-events | 5 +
18
include/hw/vmapple/bdif.h | 31 +++++
19
5 files changed, 285 insertions(+)
20
create mode 100644 hw/vmapple/bdif.c
21
create mode 100644 include/hw/vmapple/bdif.h
22
23
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
24
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/vmapple/Kconfig
26
+++ b/hw/vmapple/Kconfig
27
@@ -XXX,XX +XXX,XX @@
28
config VMAPPLE_AES
29
bool
30
31
+config VMAPPLE_BDIF
32
+ bool
33
+
34
diff --git a/hw/vmapple/bdif.c b/hw/vmapple/bdif.c
35
new file mode 100644
36
index XXXXXXX..XXXXXXX
37
--- /dev/null
38
+++ b/hw/vmapple/bdif.c
39
@@ -XXX,XX +XXX,XX @@
40
+/*
41
+ * VMApple Backdoor Interface
42
+ *
43
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
44
+ *
45
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
46
+ * See the COPYING file in the top-level directory.
47
+ */
48
+
49
+#include "qemu/osdep.h"
50
+#include "hw/vmapple/bdif.h"
51
+#include "qemu/log.h"
52
+#include "qemu/module.h"
53
+#include "qapi/error.h"
54
+#include "trace.h"
55
+#include "hw/block/block.h"
56
+#include "sysemu/block-backend.h"
57
+
58
+#define REG_DEVID_MASK 0xffff0000
59
+#define DEVID_ROOT 0x00000000
60
+#define DEVID_AUX 0x00010000
61
+#define DEVID_USB 0x00100000
62
+
63
+#define REG_STATUS 0x0
64
+#define REG_STATUS_ACTIVE BIT(0)
65
+#define REG_CFG 0x4
66
+#define REG_CFG_ACTIVE BIT(1)
67
+#define REG_UNK1 0x8
68
+#define REG_BUSY 0x10
69
+#define REG_BUSY_READY BIT(0)
70
+#define REG_UNK2 0x400
71
+#define REG_CMD 0x408
72
+#define REG_NEXT_DEVICE 0x420
73
+#define REG_UNK3 0x434
74
+
75
+typedef struct vblk_sector {
76
+ uint32_t pad;
77
+ uint32_t pad2;
78
+ uint32_t sector;
79
+ uint32_t pad3;
80
+} VblkSector;
81
+
82
+typedef struct vblk_req_cmd {
83
+ uint64_t addr;
84
+ uint32_t len;
85
+ uint32_t flags;
86
+} VblkReqCmd;
87
+
88
+typedef struct vblk_req {
89
+ VblkReqCmd sector;
90
+ VblkReqCmd data;
91
+ VblkReqCmd retval;
92
+} VblkReq;
93
+
94
+#define VBLK_DATA_FLAGS_READ 0x00030001
95
+#define VBLK_DATA_FLAGS_WRITE 0x00010001
96
+
97
+#define VBLK_RET_SUCCESS 0
98
+#define VBLK_RET_FAILED 1
99
+
100
+static uint64_t bdif_read(void *opaque, hwaddr offset, unsigned size)
101
+{
102
+ uint64_t ret = -1;
103
+ uint64_t devid = (offset & REG_DEVID_MASK);
104
+
105
+ switch (offset & ~REG_DEVID_MASK) {
106
+ case REG_STATUS:
107
+ ret = REG_STATUS_ACTIVE;
108
+ break;
109
+ case REG_CFG:
110
+ ret = REG_CFG_ACTIVE;
111
+ break;
112
+ case REG_UNK1:
113
+ ret = 0x420;
114
+ break;
115
+ case REG_BUSY:
116
+ ret = REG_BUSY_READY;
117
+ break;
118
+ case REG_UNK2:
119
+ ret = 0x1;
120
+ break;
121
+ case REG_UNK3:
122
+ ret = 0x0;
123
+ break;
124
+ case REG_NEXT_DEVICE:
125
+ switch (devid) {
126
+ case DEVID_ROOT:
127
+ ret = 0x8000000;
128
+ break;
129
+ case DEVID_AUX:
130
+ ret = 0x10000;
131
+ break;
132
+ }
133
+ break;
134
+ }
135
+
136
+ trace_bdif_read(offset, size, ret);
137
+ return ret;
138
+}
139
+
140
+static void le2cpu_sector(VblkSector *sector)
141
+{
142
+ sector->sector = le32_to_cpu(sector->sector);
143
+}
144
+
145
+static void le2cpu_reqcmd(VblkReqCmd *cmd)
146
+{
147
+ cmd->addr = le64_to_cpu(cmd->addr);
148
+ cmd->len = le32_to_cpu(cmd->len);
149
+ cmd->flags = le32_to_cpu(cmd->flags);
150
+}
151
+
152
+static void le2cpu_req(VblkReq *req)
153
+{
154
+ le2cpu_reqcmd(&req->sector);
155
+ le2cpu_reqcmd(&req->data);
156
+ le2cpu_reqcmd(&req->retval);
157
+}
158
+
159
+static void vblk_cmd(uint64_t devid, BlockBackend *blk, uint64_t value,
160
+ uint64_t static_off)
161
+{
162
+ VblkReq req;
163
+ VblkSector sector;
164
+ uint64_t off = 0;
165
+ char *buf = NULL;
166
+ uint8_t ret = VBLK_RET_FAILED;
167
+ int r;
168
+
169
+ cpu_physical_memory_read(value, &req, sizeof(req));
170
+ le2cpu_req(&req);
171
+
172
+ if (req.sector.len != sizeof(sector)) {
173
+ ret = VBLK_RET_FAILED;
174
+ goto out;
175
+ }
176
+
177
+ /* Read the vblk command */
178
+ cpu_physical_memory_read(req.sector.addr, &sector, sizeof(sector));
179
+ le2cpu_sector(&sector);
180
+
181
+ off = sector.sector * 512ULL + static_off;
182
+
183
+ /* Sanity check that we're not allocating bogus sizes */
184
+ if (req.data.len > (128 * 1024 * 1024)) {
185
+ goto out;
186
+ }
187
+
188
+ buf = g_malloc0(req.data.len);
189
+ switch (req.data.flags) {
190
+ case VBLK_DATA_FLAGS_READ:
191
+ r = blk_pread(blk, off, req.data.len, buf, 0);
192
+ trace_bdif_vblk_read(devid == DEVID_AUX ? "aux" : "root",
193
+ req.data.addr, off, req.data.len, r);
194
+ if (r < 0) {
195
+ goto out;
196
+ }
197
+ cpu_physical_memory_write(req.data.addr, buf, req.data.len);
198
+ ret = VBLK_RET_SUCCESS;
199
+ break;
200
+ case VBLK_DATA_FLAGS_WRITE:
201
+ /* Not needed, iBoot only reads */
202
+ break;
203
+ default:
204
+ break;
205
+ }
206
+
207
+out:
208
+ g_free(buf);
209
+ cpu_physical_memory_write(req.retval.addr, &ret, 1);
210
+}
211
+
212
+static void bdif_write(void *opaque, hwaddr offset,
213
+ uint64_t value, unsigned size)
214
+{
215
+ VMAppleBdifState *s = opaque;
216
+ uint64_t devid = (offset & REG_DEVID_MASK);
217
+
218
+ trace_bdif_write(offset, size, value);
219
+
220
+ switch (offset & ~REG_DEVID_MASK) {
221
+ case REG_CMD:
222
+ switch (devid) {
223
+ case DEVID_ROOT:
224
+ vblk_cmd(devid, s->root, value, 0x0);
225
+ break;
226
+ case DEVID_AUX:
227
+ vblk_cmd(devid, s->aux, value, 0x0);
228
+ break;
229
+ }
230
+ break;
231
+ }
232
+}
233
+
234
+static const MemoryRegionOps bdif_ops = {
235
+ .read = bdif_read,
236
+ .write = bdif_write,
237
+ .endianness = DEVICE_NATIVE_ENDIAN,
238
+ .valid = {
239
+ .min_access_size = 1,
240
+ .max_access_size = 8,
241
+ },
242
+ .impl = {
243
+ .min_access_size = 1,
244
+ .max_access_size = 8,
245
+ },
246
+};
247
+
248
+static void bdif_init(Object *obj)
249
+{
250
+ VMAppleBdifState *s = VMAPPLE_BDIF(obj);
251
+
252
+ memory_region_init_io(&s->mmio, obj, &bdif_ops, obj,
253
+ "VMApple Backdoor Interface", VMAPPLE_BDIF_SIZE);
254
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
255
+}
256
+
257
+static Property bdif_properties[] = {
258
+ DEFINE_PROP_DRIVE("aux", VMAppleBdifState, aux),
259
+ DEFINE_PROP_DRIVE("root", VMAppleBdifState, root),
260
+ DEFINE_PROP_END_OF_LIST(),
261
+};
262
+
263
+static void bdif_class_init(ObjectClass *klass, void *data)
264
+{
265
+ DeviceClass *dc = DEVICE_CLASS(klass);
266
+
267
+ dc->desc = "VMApple Backdoor Interface";
268
+ device_class_set_props(dc, bdif_properties);
269
+}
270
+
271
+static const TypeInfo bdif_info = {
272
+ .name = TYPE_VMAPPLE_BDIF,
273
+ .parent = TYPE_SYS_BUS_DEVICE,
274
+ .instance_size = sizeof(VMAppleBdifState),
275
+ .instance_init = bdif_init,
276
+ .class_init = bdif_class_init,
277
+};
278
+
279
+static void bdif_register_types(void)
280
+{
281
+ type_register_static(&bdif_info);
282
+}
283
+
284
+type_init(bdif_register_types)
285
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
286
index XXXXXXX..XXXXXXX 100644
287
--- a/hw/vmapple/meson.build
288
+++ b/hw/vmapple/meson.build
289
@@ -1 +1,2 @@
290
system_ss.add(when: 'CONFIG_VMAPPLE_AES', if_true: files('aes.c'))
291
+system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
292
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
293
index XXXXXXX..XXXXXXX 100644
294
--- a/hw/vmapple/trace-events
295
+++ b/hw/vmapple/trace-events
296
@@ -XXX,XX +XXX,XX @@ aes_2_write_unknown(uint64_t offset) "offset=0x%"PRIx64
297
aes_2_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
298
aes_dump_data(const char *desc, const char *hex) "%s%s"
299
300
+# bdif.c
301
+bdif_read(uint64_t offset, uint32_t size, uint64_t value) "offset=0x%"PRIx64" size=0x%x value=0x%"PRIx64
302
+bdif_write(uint64_t offset, uint32_t size, uint64_t value) "offset=0x%"PRIx64" size=0x%x value=0x%"PRIx64
303
+bdif_vblk_read(const char *dev, uint64_t addr, uint64_t offset, uint32_t len, int r) "dev=%s addr=0x%"PRIx64" off=0x%"PRIx64" size=0x%x r=%d"
304
+
305
diff --git a/include/hw/vmapple/bdif.h b/include/hw/vmapple/bdif.h
306
new file mode 100644
307
index XXXXXXX..XXXXXXX
308
--- /dev/null
309
+++ b/include/hw/vmapple/bdif.h
310
@@ -XXX,XX +XXX,XX @@
311
+/*
312
+ * VMApple Backdoor Interface
313
+ *
314
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
315
+ *
316
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
317
+ * See the COPYING file in the top-level directory.
318
+ */
319
+
320
+#ifndef HW_VMAPPLE_BDIF_H
321
+#define HW_VMAPPLE_BDIF_H
322
+
323
+#include "hw/sysbus.h"
324
+#include "qom/object.h"
325
+
326
+#define TYPE_VMAPPLE_BDIF "vmapple-bdif"
327
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleBdifState, VMAPPLE_BDIF)
328
+
329
+struct VMAppleBdifState {
330
+ /* <private> */
331
+ SysBusDevice parent_obj;
332
+
333
+ /* <public> */
334
+ BlockBackend *aux;
335
+ BlockBackend *root;
336
+ MemoryRegion mmio;
337
+};
338
+
339
+#define VMAPPLE_BDIF_SIZE 0x00200000
340
+
341
+#endif /* HW_VMAPPLE_BDIF_H */
342
--
343
2.39.3 (Apple Git-145)
344
345
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
Instead of device tree or other more standardized means, VMApple passes
4
platform configuration to the first stage boot loader in a binary encoded
5
format that resides at a dedicated RAM region in physical address space.
6
7
This patch models this configuration space as a qdev device which we can
8
then map at the fixed location in the address space. That way, we can
9
influence and annotate all configuration fields easily.
10
11
Signed-off-by: Alexander Graf <graf@amazon.com>
12
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
13
14
---
15
v3:
16
17
* Replaced legacy device reset method with Resettable method
18
19
hw/vmapple/Kconfig | 3 ++
20
hw/vmapple/cfg.c | 106 +++++++++++++++++++++++++++++++++++++++
21
hw/vmapple/meson.build | 1 +
22
include/hw/vmapple/cfg.h | 68 +++++++++++++++++++++++++
23
4 files changed, 178 insertions(+)
24
create mode 100644 hw/vmapple/cfg.c
25
create mode 100644 include/hw/vmapple/cfg.h
26
27
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
28
index XXXXXXX..XXXXXXX 100644
29
--- a/hw/vmapple/Kconfig
30
+++ b/hw/vmapple/Kconfig
31
@@ -XXX,XX +XXX,XX @@ config VMAPPLE_AES
32
config VMAPPLE_BDIF
33
bool
34
35
+config VMAPPLE_CFG
36
+ bool
37
+
38
diff --git a/hw/vmapple/cfg.c b/hw/vmapple/cfg.c
39
new file mode 100644
40
index XXXXXXX..XXXXXXX
41
--- /dev/null
42
+++ b/hw/vmapple/cfg.c
43
@@ -XXX,XX +XXX,XX @@
44
+/*
45
+ * VMApple Configuration Region
46
+ *
47
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
48
+ *
49
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
50
+ * See the COPYING file in the top-level directory.
51
+ */
52
+
53
+#include "qemu/osdep.h"
54
+#include "hw/vmapple/cfg.h"
55
+#include "qemu/log.h"
56
+#include "qemu/module.h"
57
+#include "qapi/error.h"
58
+
59
+static void vmapple_cfg_reset(Object *obj, ResetType type)
60
+{
61
+ VMAppleCfgState *s = VMAPPLE_CFG(obj);
62
+ VMAppleCfg *cfg;
63
+
64
+ cfg = memory_region_get_ram_ptr(&s->mem);
65
+ memset((void *)cfg, 0, VMAPPLE_CFG_SIZE);
66
+ *cfg = s->cfg;
67
+}
68
+
69
+static void vmapple_cfg_realize(DeviceState *dev, Error **errp)
70
+{
71
+ VMAppleCfgState *s = VMAPPLE_CFG(dev);
72
+ uint32_t i;
73
+
74
+ strncpy(s->cfg.serial, s->serial, sizeof(s->cfg.serial));
75
+ strncpy(s->cfg.model, s->model, sizeof(s->cfg.model));
76
+ strncpy(s->cfg.soc_name, s->soc_name, sizeof(s->cfg.soc_name));
77
+ strncpy(s->cfg.unk8, "D/A", sizeof(s->cfg.soc_name));
78
+ s->cfg.ecid = cpu_to_be64(s->cfg.ecid);
79
+ s->cfg.version = 2;
80
+ s->cfg.unk1 = 1;
81
+ s->cfg.unk2 = 1;
82
+ s->cfg.unk3 = 0x20;
83
+ s->cfg.unk4 = 0;
84
+ s->cfg.unk5 = 1;
85
+ s->cfg.unk6 = 1;
86
+ s->cfg.unk7 = 0;
87
+ s->cfg.unk10 = 1;
88
+
89
+ g_assert(s->cfg.nr_cpus < ARRAY_SIZE(s->cfg.cpu_ids));
90
+ for (i = 0; i < s->cfg.nr_cpus; i++) {
91
+ s->cfg.cpu_ids[i] = i;
92
+ }
93
+}
94
+
95
+static void vmapple_cfg_init(Object *obj)
96
+{
97
+ VMAppleCfgState *s = VMAPPLE_CFG(obj);
98
+
99
+ memory_region_init_ram(&s->mem, obj, "VMApple Config", VMAPPLE_CFG_SIZE,
100
+ &error_fatal);
101
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mem);
102
+
103
+ s->serial = (char *)"1234";
104
+ s->model = (char *)"VM0001";
105
+ s->soc_name = (char *)"Apple M1 (Virtual)";
106
+}
107
+
108
+static Property vmapple_cfg_properties[] = {
109
+ DEFINE_PROP_UINT32("nr-cpus", VMAppleCfgState, cfg.nr_cpus, 1),
110
+ DEFINE_PROP_UINT64("ecid", VMAppleCfgState, cfg.ecid, 0),
111
+ DEFINE_PROP_UINT64("ram-size", VMAppleCfgState, cfg.ram_size, 0),
112
+ DEFINE_PROP_UINT32("run_installer1", VMAppleCfgState, cfg.run_installer1, 0),
113
+ DEFINE_PROP_UINT32("run_installer2", VMAppleCfgState, cfg.run_installer2, 0),
114
+ DEFINE_PROP_UINT32("rnd", VMAppleCfgState, cfg.rnd, 0),
115
+ DEFINE_PROP_MACADDR("mac-en0", VMAppleCfgState, cfg.mac_en0),
116
+ DEFINE_PROP_MACADDR("mac-en1", VMAppleCfgState, cfg.mac_en1),
117
+ DEFINE_PROP_MACADDR("mac-wifi0", VMAppleCfgState, cfg.mac_wifi0),
118
+ DEFINE_PROP_MACADDR("mac-bt0", VMAppleCfgState, cfg.mac_bt0),
119
+ DEFINE_PROP_STRING("serial", VMAppleCfgState, serial),
120
+ DEFINE_PROP_STRING("model", VMAppleCfgState, model),
121
+ DEFINE_PROP_STRING("soc_name", VMAppleCfgState, soc_name),
122
+ DEFINE_PROP_END_OF_LIST(),
123
+};
124
+
125
+static void vmapple_cfg_class_init(ObjectClass *klass, void *data)
126
+{
127
+ DeviceClass *dc = DEVICE_CLASS(klass);
128
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
129
+
130
+ dc->realize = vmapple_cfg_realize;
131
+ dc->desc = "VMApple Configuration Region";
132
+ device_class_set_props(dc, vmapple_cfg_properties);
133
+ rc->phases.hold = vmapple_cfg_reset;
134
+}
135
+
136
+static const TypeInfo vmapple_cfg_info = {
137
+ .name = TYPE_VMAPPLE_CFG,
138
+ .parent = TYPE_SYS_BUS_DEVICE,
139
+ .instance_size = sizeof(VMAppleCfgState),
140
+ .instance_init = vmapple_cfg_init,
141
+ .class_init = vmapple_cfg_class_init,
142
+};
143
+
144
+static void vmapple_cfg_register_types(void)
145
+{
146
+ type_register_static(&vmapple_cfg_info);
147
+}
148
+
149
+type_init(vmapple_cfg_register_types)
150
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
151
index XXXXXXX..XXXXXXX 100644
152
--- a/hw/vmapple/meson.build
153
+++ b/hw/vmapple/meson.build
154
@@ -XXX,XX +XXX,XX @@
155
system_ss.add(when: 'CONFIG_VMAPPLE_AES', if_true: files('aes.c'))
156
system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
157
+system_ss.add(when: 'CONFIG_VMAPPLE_CFG', if_true: files('cfg.c'))
158
diff --git a/include/hw/vmapple/cfg.h b/include/hw/vmapple/cfg.h
159
new file mode 100644
160
index XXXXXXX..XXXXXXX
161
--- /dev/null
162
+++ b/include/hw/vmapple/cfg.h
163
@@ -XXX,XX +XXX,XX @@
164
+/*
165
+ * VMApple Configuration Region
166
+ *
167
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
168
+ *
169
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
170
+ * See the COPYING file in the top-level directory.
171
+ */
172
+
173
+#ifndef HW_VMAPPLE_CFG_H
174
+#define HW_VMAPPLE_CFG_H
175
+
176
+#include "hw/sysbus.h"
177
+#include "qom/object.h"
178
+#include "net/net.h"
179
+
180
+typedef struct VMAppleCfg {
181
+ uint32_t version; /* 0x000 */
182
+ uint32_t nr_cpus; /* 0x004 */
183
+ uint32_t unk1; /* 0x008 */
184
+ uint32_t unk2; /* 0x00c */
185
+ uint32_t unk3; /* 0x010 */
186
+ uint32_t unk4; /* 0x014 */
187
+ uint64_t ecid; /* 0x018 */
188
+ uint64_t ram_size; /* 0x020 */
189
+ uint32_t run_installer1; /* 0x028 */
190
+ uint32_t unk5; /* 0x02c */
191
+ uint32_t unk6; /* 0x030 */
192
+ uint32_t run_installer2; /* 0x034 */
193
+ uint32_t rnd; /* 0x038 */
194
+ uint32_t unk7; /* 0x03c */
195
+ MACAddr mac_en0; /* 0x040 */
196
+ uint8_t pad1[2];
197
+ MACAddr mac_en1; /* 0x048 */
198
+ uint8_t pad2[2];
199
+ MACAddr mac_wifi0; /* 0x050 */
200
+ uint8_t pad3[2];
201
+ MACAddr mac_bt0; /* 0x058 */
202
+ uint8_t pad4[2];
203
+ uint8_t reserved[0xa0]; /* 0x060 */
204
+ uint32_t cpu_ids[0x80]; /* 0x100 */
205
+ uint8_t scratch[0x200]; /* 0x180 */
206
+ char serial[32]; /* 0x380 */
207
+ char unk8[32]; /* 0x3a0 */
208
+ char model[32]; /* 0x3c0 */
209
+ uint8_t unk9[32]; /* 0x3e0 */
210
+ uint32_t unk10; /* 0x400 */
211
+ char soc_name[32]; /* 0x404 */
212
+} VMAppleCfg;
213
+
214
+#define TYPE_VMAPPLE_CFG "vmapple-cfg"
215
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleCfgState, VMAPPLE_CFG)
216
+
217
+struct VMAppleCfgState {
218
+ /* <private> */
219
+ SysBusDevice parent_obj;
220
+ VMAppleCfg cfg;
221
+
222
+ /* <public> */
223
+ MemoryRegion mem;
224
+ char *serial;
225
+ char *model;
226
+ char *soc_name;
227
+};
228
+
229
+#define VMAPPLE_CFG_SIZE 0x00010000
230
+
231
+#endif /* HW_VMAPPLE_CFG_H */
232
--
233
2.39.3 (Apple Git-145)
234
235
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
Apple has its own virtio-blk PCI device ID where it deviates from the
4
official virtio-pci spec slightly: It puts a new "apple type"
5
field at a static offset in config space and introduces a new barrier
6
command.
7
8
This patch first creates a mechanism for virtio-blk downstream classes to
9
handle unknown commands. It then creates such a downstream class and a new
10
vmapple-virtio-blk-pci class which support the additional apple type config
11
identifier as well as the barrier command.
12
13
It then exposes 2 subclasses from that that we can use to expose root and
14
aux virtio-blk devices: "vmapple-virtio-root" and "vmapple-virtio-aux".
15
16
Signed-off-by: Alexander Graf <graf@amazon.com>
17
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
18
---
19
hw/block/virtio-blk.c | 19 ++-
20
hw/vmapple/Kconfig | 3 +
21
hw/vmapple/meson.build | 1 +
22
hw/vmapple/virtio-blk.c | 212 ++++++++++++++++++++++++++++++++
23
include/hw/pci/pci_ids.h | 1 +
24
include/hw/virtio/virtio-blk.h | 12 +-
25
include/hw/vmapple/virtio-blk.h | 39 ++++++
26
7 files changed, 282 insertions(+), 5 deletions(-)
27
create mode 100644 hw/vmapple/virtio-blk.c
28
create mode 100644 include/hw/vmapple/virtio-blk.h
29
30
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/hw/block/virtio-blk.c
33
+++ b/hw/block/virtio-blk.c
34
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
35
req->mr_next = NULL;
36
}
37
38
-static void virtio_blk_free_request(VirtIOBlockReq *req)
39
+void virtio_blk_free_request(VirtIOBlockReq *req)
40
{
41
g_free(req);
42
}
43
44
-static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
45
+void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
46
{
47
VirtIOBlock *s = req->dev;
48
VirtIODevice *vdev = VIRTIO_DEVICE(s);
49
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
50
break;
51
}
52
default:
53
- virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
54
- virtio_blk_free_request(req);
55
+ {
56
+ /*
57
+ * Give subclasses a chance to handle unknown requests. This way the
58
+ * class lookup is not in the hot path.
59
+ */
60
+ VirtIOBlkClass *vbk = VIRTIO_BLK_GET_CLASS(s);
61
+ if (!vbk->handle_unknown_request ||
62
+ !vbk->handle_unknown_request(req, mrb, type)) {
63
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
64
+ virtio_blk_free_request(req);
65
+ }
66
+ }
67
}
68
return 0;
69
}
70
@@ -XXX,XX +XXX,XX @@ static const TypeInfo virtio_blk_info = {
71
.instance_size = sizeof(VirtIOBlock),
72
.instance_init = virtio_blk_instance_init,
73
.class_init = virtio_blk_class_init,
74
+ .class_size = sizeof(VirtIOBlkClass),
75
};
76
77
static void virtio_register_types(void)
78
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
79
index XXXXXXX..XXXXXXX 100644
80
--- a/hw/vmapple/Kconfig
81
+++ b/hw/vmapple/Kconfig
82
@@ -XXX,XX +XXX,XX @@ config VMAPPLE_BDIF
83
config VMAPPLE_CFG
84
bool
85
86
+config VMAPPLE_VIRTIO_BLK
87
+ bool
88
+
89
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
90
index XXXXXXX..XXXXXXX 100644
91
--- a/hw/vmapple/meson.build
92
+++ b/hw/vmapple/meson.build
93
@@ -XXX,XX +XXX,XX @@
94
system_ss.add(when: 'CONFIG_VMAPPLE_AES', if_true: files('aes.c'))
95
system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
96
system_ss.add(when: 'CONFIG_VMAPPLE_CFG', if_true: files('cfg.c'))
97
+system_ss.add(when: 'CONFIG_VMAPPLE_VIRTIO_BLK', if_true: files('virtio-blk.c'))
98
diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c
99
new file mode 100644
100
index XXXXXXX..XXXXXXX
101
--- /dev/null
102
+++ b/hw/vmapple/virtio-blk.c
103
@@ -XXX,XX +XXX,XX @@
104
+/*
105
+ * VMApple specific VirtIO Block implementation
106
+ *
107
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
108
+ *
109
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
110
+ * See the COPYING file in the top-level directory.
111
+ *
112
+ * VMApple uses almost standard VirtIO Block, but with a few key differences:
113
+ *
114
+ * - Different PCI device/vendor ID
115
+ * - An additional "type" identifier to differentiate AUX and Root volumes
116
+ * - An additional BARRIER command
117
+ */
118
+
119
+#include "qemu/osdep.h"
120
+#include "hw/vmapple/virtio-blk.h"
121
+#include "qemu/log.h"
122
+#include "qemu/module.h"
123
+#include "qapi/error.h"
124
+
125
+#define VIRTIO_BLK_T_APPLE_BARRIER 0x10000
126
+
127
+#define VIRTIO_APPLE_TYPE_ROOT 1
128
+#define VIRTIO_APPLE_TYPE_AUX 2
129
+
130
+static bool vmapple_virtio_blk_handle_unknown_request(VirtIOBlockReq *req,
131
+ MultiReqBuffer *mrb,
132
+ uint32_t type)
133
+{
134
+ switch (type) {
135
+ case VIRTIO_BLK_T_APPLE_BARRIER:
136
+ /* We ignore barriers for now. YOLO. */
137
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
138
+ virtio_blk_free_request(req);
139
+ return true;
140
+ default:
141
+ return false;
142
+ }
143
+}
144
+
145
+/*
146
+ * VMApple virtio-blk uses the same config format as normal virtio, with one
147
+ * exception: It adds an "apple type" specififer at the same location that
148
+ * the spec reserves for max_secure_erase_sectors. Let's hook into the
149
+ * get_config code path here, run it as usual and then patch in the apple type.
150
+ */
151
+static void vmapple_virtio_blk_get_config(VirtIODevice *vdev, uint8_t *config)
152
+{
153
+ VMAppleVirtIOBlk *dev = VMAPPLE_VIRTIO_BLK(vdev);
154
+ VMAppleVirtIOBlkClass *vvbk = VMAPPLE_VIRTIO_BLK_GET_CLASS(dev);
155
+ struct virtio_blk_config *blkcfg = (struct virtio_blk_config *)config;
156
+
157
+ vvbk->get_config(vdev, config);
158
+
159
+ g_assert(dev->parent_obj.config_size >= endof(struct virtio_blk_config, zoned));
160
+
161
+ /* Apple abuses the field for max_secure_erase_sectors as type id */
162
+ blkcfg->max_secure_erase_sectors = dev->apple_type;
163
+}
164
+
165
+static Property vmapple_virtio_blk_properties[] = {
166
+ DEFINE_PROP_UINT32("apple-type", VMAppleVirtIOBlk, apple_type, 0),
167
+ DEFINE_PROP_END_OF_LIST(),
168
+};
169
+
170
+static void vmapple_virtio_blk_class_init(ObjectClass *klass, void *data)
171
+{
172
+ DeviceClass *dc = DEVICE_CLASS(klass);
173
+ VirtIOBlkClass *vbk = VIRTIO_BLK_CLASS(klass);
174
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
175
+ VMAppleVirtIOBlkClass *vvbk = VMAPPLE_VIRTIO_BLK_CLASS(klass);
176
+
177
+ vbk->handle_unknown_request = vmapple_virtio_blk_handle_unknown_request;
178
+ vvbk->get_config = vdc->get_config;
179
+ vdc->get_config = vmapple_virtio_blk_get_config;
180
+ device_class_set_props(dc, vmapple_virtio_blk_properties);
181
+}
182
+
183
+static const TypeInfo vmapple_virtio_blk_info = {
184
+ .name = TYPE_VMAPPLE_VIRTIO_BLK,
185
+ .parent = TYPE_VIRTIO_BLK,
186
+ .instance_size = sizeof(VMAppleVirtIOBlk),
187
+ .class_init = vmapple_virtio_blk_class_init,
188
+};
189
+
190
+/* PCI Devices */
191
+
192
+typedef struct VMAppleVirtIOBlkPCI {
193
+ VirtIOPCIProxy parent_obj;
194
+ VMAppleVirtIOBlk vdev;
195
+ uint32_t apple_type;
196
+} VMAppleVirtIOBlkPCI;
197
+
198
+/*
199
+ * vmapple-virtio-blk-pci: This extends VirtioPCIProxy.
200
+ */
201
+#define TYPE_VMAPPLE_VIRTIO_BLK_PCI "vmapple-virtio-blk-pci-base"
202
+DECLARE_INSTANCE_CHECKER(VMAppleVirtIOBlkPCI, VMAPPLE_VIRTIO_BLK_PCI,
203
+ TYPE_VMAPPLE_VIRTIO_BLK_PCI)
204
+
205
+static Property vmapple_virtio_blk_pci_properties[] = {
206
+ DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
207
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
208
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
209
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
210
+ DEV_NVECTORS_UNSPECIFIED),
211
+ DEFINE_PROP_END_OF_LIST(),
212
+};
213
+
214
+static void vmapple_virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
215
+{
216
+ VMAppleVirtIOBlkPCI *dev = VMAPPLE_VIRTIO_BLK_PCI(vpci_dev);
217
+ DeviceState *vdev = DEVICE(&dev->vdev);
218
+ VirtIOBlkConf *conf = &dev->vdev.parent_obj.conf;
219
+
220
+ if (conf->num_queues == VIRTIO_BLK_AUTO_NUM_QUEUES) {
221
+ conf->num_queues = virtio_pci_optimal_num_queues(0);
222
+ }
223
+
224
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
225
+ vpci_dev->nvectors = conf->num_queues + 1;
226
+ }
227
+
228
+ /*
229
+ * We don't support zones, but we need the additional config space size.
230
+ * Let's just expose the feature so the rest of the virtio-blk logic
231
+ * allocates enough space for us. The guest will ignore zones anyway.
232
+ */
233
+ virtio_add_feature(&dev->vdev.parent_obj.host_features, VIRTIO_BLK_F_ZONED);
234
+ /* Propagate the apple type down to the virtio-blk device */
235
+ qdev_prop_set_uint32(DEVICE(&dev->vdev), "apple-type", dev->apple_type);
236
+ /* and spawn the virtio-blk device */
237
+ qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
238
+
239
+ /*
240
+ * The virtio-pci machinery adjusts its vendor/device ID based on whether
241
+ * we support modern or legacy virtio. Let's patch it back to the Apple
242
+ * identifiers here.
243
+ */
244
+ pci_config_set_vendor_id(vpci_dev->pci_dev.config, PCI_VENDOR_ID_APPLE);
245
+ pci_config_set_device_id(vpci_dev->pci_dev.config, PCI_DEVICE_ID_APPLE_VIRTIO_BLK);
246
+}
247
+
248
+static void vmapple_virtio_blk_pci_class_init(ObjectClass *klass, void *data)
249
+{
250
+ DeviceClass *dc = DEVICE_CLASS(klass);
251
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
252
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
253
+
254
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
255
+ device_class_set_props(dc, vmapple_virtio_blk_pci_properties);
256
+ k->realize = vmapple_virtio_blk_pci_realize;
257
+ pcidev_k->vendor_id = PCI_VENDOR_ID_APPLE;
258
+ pcidev_k->device_id = PCI_DEVICE_ID_APPLE_VIRTIO_BLK;
259
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
260
+ pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
261
+}
262
+
263
+static void vmapple_virtio_blk_pci_instance_init(Object *obj)
264
+{
265
+ VMAppleVirtIOBlkPCI *dev = VMAPPLE_VIRTIO_BLK_PCI(obj);
266
+
267
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
268
+ TYPE_VMAPPLE_VIRTIO_BLK);
269
+}
270
+
271
+static const VirtioPCIDeviceTypeInfo vmapple_virtio_blk_pci_info = {
272
+ .base_name = TYPE_VMAPPLE_VIRTIO_BLK_PCI,
273
+ .generic_name = "vmapple-virtio-blk-pci",
274
+ .instance_size = sizeof(VMAppleVirtIOBlkPCI),
275
+ .instance_init = vmapple_virtio_blk_pci_instance_init,
276
+ .class_init = vmapple_virtio_blk_pci_class_init,
277
+};
278
+
279
+static void vmapple_virtio_root_instance_init(Object *obj)
280
+{
281
+ VMAppleVirtIOBlkPCI *dev = VMAPPLE_VIRTIO_BLK_PCI(obj);
282
+
283
+ dev->apple_type = VIRTIO_APPLE_TYPE_ROOT;
284
+}
285
+
286
+static const TypeInfo vmapple_virtio_root_info = {
287
+ .name = TYPE_VMAPPLE_VIRTIO_ROOT,
288
+ .parent = "vmapple-virtio-blk-pci",
289
+ .instance_size = sizeof(VMAppleVirtIOBlkPCI),
290
+ .instance_init = vmapple_virtio_root_instance_init,
291
+};
292
+
293
+static void vmapple_virtio_aux_instance_init(Object *obj)
294
+{
295
+ VMAppleVirtIOBlkPCI *dev = VMAPPLE_VIRTIO_BLK_PCI(obj);
296
+
297
+ dev->apple_type = VIRTIO_APPLE_TYPE_AUX;
298
+}
299
+
300
+static const TypeInfo vmapple_virtio_aux_info = {
301
+ .name = TYPE_VMAPPLE_VIRTIO_AUX,
302
+ .parent = "vmapple-virtio-blk-pci",
303
+ .instance_size = sizeof(VMAppleVirtIOBlkPCI),
304
+ .instance_init = vmapple_virtio_aux_instance_init,
305
+};
306
+
307
+static void vmapple_virtio_blk_register_types(void)
308
+{
309
+ type_register_static(&vmapple_virtio_blk_info);
310
+ virtio_pci_types_register(&vmapple_virtio_blk_pci_info);
311
+ type_register_static(&vmapple_virtio_root_info);
312
+ type_register_static(&vmapple_virtio_aux_info);
313
+}
314
+
315
+type_init(vmapple_virtio_blk_register_types)
316
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
317
index XXXXXXX..XXXXXXX 100644
318
--- a/include/hw/pci/pci_ids.h
319
+++ b/include/hw/pci/pci_ids.h
320
@@ -XXX,XX +XXX,XX @@
321
#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
322
#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b
323
#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021
324
+#define PCI_DEVICE_ID_APPLE_VIRTIO_BLK 0x1a00
325
326
#define PCI_VENDOR_ID_SUN 0x108e
327
#define PCI_DEVICE_ID_SUN_EBUS 0x1000
328
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
329
index XXXXXXX..XXXXXXX 100644
330
--- a/include/hw/virtio/virtio-blk.h
331
+++ b/include/hw/virtio/virtio-blk.h
332
@@ -XXX,XX +XXX,XX @@
333
#include "qapi/qapi-types-virtio.h"
334
335
#define TYPE_VIRTIO_BLK "virtio-blk-device"
336
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlock, VIRTIO_BLK)
337
+OBJECT_DECLARE_TYPE(VirtIOBlock, VirtIOBlkClass, VIRTIO_BLK)
338
339
/* This is the last element of the write scatter-gather list */
340
struct virtio_blk_inhdr
341
@@ -XXX,XX +XXX,XX @@ typedef struct MultiReqBuffer {
342
bool is_write;
343
} MultiReqBuffer;
344
345
+typedef struct VirtIOBlkClass {
346
+ /*< private >*/
347
+ VirtioDeviceClass parent;
348
+ /*< public >*/
349
+ bool (*handle_unknown_request)(VirtIOBlockReq *req, MultiReqBuffer *mrb,
350
+ uint32_t type);
351
+} VirtIOBlkClass;
352
+
353
void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq);
354
+void virtio_blk_free_request(VirtIOBlockReq *req);
355
+void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status);
356
357
#endif
358
diff --git a/include/hw/vmapple/virtio-blk.h b/include/hw/vmapple/virtio-blk.h
359
new file mode 100644
360
index XXXXXXX..XXXXXXX
361
--- /dev/null
362
+++ b/include/hw/vmapple/virtio-blk.h
363
@@ -XXX,XX +XXX,XX @@
364
+/*
365
+ * VMApple specific VirtIO Block implementation
366
+ *
367
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
368
+ *
369
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
370
+ * See the COPYING file in the top-level directory.
371
+ */
372
+
373
+#ifndef HW_VMAPPLE_CFG_H
374
+#define HW_VMAPPLE_CFG_H
375
+
376
+#include "hw/sysbus.h"
377
+#include "qom/object.h"
378
+#include "hw/virtio/virtio-pci.h"
379
+#include "hw/virtio/virtio-blk.h"
380
+
381
+#define TYPE_VMAPPLE_VIRTIO_BLK "vmapple-virtio-blk"
382
+#define TYPE_VMAPPLE_VIRTIO_ROOT "vmapple-virtio-root"
383
+#define TYPE_VMAPPLE_VIRTIO_AUX "vmapple-virtio-aux"
384
+
385
+OBJECT_DECLARE_TYPE(VMAppleVirtIOBlk, VMAppleVirtIOBlkClass, VMAPPLE_VIRTIO_BLK)
386
+
387
+typedef struct VMAppleVirtIOBlkClass {
388
+ /*< private >*/
389
+ VirtIOBlkClass parent;
390
+ /*< public >*/
391
+ void (*get_config)(VirtIODevice *vdev, uint8_t *config);
392
+} VMAppleVirtIOBlkClass;
393
+
394
+typedef struct VMAppleVirtIOBlk {
395
+ /* <private> */
396
+ VirtIOBlock parent_obj;
397
+
398
+ /* <public> */
399
+ uint32_t apple_type;
400
+} VMAppleVirtIOBlk;
401
+
402
+#endif /* HW_VMAPPLE_CFG_H */
403
--
404
2.39.3 (Apple Git-145)
405
406
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <graf@amazon.com>
2
1
3
Apple defines a new "vmapple" machine type as part of its proprietary
4
macOS Virtualization.Framework vmm. This machine type is similar to the
5
virt one, but with subtle differences in base devices, a few special
6
vmapple device additions and a vastly different boot chain.
7
8
This patch reimplements this machine type in QEMU. To use it, you
9
have to have a readily installed version of macOS for VMApple,
10
run on macOS with -accel hvf, pass the Virtualization.Framework
11
boot rom (AVPBooter) in via -bios, pass the aux and root volume as pflash
12
and pass aux and root volume as virtio drives. In addition, you also
13
need to find the machine UUID and pass that as -M vmapple,uuid= parameter:
14
15
$ qemu-system-aarch64 -accel hvf -M vmapple,uuid=0x1234 -m 4G \
16
-bios /System/Library/Frameworks/Virtualization.framework/Versions/A/Resources/AVPBooter.vmapple2.bin
17
-drive file=aux,if=pflash,format=raw \
18
-drive file=root,if=pflash,format=raw \
19
-drive file=aux,if=none,id=aux,format=raw \
20
-device vmapple-virtio-aux,drive=aux \
21
-drive file=root,if=none,id=root,format=raw \
22
-device vmapple-virtio-root,drive=root
23
24
With all these in place, you should be able to see macOS booting
25
successfully.
26
27
Known issues:
28
- Keyboard and mouse/tablet input is laggy. The reason for this is
29
either that macOS's XHCI driver is broken when the device/platform
30
does not support MSI/MSI-X, or there's some unfortunate interplay
31
with Qemu's XHCI implementation in this scenario.
32
- Currently only macOS 12 guests are supported. The boot process for
33
13+ will need further investigation and adjustment.
34
35
Signed-off-by: Alexander Graf <graf@amazon.com>
36
Co-authored-by: Phil Dennis-Jordan <phil@philjordan.eu>
37
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
38
39
---
40
v3:
41
* Rebased on latest upstream, updated affinity and NIC creation
42
API usage
43
* Included Apple-variant virtio-blk in build dependency
44
* Updated API usage for setting 'redist-region-count' array-typed property on GIC.
45
* Switched from virtio HID devices (for which macOS 12 does not contain drivers) to an XHCI USB controller and USB HID devices.
46
47
MAINTAINERS | 1 +
48
docs/system/arm/vmapple.rst | 63 ++++
49
docs/system/target-arm.rst | 1 +
50
hw/vmapple/Kconfig | 20 ++
51
hw/vmapple/meson.build | 1 +
52
hw/vmapple/vmapple.c | 661 ++++++++++++++++++++++++++++++++++++
53
6 files changed, 747 insertions(+)
54
create mode 100644 docs/system/arm/vmapple.rst
55
create mode 100644 hw/vmapple/vmapple.c
56
57
diff --git a/MAINTAINERS b/MAINTAINERS
58
index XXXXXXX..XXXXXXX 100644
59
--- a/MAINTAINERS
60
+++ b/MAINTAINERS
61
@@ -XXX,XX +XXX,XX @@ R: Phil Dennis-Jordan <phil@philjordan.eu>
62
S: Maintained
63
F: hw/vmapple/*
64
F: include/hw/vmapple/*
65
+F: docs/system/arm/vmapple.rst
66
67
Subsystems
68
----------
69
diff --git a/docs/system/arm/vmapple.rst b/docs/system/arm/vmapple.rst
70
new file mode 100644
71
index XXXXXXX..XXXXXXX
72
--- /dev/null
73
+++ b/docs/system/arm/vmapple.rst
74
@@ -XXX,XX +XXX,XX @@
75
+VMApple machine emulation
76
+========================================================================================
77
+
78
+VMApple is the device model that the macOS built-in hypervisor called "Virtualization.framework"
79
+exposes to Apple Silicon macOS guests. The "vmapple" machine model in QEMU implements the same
80
+device model, but does not use any code from Virtualization.Framework.
81
+
82
+Prerequisites
83
+-------------
84
+
85
+To run the vmapple machine model, you need to
86
+
87
+ * Run on Apple Silicon
88
+ * Run on macOS 12.0 or above
89
+ * Have an already installed copy of a Virtualization.Framework macOS 12 virtual machine. I will
90
+ assume that you installed it using the macosvm CLI.
91
+
92
+First, we need to extract the UUID from the virtual machine that you installed. You can do this
93
+by running the following shell script:
94
+
95
+.. code-block:: bash
96
+ :caption: uuid.sh script to extract the UUID from a macosvm.json file
97
+
98
+ #!/bin/bash
99
+
100
+ MID=$(cat "$1" | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(obj["machineId"]);')
101
+ echo "$MID" | base64 -d | plutil -extract ECID raw -
102
+
103
+Now we also need to trim the aux partition. It contains metadata that we can just discard:
104
+
105
+.. code-block:: bash
106
+ :caption: Command to trim the aux file
107
+
108
+ $ dd if="aux.img" of="aux.img.trimmed" bs=$(( 0x4000 )) skip=1
109
+
110
+How to run
111
+----------
112
+
113
+Then, we can launch QEMU with the Virtualization.Framework pre-boot environment and the readily
114
+installed target disk images. I recommend to port forward the VM's ssh and vnc ports to the host
115
+to get better interactive access into the target system:
116
+
117
+.. code-block:: bash
118
+ :caption: Example execution command line
119
+
120
+ $ UUID=$(uuid.sh macosvm.json)
121
+ $ AVPBOOTER=/System/Library/Frameworks/Virtualization.framework/Resources/AVPBooter.vmapple2.bin
122
+ $ AUX=aux.img.trimmed
123
+ $ DISK=disk.img
124
+ $ qemu-system-aarch64 \
125
+ -serial mon:stdio \
126
+ -m 4G \
127
+ -accel hvf \
128
+ -M vmapple,uuid=$UUID \
129
+ -bios $AVPBOOTER \
130
+ -drive file="$AUX",if=pflash,format=raw \
131
+ -drive file="$DISK",if=pflash,format=raw \
132
+ -drive file="$AUX",if=none,id=aux,format=raw \
133
+ -drive file="$DISK",if=none,id=root,format=raw \
134
+ -device vmapple-virtio-aux,drive=aux \
135
+ -device vmapple-virtio-root,drive=root \
136
+ -net user,ipv6=off,hostfwd=tcp::2222-:22,hostfwd=tcp::5901-:5900 \
137
+ -net nic,model=virtio-net-pci \
138
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
139
index XXXXXXX..XXXXXXX 100644
140
--- a/docs/system/target-arm.rst
141
+++ b/docs/system/target-arm.rst
142
@@ -XXX,XX +XXX,XX @@ undocumented; you can get a complete list by running
143
arm/stellaris
144
arm/stm32
145
arm/virt
146
+ arm/vmapple
147
arm/xenpvh
148
arm/xlnx-versal-virt
149
arm/xlnx-zynq
150
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
151
index XXXXXXX..XXXXXXX 100644
152
--- a/hw/vmapple/Kconfig
153
+++ b/hw/vmapple/Kconfig
154
@@ -XXX,XX +XXX,XX @@ config VMAPPLE_CFG
155
config VMAPPLE_VIRTIO_BLK
156
bool
157
158
+config VMAPPLE
159
+ bool
160
+ depends on ARM
161
+ depends on HVF
162
+ default y if ARM
163
+ imply PCI_DEVICES
164
+ select ARM_GIC
165
+ select PLATFORM_BUS
166
+ select PCI_EXPRESS
167
+ select PCI_EXPRESS_GENERIC_BRIDGE
168
+ select PL011 # UART
169
+ select PL031 # RTC
170
+ select PL061 # GPIO
171
+ select GPIO_PWR
172
+ select PVPANIC_MMIO
173
+ select VMAPPLE_AES
174
+ select VMAPPLE_BDIF
175
+ select VMAPPLE_CFG
176
+ select MAC_PVG_VMAPPLE
177
+ select VMAPPLE_VIRTIO_BLK
178
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
179
index XXXXXXX..XXXXXXX 100644
180
--- a/hw/vmapple/meson.build
181
+++ b/hw/vmapple/meson.build
182
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_VMAPPLE_AES', if_true: files('aes.c'))
183
system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
184
system_ss.add(when: 'CONFIG_VMAPPLE_CFG', if_true: files('cfg.c'))
185
system_ss.add(when: 'CONFIG_VMAPPLE_VIRTIO_BLK', if_true: files('virtio-blk.c'))
186
+specific_ss.add(when: 'CONFIG_VMAPPLE', if_true: files('vmapple.c'))
187
diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c
188
new file mode 100644
189
index XXXXXXX..XXXXXXX
190
--- /dev/null
191
+++ b/hw/vmapple/vmapple.c
192
@@ -XXX,XX +XXX,XX @@
193
+/*
194
+ * VMApple machine emulation
195
+ *
196
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
197
+ *
198
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
199
+ * See the COPYING file in the top-level directory.
200
+ *
201
+ * VMApple is the device model that the macOS built-in hypervisor called
202
+ * "Virtualization.framework" exposes to Apple Silicon macOS guests. The
203
+ * machine model in this file implements the same device model in QEMU, but
204
+ * does not use any code from Virtualization.Framework.
205
+ */
206
+
207
+#include "qemu/osdep.h"
208
+#include "qemu/help-texts.h"
209
+#include "qemu/datadir.h"
210
+#include "qemu/units.h"
211
+#include "qemu/option.h"
212
+#include "monitor/qdev.h"
213
+#include "hw/sysbus.h"
214
+#include "hw/arm/boot.h"
215
+#include "hw/arm/primecell.h"
216
+#include "hw/boards.h"
217
+#include "hw/usb.h"
218
+#include "net/net.h"
219
+#include "sysemu/sysemu.h"
220
+#include "sysemu/runstate.h"
221
+#include "sysemu/kvm.h"
222
+#include "sysemu/hvf.h"
223
+#include "hw/loader.h"
224
+#include "qapi/error.h"
225
+#include "qapi/qmp/qlist.h"
226
+#include "qemu/bitops.h"
227
+#include "qemu/error-report.h"
228
+#include "qemu/module.h"
229
+#include "hw/pci-host/gpex.h"
230
+#include "hw/virtio/virtio-pci.h"
231
+#include "hw/qdev-properties.h"
232
+#include "hw/intc/arm_gic.h"
233
+#include "hw/intc/arm_gicv3_common.h"
234
+#include "hw/irq.h"
235
+#include "hw/usb/xhci.h"
236
+#include "qapi/visitor.h"
237
+#include "qapi/qapi-visit-common.h"
238
+#include "standard-headers/linux/input.h"
239
+#include "target/arm/internals.h"
240
+#include "target/arm/kvm_arm.h"
241
+#include "hw/char/pl011.h"
242
+#include "qemu/guest-random.h"
243
+#include "sysemu/reset.h"
244
+#include "qemu/log.h"
245
+#include "hw/vmapple/cfg.h"
246
+#include "hw/misc/pvpanic.h"
247
+#include "hw/vmapple/bdif.h"
248
+
249
+struct VMAppleMachineClass {
250
+ MachineClass parent;
251
+};
252
+
253
+struct VMAppleMachineState {
254
+ MachineState parent;
255
+
256
+ Notifier machine_done;
257
+ struct arm_boot_info bootinfo;
258
+ MemMapEntry *memmap;
259
+ const int *irqmap;
260
+ DeviceState *gic;
261
+ DeviceState *cfg;
262
+ Notifier powerdown_notifier;
263
+ PCIBus *bus;
264
+ MemoryRegion fw_mr;
265
+ uint64_t uuid;
266
+};
267
+
268
+#define DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, latest) \
269
+ static void vmapple##major##_##minor##_class_init(ObjectClass *oc, \
270
+ void *data) \
271
+ { \
272
+ MachineClass *mc = MACHINE_CLASS(oc); \
273
+ vmapple_machine_##major##_##minor##_options(mc); \
274
+ mc->desc = "QEMU " # major "." # minor " Apple Virtual Machine"; \
275
+ if (latest) { \
276
+ mc->alias = "vmapple"; \
277
+ } \
278
+ } \
279
+ static const TypeInfo machvmapple##major##_##minor##_info = { \
280
+ .name = MACHINE_TYPE_NAME("vmapple-" # major "." # minor), \
281
+ .parent = TYPE_VMAPPLE_MACHINE, \
282
+ .class_init = vmapple##major##_##minor##_class_init, \
283
+ }; \
284
+ static void machvmapple_machine_##major##_##minor##_init(void) \
285
+ { \
286
+ type_register_static(&machvmapple##major##_##minor##_info); \
287
+ } \
288
+ type_init(machvmapple_machine_##major##_##minor##_init);
289
+
290
+#define DEFINE_VMAPPLE_MACHINE_AS_LATEST(major, minor) \
291
+ DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, true)
292
+#define DEFINE_VMAPPLE_MACHINE(major, minor) \
293
+ DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, false)
294
+
295
+#define TYPE_VMAPPLE_MACHINE MACHINE_TYPE_NAME("vmapple")
296
+OBJECT_DECLARE_TYPE(VMAppleMachineState, VMAppleMachineClass, VMAPPLE_MACHINE)
297
+
298
+/* Number of external interrupt lines to configure the GIC with */
299
+#define NUM_IRQS 256
300
+
301
+enum {
302
+ VMAPPLE_FIRMWARE,
303
+ VMAPPLE_CONFIG,
304
+ VMAPPLE_MEM,
305
+ VMAPPLE_GIC_DIST,
306
+ VMAPPLE_GIC_REDIST,
307
+ VMAPPLE_UART,
308
+ VMAPPLE_RTC,
309
+ VMAPPLE_PCIE,
310
+ VMAPPLE_PCIE_MMIO,
311
+ VMAPPLE_PCIE_ECAM,
312
+ VMAPPLE_GPIO,
313
+ VMAPPLE_PVPANIC,
314
+ VMAPPLE_APV_GFX,
315
+ VMAPPLE_APV_IOSFC,
316
+ VMAPPLE_AES_1,
317
+ VMAPPLE_AES_2,
318
+ VMAPPLE_BDOOR,
319
+ VMAPPLE_MEMMAP_LAST,
320
+};
321
+
322
+static MemMapEntry memmap[] = {
323
+ [VMAPPLE_FIRMWARE] = { 0x00100000, 0x00100000 },
324
+ [VMAPPLE_CONFIG] = { 0x00400000, 0x00010000 },
325
+
326
+ [VMAPPLE_GIC_DIST] = { 0x10000000, 0x00010000 },
327
+ [VMAPPLE_GIC_REDIST] = { 0x10010000, 0x00400000 },
328
+
329
+ [VMAPPLE_UART] = { 0x20010000, 0x00010000 },
330
+ [VMAPPLE_RTC] = { 0x20050000, 0x00001000 },
331
+ [VMAPPLE_GPIO] = { 0x20060000, 0x00001000 },
332
+ [VMAPPLE_PVPANIC] = { 0x20070000, 0x00000002 },
333
+ [VMAPPLE_BDOOR] = { 0x30000000, 0x00200000 },
334
+ [VMAPPLE_APV_GFX] = { 0x30200000, 0x00010000 },
335
+ [VMAPPLE_APV_IOSFC] = { 0x30210000, 0x00010000 },
336
+ [VMAPPLE_AES_1] = { 0x30220000, 0x00004000 },
337
+ [VMAPPLE_AES_2] = { 0x30230000, 0x00004000 },
338
+ [VMAPPLE_PCIE_ECAM] = { 0x40000000, 0x10000000 },
339
+ [VMAPPLE_PCIE_MMIO] = { 0x50000000, 0x1fff0000 },
340
+
341
+ /* Actual RAM size depends on configuration */
342
+ [VMAPPLE_MEM] = { 0x70000000ULL, GiB},
343
+};
344
+
345
+static const int irqmap[] = {
346
+ [VMAPPLE_UART] = 1,
347
+ [VMAPPLE_RTC] = 2,
348
+ [VMAPPLE_GPIO] = 0x5,
349
+ [VMAPPLE_APV_IOSFC] = 0x10,
350
+ [VMAPPLE_APV_GFX] = 0x11,
351
+ [VMAPPLE_AES_1] = 0x12,
352
+ [VMAPPLE_PCIE] = 0x20,
353
+};
354
+
355
+#define GPEX_NUM_IRQS 16
356
+
357
+static void create_bdif(VMAppleMachineState *vms, MemoryRegion *mem)
358
+{
359
+ DeviceState *bdif;
360
+ SysBusDevice *bdif_sb;
361
+ DriveInfo *di_aux = drive_get(IF_PFLASH, 0, 0);
362
+ DriveInfo *di_root = drive_get(IF_PFLASH, 0, 1);
363
+
364
+ if (!di_aux) {
365
+ error_report("No AUX device found. Please specify one as pflash drive");
366
+ exit(1);
367
+ }
368
+
369
+ if (!di_root) {
370
+ /* Fall back to the first IF_VIRTIO device as root device */
371
+ di_root = drive_get(IF_VIRTIO, 0, 0);
372
+ }
373
+
374
+ if (!di_root) {
375
+ error_report("No root device found. Please specify one as virtio drive");
376
+ exit(1);
377
+ }
378
+
379
+ /* PV backdoor device */
380
+ bdif = qdev_new(TYPE_VMAPPLE_BDIF);
381
+ bdif_sb = SYS_BUS_DEVICE(bdif);
382
+ sysbus_mmio_map(bdif_sb, 0, vms->memmap[VMAPPLE_BDOOR].base);
383
+
384
+ qdev_prop_set_drive(DEVICE(bdif), "aux", blk_by_legacy_dinfo(di_aux));
385
+ qdev_prop_set_drive(DEVICE(bdif), "root", blk_by_legacy_dinfo(di_root));
386
+
387
+ sysbus_realize_and_unref(bdif_sb, &error_fatal);
388
+}
389
+
390
+static void create_pvpanic(VMAppleMachineState *vms, MemoryRegion *mem)
391
+{
392
+ SysBusDevice *cfg;
393
+
394
+ vms->cfg = qdev_new(TYPE_PVPANIC_MMIO_DEVICE);
395
+ cfg = SYS_BUS_DEVICE(vms->cfg);
396
+ sysbus_mmio_map(cfg, 0, vms->memmap[VMAPPLE_PVPANIC].base);
397
+
398
+ sysbus_realize_and_unref(cfg, &error_fatal);
399
+}
400
+
401
+static void create_cfg(VMAppleMachineState *vms, MemoryRegion *mem)
402
+{
403
+ SysBusDevice *cfg;
404
+ MachineState *machine = MACHINE(vms);
405
+ uint32_t rnd = 1;
406
+
407
+ vms->cfg = qdev_new(TYPE_VMAPPLE_CFG);
408
+ cfg = SYS_BUS_DEVICE(vms->cfg);
409
+ sysbus_mmio_map(cfg, 0, vms->memmap[VMAPPLE_CONFIG].base);
410
+
411
+ qemu_guest_getrandom_nofail(&rnd, sizeof(rnd));
412
+
413
+ qdev_prop_set_uint32(vms->cfg, "nr-cpus", machine->smp.cpus);
414
+ qdev_prop_set_uint64(vms->cfg, "ecid", vms->uuid);
415
+ qdev_prop_set_uint64(vms->cfg, "ram-size", machine->ram_size);
416
+ qdev_prop_set_uint32(vms->cfg, "rnd", rnd);
417
+
418
+ sysbus_realize_and_unref(cfg, &error_fatal);
419
+}
420
+
421
+static void create_gfx(VMAppleMachineState *vms, MemoryRegion *mem)
422
+{
423
+ int irq_gfx = vms->irqmap[VMAPPLE_APV_GFX];
424
+ int irq_iosfc = vms->irqmap[VMAPPLE_APV_IOSFC];
425
+ SysBusDevice *aes;
426
+
427
+ aes = SYS_BUS_DEVICE(qdev_new("apple-gfx-vmapple"));
428
+ sysbus_mmio_map(aes, 0, vms->memmap[VMAPPLE_APV_GFX].base);
429
+ sysbus_mmio_map(aes, 1, vms->memmap[VMAPPLE_APV_IOSFC].base);
430
+ sysbus_connect_irq(aes, 0, qdev_get_gpio_in(vms->gic, irq_gfx));
431
+ sysbus_connect_irq(aes, 1, qdev_get_gpio_in(vms->gic, irq_iosfc));
432
+ sysbus_realize_and_unref(aes, &error_fatal);
433
+}
434
+
435
+static void create_aes(VMAppleMachineState *vms, MemoryRegion *mem)
436
+{
437
+ int irq = vms->irqmap[VMAPPLE_AES_1];
438
+ SysBusDevice *aes;
439
+
440
+ aes = SYS_BUS_DEVICE(qdev_new("apple-aes"));
441
+ sysbus_mmio_map(aes, 0, vms->memmap[VMAPPLE_AES_1].base);
442
+ sysbus_mmio_map(aes, 1, vms->memmap[VMAPPLE_AES_2].base);
443
+ sysbus_connect_irq(aes, 0, qdev_get_gpio_in(vms->gic, irq));
444
+ sysbus_realize_and_unref(aes, &error_fatal);
445
+}
446
+
447
+static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index)
448
+{
449
+ return NUM_IRQS + cpu_nr * GIC_INTERNAL + ppi_index;
450
+}
451
+
452
+static void create_gic(VMAppleMachineState *vms, MemoryRegion *mem)
453
+{
454
+ MachineState *ms = MACHINE(vms);
455
+ /* We create a standalone GIC */
456
+ SysBusDevice *gicbusdev;
457
+ QList *redist_region_count;
458
+ int i;
459
+ unsigned int smp_cpus = ms->smp.cpus;
460
+
461
+ vms->gic = qdev_new(gicv3_class_name());
462
+ qdev_prop_set_uint32(vms->gic, "revision", 3);
463
+ qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
464
+ /*
465
+ * Note that the num-irq property counts both internal and external
466
+ * interrupts; there are always 32 of the former (mandated by GIC spec).
467
+ */
468
+ qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32);
469
+
470
+ uint32_t redist0_capacity =
471
+ vms->memmap[VMAPPLE_GIC_REDIST].size / GICV3_REDIST_SIZE;
472
+ uint32_t redist0_count = MIN(smp_cpus, redist0_capacity);
473
+
474
+ redist_region_count = qlist_new();
475
+ qlist_append_int(redist_region_count, redist0_count);
476
+ qdev_prop_set_array(vms->gic, "redist-region-count", redist_region_count);
477
+
478
+ gicbusdev = SYS_BUS_DEVICE(vms->gic);
479
+ sysbus_realize_and_unref(gicbusdev, &error_fatal);
480
+ sysbus_mmio_map(gicbusdev, 0, vms->memmap[VMAPPLE_GIC_DIST].base);
481
+ sysbus_mmio_map(gicbusdev, 1, vms->memmap[VMAPPLE_GIC_REDIST].base);
482
+
483
+ /*
484
+ * Wire the outputs from each CPU's generic timer and the GICv3
485
+ * maintenance interrupt signal to the appropriate GIC PPI inputs,
486
+ * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
487
+ */
488
+ for (i = 0; i < smp_cpus; i++) {
489
+ DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
490
+
491
+ /* Map the virt timer to PPI 27 */
492
+ qdev_connect_gpio_out(cpudev, GTIMER_VIRT,
493
+ qdev_get_gpio_in(vms->gic,
494
+ arm_gic_ppi_index(i, 27)));
495
+
496
+ /* Map the GIC IRQ and FIQ lines to CPU */
497
+ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
498
+ sysbus_connect_irq(gicbusdev, i + smp_cpus,
499
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
500
+ }
501
+}
502
+
503
+static void create_uart(const VMAppleMachineState *vms, int uart,
504
+ MemoryRegion *mem, Chardev *chr)
505
+{
506
+ hwaddr base = vms->memmap[uart].base;
507
+ int irq = vms->irqmap[uart];
508
+ DeviceState *dev = qdev_new(TYPE_PL011);
509
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
510
+
511
+ qdev_prop_set_chr(dev, "chardev", chr);
512
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
513
+ memory_region_add_subregion(mem, base,
514
+ sysbus_mmio_get_region(s, 0));
515
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
516
+}
517
+
518
+static void create_rtc(const VMAppleMachineState *vms)
519
+{
520
+ hwaddr base = vms->memmap[VMAPPLE_RTC].base;
521
+ int irq = vms->irqmap[VMAPPLE_RTC];
522
+
523
+ sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq));
524
+}
525
+
526
+static DeviceState *gpio_key_dev;
527
+static void vmapple_powerdown_req(Notifier *n, void *opaque)
528
+{
529
+ /* use gpio Pin 3 for power button event */
530
+ qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
531
+}
532
+
533
+static void create_gpio_devices(const VMAppleMachineState *vms, int gpio,
534
+ MemoryRegion *mem)
535
+{
536
+ DeviceState *pl061_dev;
537
+ hwaddr base = vms->memmap[gpio].base;
538
+ int irq = vms->irqmap[gpio];
539
+ SysBusDevice *s;
540
+
541
+ pl061_dev = qdev_new("pl061");
542
+ /* Pull lines down to 0 if not driven by the PL061 */
543
+ qdev_prop_set_uint32(pl061_dev, "pullups", 0);
544
+ qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff);
545
+ s = SYS_BUS_DEVICE(pl061_dev);
546
+ sysbus_realize_and_unref(s, &error_fatal);
547
+ memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
548
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
549
+ gpio_key_dev = sysbus_create_simple("gpio-key", -1,
550
+ qdev_get_gpio_in(pl061_dev, 3));
551
+}
552
+
553
+static void vmapple_firmware_init(VMAppleMachineState *vms,
554
+ MemoryRegion *sysmem)
555
+{
556
+ hwaddr size = vms->memmap[VMAPPLE_FIRMWARE].size;
557
+ hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base;
558
+ const char *bios_name;
559
+ int image_size;
560
+ char *fname;
561
+
562
+ bios_name = MACHINE(vms)->firmware;
563
+ if (!bios_name) {
564
+ error_report("No firmware specified");
565
+ exit(1);
566
+ }
567
+
568
+ fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
569
+ if (!fname) {
570
+ error_report("Could not find ROM image '%s'", bios_name);
571
+ exit(1);
572
+ }
573
+
574
+ memory_region_init_ram(&vms->fw_mr, NULL, "firmware", size, NULL);
575
+ image_size = load_image_mr(fname, &vms->fw_mr);
576
+
577
+ g_free(fname);
578
+ if (image_size < 0) {
579
+ error_report("Could not load ROM image '%s'", bios_name);
580
+ exit(1);
581
+ }
582
+
583
+ memory_region_add_subregion(get_system_memory(), base, &vms->fw_mr);
584
+}
585
+
586
+static void create_pcie(VMAppleMachineState *vms)
587
+{
588
+ hwaddr base_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].base;
589
+ hwaddr size_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].size;
590
+ hwaddr base_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].base;
591
+ hwaddr size_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].size;
592
+ int irq = vms->irqmap[VMAPPLE_PCIE];
593
+ MemoryRegion *mmio_alias;
594
+ MemoryRegion *mmio_reg;
595
+ MemoryRegion *ecam_alias;
596
+ MemoryRegion *ecam_reg;
597
+ DeviceState *dev;
598
+ int i;
599
+ PCIHostState *pci;
600
+ DeviceState *usb_controller;
601
+ USBBus *usb_bus;
602
+
603
+ dev = qdev_new(TYPE_GPEX_HOST);
604
+ qdev_prop_set_uint32(dev, "nr-irqs", GPEX_NUM_IRQS);
605
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
606
+
607
+ /* Map only the first size_ecam bytes of ECAM space */
608
+ ecam_alias = g_new0(MemoryRegion, 1);
609
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
610
+ memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
611
+ ecam_reg, 0, size_ecam);
612
+ memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias);
613
+
614
+ /*
615
+ * Map the MMIO window from [0x50000000-0x7fff0000] in PCI space into
616
+ * system address space at [0x50000000-0x7fff0000].
617
+ */
618
+ mmio_alias = g_new0(MemoryRegion, 1);
619
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
620
+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
621
+ mmio_reg, base_mmio, size_mmio);
622
+ memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
623
+
624
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
625
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
626
+ qdev_get_gpio_in(vms->gic, irq + i));
627
+ gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
628
+ }
629
+
630
+ pci = PCI_HOST_BRIDGE(dev);
631
+ vms->bus = pci->bus;
632
+ g_assert_nonnull(vms->bus);
633
+
634
+ while ((dev = qemu_create_nic_device("virtio-net-pci", true, NULL))) {
635
+ qdev_realize_and_unref(dev, BUS(vms->bus), &error_fatal);
636
+ }
637
+
638
+ usb_controller = qdev_new(TYPE_QEMU_XHCI);
639
+ qdev_realize_and_unref(usb_controller, BUS(pci->bus), &error_fatal);
640
+
641
+ usb_bus = USB_BUS(object_resolve_type_unambiguous(TYPE_USB_BUS,
642
+ &error_fatal));
643
+ usb_create_simple(usb_bus, "usb-kbd");
644
+ usb_create_simple(usb_bus, "usb-tablet");
645
+}
646
+
647
+static void vmapple_reset(void *opaque)
648
+{
649
+ VMAppleMachineState *vms = opaque;
650
+ hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base;
651
+
652
+ cpu_set_pc(first_cpu, base);
653
+}
654
+
655
+static void mach_vmapple_init(MachineState *machine)
656
+{
657
+ VMAppleMachineState *vms = VMAPPLE_MACHINE(machine);
658
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
659
+ const CPUArchIdList *possible_cpus;
660
+ MemoryRegion *sysmem = get_system_memory();
661
+ int n;
662
+ unsigned int smp_cpus = machine->smp.cpus;
663
+ unsigned int max_cpus = machine->smp.max_cpus;
664
+
665
+ vms->memmap = memmap;
666
+ machine->usb = true;
667
+
668
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
669
+ assert(possible_cpus->len == max_cpus);
670
+ for (n = 0; n < possible_cpus->len; n++) {
671
+ Object *cpu;
672
+ CPUState *cs;
673
+
674
+ if (n >= smp_cpus) {
675
+ break;
676
+ }
677
+
678
+ cpu = object_new(possible_cpus->cpus[n].type);
679
+ object_property_set_int(cpu, "mp-affinity",
680
+ possible_cpus->cpus[n].arch_id, NULL);
681
+
682
+ cs = CPU(cpu);
683
+ cs->cpu_index = n;
684
+
685
+ numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpu),
686
+ &error_fatal);
687
+
688
+ object_property_set_bool(cpu, "has_el3", false, NULL);
689
+ object_property_set_bool(cpu, "has_el2", false, NULL);
690
+ object_property_set_int(cpu, "psci-conduit", QEMU_PSCI_CONDUIT_HVC,
691
+ NULL);
692
+
693
+ /* Secondary CPUs start in PSCI powered-down state */
694
+ if (n > 0) {
695
+ object_property_set_bool(cpu, "start-powered-off", true, NULL);
696
+ }
697
+
698
+ object_property_set_link(cpu, "memory", OBJECT(sysmem), &error_abort);
699
+ qdev_realize(DEVICE(cpu), NULL, &error_fatal);
700
+ object_unref(cpu);
701
+ }
702
+
703
+ memory_region_add_subregion(sysmem, vms->memmap[VMAPPLE_MEM].base,
704
+ machine->ram);
705
+
706
+ create_gic(vms, sysmem);
707
+ create_bdif(vms, sysmem);
708
+ create_pvpanic(vms, sysmem);
709
+ create_aes(vms, sysmem);
710
+ create_gfx(vms, sysmem);
711
+ create_uart(vms, VMAPPLE_UART, sysmem, serial_hd(0));
712
+ create_rtc(vms);
713
+ create_pcie(vms);
714
+
715
+ create_gpio_devices(vms, VMAPPLE_GPIO, sysmem);
716
+
717
+ vmapple_firmware_init(vms, sysmem);
718
+ create_cfg(vms, sysmem);
719
+
720
+ /* connect powerdown request */
721
+ vms->powerdown_notifier.notify = vmapple_powerdown_req;
722
+ qemu_register_powerdown_notifier(&vms->powerdown_notifier);
723
+
724
+ vms->bootinfo.ram_size = machine->ram_size;
725
+ vms->bootinfo.board_id = -1;
726
+ vms->bootinfo.loader_start = vms->memmap[VMAPPLE_MEM].base;
727
+ vms->bootinfo.skip_dtb_autoload = true;
728
+ vms->bootinfo.firmware_loaded = true;
729
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
730
+
731
+ qemu_register_reset(vmapple_reset, vms);
732
+}
733
+
734
+static CpuInstanceProperties
735
+vmapple_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
736
+{
737
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
738
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
739
+
740
+ assert(cpu_index < possible_cpus->len);
741
+ return possible_cpus->cpus[cpu_index].props;
742
+}
743
+
744
+
745
+static int64_t vmapple_get_default_cpu_node_id(const MachineState *ms, int idx)
746
+{
747
+ return idx % ms->numa_state->num_nodes;
748
+}
749
+
750
+static const CPUArchIdList *vmapple_possible_cpu_arch_ids(MachineState *ms)
751
+{
752
+ int n;
753
+ unsigned int max_cpus = ms->smp.max_cpus;
754
+
755
+ if (ms->possible_cpus) {
756
+ assert(ms->possible_cpus->len == max_cpus);
757
+ return ms->possible_cpus;
758
+ }
759
+
760
+ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
761
+ sizeof(CPUArchId) * max_cpus);
762
+ ms->possible_cpus->len = max_cpus;
763
+ for (n = 0; n < ms->possible_cpus->len; n++) {
764
+ ms->possible_cpus->cpus[n].type = ms->cpu_type;
765
+ ms->possible_cpus->cpus[n].arch_id =
766
+ arm_build_mp_affinity(n, GICV3_TARGETLIST_BITS);
767
+ ms->possible_cpus->cpus[n].props.has_thread_id = true;
768
+ ms->possible_cpus->cpus[n].props.thread_id = n;
769
+ }
770
+ return ms->possible_cpus;
771
+}
772
+
773
+static void vmapple_get_uuid(Object *obj, Visitor *v, const char *name,
774
+ void *opaque, Error **errp)
775
+{
776
+ VMAppleMachineState *vms = VMAPPLE_MACHINE(obj);
777
+ uint64_t value = be64_to_cpu(vms->uuid);
778
+
779
+ visit_type_uint64(v, name, &value, errp);
780
+}
781
+
782
+static void vmapple_set_uuid(Object *obj, Visitor *v, const char *name,
783
+ void *opaque, Error **errp)
784
+{
785
+ VMAppleMachineState *vms = VMAPPLE_MACHINE(obj);
786
+ Error *error = NULL;
787
+ uint64_t value;
788
+
789
+ visit_type_uint64(v, name, &value, &error);
790
+ if (error) {
791
+ error_propagate(errp, error);
792
+ return;
793
+ }
794
+
795
+ vms->uuid = cpu_to_be64(value);
796
+}
797
+
798
+static void vmapple_machine_class_init(ObjectClass *oc, void *data)
799
+{
800
+ MachineClass *mc = MACHINE_CLASS(oc);
801
+
802
+ mc->init = mach_vmapple_init;
803
+ mc->max_cpus = 32;
804
+ mc->block_default_type = IF_VIRTIO;
805
+ mc->no_cdrom = 1;
806
+ mc->pci_allow_0_address = true;
807
+ mc->minimum_page_bits = 12;
808
+ mc->possible_cpu_arch_ids = vmapple_possible_cpu_arch_ids;
809
+ mc->cpu_index_to_instance_props = vmapple_cpu_index_to_props;
810
+ if (hvf_enabled()) {
811
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("host");
812
+ } else {
813
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("max");
814
+ }
815
+ mc->get_default_cpu_node_id = vmapple_get_default_cpu_node_id;
816
+ mc->default_ram_id = "mach-vmapple.ram";
817
+
818
+ object_register_sugar_prop(TYPE_VIRTIO_PCI, "disable-legacy",
819
+ "on", true);
820
+
821
+ object_class_property_add(oc, "uuid", "uint64", vmapple_get_uuid,
822
+ vmapple_set_uuid, NULL, NULL);
823
+ object_class_property_set_description(oc, "uuid", "Machine UUID (SDOM)");
824
+}
825
+
826
+static void vmapple_instance_init(Object *obj)
827
+{
828
+ VMAppleMachineState *vms = VMAPPLE_MACHINE(obj);
829
+
830
+ vms->irqmap = irqmap;
831
+}
832
+
833
+static const TypeInfo vmapple_machine_info = {
834
+ .name = TYPE_VMAPPLE_MACHINE,
835
+ .parent = TYPE_MACHINE,
836
+ .abstract = true,
837
+ .instance_size = sizeof(VMAppleMachineState),
838
+ .class_size = sizeof(VMAppleMachineClass),
839
+ .class_init = vmapple_machine_class_init,
840
+ .instance_init = vmapple_instance_init,
841
+};
842
+
843
+static void machvmapple_machine_init(void)
844
+{
845
+ type_register_static(&vmapple_machine_info);
846
+}
847
+type_init(machvmapple_machine_init);
848
+
849
+static void vmapple_machine_8_1_options(MachineClass *mc)
850
+{
851
+}
852
+DEFINE_VMAPPLE_MACHINE_AS_LATEST(8, 1)
853
+
854
--
855
2.39.3 (Apple Git-145)
856
857
diff view generated by jsdifflib