From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103403; cv=none;
	d=zohomail.com; s=zohoarc;
	b=fVSbdcDyPWMMoZfrKYD3AZJMojk8mE9cbtUOp1sEY+YtOdX4/UCGhI9VWjKnlCkf3pir23NeMT/eMVGh9BLMsN0Or8hn1y1B3o4BMFl9ywn9gH74XwUlp5rknHQw1WefAwwkc55LeJjm/0h3/Y87Tpur6mMz5Ue260F/eXSp6RY=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103403;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=XmgJyWpCuCi2HoyxP/grcFhqMBy46PCyGsue2fZsSxs=;
	b=gAUdrgvObZF1PkIeQ7DQgPYdY2UXEQpQHmDpZ3jitBuF67U1Y0Ri5jytsTjzF9eFTr6wmEFgkV9zRmaFIs/WCO7inXipRq77yk/NROM9Gq26NtAiif787JVi0/0aJqZEDPG5jghV2OEpzKbHP0iD+VeZEfnkCLrjohGcXrdHWUA=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 17341034036181003.3857382482536;
 Fri, 13 Dec 2024 07:23:23 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Sg-0006M0-1C; Fri, 13 Dec 2024 10:20:14 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rp-0004cH-Vi
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:25 -0500
Received: from mail-ej1-x635.google.com ([2a00:1450:4864:20::635])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rg-0005Fz-3Y
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:21 -0500
Received: by mail-ej1-x635.google.com with SMTP id
 a640c23a62f3a-aab925654d9so21383966b.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:10 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.07
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:09 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103150;
 x=1734707950;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=XmgJyWpCuCi2HoyxP/grcFhqMBy46PCyGsue2fZsSxs=;
 b=iNTLhDTUTvBUkAVGSp8N8kgJvGrbBZwC2rX+bErHv8ETawvUy9vWaDRrgcp41wLJtM
 RMX1eSreMb/bC76sFtx+YLDtEHR9UKSt4VAxivDFG2CO7Nd6t+px4CCkz1eu6TzQiaVD
 +5kAEcfpkgclnwp9c1rpqwtVYow6tfsEqY/HueilaZNExO3RWeeITcK95J0tD45rRB6u
 rwD7LTT/cB2Gx7bBjSlAl4wpjufSQYpAHSY7oeYb5vFHneFUlnrs+GpiQdhx0vMPgK7Q
 8FhnHw+1Pe/JbL/VqqA3yrJUKwqhGQFnEmnZyP54Fse72xP52Bn5itnbg+yNaGQpXIVZ
 oHqQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103150; x=1734707950;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=XmgJyWpCuCi2HoyxP/grcFhqMBy46PCyGsue2fZsSxs=;
 b=ucwzGD9u78tz2FbSCRdfCAw2H+qV0HMDWPDE4k6P5rffrrlGkHPQ4b4cg1toEUguMn
 p634/wtr9cuwL8onNhNYulEOajMWJd5c0lMUFHIDqwmAXY6n29mg570ZqdKdICVDHNBk
 4HnhVJncGfgEzYxJSDUIlhHza+hnkBdx3pjgnwZFtwbYH6VcHOhYvxywr1cEwI1hzfqr
 CbYcpchQf+B8D6HTYU7xdONRB4xiE44OgYtf5qw87nIIdmZhINkW2ZF8rd8YyyZP9c9j
 Mstswdyh/1gk+modAVIU9FlYctfkUV+wK015XkvwJOHhwP6o9Gr3Y8tyWB0e54zlVm6M
 QFbg==
X-Gm-Message-State: AOJu0YwOOBsVS95aeYZ1O4walmTbLX1iZvI6n09rVhldAIlibDJVMQGR
 A/xCpBZPXFdSThKMyzZetXeSFyKr4uxIKnhaVTiUx4XXOrA4jpgUp4875isRlO6FlesrXYBuACS
 i4Q==
X-Gm-Gg: ASbGnculxpICUtj7iMM98v9wQTfvbk/WX1u+p2qi7r8mHulflotQYYDZeu43MyRnoVG
 wb+GWiZsfDqAiPgc14d+By2AYmQu9un/w8hu5zdg7JRxc4+zGxKEnxv/DhrAeFNW0kTLVkeNvzd
 TaeeFi5Px5bGL64ruLoob+hX0zwQQchw8vtY2gmVPbRSwdgUasvgYVXCX8PXGuGwe843bE1nw2t
 yI9zjcNYQFx/6kNdnU5cSnKctOJCnqn7+S+IZWqVqcot7dHI+OzJ7TfAXYM+qXSCQIqj6QWUgYp
 EbcW/+v1/R45OMCn6XB1k2/vYRgrRadp
X-Google-Smtp-Source: 
 AGHT+IE87ed/KYgzfuMDvj/kYyF+apybNVcnyAN7xOlS6enMJWm+XuMRb835wxqYQIw7R5y57LnOug==
X-Received: by 2002:a17:907:94cd:b0:aa6:8a1b:8b74 with SMTP id
 a640c23a62f3a-aab77ec424cmr271245666b.53.1734103149675;
 Fri, 13 Dec 2024 07:19:09 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu
Subject: [PATCH v14 01/15] ui & main loop: Redesign of system-specific main
 thread event handling
Date: Fri, 13 Dec 2024 16:18:07 +0100
Message-Id: <20241213151821.65748-18-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::635;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x635.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103405200116600
Content-Type: text/plain; charset="utf-8"

macOS's Cocoa event handling must be done on the initial (main) thread
of the process. Furthermore, if library or application code uses
libdispatch, the main dispatch queue must be handling events on the main
thread as well.

So far, this has affected Qemu in both the Cocoa and SDL UIs, although
in different ways: the Cocoa UI replaces the default qemu_main function
with one that spins Qemu's internal main event loop off onto a
background thread. SDL (which uses Cocoa internally) on the other hand
uses a polling approach within Qemu's main event loop. Events are
polled during the SDL UI's dpy_refresh callback, which happens to run
on the main thread by default.

As UIs are mutually exclusive, this works OK as long as nothing else
needs platform-native event handling. In the next patch, a new device is
introduced based on the ParavirtualizedGraphics.framework in macOS.
This uses libdispatch internally, and only works when events are being
handled on the main runloop. With the current system, it works when
using either the Cocoa or the SDL UI. However, it does not when running
headless. Moreover, any attempt to install a similar scheme to the
Cocoa UI's main thread replacement fails when combined with the SDL
UI.

This change tidies up main thread management to be more flexible.

 * The qemu_main global function pointer is a custom function for the
   main thread, and it may now be NULL. When it is, the main thread
   runs the main Qemu loop. This represents the traditional setup.
 * When non-null, spawning the main Qemu event loop on a separate
   thread is now done centrally rather than inside the Cocoa UI code.
 * For most platforms, qemu_main is indeed NULL by default, but on
   Darwin, it defaults to a function that runs the CFRunLoop.
 * The Cocoa UI sets qemu_main to a function which runs the
   NSApplication event handling runloop, as is usual for a Cocoa app.
 * The SDL UI overrides the qemu_main function to NULL, thus
   specifying that Qemu's main loop must run on the main
   thread.
 * The GTK UI also overrides the qemu_main function to NULL.
 * For other UIs, or in the absence of UIs, the platform's default
   behaviour is followed.

This means that on macOS, the platform's runloop events are always
handled, regardless of chosen UI. The new PV graphics device will
thus work in all configurations. There is no functional change on other
operating systems.

Implementing this via a global function pointer variable is a bit
ugly, but it's probably worth investigating the existing UI thread rule
violations in the SDL (e.g. #2537) and GTK+ back-ends. Fixing those
issues might precipitate requirements similar but not identical to those
of the Cocoa UI; hopefully we'll see some kind of pattern emerge, which
can then be used as a basis for an overhaul. (In fact, it may turn
out to be simplest to split the UI/native platform event thread from the
QEMU main event loop on all platforms, with any UI or even none at all.)

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v5:

 * Simplified the way of setting/clearing the main loop by going back
   to setting qemu_main directly, but narrowing the scope of what it
   needs to do, and it can now be NULL.

v6:

 * Folded function qemu_run_default_main_on_new_thread's code into
   main()
 * Removed whitespace changes left over on lines near code removed
   between v4 and v5

v9:

 * Set qemu_main to NULL for GTK UI as well.

v10:

 * Added comments clarifying the functionality and purpose of qemu_main.

v11:

 * Removed the qemu_main_fn typedef again.
 * Consolidation of main, qemu_default_main, and call_qemu_default_main
   so that the latter has been eliminated altogether.
 * Reinstated the #include <SDL.h> directive, added comment saying
   why it's needed.
 * Improved the comment on the qemu_main global variable.
 * Expanded the commit message.

v12:

 * More precise wording of code comments.

 include/qemu-main.h | 14 +++++++++++-
 system/main.c       | 37 +++++++++++++++++++++++++++----
 ui/cocoa.m          | 54 +++++++++++----------------------------------
 ui/gtk.c            |  4 ++++
 ui/sdl2.c           |  4 ++++
 5 files changed, 67 insertions(+), 46 deletions(-)

diff --git a/include/qemu-main.h b/include/qemu-main.h
index 940960a7dbc..2ee83bedff3 100644
--- a/include/qemu-main.h
+++ b/include/qemu-main.h
@@ -5,7 +5,19 @@
 #ifndef QEMU_MAIN_H
 #define QEMU_MAIN_H
=20
-int qemu_default_main(void);
+/*
+ * The function to run on the main (initial) thread of the process.
+ * NULL means QEMU's main event loop.
+ * When non-NULL, QEMU's main event loop will run on a purposely created
+ * thread, after which the provided function pointer will be invoked on
+ * the initial thread.
+ * This is useful on platforms which treat the main thread as special
+ * (macOS/Darwin) and/or require all UI API calls to occur from the main
+ * thread. Those platforms can initialise it to a specific function,
+ * while UI implementations may reset it to NULL during their init if they
+ * will handle system and UI events on the main thread via QEMU's own main
+ * event loop.
+ */
 extern int (*qemu_main)(void);
=20
 #endif /* QEMU_MAIN_H */
diff --git a/system/main.c b/system/main.c
index 9b91d21ea8c..668d0ecfe8c 100644
--- a/system/main.c
+++ b/system/main.c
@@ -24,26 +24,55 @@
=20
 #include "qemu/osdep.h"
 #include "qemu-main.h"
+#include "qemu/main-loop.h"
 #include "sysemu/sysemu.h"
=20
 #ifdef CONFIG_SDL
+/*
+ * SDL insists on wrapping the main() function with its own implementation=
 on
+ * some platforms; it does so via a macro that renames our main function, =
so
+ * <SDL.h> must be #included here even with no SDL code called from this f=
ile.
+ */
 #include <SDL.h>
 #endif
=20
-int qemu_default_main(void)
+#ifdef CONFIG_DARWIN
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+static void *qemu_default_main(void *opaque)
 {
     int status;
=20
+    bql_lock();
     status =3D qemu_main_loop();
     qemu_cleanup(status);
+    bql_unlock();
=20
-    return status;
+    exit(status);
 }
=20
-int (*qemu_main)(void) =3D qemu_default_main;
+int (*qemu_main)(void);
+
+#ifdef CONFIG_DARWIN
+static int os_darwin_cfrunloop_main(void)
+{
+    CFRunLoopRun();
+    g_assert_not_reached();
+}
+int (*qemu_main)(void) =3D os_darwin_cfrunloop_main;
+#endif
=20
 int main(int argc, char **argv)
 {
     qemu_init(argc, argv);
-    return qemu_main();
+    bql_unlock();
+    if (qemu_main) {
+        QemuThread main_loop_thread;
+        qemu_thread_create(&main_loop_thread, "qemu_main",
+                           qemu_default_main, NULL, QEMU_THREAD_DETACHED);
+        return qemu_main();
+    } else {
+        qemu_default_main(NULL);
+    }
 }
diff --git a/ui/cocoa.m b/ui/cocoa.m
index dd88115dc6f..0a9ad824aa5 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -73,6 +73,8 @@
     int height;
 } QEMUScreen;
=20
+@class QemuCocoaPasteboardTypeOwner;
+
 static void cocoa_update(DisplayChangeListener *dcl,
                          int x, int y, int w, int h);
=20
@@ -107,6 +109,7 @@ static void cocoa_switch(DisplayChangeListener *dcl,
 static NSInteger cbchangecount =3D -1;
 static QemuClipboardInfo *cbinfo;
 static QemuEvent cbevent;
+static QemuCocoaPasteboardTypeOwner *cbowner;
=20
 // Utility functions to run specified code block with the BQL held
 typedef void (^CodeBlock)(void);
@@ -1326,8 +1329,10 @@ - (void) dealloc
 {
     COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
=20
-    if (cocoaView)
-        [cocoaView release];
+    [cocoaView release];
+    [cbowner release];
+    cbowner =3D nil;
+
     [super dealloc];
 }
=20
@@ -1943,8 +1948,6 @@ - (void)pasteboard:(NSPasteboard *)sender provideData=
ForType:(NSPasteboardType)t
=20
 @end
=20
-static QemuCocoaPasteboardTypeOwner *cbowner;
-
 static void cocoa_clipboard_notify(Notifier *notifier, void *data);
 static void cocoa_clipboard_request(QemuClipboardInfo *info,
                                     QemuClipboardType type);
@@ -2007,43 +2010,8 @@ static void cocoa_clipboard_request(QemuClipboardInf=
o *info,
     }
 }
=20
-/*
- * The startup process for the OSX/Cocoa UI is complicated, because
- * OSX insists that the UI runs on the initial main thread, and so we
- * need to start a second thread which runs the qemu_default_main():
- * in main():
- *  in cocoa_display_init():
- *   assign cocoa_main to qemu_main
- *   create application, menus, etc
- *  in cocoa_main():
- *   create qemu-main thread
- *   enter OSX run loop
- */
-
-static void *call_qemu_main(void *opaque)
-{
-    int status;
-
-    COCOA_DEBUG("Second thread: calling qemu_default_main()\n");
-    bql_lock();
-    status =3D qemu_default_main();
-    bql_unlock();
-    COCOA_DEBUG("Second thread: qemu_default_main() returned, exiting\n");
-    [cbowner release];
-    exit(status);
-}
-
 static int cocoa_main(void)
 {
-    QemuThread thread;
-
-    COCOA_DEBUG("Entered %s()\n", __func__);
-
-    bql_unlock();
-    qemu_thread_create(&thread, "qemu_main", call_qemu_main,
-                       NULL, QEMU_THREAD_DETACHED);
-
-    // Start the main event loop
     COCOA_DEBUG("Main thread: entering OSX run loop\n");
     [NSApp run];
     COCOA_DEBUG("Main thread: left OSX run loop, which should never happen=
\n");
@@ -2125,8 +2093,6 @@ static void cocoa_display_init(DisplayState *ds, Disp=
layOptions *opts)
=20
     COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
=20
-    qemu_main =3D cocoa_main;
-
     // Pull this console process up to being a fully-fledged graphical
     // app with a menubar and Dock icon
     ProcessSerialNumber psn =3D { 0, kCurrentProcess };
@@ -2190,6 +2156,12 @@ static void cocoa_display_init(DisplayState *ds, Dis=
playOptions *opts)
     qemu_clipboard_peer_register(&cbpeer);
=20
     [pool release];
+
+    /*
+     * The Cocoa UI will run the NSApplication runloop on the main thread
+     * rather than the default Core Foundation one.
+     */
+    qemu_main =3D cocoa_main;
 }
=20
 static QemuDisplay qemu_display_cocoa =3D {
diff --git a/ui/gtk.c b/ui/gtk.c
index bf9d3dd679a..c8dcd95350c 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -38,6 +38,7 @@
 #include "qemu/cutils.h"
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
+#include "qemu-main.h"
=20
 #include "ui/console.h"
 #include "ui/gtk.h"
@@ -2485,6 +2486,9 @@ static void gtk_display_init(DisplayState *ds, Displa=
yOptions *opts)
 #ifdef CONFIG_GTK_CLIPBOARD
     gd_clipboard_init(s);
 #endif /* CONFIG_GTK_CLIPBOARD */
+
+    /* GTK's event polling must happen on the main thread. */
+    qemu_main =3D NULL;
 }
=20
 static void early_gtk_display_init(DisplayOptions *opts)
diff --git a/ui/sdl2.c b/ui/sdl2.c
index bd4f5a9da14..44ab2762262 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -34,6 +34,7 @@
 #include "sysemu/sysemu.h"
 #include "ui/win32-kbd-hook.h"
 #include "qemu/log.h"
+#include "qemu-main.h"
=20
 static int sdl2_num_outputs;
 static struct sdl2_console *sdl2_console;
@@ -965,6 +966,9 @@ static void sdl2_display_init(DisplayState *ds, Display=
Options *o)
     }
=20
     atexit(sdl_cleanup);
+
+    /* SDL's event polling (in dpy_refresh) must happen on the main thread=
. */
+    qemu_main =3D NULL;
 }
=20
 static QemuDisplay qemu_display_sdl2 =3D {
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103249; cv=none;
	d=zohomail.com; s=zohoarc;
	b=KKMk89o32QSeNQFh1cAFVMji74PQ6vyyCIRjaAa6EbWYprOKufesvMKa/6Noi8l2d2On9x0cfCoaRSJw5U8lXz1IpzkuoVXyqphB8DzBHubDWcy4ZoYPzt+g3AZD9Olwt16ydIuiFCHmP2jQ/GeBvp6IRk56JwpfCy72JViO/l4=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103249;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=XmgJyWpCuCi2HoyxP/grcFhqMBy46PCyGsue2fZsSxs=;
	b=Z2lZUeken5iI85WOhiafiCBnvHNy6oQrC3fz+4bB/Tw7+scIYnbzdBfndNUwROELgm2vjQjXFS9WUPAmW+mbsZnQFHyFCakUin7qrG4bn+mdSjlhnplm3h8RDIGEt0/WTST2jzvj9eCDhY2y5cR8zUIdYRWCtbzPHxw78a/TPPU=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103249656854.7811730352515;
 Fri, 13 Dec 2024 07:20:49 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7RL-0004Mc-9j; Fri, 13 Dec 2024 10:18:51 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RH-0004KN-U2
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:47 -0500
Received: from mail-ej1-x629.google.com ([2a00:1450:4864:20::629])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RB-00053p-85
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:47 -0500
Received: by mail-ej1-x629.google.com with SMTP id
 a640c23a62f3a-aa69077b93fso275511366b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:40 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.37
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:38 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103119;
 x=1734707919;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=XmgJyWpCuCi2HoyxP/grcFhqMBy46PCyGsue2fZsSxs=;
 b=QtQCRVIrp/jN4qr9FIlBZboghUCEn/XJkBc2q48dpqUNPznZBG7FrY0/ajl4cDmWvO
 p7RDnC+oDc7dTYTm5b+SNns/axXpKptQXyU6sEf4QFiWR8qB7h/08jRAzhZaQQby/zWc
 rgE2CJUnF5IuALQAL20ptiLBQ4KmiNRfMguzwHkoGpbzOE+pVBxu54xIsdKi26rJqVvP
 eiL2eRY9vfq2uC0HWahAS60Cq1Itjqa89RYm3qqiNds3eWw4sPvwfjO8p0TAtl0SI/CD
 2mvILSZbfdRYS8FuqTEytJPXNtZ+VPxi+43SxR6WRObLeo7DDFwtBDylQzqDzFNQzeME
 KkQg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103119; x=1734707919;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=XmgJyWpCuCi2HoyxP/grcFhqMBy46PCyGsue2fZsSxs=;
 b=SK2nTw8ZLEtAjeCnc/vZ6qiMy0kBzhWPckdkUY0JXa5OyzRJzXspE/8BFcTPhEmbaa
 SMGXfNMNjfv+GyKKe7dbPAGrA0rYwsmOtKV7DezS4dPLkmrJx0Da9XvBUSRAvYVkTMXN
 IJ3S9dDb39I/k4TqMa2vEafTSclzI0L5rnq8yaxKEDz7SMLjV2o2HqJQb2bgaCd4YqZY
 1VfTpgjht661akItzJ7lfJX6IeOd+B8udKTMAPn7cQCuUaAOXoUfU7KddpwmItB2Pfmi
 Kat6WTNoWlkbWmkh5ZkcHoHqsjiPy4fJSo46YXfFhgWwI1QzarlbY2nCOhKNyWvQppQ1
 RAWw==
X-Gm-Message-State: AOJu0YxhK4cMQgf32qimMPem1DRbP+0vYjNeEEPvDxw8x9gW6dnOUQHH
 ShAvtpeaVEyOOYY8EjJD9+y/xfWGmbYT5ot2005MuQZBP/+SbPHd32RacafzlKrxwms1mWg866g
 nSg==
X-Gm-Gg: ASbGnctVPe2PwmZuLU+B6OhGoO2Ee+k6Mj/H7aYgzqx76ZKvy5q4f5Q0atOpev2LkdI
 PooJZLR1L5EMP2g78kIlpwrKoSJ0W+M/9PoIBrsWXdY/42x4+IMh+5Ejmkgc92gLwyQB56anNx5
 rhy59m4bibjk32y4TqPlnacgnxOosEUGsNx6fyTGk/Tp+2S7AWyLkK866NYqwlFNu3KnJPUJPRO
 NRu7CtFmTfHyGqUmHfpVt/yPsvhYwdPukupuA4e9CNWU/COjpoXJT6UI9f9cYJZFXAGPr2zJ5Jq
 fv7/o8dh6sD50hzYDP/LZ+oLfE7F0Lz5
X-Google-Smtp-Source: 
 AGHT+IEGOL600bCjkghFWe6DjI9dqptArMLUpVpUrNKLLwuOwEZO0GVhvK797SnEDD8bk8xEtxfMhg==
X-Received: by 2002:a17:907:3dab:b0:aa6:9372:cac7 with SMTP id
 a640c23a62f3a-aab779b1333mr390391566b.31.1734103118960;
 Fri, 13 Dec 2024 07:18:38 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu
Subject: [PATCH v13 01/15] ui & main loop: Redesign of system-specific main
 thread event handling
Date: Fri, 13 Dec 2024 16:17:51 +0100
Message-Id: <20241213151821.65748-2-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::629;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x629.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103250900116600
Content-Type: text/plain; charset="utf-8"

macOS's Cocoa event handling must be done on the initial (main) thread
of the process. Furthermore, if library or application code uses
libdispatch, the main dispatch queue must be handling events on the main
thread as well.

So far, this has affected Qemu in both the Cocoa and SDL UIs, although
in different ways: the Cocoa UI replaces the default qemu_main function
with one that spins Qemu's internal main event loop off onto a
background thread. SDL (which uses Cocoa internally) on the other hand
uses a polling approach within Qemu's main event loop. Events are
polled during the SDL UI's dpy_refresh callback, which happens to run
on the main thread by default.

As UIs are mutually exclusive, this works OK as long as nothing else
needs platform-native event handling. In the next patch, a new device is
introduced based on the ParavirtualizedGraphics.framework in macOS.
This uses libdispatch internally, and only works when events are being
handled on the main runloop. With the current system, it works when
using either the Cocoa or the SDL UI. However, it does not when running
headless. Moreover, any attempt to install a similar scheme to the
Cocoa UI's main thread replacement fails when combined with the SDL
UI.

This change tidies up main thread management to be more flexible.

 * The qemu_main global function pointer is a custom function for the
   main thread, and it may now be NULL. When it is, the main thread
   runs the main Qemu loop. This represents the traditional setup.
 * When non-null, spawning the main Qemu event loop on a separate
   thread is now done centrally rather than inside the Cocoa UI code.
 * For most platforms, qemu_main is indeed NULL by default, but on
   Darwin, it defaults to a function that runs the CFRunLoop.
 * The Cocoa UI sets qemu_main to a function which runs the
   NSApplication event handling runloop, as is usual for a Cocoa app.
 * The SDL UI overrides the qemu_main function to NULL, thus
   specifying that Qemu's main loop must run on the main
   thread.
 * The GTK UI also overrides the qemu_main function to NULL.
 * For other UIs, or in the absence of UIs, the platform's default
   behaviour is followed.

This means that on macOS, the platform's runloop events are always
handled, regardless of chosen UI. The new PV graphics device will
thus work in all configurations. There is no functional change on other
operating systems.

Implementing this via a global function pointer variable is a bit
ugly, but it's probably worth investigating the existing UI thread rule
violations in the SDL (e.g. #2537) and GTK+ back-ends. Fixing those
issues might precipitate requirements similar but not identical to those
of the Cocoa UI; hopefully we'll see some kind of pattern emerge, which
can then be used as a basis for an overhaul. (In fact, it may turn
out to be simplest to split the UI/native platform event thread from the
QEMU main event loop on all platforms, with any UI or even none at all.)

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v5:

 * Simplified the way of setting/clearing the main loop by going back
   to setting qemu_main directly, but narrowing the scope of what it
   needs to do, and it can now be NULL.

v6:

 * Folded function qemu_run_default_main_on_new_thread's code into
   main()
 * Removed whitespace changes left over on lines near code removed
   between v4 and v5

v9:

 * Set qemu_main to NULL for GTK UI as well.

v10:

 * Added comments clarifying the functionality and purpose of qemu_main.

v11:

 * Removed the qemu_main_fn typedef again.
 * Consolidation of main, qemu_default_main, and call_qemu_default_main
   so that the latter has been eliminated altogether.
 * Reinstated the #include <SDL.h> directive, added comment saying
   why it's needed.
 * Improved the comment on the qemu_main global variable.
 * Expanded the commit message.

v12:

 * More precise wording of code comments.

 include/qemu-main.h | 14 +++++++++++-
 system/main.c       | 37 +++++++++++++++++++++++++++----
 ui/cocoa.m          | 54 +++++++++++----------------------------------
 ui/gtk.c            |  4 ++++
 ui/sdl2.c           |  4 ++++
 5 files changed, 67 insertions(+), 46 deletions(-)

diff --git a/include/qemu-main.h b/include/qemu-main.h
index 940960a7dbc..2ee83bedff3 100644
--- a/include/qemu-main.h
+++ b/include/qemu-main.h
@@ -5,7 +5,19 @@
 #ifndef QEMU_MAIN_H
 #define QEMU_MAIN_H
=20
-int qemu_default_main(void);
+/*
+ * The function to run on the main (initial) thread of the process.
+ * NULL means QEMU's main event loop.
+ * When non-NULL, QEMU's main event loop will run on a purposely created
+ * thread, after which the provided function pointer will be invoked on
+ * the initial thread.
+ * This is useful on platforms which treat the main thread as special
+ * (macOS/Darwin) and/or require all UI API calls to occur from the main
+ * thread. Those platforms can initialise it to a specific function,
+ * while UI implementations may reset it to NULL during their init if they
+ * will handle system and UI events on the main thread via QEMU's own main
+ * event loop.
+ */
 extern int (*qemu_main)(void);
=20
 #endif /* QEMU_MAIN_H */
diff --git a/system/main.c b/system/main.c
index 9b91d21ea8c..668d0ecfe8c 100644
--- a/system/main.c
+++ b/system/main.c
@@ -24,26 +24,55 @@
=20
 #include "qemu/osdep.h"
 #include "qemu-main.h"
+#include "qemu/main-loop.h"
 #include "sysemu/sysemu.h"
=20
 #ifdef CONFIG_SDL
+/*
+ * SDL insists on wrapping the main() function with its own implementation=
 on
+ * some platforms; it does so via a macro that renames our main function, =
so
+ * <SDL.h> must be #included here even with no SDL code called from this f=
ile.
+ */
 #include <SDL.h>
 #endif
=20
-int qemu_default_main(void)
+#ifdef CONFIG_DARWIN
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+static void *qemu_default_main(void *opaque)
 {
     int status;
=20
+    bql_lock();
     status =3D qemu_main_loop();
     qemu_cleanup(status);
+    bql_unlock();
=20
-    return status;
+    exit(status);
 }
=20
-int (*qemu_main)(void) =3D qemu_default_main;
+int (*qemu_main)(void);
+
+#ifdef CONFIG_DARWIN
+static int os_darwin_cfrunloop_main(void)
+{
+    CFRunLoopRun();
+    g_assert_not_reached();
+}
+int (*qemu_main)(void) =3D os_darwin_cfrunloop_main;
+#endif
=20
 int main(int argc, char **argv)
 {
     qemu_init(argc, argv);
-    return qemu_main();
+    bql_unlock();
+    if (qemu_main) {
+        QemuThread main_loop_thread;
+        qemu_thread_create(&main_loop_thread, "qemu_main",
+                           qemu_default_main, NULL, QEMU_THREAD_DETACHED);
+        return qemu_main();
+    } else {
+        qemu_default_main(NULL);
+    }
 }
diff --git a/ui/cocoa.m b/ui/cocoa.m
index dd88115dc6f..0a9ad824aa5 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -73,6 +73,8 @@
     int height;
 } QEMUScreen;
=20
+@class QemuCocoaPasteboardTypeOwner;
+
 static void cocoa_update(DisplayChangeListener *dcl,
                          int x, int y, int w, int h);
=20
@@ -107,6 +109,7 @@ static void cocoa_switch(DisplayChangeListener *dcl,
 static NSInteger cbchangecount =3D -1;
 static QemuClipboardInfo *cbinfo;
 static QemuEvent cbevent;
+static QemuCocoaPasteboardTypeOwner *cbowner;
=20
 // Utility functions to run specified code block with the BQL held
 typedef void (^CodeBlock)(void);
@@ -1326,8 +1329,10 @@ - (void) dealloc
 {
     COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
=20
-    if (cocoaView)
-        [cocoaView release];
+    [cocoaView release];
+    [cbowner release];
+    cbowner =3D nil;
+
     [super dealloc];
 }
=20
@@ -1943,8 +1948,6 @@ - (void)pasteboard:(NSPasteboard *)sender provideData=
ForType:(NSPasteboardType)t
=20
 @end
=20
-static QemuCocoaPasteboardTypeOwner *cbowner;
-
 static void cocoa_clipboard_notify(Notifier *notifier, void *data);
 static void cocoa_clipboard_request(QemuClipboardInfo *info,
                                     QemuClipboardType type);
@@ -2007,43 +2010,8 @@ static void cocoa_clipboard_request(QemuClipboardInf=
o *info,
     }
 }
=20
-/*
- * The startup process for the OSX/Cocoa UI is complicated, because
- * OSX insists that the UI runs on the initial main thread, and so we
- * need to start a second thread which runs the qemu_default_main():
- * in main():
- *  in cocoa_display_init():
- *   assign cocoa_main to qemu_main
- *   create application, menus, etc
- *  in cocoa_main():
- *   create qemu-main thread
- *   enter OSX run loop
- */
-
-static void *call_qemu_main(void *opaque)
-{
-    int status;
-
-    COCOA_DEBUG("Second thread: calling qemu_default_main()\n");
-    bql_lock();
-    status =3D qemu_default_main();
-    bql_unlock();
-    COCOA_DEBUG("Second thread: qemu_default_main() returned, exiting\n");
-    [cbowner release];
-    exit(status);
-}
-
 static int cocoa_main(void)
 {
-    QemuThread thread;
-
-    COCOA_DEBUG("Entered %s()\n", __func__);
-
-    bql_unlock();
-    qemu_thread_create(&thread, "qemu_main", call_qemu_main,
-                       NULL, QEMU_THREAD_DETACHED);
-
-    // Start the main event loop
     COCOA_DEBUG("Main thread: entering OSX run loop\n");
     [NSApp run];
     COCOA_DEBUG("Main thread: left OSX run loop, which should never happen=
\n");
@@ -2125,8 +2093,6 @@ static void cocoa_display_init(DisplayState *ds, Disp=
layOptions *opts)
=20
     COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
=20
-    qemu_main =3D cocoa_main;
-
     // Pull this console process up to being a fully-fledged graphical
     // app with a menubar and Dock icon
     ProcessSerialNumber psn =3D { 0, kCurrentProcess };
@@ -2190,6 +2156,12 @@ static void cocoa_display_init(DisplayState *ds, Dis=
playOptions *opts)
     qemu_clipboard_peer_register(&cbpeer);
=20
     [pool release];
+
+    /*
+     * The Cocoa UI will run the NSApplication runloop on the main thread
+     * rather than the default Core Foundation one.
+     */
+    qemu_main =3D cocoa_main;
 }
=20
 static QemuDisplay qemu_display_cocoa =3D {
diff --git a/ui/gtk.c b/ui/gtk.c
index bf9d3dd679a..c8dcd95350c 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -38,6 +38,7 @@
 #include "qemu/cutils.h"
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
+#include "qemu-main.h"
=20
 #include "ui/console.h"
 #include "ui/gtk.h"
@@ -2485,6 +2486,9 @@ static void gtk_display_init(DisplayState *ds, Displa=
yOptions *opts)
 #ifdef CONFIG_GTK_CLIPBOARD
     gd_clipboard_init(s);
 #endif /* CONFIG_GTK_CLIPBOARD */
+
+    /* GTK's event polling must happen on the main thread. */
+    qemu_main =3D NULL;
 }
=20
 static void early_gtk_display_init(DisplayOptions *opts)
diff --git a/ui/sdl2.c b/ui/sdl2.c
index bd4f5a9da14..44ab2762262 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -34,6 +34,7 @@
 #include "sysemu/sysemu.h"
 #include "ui/win32-kbd-hook.h"
 #include "qemu/log.h"
+#include "qemu-main.h"
=20
 static int sdl2_num_outputs;
 static struct sdl2_console *sdl2_console;
@@ -965,6 +966,9 @@ static void sdl2_display_init(DisplayState *ds, Display=
Options *o)
     }
=20
     atexit(sdl_cleanup);
+
+    /* SDL's event polling (in dpy_refresh) must happen on the main thread=
. */
+    qemu_main =3D NULL;
 }
=20
 static QemuDisplay qemu_display_sdl2 =3D {
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103752; cv=none;
	d=zohomail.com; s=zohoarc;
	b=LjLXqhjc1kCdLnODmzXDMk7mHP7rJanuDpt1gBYwxq8NjqW/pcQfvF6HgxpOyrDtGeLX2hPqsd9G8TnZTfgVM6tQjIAi1czHSbKo9I7FeiGCyi/fmmW7JA1l7mHwPWMHGVyG6iqTkwtyUTtrls0TuKdLd5BrEdeWnuyXAVBk5rI=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103752;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=zDE6dZztI5U2peYmtLQlBjA/pUyMd6cxpgOj52p0H2A=;
	b=X3mP+iVBvrhpjx3JiYOjjDPPk7elQsq9kKE701KEWdl+LU350UR8UMoOwtYgIyJNMbotShMokuWsV7rk92Mj65MkqP9PBJ7KWbFTNOKM5zEtJZYFtjtWsW8uM5rXYQ6CacCO3V01MGJJiyvFOstgxahXmjJQEsOGOLEtQ7H1Pcs=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103752120938.6685035519996;
 Fri, 13 Dec 2024 07:29:12 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SX-0005hq-4T; Fri, 13 Dec 2024 10:20:05 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rz-0004fc-St
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:33 -0500
Received: from mail-ej1-x62c.google.com ([2a00:1450:4864:20::62c])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rh-0005HV-KN
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:26 -0500
Received: by mail-ej1-x62c.google.com with SMTP id
 a640c23a62f3a-aa689a37dd4so349465866b.3
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:13 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.09
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:11 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103152;
 x=1734707952;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=zDE6dZztI5U2peYmtLQlBjA/pUyMd6cxpgOj52p0H2A=;
 b=lvCVforcDyMUpiixG/ANTtaxeG6MTkltQrAFvIOv7LPpRyzpgN7uyH/QQba/TaAO/G
 1RFkplniNiqqr1fUCMKAbwofJtWddUpcsvzd4S+3dUi+0aXIu+IjHmYt76clF3/vlEQo
 dIOkwuOFYF0JvN6t4PdgIdnPXMg6DwjZgrPyQg18JHxc2VWB23HEgeKJA6wRhKQNK9uY
 XoMrylurMmzlGaXyMXN/ofyD96sO71kO8KYcjtn0Dd6K9LGeBztyUNjt3BPprTp/c2lF
 kBrogiryehsFHBSBeVFW0HlIu8ZVtcfwyk+16RT5JBljgReRj7OLeDC1mrwu0wq50sWb
 1yww==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103152; x=1734707952;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=zDE6dZztI5U2peYmtLQlBjA/pUyMd6cxpgOj52p0H2A=;
 b=WPQKZTFu8rA3YDpzHDlHsUAEVpVniAX7c1na23z8I6Yd0Tg+eNZ963cPEv5Hsgd2TL
 7+ngohaL+BWDrKjBxIiopfS6sGxip7Cmi2QYSzNfZlcUiOGFVtG7N1rwleAOQwwE+/zW
 NUTm6ZKRE4LAEYHSltyBXUBVcKEB7luxgBkTkDjKnO/7kZY6JF6mb4+G/0JIYLevz/py
 jAcdERT4aP4auenIHYLLYt7m1hvtnu82V2Jqe0ojLhM+ZI5v6oK8S37Ub3938rY73773
 u0YkMelQZgxs3mLej11v0EdQq4zqfdClFLG2fuMF4vSZW0QcvaVfm327CwvZm0nMwKwT
 3yGw==
X-Gm-Message-State: AOJu0YwkHf+vZ/ZtVe98gR5RgIG8c5dIgKbyYGlZs9CgC/UJk1jwmNjf
 sHeSO/wLvibHbs3sELDGnXr5ULWtA+e96aDK/YvLVsCSrEUNMHlibSbFXvJHc+zE3p/KDmJ/RVg
 bxA==
X-Gm-Gg: ASbGnctJT10hKWpaH+sHGMbDVWZfV1jmZRkiy1D97ic+Oavz0mCb87j9VPYrvjIHl9M
 AZnYE4wdukncvun4ioqOTeKpVYN06cXuKc++GBF1zk03rzY5lszmlq4EBtazlUjpnBWOKeK732b
 HZY9EiJhZhFJmneRZfuu/gqJxkjrzCKzTnxS2FFHnlgNmQHwlxkKDrLH6pdjTnabol0xE13SIj2
 9kdBWoBTLbNPAfg2eU+DWkamCO1PseodwoV6mbDTrkxpodgMX7aNo6FdvZzemlephs7/sAKEDNW
 gWbzhLhSGOdW3KD9hKpFRuYhOMy/Rx1N
X-Google-Smtp-Source: 
 AGHT+IEaZYiGslU9eBjjm/Kaw3iolyY5TT2AfpQpbWulE/S6QOFxeywS+4uiJT+JA+12AfTz2UrgBg==
X-Received: by 2002:a17:907:94c9:b0:aa6:8186:5cab with SMTP id
 a640c23a62f3a-aab77eb0050mr275671566b.54.1734103151683;
 Fri, 13 Dec 2024 07:19:11 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 02/15] hw/display/apple-gfx: Introduce
 ParavirtualizedGraphics.Framework support
Date: Fri, 13 Dec 2024 16:18:08 +0100
Message-Id: <20241213151821.65748-19-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62c;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62c.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103752912116600

MacOS provides a framework (library) that allows any vmm to implement a
paravirtualized 3d graphics passthrough to the host metal stack called
ParavirtualizedGraphics.Framework (PVG). The library abstracts away
almost every aspect of the paravirtualized device model and only provides
and receives callbacks on MMIO access as well as to share memory address
space between the VM and PVG.

This patch implements a QEMU device that drives PVG for the VMApple
variant of it.

Signed-off-by: Alexander Graf <graf@amazon.com>
Co-authored-by: Alexander Graf <graf@amazon.com>

Subsequent changes:

 * Cherry-pick/rebase conflict fixes, API use updates.
 * Moved from hw/vmapple/ (useful outside that machine type)
 * Overhaul of threading model, many thread safety improvements.
 * Asynchronous rendering.
 * Memory and object lifetime fixes.
 * Refactoring to split generic and (vmapple) MMIO variant specific
   code.

Implementation wise, most of the complexity lies in the differing threading
models of ParavirtualizedGraphics.framework, which uses libdispatch and
internal locks, versus QEMU, which heavily uses the BQL, especially during
memory-mapped device I/O. Great care has therefore been taken to prevent
deadlocks by never calling into PVG methods while holding the BQL, and
similarly never acquiring the BQL in a callback from PVG. Different strateg=
ies
have been used (libdispatch, blocking and non-blocking BHs, RCU, etc.)
depending on the specific requirements at each framework entry and exit poi=
nt.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v2:

 * Cherry-pick/rebase conflict fixes
 * BQL function renaming
 * Moved from hw/vmapple/ (useful outside that machine type)
 * Code review comments: Switched to DEFINE_TYPES macro & little endian
   MMIO.
 * Removed some dead/superfluous code
 * Mad set_mode thread & memory safe
 * Added migration blocker due to lack of (de-)serialisation.
 * Fixes to ObjC refcounting and autorelease pool usage.
 * Fixed ObjC new/init misuse
 * Switched to ObjC category extension for private property.
 * Simplified task memory mapping and made it thread safe.
 * Refactoring to split generic and vmapple MMIO variant specific
   code.
 * Switched to asynchronous MMIO writes on x86-64
 * Rendering and graphics update are now done asynchronously
 * Fixed cursor handling
 * Coding convention fixes
 * Removed software cursor compositing

v3:

 * Rebased on latest upstream, fixed breakages including switching to Reset=
table methods.
 * Squashed patches dealing with dGPUs, MMIO area size, and GPU picking.
 * Allow re-entrant MMIO; this simplifies the code and solves the divergence
   between x86-64 and arm64 variants.

v4:

 * Renamed '-vmapple' device variant to '-mmio'
 * MMIO device type now requires aarch64 host and guest
 * Complete overhaul of the glue code for making Qemu's and
   ParavirtualizedGraphics.framework's threading and synchronisation models
   work together. Calls into PVG are from dispatch queues while the
   BQL-holding initiating thread processes AIO context events; callbacks fr=
om
   PVG are scheduled as BHs on the BQL/main AIO context, awaiting completion
   where necessary.
 * Guest frame rendering state is covered by the BQL, with only the PVG cal=
ls
   outside the lock, and serialised on the named render_queue.
 * Simplified logic for dropping frames in-flight during mode changes, fixed
   bug in pending frames logic.
 * Addressed smaller code review notes such as: function naming, object type
   declarations, type names/declarations/casts, code formatting, #include
   order, over-cautious ObjC retain/release, what goes in init vs realize,
   etc.

v5:

 * Smaller non-functional fixes in response to review comments, such as usi=
ng
   NULL for the AIO_WAIT_WHILE context argument, type name formatting,
   deleting leftover debug code, logging improvements, state struct field
   order and documentation improvements, etc.
 * Instead of a single condition variable for all synchronous BH job types,
   there is now one for each callback block. This reduces the number
   of threads being awoken unnecessarily to near zero.
 * MMIO device variant: Unified the BH job for raising interrupts.
 * Use DMA APIs for PVG framework's guest memory read requests.
 * Thread safety improvements: ensure mutable AppleGFXState fields are not
   accessed outside the appropriate lock. Added dedicated mutex for the task
   list.
 * Retain references to MemoryRegions for which there exist mappings in each
   PGTask, and for IOSurface mappings.

v6:

 * Switched PGTask_s's' mapped_regions from GPtrArray to GArray
 * Allow DisplaySurface to manage its own vram now that texture -> vram copy
   occurs under BQL.
 * Memory mapping operations now use RCU_READ_LOCK_GUARD() where possible
   instead of a heavy-weight BH job to acquire the BQL.
 * Changed PVG cursor and mode setting callbacks to kick off BHs instead of
   libdispatch tasks which then locked the BQL explicitly.
 * The single remaining callback which must wait for a BH to complete now
   creates an ephemeral QemuSemaphore to await completion.
 * Re-removed tracking of mapped surface manager memory regions. Just look =
up
   and ref/unref the memory regions in the map/unmap callbacks.
 * Re-ordered functions in apple-gfx.m to group them by area of functionali=
ty.
 * Improved comments and tweaked some names.

v7:

 * Use g_ptr_array_find() helper function
 * Error handling coding style tweak

v8:

 * Renamed apple_gfx_host_address_for_gpa_range() to
   apple_gfx_host_ptr_for_gpa_range(), and made it return a void* instead of
   uintptr_t. Fixed up callers and related code.
 * Some adjustments to types used.
 * Variable naming tweaks for better clarity.
 * Fixed leak in unlikely realize error case.
 * Fixed typo in unmap call.
 * Don't bother with dummy argument for g_ptr_array_find(), NULL works too.

v9:

 * Pass device pointer to graphic_console_init().
 * Slightly re-ordered initialisation code.
 * Simplified error handling during realize().
 * Simplified code without functional changes, adjusted code & comment
   formatting.

v10:

 * Reworked the way frame rendering code is threaded to use BHs for sections
   requiring BQL.
 * Fix for ./configure error on non-macOS platforms.
 * Code formatting tweaks.

v11:

 * Generate unique display serial number for each apple-gfx device instance.
 * Dropped redundant local variable initialisation.

v12:

 * Removed 2 redundant variable initialisations.
 * Removed dedicated rendering dispatch_queue, use global queue instead.
 * Fixed an object leak regression introduced in v10. Solved by placing
   @autoreleasepool blocks around the relevant Objective-C code in the BH
   functions replacing the dispatch_async tasks. (dispatch_async implicitly
   cleaned up autoreleased objects.)
 * Fixed missing retain/release of command buffers when handing off to a
   non-BH thread. (Problem masked at runtime by above leak.)
 * Better handling of render command encoding errors.
 * Re-arranged positions of static variables in the file.

 hw/display/Kconfig          |   9 +
 hw/display/apple-gfx-mmio.m | 281 +++++++++++++
 hw/display/apple-gfx.h      |  66 +++
 hw/display/apple-gfx.m      | 783 ++++++++++++++++++++++++++++++++++++
 hw/display/meson.build      |   6 +
 hw/display/trace-events     |  28 ++
 meson.build                 |   4 +
 7 files changed, 1177 insertions(+)
 create mode 100644 hw/display/apple-gfx-mmio.m
 create mode 100644 hw/display/apple-gfx.h
 create mode 100644 hw/display/apple-gfx.m

diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index 2250c740078..6a9b7b19ada 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -140,3 +140,12 @@ config XLNX_DISPLAYPORT
=20
 config DM163
     bool
+
+config MAC_PVG
+    bool
+    default y
+
+config MAC_PVG_MMIO
+    bool
+    depends on MAC_PVG && AARCH64
+
diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m
new file mode 100644
index 00000000000..1a46ff48b75
--- /dev/null
+++ b/hw/display/apple-gfx-mmio.m
@@ -0,0 +1,281 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device, MMIO (arm64) varia=
nt
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS prov=
ides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU as an MMIO-ba=
sed
+ * system device for macOS on arm64 VMs.
+ */
+
+#include "qemu/osdep.h"
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+#include "apple-gfx.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "trace.h"
+#include "qemu/log.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXMMIOState, APPLE_GFX_MMIO)
+
+/*
+ * ParavirtualizedGraphics.Framework only ships header files for the PCI
+ * variant which does not include IOSFC descriptors and host devices. We a=
dd
+ * their definitions here so that we can also work with the ARM version.
+ */
+typedef bool(^IOSFCRaiseInterrupt)(uint32_t vector);
+typedef bool(^IOSFCUnmapMemory)(
+    void *, void *, void *, void *, void *, void *);
+typedef bool(^IOSFCMapMemory)(
+    uint64_t phys, uint64_t len, bool ro, void **va, void *, void *);
+
+@interface PGDeviceDescriptor (IOSurfaceMapper)
+@property (readwrite, nonatomic) bool usingIOSurfaceMapper;
+@end
+
+@interface PGIOSurfaceHostDeviceDescriptor : NSObject
+-(PGIOSurfaceHostDeviceDescriptor *)init;
+@property (readwrite, nonatomic, copy, nullable) IOSFCMapMemory mapMemory;
+@property (readwrite, nonatomic, copy, nullable) IOSFCUnmapMemory unmapMem=
ory;
+@property (readwrite, nonatomic, copy, nullable) IOSFCRaiseInterrupt raise=
Interrupt;
+@end
+
+@interface PGIOSurfaceHostDevice : NSObject
+-(instancetype)initWithDescriptor:(PGIOSurfaceHostDeviceDescriptor *)desc;
+-(uint32_t)mmioReadAtOffset:(size_t)offset;
+-(void)mmioWriteAtOffset:(size_t)offset value:(uint32_t)value;
+@end
+
+struct AppleGFXMapSurfaceMemoryJob;
+struct AppleGFXMMIOState {
+    SysBusDevice parent_obj;
+
+    AppleGFXState common;
+
+    qemu_irq irq_gfx;
+    qemu_irq irq_iosfc;
+    MemoryRegion iomem_iosfc;
+    PGIOSurfaceHostDevice *pgiosfc;
+};
+
+typedef struct AppleGFXMMIOJob {
+    AppleGFXMMIOState *state;
+    uint64_t offset;
+    uint64_t value;
+    bool completed;
+} AppleGFXMMIOJob;
+
+static void iosfc_do_read(void *opaque)
+{
+    AppleGFXMMIOJob *job =3D opaque;
+    job->value =3D [job->state->pgiosfc mmioReadAtOffset:job->offset];
+    qatomic_set(&job->completed, true);
+    aio_wait_kick();
+}
+
+static uint64_t iosfc_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AppleGFXMMIOJob job =3D {
+        .state =3D opaque,
+        .offset =3D offset,
+        .completed =3D false,
+    };
+    dispatch_queue_t queue =3D
+        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+    dispatch_async_f(queue, &job, iosfc_do_read);
+    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+    trace_apple_gfx_mmio_iosfc_read(offset, job.value);
+    return job.value;
+}
+
+static void iosfc_do_write(void *opaque)
+{
+    AppleGFXMMIOJob *job =3D opaque;
+    [job->state->pgiosfc mmioWriteAtOffset:job->offset value:job->value];
+    qatomic_set(&job->completed, true);
+    aio_wait_kick();
+}
+
+static void iosfc_write(void *opaque, hwaddr offset, uint64_t val,
+                        unsigned size)
+{
+    AppleGFXMMIOJob job =3D {
+        .state =3D opaque,
+        .offset =3D offset,
+        .value =3D val,
+        .completed =3D false,
+    };
+    dispatch_queue_t queue =3D
+        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+    dispatch_async_f(queue, &job, iosfc_do_write);
+    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+    trace_apple_gfx_mmio_iosfc_write(offset, val);
+}
+
+static const MemoryRegionOps apple_iosfc_ops =3D {
+    .read =3D iosfc_read,
+    .write =3D iosfc_write,
+    .endianness =3D DEVICE_LITTLE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+};
+
+static void raise_irq_bh(void *opaque)
+{
+    qemu_irq *irq =3D opaque;
+
+    qemu_irq_pulse(*irq);
+}
+
+static void *apple_gfx_mmio_map_surface_memory(uint64_t guest_physical_add=
ress,
+                                               uint64_t length, bool read_=
only)
+{
+    void *mem;
+    MemoryRegion *region =3D NULL;
+
+    RCU_READ_LOCK_GUARD();
+    mem =3D apple_gfx_host_ptr_for_gpa_range(guest_physical_address,
+                                           length, read_only, &region);
+    if (mem) {
+        memory_region_ref(region);
+    }
+    return mem;
+}
+
+static bool apple_gfx_mmio_unmap_surface_memory(void *ptr)
+{
+    MemoryRegion *region;
+    ram_addr_t offset =3D 0;
+
+    RCU_READ_LOCK_GUARD();
+    region =3D memory_region_from_host(ptr, &offset);
+    if (!region) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: memory at %p to be unmapped no=
t "
+                      "found.\n",
+                      __func__, ptr);
+        return false;
+    }
+
+    trace_apple_gfx_iosfc_unmap_memory_region(ptr, region);
+    memory_region_unref(region);
+    return true;
+}
+
+static PGIOSurfaceHostDevice *apple_gfx_prepare_iosurface_host_device(
+    AppleGFXMMIOState *s)
+{
+    PGIOSurfaceHostDeviceDescriptor *iosfc_desc =3D
+        [PGIOSurfaceHostDeviceDescriptor new];
+    PGIOSurfaceHostDevice *iosfc_host_dev;
+
+    iosfc_desc.mapMemory =3D
+        ^bool(uint64_t phys, uint64_t len, bool ro, void **va, void *e, vo=
id *f) {
+            *va =3D apple_gfx_mmio_map_surface_memory(phys, len, ro);
+
+            trace_apple_gfx_iosfc_map_memory(phys, len, ro, va, e, f, *va);
+
+            return *va !=3D NULL;
+        };
+
+    iosfc_desc.unmapMemory =3D
+        ^bool(void *va, void *b, void *c, void *d, void *e, void *f) {
+            return apple_gfx_mmio_unmap_surface_memory(va);
+        };
+
+    iosfc_desc.raiseInterrupt =3D ^bool(uint32_t vector) {
+        trace_apple_gfx_iosfc_raise_irq(vector);
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                raise_irq_bh, &s->irq_iosfc);
+        return true;
+    };
+
+    iosfc_host_dev =3D
+        [[PGIOSurfaceHostDevice alloc] initWithDescriptor:iosfc_desc];
+    [iosfc_desc release];
+    return iosfc_host_dev;
+}
+
+static void apple_gfx_mmio_realize(DeviceState *dev, Error **errp)
+{
+    @autoreleasepool {
+        AppleGFXMMIOState *s =3D APPLE_GFX_MMIO(dev);
+        PGDeviceDescriptor *desc =3D [PGDeviceDescriptor new];
+
+        desc.raiseInterrupt =3D ^(uint32_t vector) {
+            trace_apple_gfx_raise_irq(vector);
+            aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                    raise_irq_bh, &s->irq_gfx);
+        };
+
+        desc.usingIOSurfaceMapper =3D true;
+        s->pgiosfc =3D apple_gfx_prepare_iosurface_host_device(s);
+
+        if (!apple_gfx_common_realize(&s->common, dev, desc, errp)) {
+            [s->pgiosfc release];
+            s->pgiosfc =3D nil;
+        }
+
+        [desc release];
+        desc =3D nil;
+    }
+}
+
+static void apple_gfx_mmio_init(Object *obj)
+{
+    AppleGFXMMIOState *s =3D APPLE_GFX_MMIO(obj);
+
+    apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_MMIO);
+
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->common.iomem_gfx);
+    memory_region_init_io(&s->iomem_iosfc, obj, &apple_iosfc_ops, s,
+                          TYPE_APPLE_GFX_MMIO, 0x10000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem_iosfc);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_gfx);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_iosfc);
+}
+
+static void apple_gfx_mmio_reset(Object *obj, ResetType type)
+{
+    AppleGFXMMIOState *s =3D APPLE_GFX_MMIO(obj);
+    [s->common.pgdev reset];
+}
+
+
+static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+    ResettableClass *rc =3D RESETTABLE_CLASS(klass);
+
+    rc->phases.hold =3D apple_gfx_mmio_reset;
+    dc->hotpluggable =3D false;
+    dc->realize =3D apple_gfx_mmio_realize;
+}
+
+static TypeInfo apple_gfx_mmio_types[] =3D {
+    {
+        .name          =3D TYPE_APPLE_GFX_MMIO,
+        .parent        =3D TYPE_SYS_BUS_DEVICE,
+        .instance_size =3D sizeof(AppleGFXMMIOState),
+        .class_init    =3D apple_gfx_mmio_class_init,
+        .instance_init =3D apple_gfx_mmio_init,
+    }
+};
+DEFINE_TYPES(apple_gfx_mmio_types)
diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h
new file mode 100644
index 00000000000..ef2455e3bdc
--- /dev/null
+++ b/hw/display/apple-gfx.h
@@ -0,0 +1,66 @@
+/*
+ * Data structures and functions shared between variants of the macOS
+ * ParavirtualizedGraphics.framework based apple-gfx display adapter.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_APPLE_GFX_H
+#define QEMU_APPLE_GFX_H
+
+#define TYPE_APPLE_GFX_MMIO         "apple-gfx-mmio"
+#define TYPE_APPLE_GFX_PCI          "apple-gfx-pci"
+
+#include "qemu/osdep.h"
+#include <dispatch/dispatch.h>
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+#include "qemu/typedefs.h"
+#include "exec/memory.h"
+#include "ui/surface.h"
+
+@class PGDeviceDescriptor;
+@protocol PGDevice;
+@protocol PGDisplay;
+@protocol MTLDevice;
+@protocol MTLTexture;
+@protocol MTLCommandQueue;
+
+typedef QTAILQ_HEAD(, PGTask_s) PGTaskList;
+
+typedef struct AppleGFXState {
+    /* Initialised on init/realize() */
+    MemoryRegion iomem_gfx;
+    id<PGDevice> pgdev;
+    id<PGDisplay> pgdisp;
+    QemuConsole *con;
+    id<MTLDevice> mtl;
+    id<MTLCommandQueue> mtl_queue;
+
+    /* List `tasks` is protected by task_mutex */
+    QemuMutex task_mutex;
+    PGTaskList tasks;
+
+    /* Mutable state (BQL protected) */
+    QEMUCursor *cursor;
+    DisplaySurface *surface;
+    id<MTLTexture> texture;
+    int8_t pending_frames; /* # guest frames in the rendering pipeline */
+    bool gfx_update_requested; /* QEMU display system wants a new frame */
+    bool new_frame_ready; /* Guest has rendered a frame, ready to be used =
*/
+    bool using_managed_texture_storage;
+    uint32_t rendering_frame_width;
+    uint32_t rendering_frame_height;
+
+    /* Mutable state (atomic) */
+    bool cursor_show;
+} AppleGFXState;
+
+void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_=
name);
+bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
+                              PGDeviceDescriptor *desc, Error **errp);
+void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_physical,
+                                       uint64_t length, bool read_only,
+                                       MemoryRegion **mapping_in_region);
+
+#endif
+
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
new file mode 100644
index 00000000000..bfaff2b2be2
--- /dev/null
+++ b/hw/display/apple-gfx.m
@@ -0,0 +1,783 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS prov=
ides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU.
+ */
+
+#include "qemu/osdep.h"
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+#include <mach/mach_vm.h>
+#include "apple-gfx.h"
+#include "trace.h"
+#include "qemu-main.h"
+#include "exec/address-spaces.h"
+#include "migration/blocker.h"
+#include "monitor/monitor.h"
+#include "qemu/main-loop.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qapi/visitor.h"
+#include "qapi/error.h"
+#include "sysemu/dma.h"
+#include "ui/console.h"
+
+static const PGDisplayCoord_t apple_gfx_modes[] =3D {
+    { .x =3D 1440, .y =3D 1080 },
+    { .x =3D 1280, .y =3D 1024 },
+};
+
+static Error *apple_gfx_mig_blocker;
+static uint32_t next_pgdisplay_serial_num =3D 1;
+
+static dispatch_queue_t get_background_queue(void)
+{
+    return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+}
+
+/* ------ PGTask and task operations: new/destroy/map/unmap ------ */
+
+/*
+ * This implements the type declared in <ParavirtualizedGraphics/PGDevice.=
h>
+ * which is opaque from the framework's point of view. It is used in callb=
acks
+ * in the form of its typedef PGTask_t, which also already exists in the
+ * framework headers.
+ *
+ * A "task" in PVG terminology represents a host-virtual contiguous address
+ * range which is reserved in a large chunk on task creation. The mapMemory
+ * callback then requests ranges of guest system memory (identified by the=
ir
+ * GPA) to be mapped into subranges of this reserved address space.
+ * This type of operation isn't well-supported by QEMU's memory subsystem,
+ * but it is fortunately trivial to achieve with Darwin's mach_vm_remap() =
call,
+ * which allows us to refer to the same backing memory via multiple virtual
+ * address ranges. The Mach VM APIs are therefore used throughout for mana=
ging
+ * task memory.
+ */
+struct PGTask_s {
+    QTAILQ_ENTRY(PGTask_s) node;
+    AppleGFXState *s;
+    mach_vm_address_t address;
+    uint64_t len;
+    /*
+     * All unique MemoryRegions for which a mapping has been created in in=
 this
+     * task, and on which we have thus called memory_region_ref(). There a=
re
+     * usually very few regions of system RAM in total, so we expect this =
array
+     * to be very short. Therefore, no need for sorting or fancy search
+     * algorithms, linear search will do.
+     * Protected by AppleGFXState's task_mutex.
+     */
+    GPtrArray *mapped_regions;
+};
+
+static PGTask_t *apple_gfx_new_task(AppleGFXState *s, uint64_t len)
+{
+    mach_vm_address_t task_mem;
+    PGTask_t *task;
+    kern_return_t r;
+
+    r =3D mach_vm_allocate(mach_task_self(), &task_mem, len, VM_FLAGS_ANYW=
HERE);
+    if (r !=3D KERN_SUCCESS) {
+        return NULL;
+    }
+
+    task =3D g_new0(PGTask_t, 1);
+    task->s =3D s;
+    task->address =3D task_mem;
+    task->len =3D len;
+    task->mapped_regions =3D g_ptr_array_sized_new(2 /* Usually enough */);
+
+    QEMU_LOCK_GUARD(&s->task_mutex);
+    QTAILQ_INSERT_TAIL(&s->tasks, task, node);
+
+    return task;
+}
+
+static void apple_gfx_destroy_task(AppleGFXState *s, PGTask_t *task)
+{
+    GPtrArray *regions =3D task->mapped_regions;
+    MemoryRegion *region;
+    size_t i;
+
+    for (i =3D 0; i < regions->len; ++i) {
+        region =3D g_ptr_array_index(regions, i);
+        memory_region_unref(region);
+    }
+    g_ptr_array_unref(regions);
+
+    mach_vm_deallocate(mach_task_self(), task->address, task->len);
+
+    QEMU_LOCK_GUARD(&s->task_mutex);
+    QTAILQ_REMOVE(&s->tasks, task, node);
+    g_free(task);
+}
+
+void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_physical,
+                                       uint64_t length, bool read_only,
+                                       MemoryRegion **mapping_in_region)
+{
+    MemoryRegion *ram_region;
+    char *host_ptr;
+    hwaddr ram_region_offset =3D 0;
+    hwaddr ram_region_length =3D length;
+
+    ram_region =3D address_space_translate(&address_space_memory,
+                                         guest_physical,
+                                         &ram_region_offset,
+                                         &ram_region_length, !read_only,
+                                         MEMTXATTRS_UNSPECIFIED);
+
+    if (!ram_region || ram_region_length < length ||
+        !memory_access_is_direct(ram_region, !read_only)) {
+        return NULL;
+    }
+
+    host_ptr =3D memory_region_get_ram_ptr(ram_region);
+    if (!host_ptr) {
+        return NULL;
+    }
+    host_ptr +=3D ram_region_offset;
+    *mapping_in_region =3D ram_region;
+    return host_ptr;
+}
+
+static bool apple_gfx_task_map_memory(AppleGFXState *s, PGTask_t *task,
+                                      uint64_t virtual_offset,
+                                      PGPhysicalMemoryRange_t *ranges,
+                                      uint32_t range_count, bool read_only)
+{
+    kern_return_t r;
+    void *source_ptr;
+    mach_vm_address_t target;
+    vm_prot_t cur_protection, max_protection;
+    bool success =3D true;
+    MemoryRegion *region;
+
+    RCU_READ_LOCK_GUARD();
+    QEMU_LOCK_GUARD(&s->task_mutex);
+
+    trace_apple_gfx_map_memory(task, range_count, virtual_offset, read_onl=
y);
+    for (int i =3D 0; i < range_count; i++) {
+        PGPhysicalMemoryRange_t *range =3D &ranges[i];
+
+        target =3D task->address + virtual_offset;
+        virtual_offset +=3D range->physicalLength;
+
+        trace_apple_gfx_map_memory_range(i, range->physicalAddress,
+                                         range->physicalLength);
+
+        region =3D NULL;
+        source_ptr =3D apple_gfx_host_ptr_for_gpa_range(range->physicalAdd=
ress,
+                                                      range->physicalLengt=
h,
+                                                      read_only, &region);
+        if (!source_ptr) {
+            success =3D false;
+            continue;
+        }
+
+        if (!g_ptr_array_find(task->mapped_regions, region, NULL)) {
+            g_ptr_array_add(task->mapped_regions, region);
+            memory_region_ref(region);
+        }
+
+        cur_protection =3D 0;
+        max_protection =3D 0;
+        /* Map guest RAM at range->physicalAddress into PG task memory ran=
ge */
+        r =3D mach_vm_remap(mach_task_self(),
+                          &target, range->physicalLength, vm_page_size - 1,
+                          VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
+                          mach_task_self(), (mach_vm_address_t)source_ptr,
+                          false /* shared mapping, no copy */,
+                          &cur_protection, &max_protection,
+                          VM_INHERIT_COPY);
+        trace_apple_gfx_remap(r, source_ptr, target);
+        g_assert(r =3D=3D KERN_SUCCESS);
+    }
+
+    return success;
+}
+
+static void apple_gfx_task_unmap_memory(AppleGFXState *s, PGTask_t *task,
+                                        uint64_t virtual_offset, uint64_t =
length)
+{
+    kern_return_t r;
+    mach_vm_address_t range_address;
+
+    trace_apple_gfx_unmap_memory(task, virtual_offset, length);
+
+    /*
+     * Replace task memory range with fresh 0 pages, undoing the mapping
+     * from guest RAM.
+     */
+    range_address =3D task->address + virtual_offset;
+    r =3D mach_vm_allocate(mach_task_self(), &range_address, length,
+                         VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
+    g_assert(r =3D=3D KERN_SUCCESS);
+}
+
+/* ------ Rendering and frame management ------ */
+
+static void apple_gfx_render_frame_completed_bh(void *opaque);
+
+static void apple_gfx_render_new_frame(AppleGFXState *s)
+{
+    bool managed_texture =3D s->using_managed_texture_storage;
+    uint32_t width =3D surface_width(s->surface);
+    uint32_t height =3D surface_height(s->surface);
+    MTLRegion region =3D MTLRegionMake2D(0, 0, width, height);
+    id<MTLCommandBuffer> command_buffer =3D [s->mtl_queue commandBuffer];
+    id<MTLTexture> texture =3D s->texture;
+
+    assert(bql_locked());
+    [texture retain];
+    [command_buffer retain];
+
+    s->rendering_frame_width =3D width;
+    s->rendering_frame_height =3D height;
+
+    dispatch_async(get_background_queue(), ^{
+        /*
+         * This is not safe to call from the BQL/BH due to PVG-internal lo=
cks
+         * causing deadlocks.
+         */
+        bool r =3D [s->pgdisp encodeCurrentFrameToCommandBuffer:command_bu=
ffer
+                                                 texture:texture
+                                                  region:region];
+        if (!r) {
+            [texture release];
+            [command_buffer release];
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: encodeCurrentFrameToCommandBuffer:texture:r=
egion: "
+                          "failed\n", __func__);
+            bql_lock();
+            --s->pending_frames;
+            if (s->pending_frames > 0) {
+                apple_gfx_render_new_frame(s);
+            }
+            bql_unlock();
+            return;
+        }
+
+        if (managed_texture) {
+            /* "Managed" textures exist in both VRAM and RAM and must be s=
ynced. */
+            id<MTLBlitCommandEncoder> blit =3D [command_buffer blitCommand=
Encoder];
+            [blit synchronizeResource:texture];
+            [blit endEncoding];
+        }
+        [texture release];
+        [command_buffer addCompletedHandler:
+            ^(id<MTLCommandBuffer> cb)
+            {
+                aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                        apple_gfx_render_frame_completed_b=
h, s);
+            }];
+        [command_buffer commit];
+        [command_buffer release];
+    });
+}
+
+static void copy_mtl_texture_to_surface_mem(id<MTLTexture> texture, void *=
vram)
+{
+    /*
+     * TODO: Skip this entirely on a pure Metal or headless/guest-only
+     * rendering path, else use a blit command encoder? Needs careful
+     * (double?) buffering design.
+     */
+    size_t width =3D texture.width, height =3D texture.height;
+    MTLRegion region =3D MTLRegionMake2D(0, 0, width, height);
+    [texture getBytes:vram
+          bytesPerRow:(width * 4)
+        bytesPerImage:(width * height * 4)
+           fromRegion:region
+          mipmapLevel:0
+                slice:0];
+}
+
+static void apple_gfx_render_frame_completed_bh(void *opaque)
+{
+    AppleGFXState *s =3D opaque;
+
+    @autoreleasepool {
+        --s->pending_frames;
+        assert(s->pending_frames >=3D 0);
+
+        /* Only update display if mode hasn't changed since we started ren=
dering. */
+        if (s->rendering_frame_width =3D=3D surface_width(s->surface) &&
+            s->rendering_frame_height =3D=3D surface_height(s->surface)) {
+            copy_mtl_texture_to_surface_mem(s->texture, surface_data(s->su=
rface));
+            if (s->gfx_update_requested) {
+                s->gfx_update_requested =3D false;
+                dpy_gfx_update_full(s->con);
+                graphic_hw_update_done(s->con);
+                s->new_frame_ready =3D false;
+            } else {
+                s->new_frame_ready =3D true;
+            }
+        }
+        if (s->pending_frames > 0) {
+            apple_gfx_render_new_frame(s);
+        }
+    }
+}
+
+static void apple_gfx_fb_update_display(void *opaque)
+{
+    AppleGFXState *s =3D opaque;
+
+    assert(bql_locked());
+    if (s->new_frame_ready) {
+        dpy_gfx_update_full(s->con);
+        s->new_frame_ready =3D false;
+        graphic_hw_update_done(s->con);
+    } else if (s->pending_frames > 0) {
+        s->gfx_update_requested =3D true;
+    } else {
+        graphic_hw_update_done(s->con);
+    }
+}
+
+static const GraphicHwOps apple_gfx_fb_ops =3D {
+    .gfx_update =3D apple_gfx_fb_update_display,
+    .gfx_update_async =3D true,
+};
+
+/* ------ Mouse cursor and display mode setting ------ */
+
+static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
+{
+    MTLTextureDescriptor *textureDescriptor;
+
+    if (s->surface &&
+        width =3D=3D surface_width(s->surface) &&
+        height =3D=3D surface_height(s->surface)) {
+        return;
+    }
+
+    [s->texture release];
+
+    s->surface =3D qemu_create_displaysurface(width, height);
+
+    @autoreleasepool {
+        textureDescriptor =3D
+            [MTLTextureDescriptor
+                texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
+                                             width:width
+                                            height:height
+                                         mipmapped:NO];
+        textureDescriptor.usage =3D s->pgdisp.minimumTextureUsage;
+        s->texture =3D [s->mtl newTextureWithDescriptor:textureDescriptor];
+        s->using_managed_texture_storage =3D
+            (s->texture.storageMode =3D=3D MTLStorageModeManaged);
+    }
+
+    dpy_gfx_replace_surface(s->con, s->surface);
+}
+
+static void update_cursor(AppleGFXState *s)
+{
+    assert(bql_locked());
+    dpy_mouse_set(s->con, s->pgdisp.cursorPosition.x,
+                  s->pgdisp.cursorPosition.y, qatomic_read(&s->cursor_show=
));
+}
+
+static void update_cursor_bh(void *opaque)
+{
+    AppleGFXState *s =3D opaque;
+    update_cursor(s);
+}
+
+typedef struct AppleGFXSetCursorGlyphJob {
+    AppleGFXState *s;
+    NSBitmapImageRep *glyph;
+    PGDisplayCoord_t hotspot;
+} AppleGFXSetCursorGlyphJob;
+
+static void set_cursor_glyph(void *opaque)
+{
+    AppleGFXSetCursorGlyphJob *job =3D opaque;
+    AppleGFXState *s =3D job->s;
+    NSBitmapImageRep *glyph =3D job->glyph;
+    uint32_t bpp =3D glyph.bitsPerPixel;
+    size_t width =3D glyph.pixelsWide;
+    size_t height =3D glyph.pixelsHigh;
+    size_t padding_bytes_per_row =3D glyph.bytesPerRow - width * 4;
+    const uint8_t* px_data =3D glyph.bitmapData;
+
+    trace_apple_gfx_cursor_set(bpp, width, height);
+
+    if (s->cursor) {
+        cursor_unref(s->cursor);
+        s->cursor =3D NULL;
+    }
+
+    if (bpp =3D=3D 32) { /* Shouldn't be anything else, but just to be saf=
e...*/
+        s->cursor =3D cursor_alloc(width, height);
+        s->cursor->hot_x =3D job->hotspot.x;
+        s->cursor->hot_y =3D job->hotspot.y;
+
+        uint32_t *dest_px =3D s->cursor->data;
+
+        for (size_t y =3D 0; y < height; ++y) {
+            for (size_t x =3D 0; x < width; ++x) {
+                /*
+                 * NSBitmapImageRep's red & blue channels are swapped
+                 * compared to QEMUCursor's.
+                 */
+                *dest_px =3D
+                    (px_data[0] << 16u) |
+                    (px_data[1] <<  8u) |
+                    (px_data[2] <<  0u) |
+                    (px_data[3] << 24u);
+                ++dest_px;
+                px_data +=3D 4;
+            }
+            px_data +=3D padding_bytes_per_row;
+        }
+        dpy_cursor_define(s->con, s->cursor);
+        update_cursor(s);
+    }
+    [glyph release];
+
+    g_free(job);
+}
+
+/* ------ DMA (device reading system memory) ------ */
+
+typedef struct AppleGFXReadMemoryJob {
+    QemuSemaphore sem;
+    hwaddr physical_address;
+    uint64_t length;
+    void *dst;
+    bool success;
+} AppleGFXReadMemoryJob;
+
+static void apple_gfx_do_read_memory(void *opaque)
+{
+    AppleGFXReadMemoryJob *job =3D opaque;
+    MemTxResult r;
+
+    r =3D dma_memory_read(&address_space_memory, job->physical_address,
+                        job->dst, job->length, MEMTXATTRS_UNSPECIFIED);
+    job->success =3D r =3D=3D MEMTX_OK;
+
+    qemu_sem_post(&job->sem);
+}
+
+static bool apple_gfx_read_memory(AppleGFXState *s, hwaddr physical_addres=
s,
+                                  uint64_t length, void *dst)
+{
+    AppleGFXReadMemoryJob job =3D {
+        .physical_address =3D physical_address, .length =3D length, .dst =
=3D dst
+    };
+
+    trace_apple_gfx_read_memory(physical_address, length, dst);
+
+    /* Performing DMA requires BQL, so do it in a BH. */
+    qemu_sem_init(&job.sem, 0);
+    aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                            apple_gfx_do_read_memory, &job);
+    qemu_sem_wait(&job.sem);
+    qemu_sem_destroy(&job.sem);
+    return job.success;
+}
+
+/* ------ Memory-mapped device I/O operations ------ */
+
+typedef struct AppleGFXIOJob {
+    AppleGFXState *state;
+    uint64_t offset;
+    uint64_t value;
+    bool completed;
+} AppleGFXIOJob;
+
+static void apple_gfx_do_read(void *opaque)
+{
+    AppleGFXIOJob *job =3D opaque;
+    job->value =3D [job->state->pgdev mmioReadAtOffset:job->offset];
+    qatomic_set(&job->completed, true);
+    aio_wait_kick();
+}
+
+static uint64_t apple_gfx_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AppleGFXIOJob job =3D {
+        .state =3D opaque,
+        .offset =3D offset,
+        .completed =3D false,
+    };
+    dispatch_queue_t queue =3D get_background_queue();
+
+    dispatch_async_f(queue, &job, apple_gfx_do_read);
+    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+    trace_apple_gfx_read(offset, job.value);
+    return job.value;
+}
+
+static void apple_gfx_do_write(void *opaque)
+{
+    AppleGFXIOJob *job =3D opaque;
+    [job->state->pgdev mmioWriteAtOffset:job->offset value:job->value];
+    qatomic_set(&job->completed, true);
+    aio_wait_kick();
+}
+
+static void apple_gfx_write(void *opaque, hwaddr offset, uint64_t val,
+                            unsigned size)
+{
+    /*
+     * The methods mmioReadAtOffset: and especially mmioWriteAtOffset: can
+     * trigger synchronous operations on other dispatch queues, which in t=
urn
+     * may call back out on one or more of the callback blocks. For this r=
eason,
+     * and as we are holding the BQL, we invoke the I/O methods on a pool
+     * thread and handle AIO tasks while we wait. Any work in the callbacks
+     * requiring the BQL will in turn schedule BHs which this thread will
+     * process while waiting.
+     */
+    AppleGFXIOJob job =3D {
+        .state =3D opaque,
+        .offset =3D offset,
+        .value =3D val,
+        .completed =3D false,
+    };
+    dispatch_queue_t queue =3D get_background_queue();
+
+    dispatch_async_f(queue, &job, apple_gfx_do_write);
+    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+    trace_apple_gfx_write(offset, val);
+}
+
+static const MemoryRegionOps apple_gfx_ops =3D {
+    .read =3D apple_gfx_read,
+    .write =3D apple_gfx_write,
+    .endianness =3D DEVICE_LITTLE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 4,
+    },
+};
+
+static size_t apple_gfx_get_default_mmio_range_size(void)
+{
+    size_t mmio_range_size;
+    @autoreleasepool {
+        PGDeviceDescriptor *desc =3D [PGDeviceDescriptor new];
+        mmio_range_size =3D desc.mmioLength;
+        [desc release];
+    }
+    return mmio_range_size;
+}
+
+/* ------ Initialisation and startup ------ */
+
+void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_=
name)
+{
+    size_t mmio_range_size =3D apple_gfx_get_default_mmio_range_size();
+
+    trace_apple_gfx_common_init(obj_name, mmio_range_size);
+    memory_region_init_io(&s->iomem_gfx, obj, &apple_gfx_ops, s, obj_name,
+                          mmio_range_size);
+
+    /* TODO: PVG framework supports serialising device state: integrate it=
! */
+}
+
+static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
+                                                     PGDeviceDescriptor *d=
esc)
+{
+    desc.createTask =3D ^(uint64_t vmSize, void * _Nullable * _Nonnull bas=
eAddress) {
+        PGTask_t *task =3D apple_gfx_new_task(s, vmSize);
+        *baseAddress =3D (void *)task->address;
+        trace_apple_gfx_create_task(vmSize, *baseAddress);
+        return task;
+    };
+
+    desc.destroyTask =3D ^(PGTask_t * _Nonnull task) {
+        trace_apple_gfx_destroy_task(task, task->mapped_regions->len);
+
+        apple_gfx_destroy_task(s, task);
+    };
+
+    desc.mapMemory =3D ^bool(PGTask_t * _Nonnull task, uint32_t range_coun=
t,
+                           uint64_t virtual_offset, bool read_only,
+                           PGPhysicalMemoryRange_t * _Nonnull ranges) {
+        return apple_gfx_task_map_memory(s, task, virtual_offset,
+                                         ranges, range_count, read_only);
+    };
+
+    desc.unmapMemory =3D ^bool(PGTask_t * _Nonnull task, uint64_t virtual_=
offset,
+                             uint64_t length) {
+        apple_gfx_task_unmap_memory(s, task, virtual_offset, length);
+        return true;
+    };
+
+    desc.readMemory =3D ^bool(uint64_t physical_address, uint64_t length,
+                            void * _Nonnull dst) {
+        return apple_gfx_read_memory(s, physical_address, length, dst);
+    };
+}
+
+static void new_frame_handler_bh(void *opaque)
+{
+    AppleGFXState *s =3D opaque;
+
+    /* Drop frames if guest gets too far ahead. */
+    if (s->pending_frames >=3D 2) {
+        return;
+    }
+    ++s->pending_frames;
+    if (s->pending_frames > 1) {
+        return;
+    }
+
+    @autoreleasepool {
+        apple_gfx_render_new_frame(s);
+    }
+}
+
+static PGDisplayDescriptor *apple_gfx_prepare_display_descriptor(AppleGFXS=
tate *s)
+{
+    PGDisplayDescriptor *disp_desc =3D [PGDisplayDescriptor new];
+
+    disp_desc.name =3D @"QEMU display";
+    disp_desc.sizeInMillimeters =3D NSMakeSize(400., 300.); /* A 20" displ=
ay */
+    disp_desc.queue =3D dispatch_get_main_queue();
+    disp_desc.newFrameEventHandler =3D ^(void) {
+        trace_apple_gfx_new_frame();
+        aio_bh_schedule_oneshot(qemu_get_aio_context(), new_frame_handler_=
bh, s);
+    };
+    disp_desc.modeChangeHandler =3D ^(PGDisplayCoord_t sizeInPixels,
+                                    OSType pixelFormat) {
+        trace_apple_gfx_mode_change(sizeInPixels.x, sizeInPixels.y);
+
+        BQL_LOCK_GUARD();
+        set_mode(s, sizeInPixels.x, sizeInPixels.y);
+    };
+    disp_desc.cursorGlyphHandler =3D ^(NSBitmapImageRep *glyph,
+                                     PGDisplayCoord_t hotspot) {
+        AppleGFXSetCursorGlyphJob *job =3D g_malloc0(sizeof(*job));
+        job->s =3D s;
+        job->glyph =3D glyph;
+        job->hotspot =3D hotspot;
+        [glyph retain];
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                set_cursor_glyph, job);
+    };
+    disp_desc.cursorShowHandler =3D ^(BOOL show) {
+        trace_apple_gfx_cursor_show(show);
+        qatomic_set(&s->cursor_show, show);
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                update_cursor_bh, s);
+    };
+    disp_desc.cursorMoveHandler =3D ^(void) {
+        trace_apple_gfx_cursor_move();
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                update_cursor_bh, s);
+    };
+
+    return disp_desc;
+}
+
+static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void)
+{
+    PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
+    NSArray<PGDisplayMode*>* mode_array;
+    int i;
+
+    for (i =3D 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
+        modes[i] =3D
+            [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i]=
 refreshRateInHz:60.];
+    }
+
+    mode_array =3D [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_=
gfx_modes)];
+
+    for (i =3D 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
+        [modes[i] release];
+        modes[i] =3D nil;
+    }
+
+    return mode_array;
+}
+
+static id<MTLDevice> copy_suitable_metal_device(void)
+{
+    id<MTLDevice> dev =3D nil;
+    NSArray<id<MTLDevice>> *devs =3D MTLCopyAllDevices();
+
+    /* Prefer a unified memory GPU. Failing that, pick a non-removable GPU=
. */
+    for (size_t i =3D 0; i < devs.count; ++i) {
+        if (devs[i].hasUnifiedMemory) {
+            dev =3D devs[i];
+            break;
+        }
+        if (!devs[i].removable) {
+            dev =3D devs[i];
+        }
+    }
+
+    if (dev !=3D nil) {
+        [dev retain];
+    } else {
+        dev =3D MTLCreateSystemDefaultDevice();
+    }
+    [devs release];
+
+    return dev;
+}
+
+bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
+                              PGDeviceDescriptor *desc, Error **errp)
+{
+    PGDisplayDescriptor *disp_desc;
+
+    if (apple_gfx_mig_blocker =3D=3D NULL) {
+        error_setg(&apple_gfx_mig_blocker,
+                  "Migration state blocked by apple-gfx display device");
+        if (migrate_add_blocker(&apple_gfx_mig_blocker, errp) < 0) {
+            return false;
+        }
+    }
+
+    qemu_mutex_init(&s->task_mutex);
+    QTAILQ_INIT(&s->tasks);
+    s->mtl =3D copy_suitable_metal_device();
+    s->mtl_queue =3D [s->mtl newCommandQueue];
+
+    desc.device =3D s->mtl;
+
+    apple_gfx_register_task_mapping_handlers(s, desc);
+
+    s->cursor_show =3D true;
+
+    s->pgdev =3D PGNewDeviceWithDescriptor(desc);
+
+    disp_desc =3D apple_gfx_prepare_display_descriptor(s);
+    /*
+     * Although the framework does, this integration currently does not su=
pport
+     * multiple virtual displays connected to a single PV graphics device.
+     * It is however possible to create
+     * more than one instance of the device, each with one display. The ma=
cOS
+     * guest will ignore these displays if they share the same serial numb=
er,
+     * so ensure each instance gets a unique one.
+     */
+    s->pgdisp =3D [s->pgdev newDisplayWithDescriptor:disp_desc
+                                              port:0
+                                         serialNum:next_pgdisplay_serial_n=
um++];
+    [disp_desc release];
+    s->pgdisp.modeList =3D apple_gfx_prepare_display_mode_array();
+
+    s->con =3D graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
+    return true;
+}
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 20a94973fa2..cf9e6dd35d2 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -61,6 +61,12 @@ system_ss.add(when: 'CONFIG_ARTIST', if_true: files('art=
ist.c'))
=20
 system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('ati.c', 'ati_2d.c',=
 'ati_dbg.c'), pixman])
=20
+if host_os =3D=3D 'darwin'
+  system_ss.add(when: 'CONFIG_MAC_PVG',         if_true: [files('apple-gfx=
.m'), pvg, metal])
+  if cpu =3D=3D 'aarch64'
+    system_ss.add(when: 'CONFIG_MAC_PVG_MMIO',  if_true: [files('apple-gfx=
-mmio.m'), pvg, metal])
+  endif
+endif
=20
 if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
   virtio_gpu_ss =3D ss.source_set()
diff --git a/hw/display/trace-events b/hw/display/trace-events
index d26d663f963..a50e4eea0c0 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -194,3 +194,31 @@ dm163_bits_ppi(unsigned dest_width) "dest_width : %u"
 dm163_leds(int led, uint32_t value) "led %d: 0x%x"
 dm163_channels(int channel, uint8_t value) "channel %d: 0x%x"
 dm163_refresh_rate(uint32_t rr) "refresh rate %d"
+
+# apple-gfx.m
+apple_gfx_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRIx64" res=3D=
0x%"PRIx64
+apple_gfx_write(uint64_t offset, uint64_t val) "offset=3D0x%"PRIx64" val=
=3D0x%"PRIx64
+apple_gfx_create_task(uint32_t vm_size, void *va) "vm_size=3D0x%x base_add=
r=3D%p"
+apple_gfx_destroy_task(void *task, unsigned int num_mapped_regions) "task=
=3D%p, task->mapped_regions->len=3D%u"
+apple_gfx_map_memory(void *task, uint32_t range_count, uint64_t virtual_of=
fset, uint32_t read_only) "task=3D%p range_count=3D0x%x virtual_offset=3D0x=
%"PRIx64" read_only=3D%d"
+apple_gfx_map_memory_range(uint32_t i, uint64_t phys_addr, uint64_t phys_l=
en) "[%d] phys_addr=3D0x%"PRIx64" phys_len=3D0x%"PRIx64
+apple_gfx_remap(uint64_t retval, void *source_ptr, uint64_t target) "retva=
l=3D%"PRId64" source=3D%p target=3D0x%"PRIx64
+apple_gfx_unmap_memory(void *task, uint64_t virtual_offset, uint64_t lengt=
h) "task=3D%p virtual_offset=3D0x%"PRIx64" length=3D0x%"PRIx64
+apple_gfx_read_memory(uint64_t phys_address, uint64_t length, void *dst) "=
phys_addr=3D0x%"PRIx64" length=3D0x%"PRIx64" dest=3D%p"
+apple_gfx_raise_irq(uint32_t vector) "vector=3D0x%x"
+apple_gfx_new_frame(void) ""
+apple_gfx_mode_change(uint64_t x, uint64_t y) "x=3D%"PRId64" y=3D%"PRId64
+apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint64_t height) "bpp=
=3D%d width=3D%"PRId64" height=3D0x%"PRId64
+apple_gfx_cursor_show(uint32_t show) "show=3D%d"
+apple_gfx_cursor_move(void) ""
+apple_gfx_common_init(const char *device_name, size_t mmio_size) "device: =
%s; MMIO size: %zu bytes"
+
+# apple-gfx-mmio.m
+apple_gfx_mmio_iosfc_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRI=
x64" res=3D0x%"PRIx64
+apple_gfx_mmio_iosfc_write(uint64_t offset, uint64_t val) "offset=3D0x%"PR=
Ix64" val=3D0x%"PRIx64
+apple_gfx_iosfc_map_memory(uint64_t phys, uint64_t len, uint32_t ro, void =
*va, void *e, void *f, void* va_result) "phys=3D0x%"PRIx64" len=3D0x%"PRIx6=
4" ro=3D%d va=3D%p e=3D%p f=3D%p -> *va=3D%p"
+apple_gfx_iosfc_map_memory_new_region(size_t i, void *region, uint64_t sta=
rt, uint64_t end) "index=3D%zu, region=3D%p, 0x%"PRIx64"-0x%"PRIx64
+apple_gfx_iosfc_unmap_memory(void *a, void *b, void *c, void *d, void *e, =
void *f) "a=3D%p b=3D%p c=3D%p d=3D%p e=3D%p f=3D%p"
+apple_gfx_iosfc_unmap_memory_region(void* mem, void *region) "unmapping @ =
%p from memory region %p"
+apple_gfx_iosfc_raise_irq(uint32_t vector) "vector=3D0x%x"
+
diff --git a/meson.build b/meson.build
index 147097c652e..1303664e167 100644
--- a/meson.build
+++ b/meson.build
@@ -794,6 +794,8 @@ socket =3D []
 version_res =3D []
 coref =3D []
 iokit =3D []
+pvg =3D not_found
+metal =3D []
 emulator_link_args =3D []
 midl =3D not_found
 widl =3D not_found
@@ -815,6 +817,8 @@ elif host_os =3D=3D 'darwin'
   coref =3D dependency('appleframeworks', modules: 'CoreFoundation')
   iokit =3D dependency('appleframeworks', modules: 'IOKit', required: fals=
e)
   host_dsosuf =3D '.dylib'
+  pvg =3D dependency('appleframeworks', modules: 'ParavirtualizedGraphics')
+  metal =3D dependency('appleframeworks', modules: 'Metal')
 elif host_os =3D=3D 'sunos'
   socket =3D [cc.find_library('socket'),
             cc.find_library('nsl'),
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103216; cv=none;
	d=zohomail.com; s=zohoarc;
	b=aSpIXxSRJ7cq5B2UEL1qdZxN0wOQ6fIllIK098ceqB7qAl0lDC+/82Irswm2dynF18nxCe+NKezDr/NKdWBSXTFcMbEzddg6T2PFZtbb+fpmW5Lgrppuf0B1BIgK+79UgtFxnZTv3GzEfR5smPEHQi6O3xP220prros2E7NP+IQ=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103216;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=zDE6dZztI5U2peYmtLQlBjA/pUyMd6cxpgOj52p0H2A=;
	b=WKi5iL1o1c+CXumkre/IlqWm8hVcgprrTu7CNGi61Fu9dkDvKt+euVW9Pr4NptItHovaDnCtT6+WKUHYgLMD3gKHhaZsRHEGnB16+HPLr37e0t67a0j7bPAHK+MwyS7mCQnlmgD4qQzQboW6qj0d8LcvE+tgGUPJIeHTv5ucVbw=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103216623584.9746969820502;
 Fri, 13 Dec 2024 07:20:16 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7RW-0004P8-CN; Fri, 13 Dec 2024 10:19:03 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RL-0004NH-Jw
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:51 -0500
Received: from mail-ed1-x535.google.com ([2a00:1450:4864:20::535])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RD-00054O-59
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:51 -0500
Received: by mail-ed1-x535.google.com with SMTP id
 4fb4d7f45d1cf-5d3f28a4fccso2887829a12.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:42 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.39
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:40 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103121;
 x=1734707921;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=zDE6dZztI5U2peYmtLQlBjA/pUyMd6cxpgOj52p0H2A=;
 b=fbHqe5dMD/PW42GLRxdpGPwb/RV86FuWDjmElQpn4bqUTNUXt9TdAchZyE1zCtdWrG
 gouxWYAh+aWybiBY9xMFwzjmmqBFAKH1+KE44nPjZGUNAz317nvzkF7NLUPqaskhOryl
 3pPFxQiwmDMzyf4RnaMXICDZ7QlrPKsydGd0hyQECazrwifX4qinfZsjXxV/F17fDUZC
 hLnn+DMQ3M0d0bXkEWTnE0XE2BQXzL1RfT4nslhk14dMnR6u2v6U7pVpoK5ktGjMCBla
 v1X2yba9TCVuL7IeGogAZZokCTtAdLwiBqKMtiQg649g91rjDo4pFZT/wpGVFHqVhr1c
 aj5A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103121; x=1734707921;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=zDE6dZztI5U2peYmtLQlBjA/pUyMd6cxpgOj52p0H2A=;
 b=swmHUI//sz9PLoNU+WYGnIKK4SVaDKG5SMlyFF9lcsSqI4josNbOpS+bfR+wH3zIJN
 priJd9T4d6xJPCsy0x6j6HBYEndmyMv5PQQEZrIMFu8bhwQr2qMY8Nql/9CUGsRaekKa
 sepFqMyj4o4FmVh5o3U/zbKulyPA5zHNA1DqcBd+okkYHL0FXIJ7kFU2wvr05+rPv3kg
 mVTQxbEiG9sKymCdEdz+ucEbM1Mf/R6fP/OLebwq2evLJKX2qguMI6Jc54KVNhM7lKpQ
 XBb1FCfsKladCn/bVYK7gPrP8zWFkwMNTLBV4Qcvd4gntaJ0HhhgKq644Xw6O0trisXe
 r7tg==
X-Gm-Message-State: AOJu0YzxT7ITl5l/TLnMU104hNrV6sEqSmmZgvb2E6jnUZzoBYtNwD57
 TnEBqfp0GIMh/qbFR+i2HSJ7P9QpkXa1YBmJF0yqlT3IkAmTT+r3NrpHg6jjz7WPk5dwBe+HR3+
 ZYw==
X-Gm-Gg: ASbGncso5LmRYDUw69KKKjPydyTuwD17uPEQa5BzG1dFPTxBSqwQjlJ+9uY7ufg37oX
 IilH04+01Jlanaruigeu/TJVHXt8B1RTT+u3xmexVQLyIZwqB8QENNYT6LNKg/BsFWfIrneRt2x
 aSGgM5spfRqUQ5nBspWEIGEGZXTF0SU4z/geOa/pYS5DB8edFh9/cUG3045CChh8fXOcd3Z+aJ/
 MPcC2O5Xge43Bl4shPFnv35PsjmV8IfK9n+hYhjE/6KAeilL2kAAy6mHSVO7cyVc66n+4QpoYLc
 UHnDCRz/m6WxAgq28VFjzBZ0KeMgtYwY
X-Google-Smtp-Source: 
 AGHT+IF9gMAtBjlBA7Z0DIjvL59QWPatWVFAa8aAwVQ0qj/jBivNR61WSjqvwk2v7io7iw/uIOUl1A==
X-Received: by 2002:a17:907:96ac:b0:aa6:75bd:eb5 with SMTP id
 a640c23a62f3a-aab77ee9952mr321286166b.57.1734103120913;
 Fri, 13 Dec 2024 07:18:40 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 02/15] hw/display/apple-gfx: Introduce
 ParavirtualizedGraphics.Framework support
Date: Fri, 13 Dec 2024 16:17:52 +0100
Message-Id: <20241213151821.65748-3-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::535;
 envelope-from=phil@philjordan.eu; helo=mail-ed1-x535.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103220002116600

MacOS provides a framework (library) that allows any vmm to implement a
paravirtualized 3d graphics passthrough to the host metal stack called
ParavirtualizedGraphics.Framework (PVG). The library abstracts away
almost every aspect of the paravirtualized device model and only provides
and receives callbacks on MMIO access as well as to share memory address
space between the VM and PVG.

This patch implements a QEMU device that drives PVG for the VMApple
variant of it.

Signed-off-by: Alexander Graf <graf@amazon.com>
Co-authored-by: Alexander Graf <graf@amazon.com>

Subsequent changes:

 * Cherry-pick/rebase conflict fixes, API use updates.
 * Moved from hw/vmapple/ (useful outside that machine type)
 * Overhaul of threading model, many thread safety improvements.
 * Asynchronous rendering.
 * Memory and object lifetime fixes.
 * Refactoring to split generic and (vmapple) MMIO variant specific
   code.

Implementation wise, most of the complexity lies in the differing threading
models of ParavirtualizedGraphics.framework, which uses libdispatch and
internal locks, versus QEMU, which heavily uses the BQL, especially during
memory-mapped device I/O. Great care has therefore been taken to prevent
deadlocks by never calling into PVG methods while holding the BQL, and
similarly never acquiring the BQL in a callback from PVG. Different strateg=
ies
have been used (libdispatch, blocking and non-blocking BHs, RCU, etc.)
depending on the specific requirements at each framework entry and exit poi=
nt.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v2:

 * Cherry-pick/rebase conflict fixes
 * BQL function renaming
 * Moved from hw/vmapple/ (useful outside that machine type)
 * Code review comments: Switched to DEFINE_TYPES macro & little endian
   MMIO.
 * Removed some dead/superfluous code
 * Mad set_mode thread & memory safe
 * Added migration blocker due to lack of (de-)serialisation.
 * Fixes to ObjC refcounting and autorelease pool usage.
 * Fixed ObjC new/init misuse
 * Switched to ObjC category extension for private property.
 * Simplified task memory mapping and made it thread safe.
 * Refactoring to split generic and vmapple MMIO variant specific
   code.
 * Switched to asynchronous MMIO writes on x86-64
 * Rendering and graphics update are now done asynchronously
 * Fixed cursor handling
 * Coding convention fixes
 * Removed software cursor compositing

v3:

 * Rebased on latest upstream, fixed breakages including switching to Reset=
table methods.
 * Squashed patches dealing with dGPUs, MMIO area size, and GPU picking.
 * Allow re-entrant MMIO; this simplifies the code and solves the divergence
   between x86-64 and arm64 variants.

v4:

 * Renamed '-vmapple' device variant to '-mmio'
 * MMIO device type now requires aarch64 host and guest
 * Complete overhaul of the glue code for making Qemu's and
   ParavirtualizedGraphics.framework's threading and synchronisation models
   work together. Calls into PVG are from dispatch queues while the
   BQL-holding initiating thread processes AIO context events; callbacks fr=
om
   PVG are scheduled as BHs on the BQL/main AIO context, awaiting completion
   where necessary.
 * Guest frame rendering state is covered by the BQL, with only the PVG cal=
ls
   outside the lock, and serialised on the named render_queue.
 * Simplified logic for dropping frames in-flight during mode changes, fixed
   bug in pending frames logic.
 * Addressed smaller code review notes such as: function naming, object type
   declarations, type names/declarations/casts, code formatting, #include
   order, over-cautious ObjC retain/release, what goes in init vs realize,
   etc.

v5:

 * Smaller non-functional fixes in response to review comments, such as usi=
ng
   NULL for the AIO_WAIT_WHILE context argument, type name formatting,
   deleting leftover debug code, logging improvements, state struct field
   order and documentation improvements, etc.
 * Instead of a single condition variable for all synchronous BH job types,
   there is now one for each callback block. This reduces the number
   of threads being awoken unnecessarily to near zero.
 * MMIO device variant: Unified the BH job for raising interrupts.
 * Use DMA APIs for PVG framework's guest memory read requests.
 * Thread safety improvements: ensure mutable AppleGFXState fields are not
   accessed outside the appropriate lock. Added dedicated mutex for the task
   list.
 * Retain references to MemoryRegions for which there exist mappings in each
   PGTask, and for IOSurface mappings.

v6:

 * Switched PGTask_s's' mapped_regions from GPtrArray to GArray
 * Allow DisplaySurface to manage its own vram now that texture -> vram copy
   occurs under BQL.
 * Memory mapping operations now use RCU_READ_LOCK_GUARD() where possible
   instead of a heavy-weight BH job to acquire the BQL.
 * Changed PVG cursor and mode setting callbacks to kick off BHs instead of
   libdispatch tasks which then locked the BQL explicitly.
 * The single remaining callback which must wait for a BH to complete now
   creates an ephemeral QemuSemaphore to await completion.
 * Re-removed tracking of mapped surface manager memory regions. Just look =
up
   and ref/unref the memory regions in the map/unmap callbacks.
 * Re-ordered functions in apple-gfx.m to group them by area of functionali=
ty.
 * Improved comments and tweaked some names.

v7:

 * Use g_ptr_array_find() helper function
 * Error handling coding style tweak

v8:

 * Renamed apple_gfx_host_address_for_gpa_range() to
   apple_gfx_host_ptr_for_gpa_range(), and made it return a void* instead of
   uintptr_t. Fixed up callers and related code.
 * Some adjustments to types used.
 * Variable naming tweaks for better clarity.
 * Fixed leak in unlikely realize error case.
 * Fixed typo in unmap call.
 * Don't bother with dummy argument for g_ptr_array_find(), NULL works too.

v9:

 * Pass device pointer to graphic_console_init().
 * Slightly re-ordered initialisation code.
 * Simplified error handling during realize().
 * Simplified code without functional changes, adjusted code & comment
   formatting.

v10:

 * Reworked the way frame rendering code is threaded to use BHs for sections
   requiring BQL.
 * Fix for ./configure error on non-macOS platforms.
 * Code formatting tweaks.

v11:

 * Generate unique display serial number for each apple-gfx device instance.
 * Dropped redundant local variable initialisation.

v12:

 * Removed 2 redundant variable initialisations.
 * Removed dedicated rendering dispatch_queue, use global queue instead.
 * Fixed an object leak regression introduced in v10. Solved by placing
   @autoreleasepool blocks around the relevant Objective-C code in the BH
   functions replacing the dispatch_async tasks. (dispatch_async implicitly
   cleaned up autoreleased objects.)
 * Fixed missing retain/release of command buffers when handing off to a
   non-BH thread. (Problem masked at runtime by above leak.)
 * Better handling of render command encoding errors.
 * Re-arranged positions of static variables in the file.

 hw/display/Kconfig          |   9 +
 hw/display/apple-gfx-mmio.m | 281 +++++++++++++
 hw/display/apple-gfx.h      |  66 +++
 hw/display/apple-gfx.m      | 783 ++++++++++++++++++++++++++++++++++++
 hw/display/meson.build      |   6 +
 hw/display/trace-events     |  28 ++
 meson.build                 |   4 +
 7 files changed, 1177 insertions(+)
 create mode 100644 hw/display/apple-gfx-mmio.m
 create mode 100644 hw/display/apple-gfx.h
 create mode 100644 hw/display/apple-gfx.m

diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index 2250c740078..6a9b7b19ada 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -140,3 +140,12 @@ config XLNX_DISPLAYPORT
=20
 config DM163
     bool
+
+config MAC_PVG
+    bool
+    default y
+
+config MAC_PVG_MMIO
+    bool
+    depends on MAC_PVG && AARCH64
+
diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m
new file mode 100644
index 00000000000..1a46ff48b75
--- /dev/null
+++ b/hw/display/apple-gfx-mmio.m
@@ -0,0 +1,281 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device, MMIO (arm64) varia=
nt
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS prov=
ides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU as an MMIO-ba=
sed
+ * system device for macOS on arm64 VMs.
+ */
+
+#include "qemu/osdep.h"
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+#include "apple-gfx.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "trace.h"
+#include "qemu/log.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXMMIOState, APPLE_GFX_MMIO)
+
+/*
+ * ParavirtualizedGraphics.Framework only ships header files for the PCI
+ * variant which does not include IOSFC descriptors and host devices. We a=
dd
+ * their definitions here so that we can also work with the ARM version.
+ */
+typedef bool(^IOSFCRaiseInterrupt)(uint32_t vector);
+typedef bool(^IOSFCUnmapMemory)(
+    void *, void *, void *, void *, void *, void *);
+typedef bool(^IOSFCMapMemory)(
+    uint64_t phys, uint64_t len, bool ro, void **va, void *, void *);
+
+@interface PGDeviceDescriptor (IOSurfaceMapper)
+@property (readwrite, nonatomic) bool usingIOSurfaceMapper;
+@end
+
+@interface PGIOSurfaceHostDeviceDescriptor : NSObject
+-(PGIOSurfaceHostDeviceDescriptor *)init;
+@property (readwrite, nonatomic, copy, nullable) IOSFCMapMemory mapMemory;
+@property (readwrite, nonatomic, copy, nullable) IOSFCUnmapMemory unmapMem=
ory;
+@property (readwrite, nonatomic, copy, nullable) IOSFCRaiseInterrupt raise=
Interrupt;
+@end
+
+@interface PGIOSurfaceHostDevice : NSObject
+-(instancetype)initWithDescriptor:(PGIOSurfaceHostDeviceDescriptor *)desc;
+-(uint32_t)mmioReadAtOffset:(size_t)offset;
+-(void)mmioWriteAtOffset:(size_t)offset value:(uint32_t)value;
+@end
+
+struct AppleGFXMapSurfaceMemoryJob;
+struct AppleGFXMMIOState {
+    SysBusDevice parent_obj;
+
+    AppleGFXState common;
+
+    qemu_irq irq_gfx;
+    qemu_irq irq_iosfc;
+    MemoryRegion iomem_iosfc;
+    PGIOSurfaceHostDevice *pgiosfc;
+};
+
+typedef struct AppleGFXMMIOJob {
+    AppleGFXMMIOState *state;
+    uint64_t offset;
+    uint64_t value;
+    bool completed;
+} AppleGFXMMIOJob;
+
+static void iosfc_do_read(void *opaque)
+{
+    AppleGFXMMIOJob *job =3D opaque;
+    job->value =3D [job->state->pgiosfc mmioReadAtOffset:job->offset];
+    qatomic_set(&job->completed, true);
+    aio_wait_kick();
+}
+
+static uint64_t iosfc_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AppleGFXMMIOJob job =3D {
+        .state =3D opaque,
+        .offset =3D offset,
+        .completed =3D false,
+    };
+    dispatch_queue_t queue =3D
+        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+    dispatch_async_f(queue, &job, iosfc_do_read);
+    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+    trace_apple_gfx_mmio_iosfc_read(offset, job.value);
+    return job.value;
+}
+
+static void iosfc_do_write(void *opaque)
+{
+    AppleGFXMMIOJob *job =3D opaque;
+    [job->state->pgiosfc mmioWriteAtOffset:job->offset value:job->value];
+    qatomic_set(&job->completed, true);
+    aio_wait_kick();
+}
+
+static void iosfc_write(void *opaque, hwaddr offset, uint64_t val,
+                        unsigned size)
+{
+    AppleGFXMMIOJob job =3D {
+        .state =3D opaque,
+        .offset =3D offset,
+        .value =3D val,
+        .completed =3D false,
+    };
+    dispatch_queue_t queue =3D
+        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+    dispatch_async_f(queue, &job, iosfc_do_write);
+    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+    trace_apple_gfx_mmio_iosfc_write(offset, val);
+}
+
+static const MemoryRegionOps apple_iosfc_ops =3D {
+    .read =3D iosfc_read,
+    .write =3D iosfc_write,
+    .endianness =3D DEVICE_LITTLE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+};
+
+static void raise_irq_bh(void *opaque)
+{
+    qemu_irq *irq =3D opaque;
+
+    qemu_irq_pulse(*irq);
+}
+
+static void *apple_gfx_mmio_map_surface_memory(uint64_t guest_physical_add=
ress,
+                                               uint64_t length, bool read_=
only)
+{
+    void *mem;
+    MemoryRegion *region =3D NULL;
+
+    RCU_READ_LOCK_GUARD();
+    mem =3D apple_gfx_host_ptr_for_gpa_range(guest_physical_address,
+                                           length, read_only, &region);
+    if (mem) {
+        memory_region_ref(region);
+    }
+    return mem;
+}
+
+static bool apple_gfx_mmio_unmap_surface_memory(void *ptr)
+{
+    MemoryRegion *region;
+    ram_addr_t offset =3D 0;
+
+    RCU_READ_LOCK_GUARD();
+    region =3D memory_region_from_host(ptr, &offset);
+    if (!region) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: memory at %p to be unmapped no=
t "
+                      "found.\n",
+                      __func__, ptr);
+        return false;
+    }
+
+    trace_apple_gfx_iosfc_unmap_memory_region(ptr, region);
+    memory_region_unref(region);
+    return true;
+}
+
+static PGIOSurfaceHostDevice *apple_gfx_prepare_iosurface_host_device(
+    AppleGFXMMIOState *s)
+{
+    PGIOSurfaceHostDeviceDescriptor *iosfc_desc =3D
+        [PGIOSurfaceHostDeviceDescriptor new];
+    PGIOSurfaceHostDevice *iosfc_host_dev;
+
+    iosfc_desc.mapMemory =3D
+        ^bool(uint64_t phys, uint64_t len, bool ro, void **va, void *e, vo=
id *f) {
+            *va =3D apple_gfx_mmio_map_surface_memory(phys, len, ro);
+
+            trace_apple_gfx_iosfc_map_memory(phys, len, ro, va, e, f, *va);
+
+            return *va !=3D NULL;
+        };
+
+    iosfc_desc.unmapMemory =3D
+        ^bool(void *va, void *b, void *c, void *d, void *e, void *f) {
+            return apple_gfx_mmio_unmap_surface_memory(va);
+        };
+
+    iosfc_desc.raiseInterrupt =3D ^bool(uint32_t vector) {
+        trace_apple_gfx_iosfc_raise_irq(vector);
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                raise_irq_bh, &s->irq_iosfc);
+        return true;
+    };
+
+    iosfc_host_dev =3D
+        [[PGIOSurfaceHostDevice alloc] initWithDescriptor:iosfc_desc];
+    [iosfc_desc release];
+    return iosfc_host_dev;
+}
+
+static void apple_gfx_mmio_realize(DeviceState *dev, Error **errp)
+{
+    @autoreleasepool {
+        AppleGFXMMIOState *s =3D APPLE_GFX_MMIO(dev);
+        PGDeviceDescriptor *desc =3D [PGDeviceDescriptor new];
+
+        desc.raiseInterrupt =3D ^(uint32_t vector) {
+            trace_apple_gfx_raise_irq(vector);
+            aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                    raise_irq_bh, &s->irq_gfx);
+        };
+
+        desc.usingIOSurfaceMapper =3D true;
+        s->pgiosfc =3D apple_gfx_prepare_iosurface_host_device(s);
+
+        if (!apple_gfx_common_realize(&s->common, dev, desc, errp)) {
+            [s->pgiosfc release];
+            s->pgiosfc =3D nil;
+        }
+
+        [desc release];
+        desc =3D nil;
+    }
+}
+
+static void apple_gfx_mmio_init(Object *obj)
+{
+    AppleGFXMMIOState *s =3D APPLE_GFX_MMIO(obj);
+
+    apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_MMIO);
+
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->common.iomem_gfx);
+    memory_region_init_io(&s->iomem_iosfc, obj, &apple_iosfc_ops, s,
+                          TYPE_APPLE_GFX_MMIO, 0x10000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem_iosfc);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_gfx);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_iosfc);
+}
+
+static void apple_gfx_mmio_reset(Object *obj, ResetType type)
+{
+    AppleGFXMMIOState *s =3D APPLE_GFX_MMIO(obj);
+    [s->common.pgdev reset];
+}
+
+
+static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+    ResettableClass *rc =3D RESETTABLE_CLASS(klass);
+
+    rc->phases.hold =3D apple_gfx_mmio_reset;
+    dc->hotpluggable =3D false;
+    dc->realize =3D apple_gfx_mmio_realize;
+}
+
+static TypeInfo apple_gfx_mmio_types[] =3D {
+    {
+        .name          =3D TYPE_APPLE_GFX_MMIO,
+        .parent        =3D TYPE_SYS_BUS_DEVICE,
+        .instance_size =3D sizeof(AppleGFXMMIOState),
+        .class_init    =3D apple_gfx_mmio_class_init,
+        .instance_init =3D apple_gfx_mmio_init,
+    }
+};
+DEFINE_TYPES(apple_gfx_mmio_types)
diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h
new file mode 100644
index 00000000000..ef2455e3bdc
--- /dev/null
+++ b/hw/display/apple-gfx.h
@@ -0,0 +1,66 @@
+/*
+ * Data structures and functions shared between variants of the macOS
+ * ParavirtualizedGraphics.framework based apple-gfx display adapter.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_APPLE_GFX_H
+#define QEMU_APPLE_GFX_H
+
+#define TYPE_APPLE_GFX_MMIO         "apple-gfx-mmio"
+#define TYPE_APPLE_GFX_PCI          "apple-gfx-pci"
+
+#include "qemu/osdep.h"
+#include <dispatch/dispatch.h>
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+#include "qemu/typedefs.h"
+#include "exec/memory.h"
+#include "ui/surface.h"
+
+@class PGDeviceDescriptor;
+@protocol PGDevice;
+@protocol PGDisplay;
+@protocol MTLDevice;
+@protocol MTLTexture;
+@protocol MTLCommandQueue;
+
+typedef QTAILQ_HEAD(, PGTask_s) PGTaskList;
+
+typedef struct AppleGFXState {
+    /* Initialised on init/realize() */
+    MemoryRegion iomem_gfx;
+    id<PGDevice> pgdev;
+    id<PGDisplay> pgdisp;
+    QemuConsole *con;
+    id<MTLDevice> mtl;
+    id<MTLCommandQueue> mtl_queue;
+
+    /* List `tasks` is protected by task_mutex */
+    QemuMutex task_mutex;
+    PGTaskList tasks;
+
+    /* Mutable state (BQL protected) */
+    QEMUCursor *cursor;
+    DisplaySurface *surface;
+    id<MTLTexture> texture;
+    int8_t pending_frames; /* # guest frames in the rendering pipeline */
+    bool gfx_update_requested; /* QEMU display system wants a new frame */
+    bool new_frame_ready; /* Guest has rendered a frame, ready to be used =
*/
+    bool using_managed_texture_storage;
+    uint32_t rendering_frame_width;
+    uint32_t rendering_frame_height;
+
+    /* Mutable state (atomic) */
+    bool cursor_show;
+} AppleGFXState;
+
+void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_=
name);
+bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
+                              PGDeviceDescriptor *desc, Error **errp);
+void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_physical,
+                                       uint64_t length, bool read_only,
+                                       MemoryRegion **mapping_in_region);
+
+#endif
+
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
new file mode 100644
index 00000000000..bfaff2b2be2
--- /dev/null
+++ b/hw/display/apple-gfx.m
@@ -0,0 +1,783 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS prov=
ides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU.
+ */
+
+#include "qemu/osdep.h"
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+#include <mach/mach_vm.h>
+#include "apple-gfx.h"
+#include "trace.h"
+#include "qemu-main.h"
+#include "exec/address-spaces.h"
+#include "migration/blocker.h"
+#include "monitor/monitor.h"
+#include "qemu/main-loop.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qapi/visitor.h"
+#include "qapi/error.h"
+#include "sysemu/dma.h"
+#include "ui/console.h"
+
+static const PGDisplayCoord_t apple_gfx_modes[] =3D {
+    { .x =3D 1440, .y =3D 1080 },
+    { .x =3D 1280, .y =3D 1024 },
+};
+
+static Error *apple_gfx_mig_blocker;
+static uint32_t next_pgdisplay_serial_num =3D 1;
+
+static dispatch_queue_t get_background_queue(void)
+{
+    return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+}
+
+/* ------ PGTask and task operations: new/destroy/map/unmap ------ */
+
+/*
+ * This implements the type declared in <ParavirtualizedGraphics/PGDevice.=
h>
+ * which is opaque from the framework's point of view. It is used in callb=
acks
+ * in the form of its typedef PGTask_t, which also already exists in the
+ * framework headers.
+ *
+ * A "task" in PVG terminology represents a host-virtual contiguous address
+ * range which is reserved in a large chunk on task creation. The mapMemory
+ * callback then requests ranges of guest system memory (identified by the=
ir
+ * GPA) to be mapped into subranges of this reserved address space.
+ * This type of operation isn't well-supported by QEMU's memory subsystem,
+ * but it is fortunately trivial to achieve with Darwin's mach_vm_remap() =
call,
+ * which allows us to refer to the same backing memory via multiple virtual
+ * address ranges. The Mach VM APIs are therefore used throughout for mana=
ging
+ * task memory.
+ */
+struct PGTask_s {
+    QTAILQ_ENTRY(PGTask_s) node;
+    AppleGFXState *s;
+    mach_vm_address_t address;
+    uint64_t len;
+    /*
+     * All unique MemoryRegions for which a mapping has been created in in=
 this
+     * task, and on which we have thus called memory_region_ref(). There a=
re
+     * usually very few regions of system RAM in total, so we expect this =
array
+     * to be very short. Therefore, no need for sorting or fancy search
+     * algorithms, linear search will do.
+     * Protected by AppleGFXState's task_mutex.
+     */
+    GPtrArray *mapped_regions;
+};
+
+static PGTask_t *apple_gfx_new_task(AppleGFXState *s, uint64_t len)
+{
+    mach_vm_address_t task_mem;
+    PGTask_t *task;
+    kern_return_t r;
+
+    r =3D mach_vm_allocate(mach_task_self(), &task_mem, len, VM_FLAGS_ANYW=
HERE);
+    if (r !=3D KERN_SUCCESS) {
+        return NULL;
+    }
+
+    task =3D g_new0(PGTask_t, 1);
+    task->s =3D s;
+    task->address =3D task_mem;
+    task->len =3D len;
+    task->mapped_regions =3D g_ptr_array_sized_new(2 /* Usually enough */);
+
+    QEMU_LOCK_GUARD(&s->task_mutex);
+    QTAILQ_INSERT_TAIL(&s->tasks, task, node);
+
+    return task;
+}
+
+static void apple_gfx_destroy_task(AppleGFXState *s, PGTask_t *task)
+{
+    GPtrArray *regions =3D task->mapped_regions;
+    MemoryRegion *region;
+    size_t i;
+
+    for (i =3D 0; i < regions->len; ++i) {
+        region =3D g_ptr_array_index(regions, i);
+        memory_region_unref(region);
+    }
+    g_ptr_array_unref(regions);
+
+    mach_vm_deallocate(mach_task_self(), task->address, task->len);
+
+    QEMU_LOCK_GUARD(&s->task_mutex);
+    QTAILQ_REMOVE(&s->tasks, task, node);
+    g_free(task);
+}
+
+void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_physical,
+                                       uint64_t length, bool read_only,
+                                       MemoryRegion **mapping_in_region)
+{
+    MemoryRegion *ram_region;
+    char *host_ptr;
+    hwaddr ram_region_offset =3D 0;
+    hwaddr ram_region_length =3D length;
+
+    ram_region =3D address_space_translate(&address_space_memory,
+                                         guest_physical,
+                                         &ram_region_offset,
+                                         &ram_region_length, !read_only,
+                                         MEMTXATTRS_UNSPECIFIED);
+
+    if (!ram_region || ram_region_length < length ||
+        !memory_access_is_direct(ram_region, !read_only)) {
+        return NULL;
+    }
+
+    host_ptr =3D memory_region_get_ram_ptr(ram_region);
+    if (!host_ptr) {
+        return NULL;
+    }
+    host_ptr +=3D ram_region_offset;
+    *mapping_in_region =3D ram_region;
+    return host_ptr;
+}
+
+static bool apple_gfx_task_map_memory(AppleGFXState *s, PGTask_t *task,
+                                      uint64_t virtual_offset,
+                                      PGPhysicalMemoryRange_t *ranges,
+                                      uint32_t range_count, bool read_only)
+{
+    kern_return_t r;
+    void *source_ptr;
+    mach_vm_address_t target;
+    vm_prot_t cur_protection, max_protection;
+    bool success =3D true;
+    MemoryRegion *region;
+
+    RCU_READ_LOCK_GUARD();
+    QEMU_LOCK_GUARD(&s->task_mutex);
+
+    trace_apple_gfx_map_memory(task, range_count, virtual_offset, read_onl=
y);
+    for (int i =3D 0; i < range_count; i++) {
+        PGPhysicalMemoryRange_t *range =3D &ranges[i];
+
+        target =3D task->address + virtual_offset;
+        virtual_offset +=3D range->physicalLength;
+
+        trace_apple_gfx_map_memory_range(i, range->physicalAddress,
+                                         range->physicalLength);
+
+        region =3D NULL;
+        source_ptr =3D apple_gfx_host_ptr_for_gpa_range(range->physicalAdd=
ress,
+                                                      range->physicalLengt=
h,
+                                                      read_only, &region);
+        if (!source_ptr) {
+            success =3D false;
+            continue;
+        }
+
+        if (!g_ptr_array_find(task->mapped_regions, region, NULL)) {
+            g_ptr_array_add(task->mapped_regions, region);
+            memory_region_ref(region);
+        }
+
+        cur_protection =3D 0;
+        max_protection =3D 0;
+        /* Map guest RAM at range->physicalAddress into PG task memory ran=
ge */
+        r =3D mach_vm_remap(mach_task_self(),
+                          &target, range->physicalLength, vm_page_size - 1,
+                          VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
+                          mach_task_self(), (mach_vm_address_t)source_ptr,
+                          false /* shared mapping, no copy */,
+                          &cur_protection, &max_protection,
+                          VM_INHERIT_COPY);
+        trace_apple_gfx_remap(r, source_ptr, target);
+        g_assert(r =3D=3D KERN_SUCCESS);
+    }
+
+    return success;
+}
+
+static void apple_gfx_task_unmap_memory(AppleGFXState *s, PGTask_t *task,
+                                        uint64_t virtual_offset, uint64_t =
length)
+{
+    kern_return_t r;
+    mach_vm_address_t range_address;
+
+    trace_apple_gfx_unmap_memory(task, virtual_offset, length);
+
+    /*
+     * Replace task memory range with fresh 0 pages, undoing the mapping
+     * from guest RAM.
+     */
+    range_address =3D task->address + virtual_offset;
+    r =3D mach_vm_allocate(mach_task_self(), &range_address, length,
+                         VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
+    g_assert(r =3D=3D KERN_SUCCESS);
+}
+
+/* ------ Rendering and frame management ------ */
+
+static void apple_gfx_render_frame_completed_bh(void *opaque);
+
+static void apple_gfx_render_new_frame(AppleGFXState *s)
+{
+    bool managed_texture =3D s->using_managed_texture_storage;
+    uint32_t width =3D surface_width(s->surface);
+    uint32_t height =3D surface_height(s->surface);
+    MTLRegion region =3D MTLRegionMake2D(0, 0, width, height);
+    id<MTLCommandBuffer> command_buffer =3D [s->mtl_queue commandBuffer];
+    id<MTLTexture> texture =3D s->texture;
+
+    assert(bql_locked());
+    [texture retain];
+    [command_buffer retain];
+
+    s->rendering_frame_width =3D width;
+    s->rendering_frame_height =3D height;
+
+    dispatch_async(get_background_queue(), ^{
+        /*
+         * This is not safe to call from the BQL/BH due to PVG-internal lo=
cks
+         * causing deadlocks.
+         */
+        bool r =3D [s->pgdisp encodeCurrentFrameToCommandBuffer:command_bu=
ffer
+                                                 texture:texture
+                                                  region:region];
+        if (!r) {
+            [texture release];
+            [command_buffer release];
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: encodeCurrentFrameToCommandBuffer:texture:r=
egion: "
+                          "failed\n", __func__);
+            bql_lock();
+            --s->pending_frames;
+            if (s->pending_frames > 0) {
+                apple_gfx_render_new_frame(s);
+            }
+            bql_unlock();
+            return;
+        }
+
+        if (managed_texture) {
+            /* "Managed" textures exist in both VRAM and RAM and must be s=
ynced. */
+            id<MTLBlitCommandEncoder> blit =3D [command_buffer blitCommand=
Encoder];
+            [blit synchronizeResource:texture];
+            [blit endEncoding];
+        }
+        [texture release];
+        [command_buffer addCompletedHandler:
+            ^(id<MTLCommandBuffer> cb)
+            {
+                aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                        apple_gfx_render_frame_completed_b=
h, s);
+            }];
+        [command_buffer commit];
+        [command_buffer release];
+    });
+}
+
+static void copy_mtl_texture_to_surface_mem(id<MTLTexture> texture, void *=
vram)
+{
+    /*
+     * TODO: Skip this entirely on a pure Metal or headless/guest-only
+     * rendering path, else use a blit command encoder? Needs careful
+     * (double?) buffering design.
+     */
+    size_t width =3D texture.width, height =3D texture.height;
+    MTLRegion region =3D MTLRegionMake2D(0, 0, width, height);
+    [texture getBytes:vram
+          bytesPerRow:(width * 4)
+        bytesPerImage:(width * height * 4)
+           fromRegion:region
+          mipmapLevel:0
+                slice:0];
+}
+
+static void apple_gfx_render_frame_completed_bh(void *opaque)
+{
+    AppleGFXState *s =3D opaque;
+
+    @autoreleasepool {
+        --s->pending_frames;
+        assert(s->pending_frames >=3D 0);
+
+        /* Only update display if mode hasn't changed since we started ren=
dering. */
+        if (s->rendering_frame_width =3D=3D surface_width(s->surface) &&
+            s->rendering_frame_height =3D=3D surface_height(s->surface)) {
+            copy_mtl_texture_to_surface_mem(s->texture, surface_data(s->su=
rface));
+            if (s->gfx_update_requested) {
+                s->gfx_update_requested =3D false;
+                dpy_gfx_update_full(s->con);
+                graphic_hw_update_done(s->con);
+                s->new_frame_ready =3D false;
+            } else {
+                s->new_frame_ready =3D true;
+            }
+        }
+        if (s->pending_frames > 0) {
+            apple_gfx_render_new_frame(s);
+        }
+    }
+}
+
+static void apple_gfx_fb_update_display(void *opaque)
+{
+    AppleGFXState *s =3D opaque;
+
+    assert(bql_locked());
+    if (s->new_frame_ready) {
+        dpy_gfx_update_full(s->con);
+        s->new_frame_ready =3D false;
+        graphic_hw_update_done(s->con);
+    } else if (s->pending_frames > 0) {
+        s->gfx_update_requested =3D true;
+    } else {
+        graphic_hw_update_done(s->con);
+    }
+}
+
+static const GraphicHwOps apple_gfx_fb_ops =3D {
+    .gfx_update =3D apple_gfx_fb_update_display,
+    .gfx_update_async =3D true,
+};
+
+/* ------ Mouse cursor and display mode setting ------ */
+
+static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
+{
+    MTLTextureDescriptor *textureDescriptor;
+
+    if (s->surface &&
+        width =3D=3D surface_width(s->surface) &&
+        height =3D=3D surface_height(s->surface)) {
+        return;
+    }
+
+    [s->texture release];
+
+    s->surface =3D qemu_create_displaysurface(width, height);
+
+    @autoreleasepool {
+        textureDescriptor =3D
+            [MTLTextureDescriptor
+                texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
+                                             width:width
+                                            height:height
+                                         mipmapped:NO];
+        textureDescriptor.usage =3D s->pgdisp.minimumTextureUsage;
+        s->texture =3D [s->mtl newTextureWithDescriptor:textureDescriptor];
+        s->using_managed_texture_storage =3D
+            (s->texture.storageMode =3D=3D MTLStorageModeManaged);
+    }
+
+    dpy_gfx_replace_surface(s->con, s->surface);
+}
+
+static void update_cursor(AppleGFXState *s)
+{
+    assert(bql_locked());
+    dpy_mouse_set(s->con, s->pgdisp.cursorPosition.x,
+                  s->pgdisp.cursorPosition.y, qatomic_read(&s->cursor_show=
));
+}
+
+static void update_cursor_bh(void *opaque)
+{
+    AppleGFXState *s =3D opaque;
+    update_cursor(s);
+}
+
+typedef struct AppleGFXSetCursorGlyphJob {
+    AppleGFXState *s;
+    NSBitmapImageRep *glyph;
+    PGDisplayCoord_t hotspot;
+} AppleGFXSetCursorGlyphJob;
+
+static void set_cursor_glyph(void *opaque)
+{
+    AppleGFXSetCursorGlyphJob *job =3D opaque;
+    AppleGFXState *s =3D job->s;
+    NSBitmapImageRep *glyph =3D job->glyph;
+    uint32_t bpp =3D glyph.bitsPerPixel;
+    size_t width =3D glyph.pixelsWide;
+    size_t height =3D glyph.pixelsHigh;
+    size_t padding_bytes_per_row =3D glyph.bytesPerRow - width * 4;
+    const uint8_t* px_data =3D glyph.bitmapData;
+
+    trace_apple_gfx_cursor_set(bpp, width, height);
+
+    if (s->cursor) {
+        cursor_unref(s->cursor);
+        s->cursor =3D NULL;
+    }
+
+    if (bpp =3D=3D 32) { /* Shouldn't be anything else, but just to be saf=
e...*/
+        s->cursor =3D cursor_alloc(width, height);
+        s->cursor->hot_x =3D job->hotspot.x;
+        s->cursor->hot_y =3D job->hotspot.y;
+
+        uint32_t *dest_px =3D s->cursor->data;
+
+        for (size_t y =3D 0; y < height; ++y) {
+            for (size_t x =3D 0; x < width; ++x) {
+                /*
+                 * NSBitmapImageRep's red & blue channels are swapped
+                 * compared to QEMUCursor's.
+                 */
+                *dest_px =3D
+                    (px_data[0] << 16u) |
+                    (px_data[1] <<  8u) |
+                    (px_data[2] <<  0u) |
+                    (px_data[3] << 24u);
+                ++dest_px;
+                px_data +=3D 4;
+            }
+            px_data +=3D padding_bytes_per_row;
+        }
+        dpy_cursor_define(s->con, s->cursor);
+        update_cursor(s);
+    }
+    [glyph release];
+
+    g_free(job);
+}
+
+/* ------ DMA (device reading system memory) ------ */
+
+typedef struct AppleGFXReadMemoryJob {
+    QemuSemaphore sem;
+    hwaddr physical_address;
+    uint64_t length;
+    void *dst;
+    bool success;
+} AppleGFXReadMemoryJob;
+
+static void apple_gfx_do_read_memory(void *opaque)
+{
+    AppleGFXReadMemoryJob *job =3D opaque;
+    MemTxResult r;
+
+    r =3D dma_memory_read(&address_space_memory, job->physical_address,
+                        job->dst, job->length, MEMTXATTRS_UNSPECIFIED);
+    job->success =3D r =3D=3D MEMTX_OK;
+
+    qemu_sem_post(&job->sem);
+}
+
+static bool apple_gfx_read_memory(AppleGFXState *s, hwaddr physical_addres=
s,
+                                  uint64_t length, void *dst)
+{
+    AppleGFXReadMemoryJob job =3D {
+        .physical_address =3D physical_address, .length =3D length, .dst =
=3D dst
+    };
+
+    trace_apple_gfx_read_memory(physical_address, length, dst);
+
+    /* Performing DMA requires BQL, so do it in a BH. */
+    qemu_sem_init(&job.sem, 0);
+    aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                            apple_gfx_do_read_memory, &job);
+    qemu_sem_wait(&job.sem);
+    qemu_sem_destroy(&job.sem);
+    return job.success;
+}
+
+/* ------ Memory-mapped device I/O operations ------ */
+
+typedef struct AppleGFXIOJob {
+    AppleGFXState *state;
+    uint64_t offset;
+    uint64_t value;
+    bool completed;
+} AppleGFXIOJob;
+
+static void apple_gfx_do_read(void *opaque)
+{
+    AppleGFXIOJob *job =3D opaque;
+    job->value =3D [job->state->pgdev mmioReadAtOffset:job->offset];
+    qatomic_set(&job->completed, true);
+    aio_wait_kick();
+}
+
+static uint64_t apple_gfx_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AppleGFXIOJob job =3D {
+        .state =3D opaque,
+        .offset =3D offset,
+        .completed =3D false,
+    };
+    dispatch_queue_t queue =3D get_background_queue();
+
+    dispatch_async_f(queue, &job, apple_gfx_do_read);
+    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+    trace_apple_gfx_read(offset, job.value);
+    return job.value;
+}
+
+static void apple_gfx_do_write(void *opaque)
+{
+    AppleGFXIOJob *job =3D opaque;
+    [job->state->pgdev mmioWriteAtOffset:job->offset value:job->value];
+    qatomic_set(&job->completed, true);
+    aio_wait_kick();
+}
+
+static void apple_gfx_write(void *opaque, hwaddr offset, uint64_t val,
+                            unsigned size)
+{
+    /*
+     * The methods mmioReadAtOffset: and especially mmioWriteAtOffset: can
+     * trigger synchronous operations on other dispatch queues, which in t=
urn
+     * may call back out on one or more of the callback blocks. For this r=
eason,
+     * and as we are holding the BQL, we invoke the I/O methods on a pool
+     * thread and handle AIO tasks while we wait. Any work in the callbacks
+     * requiring the BQL will in turn schedule BHs which this thread will
+     * process while waiting.
+     */
+    AppleGFXIOJob job =3D {
+        .state =3D opaque,
+        .offset =3D offset,
+        .value =3D val,
+        .completed =3D false,
+    };
+    dispatch_queue_t queue =3D get_background_queue();
+
+    dispatch_async_f(queue, &job, apple_gfx_do_write);
+    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+    trace_apple_gfx_write(offset, val);
+}
+
+static const MemoryRegionOps apple_gfx_ops =3D {
+    .read =3D apple_gfx_read,
+    .write =3D apple_gfx_write,
+    .endianness =3D DEVICE_LITTLE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 4,
+    },
+};
+
+static size_t apple_gfx_get_default_mmio_range_size(void)
+{
+    size_t mmio_range_size;
+    @autoreleasepool {
+        PGDeviceDescriptor *desc =3D [PGDeviceDescriptor new];
+        mmio_range_size =3D desc.mmioLength;
+        [desc release];
+    }
+    return mmio_range_size;
+}
+
+/* ------ Initialisation and startup ------ */
+
+void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_=
name)
+{
+    size_t mmio_range_size =3D apple_gfx_get_default_mmio_range_size();
+
+    trace_apple_gfx_common_init(obj_name, mmio_range_size);
+    memory_region_init_io(&s->iomem_gfx, obj, &apple_gfx_ops, s, obj_name,
+                          mmio_range_size);
+
+    /* TODO: PVG framework supports serialising device state: integrate it=
! */
+}
+
+static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
+                                                     PGDeviceDescriptor *d=
esc)
+{
+    desc.createTask =3D ^(uint64_t vmSize, void * _Nullable * _Nonnull bas=
eAddress) {
+        PGTask_t *task =3D apple_gfx_new_task(s, vmSize);
+        *baseAddress =3D (void *)task->address;
+        trace_apple_gfx_create_task(vmSize, *baseAddress);
+        return task;
+    };
+
+    desc.destroyTask =3D ^(PGTask_t * _Nonnull task) {
+        trace_apple_gfx_destroy_task(task, task->mapped_regions->len);
+
+        apple_gfx_destroy_task(s, task);
+    };
+
+    desc.mapMemory =3D ^bool(PGTask_t * _Nonnull task, uint32_t range_coun=
t,
+                           uint64_t virtual_offset, bool read_only,
+                           PGPhysicalMemoryRange_t * _Nonnull ranges) {
+        return apple_gfx_task_map_memory(s, task, virtual_offset,
+                                         ranges, range_count, read_only);
+    };
+
+    desc.unmapMemory =3D ^bool(PGTask_t * _Nonnull task, uint64_t virtual_=
offset,
+                             uint64_t length) {
+        apple_gfx_task_unmap_memory(s, task, virtual_offset, length);
+        return true;
+    };
+
+    desc.readMemory =3D ^bool(uint64_t physical_address, uint64_t length,
+                            void * _Nonnull dst) {
+        return apple_gfx_read_memory(s, physical_address, length, dst);
+    };
+}
+
+static void new_frame_handler_bh(void *opaque)
+{
+    AppleGFXState *s =3D opaque;
+
+    /* Drop frames if guest gets too far ahead. */
+    if (s->pending_frames >=3D 2) {
+        return;
+    }
+    ++s->pending_frames;
+    if (s->pending_frames > 1) {
+        return;
+    }
+
+    @autoreleasepool {
+        apple_gfx_render_new_frame(s);
+    }
+}
+
+static PGDisplayDescriptor *apple_gfx_prepare_display_descriptor(AppleGFXS=
tate *s)
+{
+    PGDisplayDescriptor *disp_desc =3D [PGDisplayDescriptor new];
+
+    disp_desc.name =3D @"QEMU display";
+    disp_desc.sizeInMillimeters =3D NSMakeSize(400., 300.); /* A 20" displ=
ay */
+    disp_desc.queue =3D dispatch_get_main_queue();
+    disp_desc.newFrameEventHandler =3D ^(void) {
+        trace_apple_gfx_new_frame();
+        aio_bh_schedule_oneshot(qemu_get_aio_context(), new_frame_handler_=
bh, s);
+    };
+    disp_desc.modeChangeHandler =3D ^(PGDisplayCoord_t sizeInPixels,
+                                    OSType pixelFormat) {
+        trace_apple_gfx_mode_change(sizeInPixels.x, sizeInPixels.y);
+
+        BQL_LOCK_GUARD();
+        set_mode(s, sizeInPixels.x, sizeInPixels.y);
+    };
+    disp_desc.cursorGlyphHandler =3D ^(NSBitmapImageRep *glyph,
+                                     PGDisplayCoord_t hotspot) {
+        AppleGFXSetCursorGlyphJob *job =3D g_malloc0(sizeof(*job));
+        job->s =3D s;
+        job->glyph =3D glyph;
+        job->hotspot =3D hotspot;
+        [glyph retain];
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                set_cursor_glyph, job);
+    };
+    disp_desc.cursorShowHandler =3D ^(BOOL show) {
+        trace_apple_gfx_cursor_show(show);
+        qatomic_set(&s->cursor_show, show);
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                update_cursor_bh, s);
+    };
+    disp_desc.cursorMoveHandler =3D ^(void) {
+        trace_apple_gfx_cursor_move();
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                update_cursor_bh, s);
+    };
+
+    return disp_desc;
+}
+
+static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void)
+{
+    PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
+    NSArray<PGDisplayMode*>* mode_array;
+    int i;
+
+    for (i =3D 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
+        modes[i] =3D
+            [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i]=
 refreshRateInHz:60.];
+    }
+
+    mode_array =3D [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_=
gfx_modes)];
+
+    for (i =3D 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
+        [modes[i] release];
+        modes[i] =3D nil;
+    }
+
+    return mode_array;
+}
+
+static id<MTLDevice> copy_suitable_metal_device(void)
+{
+    id<MTLDevice> dev =3D nil;
+    NSArray<id<MTLDevice>> *devs =3D MTLCopyAllDevices();
+
+    /* Prefer a unified memory GPU. Failing that, pick a non-removable GPU=
. */
+    for (size_t i =3D 0; i < devs.count; ++i) {
+        if (devs[i].hasUnifiedMemory) {
+            dev =3D devs[i];
+            break;
+        }
+        if (!devs[i].removable) {
+            dev =3D devs[i];
+        }
+    }
+
+    if (dev !=3D nil) {
+        [dev retain];
+    } else {
+        dev =3D MTLCreateSystemDefaultDevice();
+    }
+    [devs release];
+
+    return dev;
+}
+
+bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
+                              PGDeviceDescriptor *desc, Error **errp)
+{
+    PGDisplayDescriptor *disp_desc;
+
+    if (apple_gfx_mig_blocker =3D=3D NULL) {
+        error_setg(&apple_gfx_mig_blocker,
+                  "Migration state blocked by apple-gfx display device");
+        if (migrate_add_blocker(&apple_gfx_mig_blocker, errp) < 0) {
+            return false;
+        }
+    }
+
+    qemu_mutex_init(&s->task_mutex);
+    QTAILQ_INIT(&s->tasks);
+    s->mtl =3D copy_suitable_metal_device();
+    s->mtl_queue =3D [s->mtl newCommandQueue];
+
+    desc.device =3D s->mtl;
+
+    apple_gfx_register_task_mapping_handlers(s, desc);
+
+    s->cursor_show =3D true;
+
+    s->pgdev =3D PGNewDeviceWithDescriptor(desc);
+
+    disp_desc =3D apple_gfx_prepare_display_descriptor(s);
+    /*
+     * Although the framework does, this integration currently does not su=
pport
+     * multiple virtual displays connected to a single PV graphics device.
+     * It is however possible to create
+     * more than one instance of the device, each with one display. The ma=
cOS
+     * guest will ignore these displays if they share the same serial numb=
er,
+     * so ensure each instance gets a unique one.
+     */
+    s->pgdisp =3D [s->pgdev newDisplayWithDescriptor:disp_desc
+                                              port:0
+                                         serialNum:next_pgdisplay_serial_n=
um++];
+    [disp_desc release];
+    s->pgdisp.modeList =3D apple_gfx_prepare_display_mode_array();
+
+    s->con =3D graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
+    return true;
+}
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 20a94973fa2..cf9e6dd35d2 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -61,6 +61,12 @@ system_ss.add(when: 'CONFIG_ARTIST', if_true: files('art=
ist.c'))
=20
 system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('ati.c', 'ati_2d.c',=
 'ati_dbg.c'), pixman])
=20
+if host_os =3D=3D 'darwin'
+  system_ss.add(when: 'CONFIG_MAC_PVG',         if_true: [files('apple-gfx=
.m'), pvg, metal])
+  if cpu =3D=3D 'aarch64'
+    system_ss.add(when: 'CONFIG_MAC_PVG_MMIO',  if_true: [files('apple-gfx=
-mmio.m'), pvg, metal])
+  endif
+endif
=20
 if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
   virtio_gpu_ss =3D ss.source_set()
diff --git a/hw/display/trace-events b/hw/display/trace-events
index d26d663f963..a50e4eea0c0 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -194,3 +194,31 @@ dm163_bits_ppi(unsigned dest_width) "dest_width : %u"
 dm163_leds(int led, uint32_t value) "led %d: 0x%x"
 dm163_channels(int channel, uint8_t value) "channel %d: 0x%x"
 dm163_refresh_rate(uint32_t rr) "refresh rate %d"
+
+# apple-gfx.m
+apple_gfx_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRIx64" res=3D=
0x%"PRIx64
+apple_gfx_write(uint64_t offset, uint64_t val) "offset=3D0x%"PRIx64" val=
=3D0x%"PRIx64
+apple_gfx_create_task(uint32_t vm_size, void *va) "vm_size=3D0x%x base_add=
r=3D%p"
+apple_gfx_destroy_task(void *task, unsigned int num_mapped_regions) "task=
=3D%p, task->mapped_regions->len=3D%u"
+apple_gfx_map_memory(void *task, uint32_t range_count, uint64_t virtual_of=
fset, uint32_t read_only) "task=3D%p range_count=3D0x%x virtual_offset=3D0x=
%"PRIx64" read_only=3D%d"
+apple_gfx_map_memory_range(uint32_t i, uint64_t phys_addr, uint64_t phys_l=
en) "[%d] phys_addr=3D0x%"PRIx64" phys_len=3D0x%"PRIx64
+apple_gfx_remap(uint64_t retval, void *source_ptr, uint64_t target) "retva=
l=3D%"PRId64" source=3D%p target=3D0x%"PRIx64
+apple_gfx_unmap_memory(void *task, uint64_t virtual_offset, uint64_t lengt=
h) "task=3D%p virtual_offset=3D0x%"PRIx64" length=3D0x%"PRIx64
+apple_gfx_read_memory(uint64_t phys_address, uint64_t length, void *dst) "=
phys_addr=3D0x%"PRIx64" length=3D0x%"PRIx64" dest=3D%p"
+apple_gfx_raise_irq(uint32_t vector) "vector=3D0x%x"
+apple_gfx_new_frame(void) ""
+apple_gfx_mode_change(uint64_t x, uint64_t y) "x=3D%"PRId64" y=3D%"PRId64
+apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint64_t height) "bpp=
=3D%d width=3D%"PRId64" height=3D0x%"PRId64
+apple_gfx_cursor_show(uint32_t show) "show=3D%d"
+apple_gfx_cursor_move(void) ""
+apple_gfx_common_init(const char *device_name, size_t mmio_size) "device: =
%s; MMIO size: %zu bytes"
+
+# apple-gfx-mmio.m
+apple_gfx_mmio_iosfc_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRI=
x64" res=3D0x%"PRIx64
+apple_gfx_mmio_iosfc_write(uint64_t offset, uint64_t val) "offset=3D0x%"PR=
Ix64" val=3D0x%"PRIx64
+apple_gfx_iosfc_map_memory(uint64_t phys, uint64_t len, uint32_t ro, void =
*va, void *e, void *f, void* va_result) "phys=3D0x%"PRIx64" len=3D0x%"PRIx6=
4" ro=3D%d va=3D%p e=3D%p f=3D%p -> *va=3D%p"
+apple_gfx_iosfc_map_memory_new_region(size_t i, void *region, uint64_t sta=
rt, uint64_t end) "index=3D%zu, region=3D%p, 0x%"PRIx64"-0x%"PRIx64
+apple_gfx_iosfc_unmap_memory(void *a, void *b, void *c, void *d, void *e, =
void *f) "a=3D%p b=3D%p c=3D%p d=3D%p e=3D%p f=3D%p"
+apple_gfx_iosfc_unmap_memory_region(void* mem, void *region) "unmapping @ =
%p from memory region %p"
+apple_gfx_iosfc_raise_irq(uint32_t vector) "vector=3D0x%x"
+
diff --git a/meson.build b/meson.build
index 147097c652e..1303664e167 100644
--- a/meson.build
+++ b/meson.build
@@ -794,6 +794,8 @@ socket =3D []
 version_res =3D []
 coref =3D []
 iokit =3D []
+pvg =3D not_found
+metal =3D []
 emulator_link_args =3D []
 midl =3D not_found
 widl =3D not_found
@@ -815,6 +817,8 @@ elif host_os =3D=3D 'darwin'
   coref =3D dependency('appleframeworks', modules: 'CoreFoundation')
   iokit =3D dependency('appleframeworks', modules: 'IOKit', required: fals=
e)
   host_dsosuf =3D '.dylib'
+  pvg =3D dependency('appleframeworks', modules: 'ParavirtualizedGraphics')
+  metal =3D dependency('appleframeworks', modules: 'Metal')
 elif host_os =3D=3D 'sunos'
   socket =3D [cc.find_library('socket'),
             cc.find_library('nsl'),
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103467; cv=none;
	d=zohomail.com; s=zohoarc;
	b=aZc5V/QFciP2gurfiOzssY4FODcfQifBhjYrVG9YqUf1OJ/lPaY6w7Z1v6DHMYne36Pa4lr3mIFUZ+aKRKX8jSnDhQfWYpXW6KMOpsrxaWUyw8L13eVJKY7SXrUhdW3ATIBIwoIXrsC1dJzPrJQjYBCz25XQvvAcLYqSSAqMuOs=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103467;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=l9CSE0Le6C9EUk9Pa8FAy+M2SSGHzc5sfGAFZk3Ode0=;
	b=WM6v5zg7VFUVR+EaDa3FAf8n/xlsDsrRRPnPFmHG0d20Cewh2l5LZVicnT9UAeKzjtjmTp7tIJ7If4JdesCIqnDHz5WbYfvICSUTt4kbR3aK2Wk4Xq+lECldG6HYJrGkAMOkx64p2n/oYq3P4uB+dX+LpPY3/WnoNlqpV6gweDg=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 173410346713817.570962424268714;
 Fri, 13 Dec 2024 07:24:27 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Sp-0006hE-Fq; Fri, 13 Dec 2024 10:20:24 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rz-0004fk-Vv
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:33 -0500
Received: from mail-ej1-x633.google.com ([2a00:1450:4864:20::633])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rj-0005I6-F9
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:28 -0500
Received: by mail-ej1-x633.google.com with SMTP id
 a640c23a62f3a-aa69077b93fso275602066b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:14 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.11
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:13 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103153;
 x=1734707953;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=l9CSE0Le6C9EUk9Pa8FAy+M2SSGHzc5sfGAFZk3Ode0=;
 b=IXUL7DsjjLU5qRkEVBcBxmRR1jPAnytRbddClZqReYyZEIdOusjHjmi+BrL4CVCm9t
 +xtOiXP+qOrb5PuXU/+IYMKI8AJfsE3fKrVDmzWuZ8HKn6BNoLXfxvJ/bb6Od9wzXuXu
 ZpOPoMVkU5f83d2eux3ksCBu9rchpSpk/iWl8vZTdEWEhwlqhZOEFpF1n/VAuERnREpo
 3C6rS7rFfbd64I3wgKAHvyJYXYy2P6U7hWx5gADQYbGA+ee12jelwuCrB5yLSHBT8JWq
 s4I2yguLGYr6E26HpJSIF5TJr0LSEtBkKuXVgcFtgWEvYC/G4fWpaP8QnPYWo6zgl4YW
 jajw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103153; x=1734707953;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=l9CSE0Le6C9EUk9Pa8FAy+M2SSGHzc5sfGAFZk3Ode0=;
 b=ue4o6xgzWwemNgHJSy2Exb30IHSEGhuH2OeNzulTNv4f2juVUp3RmVp0WpeBfX5iKT
 zjsRhPjeSuWcPpO/BGj5c5PLmizPfN19xYqcz7Cwit7QdQV9aXFcY1ab1sZHE9f4IKLD
 N3fDIq+B2NIhnGePuJHCC4Kdio8+Zdd6mi//2KeqCuole2jOw/th2VFErR368egNwRbv
 VweI2/02p7n2jP8TIDCLv8WE5jCsjCpkIlvFD7Yfd65+4IKEoTy2rs7e49+dIvKbjfTW
 VyzpHBITdElCKmz4vCNzhVqN30DA2tSIdPBvQIe4ukf4Hz4NfrR7KshMe0FH+1Cv676I
 AYBw==
X-Gm-Message-State: AOJu0YwLvro6DTKeE8gV/2pDai8U26D9C+dBiROkf9YBR94uFR71go6U
 GBOvknzLRcRglmPLQM8TNcPg2hACbFnHjqzPyxUDHfgN94cNaKYrGfTJaHUk9EAvpx+BzzFMGMR
 dpw==
X-Gm-Gg: ASbGncsy3uciC+k/DsUrK7JCz83nH1ol8XRP+zKTpGTMhnpYQFHMRVc5BZ+IiPcaZHF
 Ea3kBh//KObTW1mFAPb7QLeekKx9uv/aNzbFJYBQsTKwisrXVlXXD++2TkVoIQguRjPIhI+c7QR
 1P7jrtwRQDvgTz+HcqwW9//uPmJLqNxrZlbrHzZr8o3WGLd9zyOb80n6g8kVPBc3FEg7Gv+QoBU
 VG+GLgfHVV9UkZYEqpeouoq6hIsTuO3l5L+PnmOClX1+RvCuz/oG0a+B3ttdzZkEnxSm6GuPa0G
 KyUjzqE4MU/uXsHQpq7Q4mFbvOx6NiZT
X-Google-Smtp-Source: 
 AGHT+IE4Br2RNK8bXW4Cxxt5S04J18WVq7NyqGXTdjyHQZnlr2qOGnJDHQYaaTzkZcYidYxs+XYl5Q==
X-Received: by 2002:a17:906:c107:b0:aa6:a732:2129 with SMTP id
 a640c23a62f3a-aab779ab5dcmr267653266b.28.1734103153460;
 Fri, 13 Dec 2024 07:19:13 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu
Subject: [PATCH v14 03/15] hw/display/apple-gfx: Adds PCI implementation
Date: Fri, 13 Dec 2024 16:18:09 +0100
Message-Id: <20241213151821.65748-20-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::633;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x633.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103469641116600

This change wires up the PCI variant of the paravirtualised
graphics device, mainly useful for x86-64 macOS guests, implemented
by macOS's ParavirtualizedGraphics.framework. It builds on code
shared with the vmapple/mmio variant of the PVG device.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Threading improvements analogous to those in common apple-gfx code
   and mmio device variant.
 * Smaller code review issues addressed.

v5:

 * Minor error handling improvement.

v6:

 * Removed an unused function parameter.

v9:

 * Fixup of changed common call.
 * Whitespace and comment formatting tweaks.

v11:

 * Comment formatting fix.

 hw/display/Kconfig         |   4 +
 hw/display/apple-gfx-pci.m | 150 +++++++++++++++++++++++++++++++++++++
 hw/display/meson.build     |   1 +
 3 files changed, 155 insertions(+)
 create mode 100644 hw/display/apple-gfx-pci.m

diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index 6a9b7b19ada..2b53dfd7d26 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -149,3 +149,7 @@ config MAC_PVG_MMIO
     bool
     depends on MAC_PVG && AARCH64
=20
+config MAC_PVG_PCI
+    bool
+    depends on MAC_PVG && PCI
+    default y if PCI_DEVICES
diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m
new file mode 100644
index 00000000000..5ff6a487cfc
--- /dev/null
+++ b/hw/display/apple-gfx-pci.m
@@ -0,0 +1,150 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device, PCI variant
+ *
+ * Copyright =C2=A9 2023-2024 Phil Dennis-Jordan
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS prov=
ides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU as a PCI devi=
ce
+ * aimed primarily at x86-64 macOS VMs.
+ */
+
+#include "apple-gfx.h"
+#include "hw/pci/pci_device.h"
+#include "hw/pci/msi.h"
+#include "qapi/error.h"
+#include "trace.h"
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+
+OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXPCIState, APPLE_GFX_PCI)
+
+struct AppleGFXPCIState {
+    PCIDevice parent_obj;
+
+    AppleGFXState common;
+};
+
+static const char* apple_gfx_pci_option_rom_path =3D NULL;
+
+static void apple_gfx_init_option_rom_path(void)
+{
+    NSURL *option_rom_url =3D PGCopyOptionROMURL();
+    const char *option_rom_path =3D option_rom_url.fileSystemRepresentatio=
n;
+    apple_gfx_pci_option_rom_path =3D g_strdup(option_rom_path);
+    [option_rom_url release];
+}
+
+static void apple_gfx_pci_init(Object *obj)
+{
+    AppleGFXPCIState *s =3D APPLE_GFX_PCI(obj);
+
+    if (!apple_gfx_pci_option_rom_path) {
+        /*
+         * The following is done on device not class init to avoid running
+         * ObjC code before fork() in -daemonize mode.
+         */
+        PCIDeviceClass *pci =3D PCI_DEVICE_CLASS(object_get_class(obj));
+        apple_gfx_init_option_rom_path();
+        pci->romfile =3D apple_gfx_pci_option_rom_path;
+    }
+
+    apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_PCI);
+}
+
+typedef struct AppleGFXPCIInterruptJob {
+    PCIDevice *device;
+    uint32_t vector;
+} AppleGFXPCIInterruptJob;
+
+static void apple_gfx_pci_raise_interrupt(void *opaque)
+{
+    AppleGFXPCIInterruptJob *job =3D opaque;
+
+    if (msi_enabled(job->device)) {
+        msi_notify(job->device, job->vector);
+    }
+    g_free(job);
+}
+
+static void apple_gfx_pci_interrupt(PCIDevice *dev, uint32_t vector)
+{
+    AppleGFXPCIInterruptJob *job;
+
+    trace_apple_gfx_raise_irq(vector);
+    job =3D g_malloc0(sizeof(*job));
+    job->device =3D dev;
+    job->vector =3D vector;
+    aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                            apple_gfx_pci_raise_interrupt, job);
+}
+
+static void apple_gfx_pci_realize(PCIDevice *dev, Error **errp)
+{
+    AppleGFXPCIState *s =3D APPLE_GFX_PCI(dev);
+    int ret;
+
+    pci_register_bar(dev, PG_PCI_BAR_MMIO,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->common.iomem_gfx);
+
+    ret =3D msi_init(dev, 0x0 /* config offset; 0 =3D find space */,
+                   PG_PCI_MAX_MSI_VECTORS, true /* msi64bit */,
+                   false /* msi_per_vector_mask */, errp);
+    if (ret !=3D 0) {
+        return;
+    }
+
+    @autoreleasepool {
+        PGDeviceDescriptor *desc =3D [PGDeviceDescriptor new];
+        desc.raiseInterrupt =3D ^(uint32_t vector) {
+            apple_gfx_pci_interrupt(dev, vector);
+        };
+
+        apple_gfx_common_realize(&s->common, DEVICE(dev), desc, errp);
+        [desc release];
+        desc =3D nil;
+    }
+}
+
+static void apple_gfx_pci_reset(Object *obj, ResetType type)
+{
+    AppleGFXPCIState *s =3D APPLE_GFX_PCI(obj);
+    [s->common.pgdev reset];
+}
+
+static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+    PCIDeviceClass *pci =3D PCI_DEVICE_CLASS(klass);
+    ResettableClass *rc =3D RESETTABLE_CLASS(klass);
+
+    rc->phases.hold =3D apple_gfx_pci_reset;
+    dc->desc =3D "macOS Paravirtualized Graphics PCI Display Controller";
+    dc->hotpluggable =3D false;
+    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+
+    pci->vendor_id =3D PG_PCI_VENDOR_ID;
+    pci->device_id =3D PG_PCI_DEVICE_ID;
+    pci->class_id =3D PCI_CLASS_DISPLAY_OTHER;
+    pci->realize =3D apple_gfx_pci_realize;
+
+    /* TODO: Property for setting mode list */
+}
+
+static TypeInfo apple_gfx_pci_types[] =3D {
+    {
+        .name          =3D TYPE_APPLE_GFX_PCI,
+        .parent        =3D TYPE_PCI_DEVICE,
+        .instance_size =3D sizeof(AppleGFXPCIState),
+        .class_init    =3D apple_gfx_pci_class_init,
+        .instance_init =3D apple_gfx_pci_init,
+        .interfaces =3D (InterfaceInfo[]) {
+            { INTERFACE_PCIE_DEVICE },
+            { },
+        },
+    }
+};
+DEFINE_TYPES(apple_gfx_pci_types)
+
diff --git a/hw/display/meson.build b/hw/display/meson.build
index cf9e6dd35d2..94f4f05d36f 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -63,6 +63,7 @@ system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('at=
i.c', 'ati_2d.c', 'ati_
=20
 if host_os =3D=3D 'darwin'
   system_ss.add(when: 'CONFIG_MAC_PVG',         if_true: [files('apple-gfx=
.m'), pvg, metal])
+  system_ss.add(when: 'CONFIG_MAC_PVG_PCI',     if_true: [files('apple-gfx=
-pci.m'), pvg, metal])
   if cpu =3D=3D 'aarch64'
     system_ss.add(when: 'CONFIG_MAC_PVG_MMIO',  if_true: [files('apple-gfx=
-mmio.m'), pvg, metal])
   endif
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103328; cv=none;
	d=zohomail.com; s=zohoarc;
	b=X8dLSf8nMGCS7wPVsJ4Snxz65AFy6SkjLz/L6XtH2vhKacvoPxGOEVFdK/eGJZBOoKR14C1fYhr5vVBmfx5o7jAoCIlp+ULPXo+4GcXnXMjLtDzoaPZJTt2PuJTDiV0HUy8lylvHCu6PZwIEMJf7UUX88SrBe/VsGKrxxa6fS/c=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103328;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=l9CSE0Le6C9EUk9Pa8FAy+M2SSGHzc5sfGAFZk3Ode0=;
	b=eY/xSPRLPPYfZtf20KFnYgDiPcR9fLBu9eWXwOefSxoM0GuO4wMHo257HtrfCItMAwajPaUmGyb3ebsy9SxOmG+eKHOpPnxcPih5tqR952lYW6H0ck5iS7QH0J4zbY/EThuGyLBzXfnV645/5mFacwUrLoF54YZgvtFjmDfM34g=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103328264171.10442190388403;
 Fri, 13 Dec 2024 07:22:08 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7S8-0004mA-4a; Fri, 13 Dec 2024 10:19:40 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RM-0004ND-4x
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:52 -0500
Received: from mail-ej1-x62e.google.com ([2a00:1450:4864:20::62e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RE-00054l-Qx
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:50 -0500
Received: by mail-ej1-x62e.google.com with SMTP id
 a640c23a62f3a-aa6aad76beeso281696166b.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:44 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.41
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:42 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103123;
 x=1734707923;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=l9CSE0Le6C9EUk9Pa8FAy+M2SSGHzc5sfGAFZk3Ode0=;
 b=rh8NCghtXHdVmiGBeHUyPRNmkLwDF1DTDTYyAApjKZftUc4hnjcXhSUjwRgOF2UBDD
 BAsDi/afK/EVLGTj6UsJkVIc3pb+p1uVxMvcZ3wVUlP4C8+VSnl7WA7obO2rJ4YxkZFu
 HXn0Ab/2JMqu/aX7/LLmycA7imjLusS/P5A8nLVxEzc0aM0jUyJfI1ZG3VUXIqUdVvec
 hWQKX+92uQ/lAbAXp3ejkluUjI4J9kndBXzDyvfV9j7A27HbFWdmMlIkpNPo30DHvRjU
 N3uJzZvtXEM8dKmnZlUGNIQ9LwoQOW+9FR9pw4R9E5su0jwyVY/Hhs5vOyeqp7AyDQUI
 J5OQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103123; x=1734707923;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=l9CSE0Le6C9EUk9Pa8FAy+M2SSGHzc5sfGAFZk3Ode0=;
 b=G+8Z2xpIQGRexlr1MuNbU+jIZS4Ti1jASFuDbjNZoxNF0ZtfXCeqAd8nTJWjVssjh+
 S/tpXCiXNbhh30qtN+Bz3rH7VMhH8IdGV7pWhqa4rEo84WP08t2ReLkx5NDn5GUcB1Xa
 631Zxp/p3s4Ig/9/uLDgpmdAhm1nWl9BjApPKqijfUnGF67WYGoywS3De9gyhpR/p8kc
 xipf37oHcIPWsLfnYq0ceHNNCfYXhDIR8gYB+g73ZHZQ2awSqlWx7GWtW5GhlgyTnvjH
 IogA2G8gFk2snaoYD4C9OPob6kbTlSXThPfMOaLcAXtiQ/jJG4JdBFTKu3PZjvvG+SsV
 KmtA==
X-Gm-Message-State: AOJu0YzrszZhnCep99AZEE2cAid3VZVVN21oubGQZQG3GcXIzAlj9oLB
 CfO5AnAEVX/QguAWP8MT2hWaP/NyTFbTJXhoKkOFWyKWSo3P9w3iRP50X+7w0LV7w9FtaaPDsWY
 mTg==
X-Gm-Gg: ASbGncsUcnhRVIWBJ2mmYXvqZmLK/qppcJ+6uAHiDZv4EiXd74YAAKZZ9j6yHslQZLE
 MCO9mj4uMkJpcc0+dNQ8f6hlmdGMUiffIDkpdItmdZH+a93euh/FqWg3ZmleauMEc6g1c8qcAOw
 wg/CWmWCgPlek6puhgnD1wOgJLDELLSIFnZQ5+j669PKbDTiIOMzab7tOQiI/iZf2P7ghVoMRbf
 65kS/LnF/zY4GtUTMsyoZULI/jMMrkCxVne9VqXezLb/1evpFgw/mPv3F9EeoNs4DJEd5Qh2eR1
 /iRTHiVcTucVUE2A9nwPCvEcfjJaLjuj
X-Google-Smtp-Source: 
 AGHT+IG1OnPsY+gc5hIvMu/qsOoKF++iy6Negq8ME2FSfR8yxpruHhRS8q3+mowXYyQF58F/XvexmQ==
X-Received: by 2002:a17:906:dc95:b0:aa6:5ec2:966c with SMTP id
 a640c23a62f3a-aab778dfea2mr402231366b.7.1734103122835;
 Fri, 13 Dec 2024 07:18:42 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu
Subject: [PATCH v13 03/15] hw/display/apple-gfx: Adds PCI implementation
Date: Fri, 13 Dec 2024 16:17:53 +0100
Message-Id: <20241213151821.65748-4-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62e;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62e.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103328904116600

This change wires up the PCI variant of the paravirtualised
graphics device, mainly useful for x86-64 macOS guests, implemented
by macOS's ParavirtualizedGraphics.framework. It builds on code
shared with the vmapple/mmio variant of the PVG device.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Threading improvements analogous to those in common apple-gfx code
   and mmio device variant.
 * Smaller code review issues addressed.

v5:

 * Minor error handling improvement.

v6:

 * Removed an unused function parameter.

v9:

 * Fixup of changed common call.
 * Whitespace and comment formatting tweaks.

v11:

 * Comment formatting fix.

 hw/display/Kconfig         |   4 +
 hw/display/apple-gfx-pci.m | 150 +++++++++++++++++++++++++++++++++++++
 hw/display/meson.build     |   1 +
 3 files changed, 155 insertions(+)
 create mode 100644 hw/display/apple-gfx-pci.m

diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index 6a9b7b19ada..2b53dfd7d26 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -149,3 +149,7 @@ config MAC_PVG_MMIO
     bool
     depends on MAC_PVG && AARCH64
=20
+config MAC_PVG_PCI
+    bool
+    depends on MAC_PVG && PCI
+    default y if PCI_DEVICES
diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m
new file mode 100644
index 00000000000..5ff6a487cfc
--- /dev/null
+++ b/hw/display/apple-gfx-pci.m
@@ -0,0 +1,150 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device, PCI variant
+ *
+ * Copyright =C2=A9 2023-2024 Phil Dennis-Jordan
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS prov=
ides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU as a PCI devi=
ce
+ * aimed primarily at x86-64 macOS VMs.
+ */
+
+#include "apple-gfx.h"
+#include "hw/pci/pci_device.h"
+#include "hw/pci/msi.h"
+#include "qapi/error.h"
+#include "trace.h"
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+
+OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXPCIState, APPLE_GFX_PCI)
+
+struct AppleGFXPCIState {
+    PCIDevice parent_obj;
+
+    AppleGFXState common;
+};
+
+static const char* apple_gfx_pci_option_rom_path =3D NULL;
+
+static void apple_gfx_init_option_rom_path(void)
+{
+    NSURL *option_rom_url =3D PGCopyOptionROMURL();
+    const char *option_rom_path =3D option_rom_url.fileSystemRepresentatio=
n;
+    apple_gfx_pci_option_rom_path =3D g_strdup(option_rom_path);
+    [option_rom_url release];
+}
+
+static void apple_gfx_pci_init(Object *obj)
+{
+    AppleGFXPCIState *s =3D APPLE_GFX_PCI(obj);
+
+    if (!apple_gfx_pci_option_rom_path) {
+        /*
+         * The following is done on device not class init to avoid running
+         * ObjC code before fork() in -daemonize mode.
+         */
+        PCIDeviceClass *pci =3D PCI_DEVICE_CLASS(object_get_class(obj));
+        apple_gfx_init_option_rom_path();
+        pci->romfile =3D apple_gfx_pci_option_rom_path;
+    }
+
+    apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_PCI);
+}
+
+typedef struct AppleGFXPCIInterruptJob {
+    PCIDevice *device;
+    uint32_t vector;
+} AppleGFXPCIInterruptJob;
+
+static void apple_gfx_pci_raise_interrupt(void *opaque)
+{
+    AppleGFXPCIInterruptJob *job =3D opaque;
+
+    if (msi_enabled(job->device)) {
+        msi_notify(job->device, job->vector);
+    }
+    g_free(job);
+}
+
+static void apple_gfx_pci_interrupt(PCIDevice *dev, uint32_t vector)
+{
+    AppleGFXPCIInterruptJob *job;
+
+    trace_apple_gfx_raise_irq(vector);
+    job =3D g_malloc0(sizeof(*job));
+    job->device =3D dev;
+    job->vector =3D vector;
+    aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                            apple_gfx_pci_raise_interrupt, job);
+}
+
+static void apple_gfx_pci_realize(PCIDevice *dev, Error **errp)
+{
+    AppleGFXPCIState *s =3D APPLE_GFX_PCI(dev);
+    int ret;
+
+    pci_register_bar(dev, PG_PCI_BAR_MMIO,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->common.iomem_gfx);
+
+    ret =3D msi_init(dev, 0x0 /* config offset; 0 =3D find space */,
+                   PG_PCI_MAX_MSI_VECTORS, true /* msi64bit */,
+                   false /* msi_per_vector_mask */, errp);
+    if (ret !=3D 0) {
+        return;
+    }
+
+    @autoreleasepool {
+        PGDeviceDescriptor *desc =3D [PGDeviceDescriptor new];
+        desc.raiseInterrupt =3D ^(uint32_t vector) {
+            apple_gfx_pci_interrupt(dev, vector);
+        };
+
+        apple_gfx_common_realize(&s->common, DEVICE(dev), desc, errp);
+        [desc release];
+        desc =3D nil;
+    }
+}
+
+static void apple_gfx_pci_reset(Object *obj, ResetType type)
+{
+    AppleGFXPCIState *s =3D APPLE_GFX_PCI(obj);
+    [s->common.pgdev reset];
+}
+
+static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+    PCIDeviceClass *pci =3D PCI_DEVICE_CLASS(klass);
+    ResettableClass *rc =3D RESETTABLE_CLASS(klass);
+
+    rc->phases.hold =3D apple_gfx_pci_reset;
+    dc->desc =3D "macOS Paravirtualized Graphics PCI Display Controller";
+    dc->hotpluggable =3D false;
+    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+
+    pci->vendor_id =3D PG_PCI_VENDOR_ID;
+    pci->device_id =3D PG_PCI_DEVICE_ID;
+    pci->class_id =3D PCI_CLASS_DISPLAY_OTHER;
+    pci->realize =3D apple_gfx_pci_realize;
+
+    /* TODO: Property for setting mode list */
+}
+
+static TypeInfo apple_gfx_pci_types[] =3D {
+    {
+        .name          =3D TYPE_APPLE_GFX_PCI,
+        .parent        =3D TYPE_PCI_DEVICE,
+        .instance_size =3D sizeof(AppleGFXPCIState),
+        .class_init    =3D apple_gfx_pci_class_init,
+        .instance_init =3D apple_gfx_pci_init,
+        .interfaces =3D (InterfaceInfo[]) {
+            { INTERFACE_PCIE_DEVICE },
+            { },
+        },
+    }
+};
+DEFINE_TYPES(apple_gfx_pci_types)
+
diff --git a/hw/display/meson.build b/hw/display/meson.build
index cf9e6dd35d2..94f4f05d36f 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -63,6 +63,7 @@ system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('at=
i.c', 'ati_2d.c', 'ati_
=20
 if host_os =3D=3D 'darwin'
   system_ss.add(when: 'CONFIG_MAC_PVG',         if_true: [files('apple-gfx=
.m'), pvg, metal])
+  system_ss.add(when: 'CONFIG_MAC_PVG_PCI',     if_true: [files('apple-gfx=
-pci.m'), pvg, metal])
   if cpu =3D=3D 'aarch64'
     system_ss.add(when: 'CONFIG_MAC_PVG_MMIO',  if_true: [files('apple-gfx=
-mmio.m'), pvg, metal])
   endif
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103506; cv=none;
	d=zohomail.com; s=zohoarc;
	b=eFLVteSSm5f8NWUj/VsoDrQden7hGQ+CMl+WilrSLpTMbp1PTGhQtAloAsLQ+sX5hw+OmDrXuo8Ifh7l+mpCoMCVlIjLrtkk4oOENnP+JahCwtNFqkFVOb8FHRE8VgE7AG6Li9IR2j1acXV2ABuVTfvtHHURylRdEg0TIgt3afc=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103506;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=gqDHKMOlEu3HBZNTrJ3yF3ObzpqK7FWFnJX02jcPijQ=;
	b=Kce1HTdoJIFYz/5waVI2TqBXC7p0icjOPb4qnP3eQQZgt7tFLeQXHaxXsoZPaBwaezeBalbcX9j/XG4YKJGBrQKaE4z2RnBCI0uKAy4419t5B73mYqrhVrkOPkYGoD9HADweURMl2xoutj1dEPE2rA/C38mQpa6g0YTbRwUBPsQ=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103506769289.21651135013894;
 Fri, 13 Dec 2024 07:25:06 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SJ-000541-2D; Fri, 13 Dec 2024 10:19:51 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RP-0004P7-HT
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:59 -0500
Received: from mail-ed1-x534.google.com ([2a00:1450:4864:20::534])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RH-00055M-5k
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:53 -0500
Received: by mail-ed1-x534.google.com with SMTP id
 4fb4d7f45d1cf-5d3f65844deso3027470a12.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:45 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.43
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:44 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103125;
 x=1734707925;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=gqDHKMOlEu3HBZNTrJ3yF3ObzpqK7FWFnJX02jcPijQ=;
 b=YW84ivYtptdEuVLos/kapXeUvcCjJn3MX32cR7t05uCbFIok2i0sOHBUB7d12p5Pdh
 0sKK4kAPlkP9mB3Be6PIlsYOyPu41w2vQLokVwr3WIgK8Y848fTCb0blIFdmU09KICsx
 MociAzyx5cIVCiOUmzwhKM0uKOXa1PV1PQDhup5wIAwcyH3BEzXmdWHfwbrjqa9YMBSJ
 MTVqfGy2LkNSuepV85kQlnrlqY55VZLJw0Glv0fnDHGAsoFKt4R2cFDJMdEszhRviQo2
 QEc0Q5BtdND+C3cC/7/Jdz997Y2RRJ58PJk2od/Hx45QpWQ4w5VgpUWYbnmld283Bu1r
 czRg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103125; x=1734707925;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=gqDHKMOlEu3HBZNTrJ3yF3ObzpqK7FWFnJX02jcPijQ=;
 b=dGgIvc5EhESOvGKQn4KuzT4hMXIR6DyskvckUnksBUKDfzwwCnnoHnVfRKOwssGtCi
 mlpF6NkYLSJvpkdm1GEtAIfQMRxFNfOsgpF0Ot6j0GpS3MvBAzE/oQl36Feowwa2aY3n
 IZVN2NNEedNKiDdaVy/ptE/NwxX9bEYvW3Yv5I8sfI8RQ0Z4zh0m3jKWimfkYkIw/6C7
 DrjXrQPzU3MYwYNC5aAmj1Q6Cy7puRRVVVX5y8g7/+rspUXf8W6SIrfX/Wvyb40qrtcg
 YWx7yCW0AoHAxue/4AYvusnB5FwLnHuoHi7yCoXuVvfJI5fpoJmrIjLWhgDpv+3TyMY0
 TdLw==
X-Gm-Message-State: AOJu0Yyw1FR7yq8BWOmetbJ9Sjj1AxaJRp5WZZtSwGD0jhEnSEI9FuYr
 LXchnuCznNW82P5c5+UNXPehBBgCOJ32es5t8T/dRFzw8Fg6CLm4a6xF4RAfGinI7PpUt66sem2
 D0Q==
X-Gm-Gg: ASbGnct/QRvsxSx0jVcejnleLbNfLOhSYlpmPQHVMA14Z0/RWl7qC4G9wqPCBOB2Cft
 B38wdwiMircj1rr32lQdosU3oXryg3PMSFVMOuJ7CD3afTKuYJQbEW+2wILpEMRm2L+vL+2glRQ
 N/QXrtKCVU+hrgCGlH6GmDijRDTZyB2m5S2OVSV8OedhCcga5HdL0cd/QKb/ndkPOnK3ERGykkn
 aF7rMmnh/M97koLNHTTtX+xAXPFt6scITEKs689F58tqSpBirqy/pFRBewSaSLuyoRYebJWCy3/
 BLaY9i7Lg9Rs8Bu4qhkZiUNckXRFqlMV
X-Google-Smtp-Source: 
 AGHT+IHsre1uf1bY28+Fn8S2p+Yue2C2yaapKMH+3Ch5MEKQareUN02+vOl5U1fO7yogcKoSRnhNuQ==
X-Received: by 2002:a17:907:3dab:b0:aa6:9372:cac7 with SMTP id
 a640c23a62f3a-aab779b1333mr390447366b.31.1734103124710;
 Fri, 13 Dec 2024 07:18:44 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu
Subject: [PATCH v13 04/15] hw/display/apple-gfx: Adds configurable mode list
Date: Fri, 13 Dec 2024 16:17:54 +0100
Message-Id: <20241213151821.65748-5-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::534;
 envelope-from=phil@philjordan.eu; helo=mail-ed1-x534.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103507763116600
Content-Type: text/plain; charset="utf-8"

This change adds a property 'display_modes' on the graphics device
which permits specifying a list of display modes. (screen resolution
and refresh rate)

The property is an array of a custom type to make the syntax slightly
less awkward to use, for example:

-device '{"driver":"apple-gfx-pci", "display-modes":["1920x1080@60", "3840x=
2160@60"]}'

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Switched to the native array property type, which recently gained
	 command line support.
 * The property has also been added to the -mmio variant.
 * Tidied up the code a little.

v5:

 * Better error handling and buffer management in property parsing and
   output.

v6:

 * Switched to using NSMutableArray for the mode list to avoid need for
   allocating a temporary array - previously done with alloca.

v7:

 * Simplified error handling in property parsing

v8:

 * More consistent integer variable types.

v9:

 * Re-ordered type definitions so we can drop a 'struct' keyword.

 hw/display/apple-gfx-mmio.m |   8 +++
 hw/display/apple-gfx-pci.m  |   9 ++-
 hw/display/apple-gfx.h      |  11 +++
 hw/display/apple-gfx.m      | 135 +++++++++++++++++++++++++++++++-----
 hw/display/trace-events     |   2 +
 5 files changed, 145 insertions(+), 20 deletions(-)

diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m
index 1a46ff48b75..13052419f09 100644
--- a/hw/display/apple-gfx-mmio.m
+++ b/hw/display/apple-gfx-mmio.m
@@ -258,6 +258,12 @@ static void apple_gfx_mmio_reset(Object *obj, ResetTyp=
e type)
     [s->common.pgdev reset];
 }
=20
+static Property apple_gfx_mmio_properties[] =3D {
+    DEFINE_PROP_ARRAY("display-modes", AppleGFXMMIOState,
+                      common.num_display_modes, common.display_modes,
+                      qdev_prop_display_mode, AppleGFXDisplayMode),
+    DEFINE_PROP_END_OF_LIST(),
+};
=20
 static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data)
 {
@@ -267,6 +273,8 @@ static void apple_gfx_mmio_class_init(ObjectClass *klas=
s, void *data)
     rc->phases.hold =3D apple_gfx_mmio_reset;
     dc->hotpluggable =3D false;
     dc->realize =3D apple_gfx_mmio_realize;
+
+    device_class_set_props(dc, apple_gfx_mmio_properties);
 }
=20
 static TypeInfo apple_gfx_mmio_types[] =3D {
diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m
index 5ff6a487cfc..765b210287d 100644
--- a/hw/display/apple-gfx-pci.m
+++ b/hw/display/apple-gfx-pci.m
@@ -114,6 +114,13 @@ static void apple_gfx_pci_reset(Object *obj, ResetType=
 type)
     [s->common.pgdev reset];
 }
=20
+static Property apple_gfx_pci_properties[] =3D {
+    DEFINE_PROP_ARRAY("display-modes", AppleGFXPCIState,
+                      common.num_display_modes, common.display_modes,
+                      qdev_prop_display_mode, AppleGFXDisplayMode),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc =3D DEVICE_CLASS(klass);
@@ -130,7 +137,7 @@ static void apple_gfx_pci_class_init(ObjectClass *klass=
, void *data)
     pci->class_id =3D PCI_CLASS_DISPLAY_OTHER;
     pci->realize =3D apple_gfx_pci_realize;
=20
-    /* TODO: Property for setting mode list */
+    device_class_set_props(dc, apple_gfx_pci_properties);
 }
=20
 static TypeInfo apple_gfx_pci_types[] =3D {
diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h
index ef2455e3bdc..a1160bf6619 100644
--- a/hw/display/apple-gfx.h
+++ b/hw/display/apple-gfx.h
@@ -16,6 +16,7 @@
 #import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
 #include "qemu/typedefs.h"
 #include "exec/memory.h"
+#include "hw/qdev-properties.h"
 #include "ui/surface.h"
=20
 @class PGDeviceDescriptor;
@@ -27,6 +28,12 @@
=20
 typedef QTAILQ_HEAD(, PGTask_s) PGTaskList;
=20
+typedef struct AppleGFXDisplayMode {
+    uint16_t width_px;
+    uint16_t height_px;
+    uint16_t refresh_rate_hz;
+} AppleGFXDisplayMode;
+
 typedef struct AppleGFXState {
     /* Initialised on init/realize() */
     MemoryRegion iomem_gfx;
@@ -35,6 +42,8 @@ typedef struct AppleGFXState {
     QemuConsole *con;
     id<MTLDevice> mtl;
     id<MTLCommandQueue> mtl_queue;
+    AppleGFXDisplayMode *display_modes;
+    uint32_t num_display_modes;
=20
     /* List `tasks` is protected by task_mutex */
     QemuMutex task_mutex;
@@ -62,5 +71,7 @@ void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_phy=
sical,
                                        uint64_t length, bool read_only,
                                        MemoryRegion **mapping_in_region);
=20
+extern const PropertyInfo qdev_prop_display_mode;
+
 #endif
=20
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
index bfaff2b2be2..f83ef497bf8 100644
--- a/hw/display/apple-gfx.m
+++ b/hw/display/apple-gfx.m
@@ -31,9 +31,10 @@
 #include "sysemu/dma.h"
 #include "ui/console.h"
=20
-static const PGDisplayCoord_t apple_gfx_modes[] =3D {
-    { .x =3D 1440, .y =3D 1080 },
-    { .x =3D 1280, .y =3D 1024 },
+static const AppleGFXDisplayMode apple_gfx_default_modes[] =3D {
+    { 1920, 1080, 60 },
+    { 1440, 1080, 60 },
+    { 1280, 1024, 60 },
 };
=20
 static Error *apple_gfx_mig_blocker;
@@ -690,22 +691,24 @@ static void new_frame_handler_bh(void *opaque)
     return disp_desc;
 }
=20
-static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void)
+static NSArray<PGDisplayMode *> *apple_gfx_create_display_mode_array(
+    const AppleGFXDisplayMode display_modes[], uint32_t display_mode_count)
 {
-    PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
-    NSArray<PGDisplayMode*>* mode_array;
-    int i;
-
-    for (i =3D 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
-        modes[i] =3D
-            [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i]=
 refreshRateInHz:60.];
-    }
-
-    mode_array =3D [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_=
gfx_modes)];
-
-    for (i =3D 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
-        [modes[i] release];
-        modes[i] =3D nil;
+    uint32_t i;
+    PGDisplayMode *mode_obj;
+    NSMutableArray<PGDisplayMode *> *mode_array =3D
+        [[NSMutableArray alloc] initWithCapacity:display_mode_count];
+
+    for (i =3D 0; i < display_mode_count; i++) {
+        const AppleGFXDisplayMode *mode =3D &display_modes[i];
+        trace_apple_gfx_display_mode(i, mode->width_px, mode->height_px);
+        PGDisplayCoord_t mode_size =3D { mode->width_px, mode->height_px };
+
+        mode_obj =3D
+            [[PGDisplayMode alloc] initWithSizeInPixels:mode_size
+                                        refreshRateInHz:mode->refresh_rate=
_hz];
+        [mode_array addObject:mode_obj];
+        [mode_obj release];
     }
=20
     return mode_array;
@@ -741,6 +744,9 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceS=
tate *dev,
                               PGDeviceDescriptor *desc, Error **errp)
 {
     PGDisplayDescriptor *disp_desc;
+    const AppleGFXDisplayMode *display_modes =3D apple_gfx_default_modes;
+    uint32_t num_display_modes =3D ARRAY_SIZE(apple_gfx_default_modes);
+    NSArray<PGDisplayMode *> *mode_array;
=20
     if (apple_gfx_mig_blocker =3D=3D NULL) {
         error_setg(&apple_gfx_mig_blocker,
@@ -776,8 +782,99 @@ bool apple_gfx_common_realize(AppleGFXState *s, Device=
State *dev,
                                               port:0
                                          serialNum:next_pgdisplay_serial_n=
um++];
     [disp_desc release];
-    s->pgdisp.modeList =3D apple_gfx_prepare_display_mode_array();
+
+    if (s->display_modes !=3D NULL && s->num_display_modes > 0) {
+        trace_apple_gfx_common_realize_modes_property(s->num_display_modes=
);
+        display_modes =3D s->display_modes;
+        num_display_modes =3D s->num_display_modes;
+    }
+    s->pgdisp.modeList =3D mode_array =3D
+        apple_gfx_create_display_mode_array(display_modes, num_display_mod=
es);
+    [mode_array release];
=20
     s->con =3D graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
     return true;
 }
+
+/* ------ Display mode list device property ------ */
+
+static void apple_gfx_get_display_mode(Object *obj, Visitor *v,
+                                       const char *name, void *opaque,
+                                       Error **errp)
+{
+    Property *prop =3D opaque;
+    AppleGFXDisplayMode *mode =3D object_field_prop_ptr(obj, prop);
+    /* 3 uint16s (max 5 digits) + 2 separator characters + nul. */
+    char buffer[5 * 3 + 2 + 1];
+    char *pos =3D buffer;
+
+    int rc =3D snprintf(buffer, sizeof(buffer),
+                      "%"PRIu16"x%"PRIu16"@%"PRIu16,
+                      mode->width_px, mode->height_px,
+                      mode->refresh_rate_hz);
+    assert(rc < sizeof(buffer));
+
+    visit_type_str(v, name, &pos, errp);
+}
+
+static void apple_gfx_set_display_mode(Object *obj, Visitor *v,
+                                       const char *name, void *opaque,
+                                       Error **errp)
+{
+    Property *prop =3D opaque;
+    AppleGFXDisplayMode *mode =3D object_field_prop_ptr(obj, prop);
+    const char *endptr;
+    g_autofree char *str =3D NULL;
+    int ret;
+    int val;
+
+    if (!visit_type_str(v, name, &str, errp)) {
+        return;
+    }
+
+    endptr =3D str;
+
+    ret =3D qemu_strtoi(endptr, &endptr, 10, &val);
+    if (ret || val > UINT16_MAX || val <=3D 0) {
+        error_setg(errp, "width in '%s' must be a decimal integer number "
+                   "of pixels in the range 1..65535", name);
+        return;
+    }
+    mode->width_px =3D val;
+    if (*endptr !=3D 'x') {
+        goto separator_error;
+    }
+
+    ret =3D qemu_strtoi(endptr + 1, &endptr, 10, &val);
+    if (ret || val > UINT16_MAX || val <=3D 0) {
+        error_setg(errp, "height in '%s' must be a decimal integer number "
+                   "of pixels in the range 1..65535", name);
+        return;
+    }
+    mode->height_px =3D val;
+    if (*endptr !=3D '@') {
+        goto separator_error;
+    }
+
+    ret =3D qemu_strtoi(endptr + 1, &endptr, 10, &val);
+    if (ret || val > UINT16_MAX || val <=3D 0) {
+        error_setg(errp, "refresh rate in '%s'"
+                   " must be a positive decimal integer (Hertz)", name);
+        return;
+    }
+    mode->refresh_rate_hz =3D val;
+    return;
+
+separator_error:
+    error_setg(errp, "Each display mode takes the format "
+               "'<width>x<height>@<rate>'");
+}
+
+const PropertyInfo qdev_prop_display_mode =3D {
+    .name  =3D "display_mode",
+    .description =3D
+        "Display mode in pixels and Hertz, as <width>x<height>@<refresh-ra=
te> "
+        "Example: 3840x2160@60",
+    .get   =3D apple_gfx_get_display_mode,
+    .set   =3D apple_gfx_set_display_mode,
+};
diff --git a/hw/display/trace-events b/hw/display/trace-events
index a50e4eea0c0..52786e6e184 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -212,6 +212,8 @@ apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint=
64_t height) "bpp=3D%d widt
 apple_gfx_cursor_show(uint32_t show) "show=3D%d"
 apple_gfx_cursor_move(void) ""
 apple_gfx_common_init(const char *device_name, size_t mmio_size) "device: =
%s; MMIO size: %zu bytes"
+apple_gfx_common_realize_modes_property(uint32_t num_modes) "using %u mode=
s supplied by 'display-modes' device property"
+apple_gfx_display_mode(uint32_t mode_idx, uint16_t width_px, uint16_t heig=
ht_px) "mode %2"PRIu32": %4"PRIu16"x%4"PRIu16
=20
 # apple-gfx-mmio.m
 apple_gfx_mmio_iosfc_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRI=
x64" res=3D0x%"PRIx64
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103394; cv=none;
	d=zohomail.com; s=zohoarc;
	b=kIW8C5kM97JEFyMxCweuamFjbqo9qNI13OSphretuKJOzmxfP6+TIxbBV7gJ55xVl862N+63tQOzmH7dQfn0sI6RmNIGG4xdLFlrVbRLGWUCAuofZhC/SWyZbe1p3u1Hqzsa3MPcxgDdum/kyf7ErU6g2/wTtvKfc74kkptliR8=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103394;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=gqDHKMOlEu3HBZNTrJ3yF3ObzpqK7FWFnJX02jcPijQ=;
	b=kJCJ1Tmu0tYdbFCeOmeoWNWoIOIyzuZbgi9vUix1v0Pwg5drX4b2vtr075n3OIoXc+TGjvtX2pt5wPGMML58bogaX/hK5wKZAYX1OFDNNQrWIue3W7hLAac04uV7kvAmIIsElS5vmuy+gkZFR9MJ+P8sg3ebQDS0TkPEmxzTvbc=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103394816622.8472628023333;
 Fri, 13 Dec 2024 07:23:14 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Sw-0006wz-VP; Fri, 13 Dec 2024 10:20:31 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rz-0004fl-Vd
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:33 -0500
Received: from mail-ej1-x62f.google.com ([2a00:1450:4864:20::62f])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rk-0005Ig-Ux
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:28 -0500
Received: by mail-ej1-x62f.google.com with SMTP id
 a640c23a62f3a-a9e8522445dso371524766b.1
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:16 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.13
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:14 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103155;
 x=1734707955;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=gqDHKMOlEu3HBZNTrJ3yF3ObzpqK7FWFnJX02jcPijQ=;
 b=r/BcQq7SPya2ve44obu9T0lbLM1HskrfSWKqm6i2XZsDKZK0jzrPo0/N+2cwJ5sEKh
 9O9znqbf/ZY3ZzpEEZttvIwyWyyw4vrfGnWQpdhb/k82gihUclYT5vEXsks+1q2guFsa
 UZTXOllKi4tWP88qUNJrxeBeUI8pCxSirmoCFADFM8zEpIpBSjZfsi4TH8z/HqLrV+CQ
 WnJy5rhE0FC1C5kNUzYNyztli0yE/NcVHJVeYT62WnUzOzRKdfxUuDmC4FghvLo5GnFF
 cg2hnMkGcC8N9msnPoJ/vP0c8JTD+Akwr8jvEsCYNgZ0AO/otuKrljp7RD47v1xZlUGd
 vdyw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103155; x=1734707955;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=gqDHKMOlEu3HBZNTrJ3yF3ObzpqK7FWFnJX02jcPijQ=;
 b=uh57RB/vCnSE51CQcbHgU6W6lB4EclHqCySAUO3xwxA9dgZ2JrgaLJXHph0R9KAyX+
 BIPPozZewsfbFL+NPJa059mcfEe7lKTux60RaI50rUwc1XMKBX3GpizH9MoAl5S4gkgx
 Rcq6LCujJeOTCFYBRD3UVVqXedI8Jta/R61W14YLbp1lMZxzLEH0F7lyn27yTURFbibP
 rFx8oMDfpV9a9PC2gE+E5G2FHnXTDn/H5jEbi2yA887uu5ahZksW0AmPXc97eQP4EK48
 1bWPCfrW1AzGndhYBKYcOrgVYwAy58iwfDdVosjJHxG3JfavB9NUYaTejYJCs7ptnOVI
 2C8A==
X-Gm-Message-State: AOJu0Yx/oSHdJABuD8yfUoe4SvrQb5PNDxjXJwvhettsJdsoaUWOja0B
 Q7zd1nY6u139aBiZKP94Wjuhf7RGtlgFP9VapXfAA0pw8idpmaM28+beA4H/BuZy9YeHFEObXxM
 shw==
X-Gm-Gg: ASbGncvyAvO2cvPknA1g7IEChsNfcp16DrPdYwl7+8FmcC8lk1any8Zuyp7JBTfZlyu
 QC0yX/a9rSt+bBKXJOeUzY3817yzf/8PZhhrRtorgOMT/vXE5zEgpslKkelP5H7nqOCJJscnoAC
 88ShOqSG/UcByQETM3iRme+MvHP4Km3wr0v4czSt/u6AgmNDewtSlJ9VKsjBBtBSNxdm5GY2VZ1
 BHeHkhP+ekvrPh3PtcpGrBIZNvKpnMm0X0TYhkoitezYtvQyk6242cLd1Vn9PYF0P/bIHPXgJ2C
 GOiE/Lx7vHkQiIwS1Ou6G8iJ8qYMHX2X
X-Google-Smtp-Source: 
 AGHT+IFXhf4lkk7OGPCdZo2c9iGPi4TnQ7zLqgQjVZLuzhslVTnPOHls3nHJs3jrZKf7Nq+C3tVZPQ==
X-Received: by 2002:a17:907:2d89:b0:aa6:832b:8d71 with SMTP id
 a640c23a62f3a-aab778d9dbemr283472366b.2.1734103155320;
 Fri, 13 Dec 2024 07:19:15 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu
Subject: [PATCH v14 04/15] hw/display/apple-gfx: Adds configurable mode list
Date: Fri, 13 Dec 2024 16:18:10 +0100
Message-Id: <20241213151821.65748-21-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62f;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62f.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103397358116600
Content-Type: text/plain; charset="utf-8"

This change adds a property 'display_modes' on the graphics device
which permits specifying a list of display modes. (screen resolution
and refresh rate)

The property is an array of a custom type to make the syntax slightly
less awkward to use, for example:

-device '{"driver":"apple-gfx-pci", "display-modes":["1920x1080@60", "3840x=
2160@60"]}'

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Switched to the native array property type, which recently gained
	 command line support.
 * The property has also been added to the -mmio variant.
 * Tidied up the code a little.

v5:

 * Better error handling and buffer management in property parsing and
   output.

v6:

 * Switched to using NSMutableArray for the mode list to avoid need for
   allocating a temporary array - previously done with alloca.

v7:

 * Simplified error handling in property parsing

v8:

 * More consistent integer variable types.

v9:

 * Re-ordered type definitions so we can drop a 'struct' keyword.

 hw/display/apple-gfx-mmio.m |   8 +++
 hw/display/apple-gfx-pci.m  |   9 ++-
 hw/display/apple-gfx.h      |  11 +++
 hw/display/apple-gfx.m      | 135 +++++++++++++++++++++++++++++++-----
 hw/display/trace-events     |   2 +
 5 files changed, 145 insertions(+), 20 deletions(-)

diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m
index 1a46ff48b75..13052419f09 100644
--- a/hw/display/apple-gfx-mmio.m
+++ b/hw/display/apple-gfx-mmio.m
@@ -258,6 +258,12 @@ static void apple_gfx_mmio_reset(Object *obj, ResetTyp=
e type)
     [s->common.pgdev reset];
 }
=20
+static Property apple_gfx_mmio_properties[] =3D {
+    DEFINE_PROP_ARRAY("display-modes", AppleGFXMMIOState,
+                      common.num_display_modes, common.display_modes,
+                      qdev_prop_display_mode, AppleGFXDisplayMode),
+    DEFINE_PROP_END_OF_LIST(),
+};
=20
 static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data)
 {
@@ -267,6 +273,8 @@ static void apple_gfx_mmio_class_init(ObjectClass *klas=
s, void *data)
     rc->phases.hold =3D apple_gfx_mmio_reset;
     dc->hotpluggable =3D false;
     dc->realize =3D apple_gfx_mmio_realize;
+
+    device_class_set_props(dc, apple_gfx_mmio_properties);
 }
=20
 static TypeInfo apple_gfx_mmio_types[] =3D {
diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m
index 5ff6a487cfc..765b210287d 100644
--- a/hw/display/apple-gfx-pci.m
+++ b/hw/display/apple-gfx-pci.m
@@ -114,6 +114,13 @@ static void apple_gfx_pci_reset(Object *obj, ResetType=
 type)
     [s->common.pgdev reset];
 }
=20
+static Property apple_gfx_pci_properties[] =3D {
+    DEFINE_PROP_ARRAY("display-modes", AppleGFXPCIState,
+                      common.num_display_modes, common.display_modes,
+                      qdev_prop_display_mode, AppleGFXDisplayMode),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc =3D DEVICE_CLASS(klass);
@@ -130,7 +137,7 @@ static void apple_gfx_pci_class_init(ObjectClass *klass=
, void *data)
     pci->class_id =3D PCI_CLASS_DISPLAY_OTHER;
     pci->realize =3D apple_gfx_pci_realize;
=20
-    /* TODO: Property for setting mode list */
+    device_class_set_props(dc, apple_gfx_pci_properties);
 }
=20
 static TypeInfo apple_gfx_pci_types[] =3D {
diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h
index ef2455e3bdc..a1160bf6619 100644
--- a/hw/display/apple-gfx.h
+++ b/hw/display/apple-gfx.h
@@ -16,6 +16,7 @@
 #import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
 #include "qemu/typedefs.h"
 #include "exec/memory.h"
+#include "hw/qdev-properties.h"
 #include "ui/surface.h"
=20
 @class PGDeviceDescriptor;
@@ -27,6 +28,12 @@
=20
 typedef QTAILQ_HEAD(, PGTask_s) PGTaskList;
=20
+typedef struct AppleGFXDisplayMode {
+    uint16_t width_px;
+    uint16_t height_px;
+    uint16_t refresh_rate_hz;
+} AppleGFXDisplayMode;
+
 typedef struct AppleGFXState {
     /* Initialised on init/realize() */
     MemoryRegion iomem_gfx;
@@ -35,6 +42,8 @@ typedef struct AppleGFXState {
     QemuConsole *con;
     id<MTLDevice> mtl;
     id<MTLCommandQueue> mtl_queue;
+    AppleGFXDisplayMode *display_modes;
+    uint32_t num_display_modes;
=20
     /* List `tasks` is protected by task_mutex */
     QemuMutex task_mutex;
@@ -62,5 +71,7 @@ void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_phy=
sical,
                                        uint64_t length, bool read_only,
                                        MemoryRegion **mapping_in_region);
=20
+extern const PropertyInfo qdev_prop_display_mode;
+
 #endif
=20
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
index bfaff2b2be2..f83ef497bf8 100644
--- a/hw/display/apple-gfx.m
+++ b/hw/display/apple-gfx.m
@@ -31,9 +31,10 @@
 #include "sysemu/dma.h"
 #include "ui/console.h"
=20
-static const PGDisplayCoord_t apple_gfx_modes[] =3D {
-    { .x =3D 1440, .y =3D 1080 },
-    { .x =3D 1280, .y =3D 1024 },
+static const AppleGFXDisplayMode apple_gfx_default_modes[] =3D {
+    { 1920, 1080, 60 },
+    { 1440, 1080, 60 },
+    { 1280, 1024, 60 },
 };
=20
 static Error *apple_gfx_mig_blocker;
@@ -690,22 +691,24 @@ static void new_frame_handler_bh(void *opaque)
     return disp_desc;
 }
=20
-static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void)
+static NSArray<PGDisplayMode *> *apple_gfx_create_display_mode_array(
+    const AppleGFXDisplayMode display_modes[], uint32_t display_mode_count)
 {
-    PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
-    NSArray<PGDisplayMode*>* mode_array;
-    int i;
-
-    for (i =3D 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
-        modes[i] =3D
-            [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i]=
 refreshRateInHz:60.];
-    }
-
-    mode_array =3D [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_=
gfx_modes)];
-
-    for (i =3D 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
-        [modes[i] release];
-        modes[i] =3D nil;
+    uint32_t i;
+    PGDisplayMode *mode_obj;
+    NSMutableArray<PGDisplayMode *> *mode_array =3D
+        [[NSMutableArray alloc] initWithCapacity:display_mode_count];
+
+    for (i =3D 0; i < display_mode_count; i++) {
+        const AppleGFXDisplayMode *mode =3D &display_modes[i];
+        trace_apple_gfx_display_mode(i, mode->width_px, mode->height_px);
+        PGDisplayCoord_t mode_size =3D { mode->width_px, mode->height_px };
+
+        mode_obj =3D
+            [[PGDisplayMode alloc] initWithSizeInPixels:mode_size
+                                        refreshRateInHz:mode->refresh_rate=
_hz];
+        [mode_array addObject:mode_obj];
+        [mode_obj release];
     }
=20
     return mode_array;
@@ -741,6 +744,9 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceS=
tate *dev,
                               PGDeviceDescriptor *desc, Error **errp)
 {
     PGDisplayDescriptor *disp_desc;
+    const AppleGFXDisplayMode *display_modes =3D apple_gfx_default_modes;
+    uint32_t num_display_modes =3D ARRAY_SIZE(apple_gfx_default_modes);
+    NSArray<PGDisplayMode *> *mode_array;
=20
     if (apple_gfx_mig_blocker =3D=3D NULL) {
         error_setg(&apple_gfx_mig_blocker,
@@ -776,8 +782,99 @@ bool apple_gfx_common_realize(AppleGFXState *s, Device=
State *dev,
                                               port:0
                                          serialNum:next_pgdisplay_serial_n=
um++];
     [disp_desc release];
-    s->pgdisp.modeList =3D apple_gfx_prepare_display_mode_array();
+
+    if (s->display_modes !=3D NULL && s->num_display_modes > 0) {
+        trace_apple_gfx_common_realize_modes_property(s->num_display_modes=
);
+        display_modes =3D s->display_modes;
+        num_display_modes =3D s->num_display_modes;
+    }
+    s->pgdisp.modeList =3D mode_array =3D
+        apple_gfx_create_display_mode_array(display_modes, num_display_mod=
es);
+    [mode_array release];
=20
     s->con =3D graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
     return true;
 }
+
+/* ------ Display mode list device property ------ */
+
+static void apple_gfx_get_display_mode(Object *obj, Visitor *v,
+                                       const char *name, void *opaque,
+                                       Error **errp)
+{
+    Property *prop =3D opaque;
+    AppleGFXDisplayMode *mode =3D object_field_prop_ptr(obj, prop);
+    /* 3 uint16s (max 5 digits) + 2 separator characters + nul. */
+    char buffer[5 * 3 + 2 + 1];
+    char *pos =3D buffer;
+
+    int rc =3D snprintf(buffer, sizeof(buffer),
+                      "%"PRIu16"x%"PRIu16"@%"PRIu16,
+                      mode->width_px, mode->height_px,
+                      mode->refresh_rate_hz);
+    assert(rc < sizeof(buffer));
+
+    visit_type_str(v, name, &pos, errp);
+}
+
+static void apple_gfx_set_display_mode(Object *obj, Visitor *v,
+                                       const char *name, void *opaque,
+                                       Error **errp)
+{
+    Property *prop =3D opaque;
+    AppleGFXDisplayMode *mode =3D object_field_prop_ptr(obj, prop);
+    const char *endptr;
+    g_autofree char *str =3D NULL;
+    int ret;
+    int val;
+
+    if (!visit_type_str(v, name, &str, errp)) {
+        return;
+    }
+
+    endptr =3D str;
+
+    ret =3D qemu_strtoi(endptr, &endptr, 10, &val);
+    if (ret || val > UINT16_MAX || val <=3D 0) {
+        error_setg(errp, "width in '%s' must be a decimal integer number "
+                   "of pixels in the range 1..65535", name);
+        return;
+    }
+    mode->width_px =3D val;
+    if (*endptr !=3D 'x') {
+        goto separator_error;
+    }
+
+    ret =3D qemu_strtoi(endptr + 1, &endptr, 10, &val);
+    if (ret || val > UINT16_MAX || val <=3D 0) {
+        error_setg(errp, "height in '%s' must be a decimal integer number "
+                   "of pixels in the range 1..65535", name);
+        return;
+    }
+    mode->height_px =3D val;
+    if (*endptr !=3D '@') {
+        goto separator_error;
+    }
+
+    ret =3D qemu_strtoi(endptr + 1, &endptr, 10, &val);
+    if (ret || val > UINT16_MAX || val <=3D 0) {
+        error_setg(errp, "refresh rate in '%s'"
+                   " must be a positive decimal integer (Hertz)", name);
+        return;
+    }
+    mode->refresh_rate_hz =3D val;
+    return;
+
+separator_error:
+    error_setg(errp, "Each display mode takes the format "
+               "'<width>x<height>@<rate>'");
+}
+
+const PropertyInfo qdev_prop_display_mode =3D {
+    .name  =3D "display_mode",
+    .description =3D
+        "Display mode in pixels and Hertz, as <width>x<height>@<refresh-ra=
te> "
+        "Example: 3840x2160@60",
+    .get   =3D apple_gfx_get_display_mode,
+    .set   =3D apple_gfx_set_display_mode,
+};
diff --git a/hw/display/trace-events b/hw/display/trace-events
index a50e4eea0c0..52786e6e184 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -212,6 +212,8 @@ apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint=
64_t height) "bpp=3D%d widt
 apple_gfx_cursor_show(uint32_t show) "show=3D%d"
 apple_gfx_cursor_move(void) ""
 apple_gfx_common_init(const char *device_name, size_t mmio_size) "device: =
%s; MMIO size: %zu bytes"
+apple_gfx_common_realize_modes_property(uint32_t num_modes) "using %u mode=
s supplied by 'display-modes' device property"
+apple_gfx_display_mode(uint32_t mode_idx, uint16_t width_px, uint16_t heig=
ht_px) "mode %2"PRIu32": %4"PRIu16"x%4"PRIu16
=20
 # apple-gfx-mmio.m
 apple_gfx_mmio_iosfc_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRI=
x64" res=3D0x%"PRIx64
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103426; cv=none;
	d=zohomail.com; s=zohoarc;
	b=M/4bztbg697NQizq33dSOM5KkrunYLteg/vLgsoX5ZFFKxclqJBDjsVkxuTQyd08aDvhqDx5lciExcfR3P/eqBWodw3vsH3iTUx+rkCq+XwgeI40LDN7z11UNTwnfSPuxC0NgA99yyuPt9UOcg3/kSy19fa5FB8faNa3N+RTjIQ=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103426;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=tYWLPafzihE8PDd+NR4N69DEyaMCy4jGTA3EEV2mGPo=;
	b=HO0+EAj+cTD63NzjAyKww69Cx8BYDROxEecROoofPII75j6JfnF3m/LXzJK3Wq4GgalX0/l4TD38hf5YBha6H6zlcVKX9Nwre39alfB1yt5fMksxM6DgsvJ7UHLr3imcxyX43RQ0BuTdLHIZuYByaDzrDMsy1ueBrWAEPOGcjYo=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103425739209.77568731820588;
 Fri, 13 Dec 2024 07:23:45 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Su-0006oA-Lz; Fri, 13 Dec 2024 10:20:28 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rz-0004fd-TT
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:33 -0500
Received: from mail-ej1-x62e.google.com ([2a00:1450:4864:20::62e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rn-0005KA-66
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:31 -0500
Received: by mail-ej1-x62e.google.com with SMTP id
 a640c23a62f3a-aa543c4db92so366326566b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:18 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.15
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:16 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103157;
 x=1734707957;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=tYWLPafzihE8PDd+NR4N69DEyaMCy4jGTA3EEV2mGPo=;
 b=njNv6LB+GMtzbIVhYBUyvt/k8suSjIkWT/KUpHgE1uqstuXs/ziRjkOWPBRBJZBHY8
 z9UcKnrD7qwEczuTE+L3tQrPg+WYIDjzTDyEWsKiqFK3cy09H7NrJDBAzUI9IGWJf08/
 /nWzJ84/4+6CaIzdhAjRJHaFRG5+Wje22rIfW/gJTcKdP56KL954pPPNACxcLb3XzHeY
 dESonfk+GvOK0Wj2OFFwTNDeUyS+P2D2nMrQyJo6zINQwrQMYaCzes5sUE+9esN7EJze
 bejr55fPYiZvQfS+pS7Ow28L9BzP8vrkjVBDRhxsVYKRlLgtA9fCs9QiK8r3fe3uqRrn
 pV9Q==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103157; x=1734707957;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=tYWLPafzihE8PDd+NR4N69DEyaMCy4jGTA3EEV2mGPo=;
 b=MRW1eRGnYpWbUjUnPfbuhTMU0tPJr/ux6PBs5PnYjeqo8T2BXFllADcxX2GFZGp0Sz
 YjYvcB9gezmba2edIBN6dP3xkW5gls/ggU46Ce+C05fRLASl+GH5JFVzRgnCY915i3OE
 V8ANhs6qjd6pYC0rAVY6FstnpFAWfcq0nHpdq/9SQpWXckItSF8FMAX8xrNjxzfDac/r
 hvf58zRhJ3kSiu3clVfFsHLDhdC0lRRGGxuqFbo6FuNaEJDaa2RQkaQ7wdnl8q800NY8
 OLWhYRpIu4rahEsFJZkWV2o3OaBEhBRwUl39ob0+acQruC3kxWO3LBVecCM7xSIBLbfa
 dK1w==
X-Gm-Message-State: AOJu0YzeEKeXYoBLwB7S4ba2P+IjLitbF5gC7/gdGJt9Hk6qTe2t0KXH
 Meuz/x49XgDD19T3PGLq7RWoMPLtjwoObBBvhJfmFOM/uxnUyVhQXTVtXuWQcBXz5v3rYd8MtwF
 mlw==
X-Gm-Gg: ASbGncsmATmgwewC8JyoBitlV/3JhTVO94cah4C0OizTuMdq8x59OayfKOcUSsuufhM
 GualIhdJqBXtz3gCbq0tW0xwYeJoYNLGORVlUX1FbGUpEvatpQJLs7TyKobVF9sZUt9V8W7By72
 QcxzxDUM8c4vhbmAYpU5utPF2HK/78KMJz4mVgIszamnm9hKZ6kpYFkc6NsHisx0WZw1+jDxYJa
 fBT7H59+hZpH8etC/2DGCZj8LmMoorvb2kD2X6+EWev0W30XNHWZZMtbqor6VcJRJtQb/M6ofRY
 gEwe//KdaH9LKcG7vHYlUtKuc8YtKlqF
X-Google-Smtp-Source: 
 AGHT+IEWGnT9wmEy9eer69vv/5vspEGKmP+OX0MGpcBLvnf3wjLriL9wwBhaQ8TRndD1zeIWw8uTww==
X-Received: by 2002:a17:907:3da6:b0:aa6:79fa:b47a with SMTP id
 a640c23a62f3a-aab778c1f2emr345555966b.7.1734103157136;
 Fri, 13 Dec 2024 07:19:17 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu,
 Roman Bolshakov <rbolshakov@ddn.com>
Subject: [PATCH v14 05/15] MAINTAINERS: Add myself as maintainer for
 apple-gfx,
 reviewer for HVF
Date: Fri, 13 Dec 2024 16:18:11 +0100
Message-Id: <20241213151821.65748-22-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62e;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62e.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103427094116600

I'm happy to take responsibility for the macOS PV graphics code. As
HVF patches don't seem to get much attention at the moment, I'm also
adding myself as designated reviewer for HVF and x86 HVF to try and
improve that.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Roman Bolshakov <rbolshakov@ddn.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index aaf0505a214..09899f7407e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -507,6 +507,7 @@ F: target/arm/hvf/
 X86 HVF CPUs
 M: Cameron Esfahani <dirty@apple.com>
 M: Roman Bolshakov <rbolshakov@ddn.com>
+R: Phil Dennis-Jordan <phil@philjordan.eu>
 W: https://wiki.qemu.org/Features/HVF
 S: Maintained
 F: target/i386/hvf/
@@ -514,6 +515,7 @@ F: target/i386/hvf/
 HVF
 M: Cameron Esfahani <dirty@apple.com>
 M: Roman Bolshakov <rbolshakov@ddn.com>
+R: Phil Dennis-Jordan <phil@philjordan.eu>
 W: https://wiki.qemu.org/Features/HVF
 S: Maintained
 F: accel/hvf/
@@ -2612,6 +2614,11 @@ F: hw/display/edid*
 F: include/hw/display/edid.h
 F: qemu-edid.c
=20
+macOS PV Graphics (apple-gfx)
+M: Phil Dennis-Jordan <phil@philjordan.eu>
+S: Maintained
+F: hw/display/apple-gfx*
+
 PIIX4 South Bridge (i82371AB)
 M: Herv=C3=A9 Poussineau <hpoussin@reactos.org>
 M: Philippe Mathieu-Daud=C3=A9 <philmd@linaro.org>
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103264; cv=none;
	d=zohomail.com; s=zohoarc;
	b=e4BxHIqftHhvb7ZsVo4h3jlZi8SJwPlqJ+6/Num1gNpCkneow/PMSR4GhZKcmwPd4WH3YFXQHOEHDWf84A8qdax+L+Hx9dMoDmvvBDv/z3W34k77XxLU+55I2X83D1HB0ommEsZcUR6dM1i5u35CdKxZNukUYGi47iaKnozTRmU=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103264;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=tYWLPafzihE8PDd+NR4N69DEyaMCy4jGTA3EEV2mGPo=;
	b=Rjb6zZZxXKmVDtcaouP+R9jjtmPUXs3I12V6TfLuBi5RUR8EF6pAKB9v24V47TFdteWa7pCL7itZbdmSsQREgBeaURrWjilQyGIE84nVY7RobFd+5cyj5+xZWgtFJlSQPHyKk2mqKD139HZmNgN/8GkhEKV6q75Twbv6SniCUqU=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103264890264.12039120213456;
 Fri, 13 Dec 2024 07:21:04 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SC-0004x1-At; Fri, 13 Dec 2024 10:19:44 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RY-0004QO-Td
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:06 -0500
Received: from mail-ej1-x630.google.com ([2a00:1450:4864:20::630])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RI-00056O-HO
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:59 -0500
Received: by mail-ej1-x630.google.com with SMTP id
 a640c23a62f3a-aa68b513abcso308328666b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:47 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.44
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:46 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103127;
 x=1734707927;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=tYWLPafzihE8PDd+NR4N69DEyaMCy4jGTA3EEV2mGPo=;
 b=V9r+s5p1L4qycksOhNx+/1gf11GEMaGtWJzxAb12hwHgzr4QYeswAYbytvBVSsIlnB
 hTGDVxjUNNmb91LXQ8MK9pdw7sPffeo2P9BjwLOuNS2ub9k80Ve11CUHjjL/UDs8G85Q
 k7+8sX4LACYOmKjmCw9S1LYsKdU8GbdfM9MuUzZoB/BXNa8WN6D/tDHY8BmeitgIzl05
 g1OiuIp2XrPGKJ/g38xf9zDP2s+vbYRa2m3Mkh4RyBE/GIDl/NgMPaCK2ORtr8f2zTku
 1WA4nyCzrkpBKex/v1aZogQJMeutMjKylOy+9RUvbrwbb4eQwke/K07VW1KESmz92rsG
 eL6g==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103127; x=1734707927;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=tYWLPafzihE8PDd+NR4N69DEyaMCy4jGTA3EEV2mGPo=;
 b=rx5JuvXtotZKHIt9SiB0546EUKF/tP8XKHNESzjX81HT8059D5W/TvFXOFJ774bxJh
 1XcA3navrufqO0J7I7CAbhDqNX5e1EKNcTPv7EBXRQOhppbcIKu1tB3lU1C80CakMogU
 4MuMR4yI/GaJsBKt8RgKwkNq8JwBGYRFAcSmdI41Xqm9/Q9piwVOuXBhpj84ZKYndi4Q
 n1clQKvv5LYQ/ytUQIEdvzLRIjZN31kwZEFhSzqG3M79zElZ6ccWMjA4bTnwfKWEp8nn
 es22NResdnj63FN3glxZi9WSpOzJH/CTS2D4wBb0UwRIjaMKQcSbtuZBnC0xqF3Pz4ql
 31/Q==
X-Gm-Message-State: AOJu0YyAjDEihNYfVMfi4sN/AUi9CBkjrenMYuaHsbUhmkKIQ9hubhhb
 TGDHtyfAvc+eHdojcMV88n+lVKe3jnCmgXUxDNY6/e6zZgoRH/rCKi0U4PfVtVOG/fu/+nodOji
 eTw==
X-Gm-Gg: ASbGnctJ9cF84C/Y5mWuL2bWs52nQhNTZvslGb07bsjDfGte2mW1GCD2QTjIs3omBxP
 zWmx+OuET6LSJdZ7kA27KthOxxe+mygrM1G0Dt29K0EZC0U9J/FOfhSfwGqmAF1HQCLzqWKRsX8
 JHvMsgbFUbMZlCKIymiUGmJE1Eve6R9vyP2IczWrt3/4uPIyth1SkVWktjrF+unc9HGI1aPZO2x
 GcoSOvpyQ+z1Vx3c78hdE8i1pO5DUJ7MauI5QC49tDqRlV5PTBoSGPB1JNUyLfNNFrRcOqayscQ
 5M68n0K+ZzoVnuq6Q87xcBApLmarIFp/
X-Google-Smtp-Source: 
 AGHT+IE+96JPa3xipTkyLG+OaubvDgRJtDfEHtmyrbi0ta+/hRuJsstPqSTuejT3HunoXcolOfsD/A==
X-Received: by 2002:a17:906:730b:b0:aa6:af4b:7c95 with SMTP id
 a640c23a62f3a-aab77ebc7a5mr331627466b.56.1734103126663;
 Fri, 13 Dec 2024 07:18:46 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu,
 Roman Bolshakov <rbolshakov@ddn.com>
Subject: [PATCH v13 05/15] MAINTAINERS: Add myself as maintainer for
 apple-gfx,
 reviewer for HVF
Date: Fri, 13 Dec 2024 16:17:55 +0100
Message-Id: <20241213151821.65748-6-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::630;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x630.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103266409116600

I'm happy to take responsibility for the macOS PV graphics code. As
HVF patches don't seem to get much attention at the moment, I'm also
adding myself as designated reviewer for HVF and x86 HVF to try and
improve that.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Roman Bolshakov <rbolshakov@ddn.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index aaf0505a214..09899f7407e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -507,6 +507,7 @@ F: target/arm/hvf/
 X86 HVF CPUs
 M: Cameron Esfahani <dirty@apple.com>
 M: Roman Bolshakov <rbolshakov@ddn.com>
+R: Phil Dennis-Jordan <phil@philjordan.eu>
 W: https://wiki.qemu.org/Features/HVF
 S: Maintained
 F: target/i386/hvf/
@@ -514,6 +515,7 @@ F: target/i386/hvf/
 HVF
 M: Cameron Esfahani <dirty@apple.com>
 M: Roman Bolshakov <rbolshakov@ddn.com>
+R: Phil Dennis-Jordan <phil@philjordan.eu>
 W: https://wiki.qemu.org/Features/HVF
 S: Maintained
 F: accel/hvf/
@@ -2612,6 +2614,11 @@ F: hw/display/edid*
 F: include/hw/display/edid.h
 F: qemu-edid.c
=20
+macOS PV Graphics (apple-gfx)
+M: Phil Dennis-Jordan <phil@philjordan.eu>
+S: Maintained
+F: hw/display/apple-gfx*
+
 PIIX4 South Bridge (i82371AB)
 M: Herv=C3=A9 Poussineau <hpoussin@reactos.org>
 M: Philippe Mathieu-Daud=C3=A9 <philmd@linaro.org>
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103216; cv=none;
	d=zohomail.com; s=zohoarc;
	b=G8EXYZcu6uUPvIer00D5Ta9Tawm36JV4WBc/2JEnyP2OB+5HFyu6FeryhK05R+EJ+NIwuzUBrph2aYDrcFLETZ5LDqb3vfgKDFb13+bmwDGdeskRxPTIP0DCmIvxbzzsjBbMBGPE+nFzg/NTue/s0S8B3/7vmpYjHaUv0M57pSE=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103216;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=yFaB4PcpJ8M8FmLVWUEWYODg72B+6C+aetlV/ZwIxaU=;
	b=dETO+YQCzPD7nDotAv7Juc9kV6/qsv0So8ilvobS4v29B0Tm1Qwy89I8B1drNlO+IEJnOWdIrYC5UVW1YcMH/oUSHb5RM+buvFBD4pFA75ZfVTw2n/H/sb1Xph1HZwZIpwVoBhgTBWl7rljspbanSRfbeGlb1Du6iJvDp69O8FE=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103216211416.6400987421805;
 Fri, 13 Dec 2024 07:20:16 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SA-0004tX-Rx; Fri, 13 Dec 2024 10:19:43 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RW-0004Pg-Ht
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:03 -0500
Received: from mail-ej1-x62f.google.com ([2a00:1450:4864:20::62f])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RM-00057Q-2l
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:18:58 -0500
Received: by mail-ej1-x62f.google.com with SMTP id
 a640c23a62f3a-aa6c0d1833eso317478666b.1
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:49 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.46
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:48 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103129;
 x=1734707929;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=yFaB4PcpJ8M8FmLVWUEWYODg72B+6C+aetlV/ZwIxaU=;
 b=UunRVQg3Zo2inyoYra3kzuxw43PP82QAr9hItAlnc98CPBbGqjkwnyhb7mcGRX5D3/
 +afHDJLg5ZU4Xex8mnhUoDYHEtNUUUKn7JpVgv7AFDwccilMskMmXQbLm04d96iRCcQY
 FTk170Eyq6AIf+HxAt1OnIai4g37Ui/K4MisRGMGP+poVb8+sgbnf5rRzTVxN/+4p4UF
 bQ0sYiGgTTWd71KwQQnWcPnaqfACSQ3rEZ02Vw72w8zdxEQpvLWwdoq0Rzh6nYprwzSd
 EsQE21oXOrGZBs1KsN17RYMlxYUwKK14A5Oel75HJ7cVptJG2Rll0byrnqt1QKAtR9Ve
 akyQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103129; x=1734707929;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=yFaB4PcpJ8M8FmLVWUEWYODg72B+6C+aetlV/ZwIxaU=;
 b=heFYqpG4blyEhFbFkvHGqiTZPpCaOA5IOweGbRPG75caBi4pLf9aQyUF5t/mZ70zYI
 lkT+49f1EYVORkOc1dHtT8T4Dkb8aQj9GrWXxT0uxCC2EMGNFG9Kg7Kk6gx9dh0MBMF5
 0hzoXkXyFBvNaghnPS2/4QMygLhEX34yjK7oji6UygL81Y5s9KJsOH2fo8zSurduvcp9
 AvBAqVk7yHEk1yfQbIE8oG3DCcezLgIPu6zEfEQJkdlTyQlASOX4d8TWDuDyysK7m7fq
 fK+B6tKUxd1sjf93x82HvXTTN6oKQ6jLDmPMMswnHeDfZlgWCbrwhQgCz3ogU+nxfSMY
 1gxQ==
X-Gm-Message-State: AOJu0YwuDzQdzer4T1LYoGChRs19hcnEwRFkHAJIeLfrZTYjZFQ6uoEK
 rrCKxuucbTzKB0XaYbcGhi27V4vpFPeNGImxAPNO8WMqRAoWEEXKFMiPG65wio7NSr71QoE+Rr+
 Ohw==
X-Gm-Gg: ASbGncvJEY8doqXygU4UvuGPxYDWTx5YlxK0pqLX2OvZGX1wPPowO7ATGXTXQfj2MUe
 VCDm/YUJOgiYlOG+dF0W+3MYEv8zm6oYmRwDubc+ZUM3B5vhtszEOB8XcX+xwj0J9cyBHtrFCD2
 KOQoH/ezCTMVPDhDL+ZZJpgDqqDBJz3qiWcLxVtEi98+x/Ika4kx8zJNEkyO5pdtym8HJsbbQ2z
 9gFKOBggqpITEd8TTTiJR1e6AxSNDJ0gH0/RU2xe5UxA8XstbMqH/vTGE8Up64CTS+HgUxj54Ai
 heysbBKnRaKml9h6mNLhgQ4zb0MopGoz
X-Google-Smtp-Source: 
 AGHT+IHtX383rqhbaJrINyKhm/0MiPO55YvqVor11Iihz0QxkBNJbA6Xzz8Kp0ukBOV2CFUyFqhheA==
X-Received: by 2002:a17:907:6d0d:b0:aa6:993a:259f with SMTP id
 a640c23a62f3a-aab77e8a866mr286048266b.40.1734103128511;
 Fri, 13 Dec 2024 07:18:48 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 06/15] hw: Add vmapple subdir
Date: Fri, 13 Dec 2024 16:17:56 +0100
Message-Id: <20241213151821.65748-7-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62f;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62f.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103219797116600
Content-Type: text/plain; charset="utf-8"

From: Alexander Graf <graf@amazon.com>

We will introduce a number of devices that are specific to the vmapple
target machine. To keep them all tidily together, let's put them into
a single target directory.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 MAINTAINERS             | 7 +++++++
 hw/Kconfig              | 1 +
 hw/meson.build          | 1 +
 hw/vmapple/Kconfig      | 1 +
 hw/vmapple/meson.build  | 0
 hw/vmapple/trace-events | 2 ++
 hw/vmapple/trace.h      | 1 +
 meson.build             | 1 +
 8 files changed, 14 insertions(+)
 create mode 100644 hw/vmapple/Kconfig
 create mode 100644 hw/vmapple/meson.build
 create mode 100644 hw/vmapple/trace-events
 create mode 100644 hw/vmapple/trace.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 09899f7407e..b6019220662 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2765,6 +2765,13 @@ F: hw/hyperv/hv-balloon*.h
 F: include/hw/hyperv/dynmem-proto.h
 F: include/hw/hyperv/hv-balloon.h
=20
+VMapple
+M: Alexander Graf <agraf@csgraf.de>
+R: Phil Dennis-Jordan <phil@philjordan.eu>
+S: Maintained
+F: hw/vmapple/*
+F: include/hw/vmapple/*
+
 Subsystems
 ----------
 Overall Audio backends
diff --git a/hw/Kconfig b/hw/Kconfig
index 1b4e9bb07f7..2871784cfdc 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -41,6 +41,7 @@ source ufs/Kconfig
 source usb/Kconfig
 source virtio/Kconfig
 source vfio/Kconfig
+source vmapple/Kconfig
 source xen/Kconfig
 source watchdog/Kconfig
=20
diff --git a/hw/meson.build b/hw/meson.build
index b827c82c5d7..9c4f6d0d636 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -39,6 +39,7 @@ subdir('ufs')
 subdir('usb')
 subdir('vfio')
 subdir('virtio')
+subdir('vmapple')
 subdir('watchdog')
 subdir('xen')
 subdir('xenpv')
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/hw/vmapple/Kconfig
@@ -0,0 +1 @@
+
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
new file mode 100644
index 00000000000..9ccc5790487
--- /dev/null
+++ b/hw/vmapple/trace-events
@@ -0,0 +1,2 @@
+# See docs/devel/tracing.rst for syntax documentation.
+
diff --git a/hw/vmapple/trace.h b/hw/vmapple/trace.h
new file mode 100644
index 00000000000..572adbefe04
--- /dev/null
+++ b/hw/vmapple/trace.h
@@ -0,0 +1 @@
+#include "trace/trace-hw_vmapple.h"
diff --git a/meson.build b/meson.build
index 1303664e167..bce1d21eec1 100644
--- a/meson.build
+++ b/meson.build
@@ -3592,6 +3592,7 @@ if have_system
     'hw/usb',
     'hw/vfio',
     'hw/virtio',
+    'hw/vmapple',
     'hw/watchdog',
     'hw/xen',
     'hw/gpio',
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103379; cv=none;
	d=zohomail.com; s=zohoarc;
	b=FzgqKoVAHFkDwzdSDFY+ovR7FEbWyXSIcpCEU0NW57hNGL10K92ED0LJbDjPxtnyqTup8VfEYkcHB/T2ATu/B+af1Qr/mwzgObiwoqOIHye/YCAp2ExSb7sTp4p2Wg7bANX/coj28KLEULaPwVs3lDbIT5fXnmLLYmytFYC6PLY=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103379;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=BFtkA3me7ERWvnCWoAANDaTDxRV9mdWjmMCXfFKS9JM=;
	b=b5ufT/msKsC4E5fH3umh+JmAUezhw9NkgbBrO6OJMHZx1VuLy3ldmos0qF1JyNydoYWTcQV4esuH+vBR3lIA12tTOmOxROp+lsMynPiEyViAhrQ4uiFlOcYT+TBLF40nwFftTAIgQddjxTShjsrAbqBVUw/X/Xn1frAoIilmtw8=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103379404347.51803860153325;
 Fri, 13 Dec 2024 07:22:59 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Sw-0006ux-Ha; Fri, 13 Dec 2024 10:20:30 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S3-0004hA-LZ
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:37 -0500
Received: from mail-ej1-x635.google.com ([2a00:1450:4864:20::635])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rp-0005LK-9M
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:33 -0500
Received: by mail-ej1-x635.google.com with SMTP id
 a640c23a62f3a-aa684b6d9c7so316721666b.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:20 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.17
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:18 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103159;
 x=1734707959;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=BFtkA3me7ERWvnCWoAANDaTDxRV9mdWjmMCXfFKS9JM=;
 b=zzzF9LdY1qpj+Kai8ldWANmutIoDQEsRhXmAXWQIcSJu0Cebs2qKJl26rmroQQj6r3
 y1qWgCgcX4vWx6dSZK4yYTuPVUasQmliMXjdbh9Z//bbl/i7Myktn6TlZlZ3IwRFjXAt
 GGrg3YgL70hc9h1MNW9zFAa5l8TcwLOyh8x/YBAiu/RsUECHBfjGSmdCcmHiW9mEnUWL
 z24n7oawiWMOxU5ijFzdGuSIoDmEJnmPlMAzMJSrwHtBbo4M20AyMgDQ7scRYqLHigK+
 5XTrqIYiRddaBJ1qQyMBhiAXAY+MJs8U/CUFjW9Bswxc6lAuu4GUKgxSnl8LfZX4p8jl
 Mvwg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103159; x=1734707959;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=BFtkA3me7ERWvnCWoAANDaTDxRV9mdWjmMCXfFKS9JM=;
 b=JXDC8PxZzM/QOurVeEWr63bIZRZ/LZo/tDK7TgTPL7/7O5xgmKdW220IYVL2QUD1fT
 Nz6270pONMoP3qfE0sLneUDIyXXEu18wY4N246iwE+CSLTw0f+BnUznhysjE+2sldi9h
 wlVpCSoJNTn3MszLwhXLlSADBtHZWNV9MLgctd/6HfFPhVyDBgxwVFG/fmv0ZNJmyh+O
 hu6GWobolMrjEnI/4BiOThI6H/ZAzvcLdxkwQDF3EaNCoavCfpT5fsFO6je6koQ/h2X/
 dgpO1jSaOJXde/c94Xa+mTgRzDOVGcSiYflaitaiwPxPq+ntXNHzkDCenNsHAVZ6uWww
 7PgA==
X-Gm-Message-State: AOJu0YwzAaHYq6BrAmaxkOo95rbPyP1tPKBzcU/+5jzniv9bd9Xp4Ie0
 BO7c8cfLm//HcgnRe4/GyClBtKKG6ROs035mg7J1BSKNRu/yKkuqUE96QddG6bGb6MDl2OrNaY4
 Yiw==
X-Gm-Gg: ASbGnctehjDs91cb+/heeQEOmnKkqcLNLvOpQjn/TPO+Eb5f9KsipbtRu1CJMVytbOX
 ZU5jE9DDzH5pzZPsq2Ex8t7mpDCPAC1/55kFreslQyurNenxAEDP1JoMOWvDgQ1xLNa/VVgGBWn
 GjuiPBlY/6ccrYYCSZbJFAhs7bpavFOnR6jk5o/E0YKeP3oGGglaZ5gXaaXRlBTGP/bWTpXfNsk
 CMnjmEBV4dU5y/fY7Sapgd2UAGDm5ZShdCK0cCJvC+gytY0FL8OFxIpnFALJLprueP7uc6o28mS
 wdQ4nSVBQfg5WbXq5ctFIUs7X999JNIm
X-Google-Smtp-Source: 
 AGHT+IGtRg694BlE+yNPc2DjwTAkEe6jAM1kFCI1lhiv6ItRLspemGqFAAJlSpO57nogcEtAL2cNGQ==
X-Received: by 2002:a17:907:7707:b0:aa6:7ec4:8bb6 with SMTP id
 a640c23a62f3a-aab778c023cmr242897066b.11.1734103158923;
 Fri, 13 Dec 2024 07:19:18 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 06/15] hw: Add vmapple subdir
Date: Fri, 13 Dec 2024 16:18:12 +0100
Message-Id: <20241213151821.65748-23-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::635;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x635.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103381257116600
Content-Type: text/plain; charset="utf-8"

From: Alexander Graf <graf@amazon.com>

We will introduce a number of devices that are specific to the vmapple
target machine. To keep them all tidily together, let's put them into
a single target directory.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 MAINTAINERS             | 7 +++++++
 hw/Kconfig              | 1 +
 hw/meson.build          | 1 +
 hw/vmapple/Kconfig      | 1 +
 hw/vmapple/meson.build  | 0
 hw/vmapple/trace-events | 2 ++
 hw/vmapple/trace.h      | 1 +
 meson.build             | 1 +
 8 files changed, 14 insertions(+)
 create mode 100644 hw/vmapple/Kconfig
 create mode 100644 hw/vmapple/meson.build
 create mode 100644 hw/vmapple/trace-events
 create mode 100644 hw/vmapple/trace.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 09899f7407e..692872d7d1c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2765,6 +2765,13 @@ F: hw/hyperv/hv-balloon*.h
 F: include/hw/hyperv/dynmem-proto.h
 F: include/hw/hyperv/hv-balloon.h
=20
+VMapple
+M: Alexander Graf <agraf@csgraf.de>
+M: Phil Dennis-Jordan <phil@philjordan.eu>
+S: Maintained
+F: hw/vmapple/*
+F: include/hw/vmapple/*
+
 Subsystems
 ----------
 Overall Audio backends
diff --git a/hw/Kconfig b/hw/Kconfig
index 1b4e9bb07f7..2871784cfdc 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -41,6 +41,7 @@ source ufs/Kconfig
 source usb/Kconfig
 source virtio/Kconfig
 source vfio/Kconfig
+source vmapple/Kconfig
 source xen/Kconfig
 source watchdog/Kconfig
=20
diff --git a/hw/meson.build b/hw/meson.build
index b827c82c5d7..9c4f6d0d636 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -39,6 +39,7 @@ subdir('ufs')
 subdir('usb')
 subdir('vfio')
 subdir('virtio')
+subdir('vmapple')
 subdir('watchdog')
 subdir('xen')
 subdir('xenpv')
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/hw/vmapple/Kconfig
@@ -0,0 +1 @@
+
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
new file mode 100644
index 00000000000..9ccc5790487
--- /dev/null
+++ b/hw/vmapple/trace-events
@@ -0,0 +1,2 @@
+# See docs/devel/tracing.rst for syntax documentation.
+
diff --git a/hw/vmapple/trace.h b/hw/vmapple/trace.h
new file mode 100644
index 00000000000..572adbefe04
--- /dev/null
+++ b/hw/vmapple/trace.h
@@ -0,0 +1 @@
+#include "trace/trace-hw_vmapple.h"
diff --git a/meson.build b/meson.build
index 1303664e167..bce1d21eec1 100644
--- a/meson.build
+++ b/meson.build
@@ -3592,6 +3592,7 @@ if have_system
     'hw/usb',
     'hw/vfio',
     'hw/virtio',
+    'hw/vmapple',
     'hw/watchdog',
     'hw/xen',
     'hw/gpio',
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103356; cv=none;
	d=zohomail.com; s=zohoarc;
	b=UkzIOW4uYEmrbW5sYdIMNIY4T+pFN1q4aE8pBqlemCwO7HqGu4kLCbrflqJDuOM/AJ1rxZDKKjZSyxjlVQVWpIS4OIkcCZA9wVk73wyb4d+/ui3dDIvvEwTEJd8tlyL+6s6TcKheWBlKtNeTZib0knyFbxcbpCTCtStLhvV9CD0=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103356;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=2oYrLMZynfGoehZjWa6pbu2oV1B5fji3Vx4MV4wrlhE=;
	b=TKpgaIAog3pQDh9MzoKU+TI03av1o3mybcDUpJBfpYdFheKUqPS7IAkR/111iDPhmldkD9V9Opl1ZseEm3bqY/6f5uZgdB1U/nGTVu6GX9kIIBe9L9Eu9FeyWUnA58XHgjETFBZJkNmtVo0xVvGAf2gwlVqFORlVVWWXp7+/n6A=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103356043855.9141006664988;
 Fri, 13 Dec 2024 07:22:36 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SC-0004xD-FS; Fri, 13 Dec 2024 10:19:44 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Ra-0004Qa-L5
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:06 -0500
Received: from mail-ej1-x62b.google.com ([2a00:1450:4864:20::62b])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RQ-00058D-6Q
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:04 -0500
Received: by mail-ej1-x62b.google.com with SMTP id
 a640c23a62f3a-aa670ffe302so343771966b.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:52 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.48
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:50 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103130;
 x=1734707930;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=2oYrLMZynfGoehZjWa6pbu2oV1B5fji3Vx4MV4wrlhE=;
 b=CqEwo0QbFJ9+nVlxP4xTwEbVqz72N5Uqoef4chm9TYmnoJOfJsh+JtXCadSyg+NsGS
 DqnTiAUz6WAdS7yBoVad1nY47+kHOqdrfJJIXENwQKfZ7lgHvrj+YO7nhH5rYfim6EkY
 ihpjTPJqxKGe0/2hXL+oV+Xd+xIrpRY72h+4YPWj/XMR1B39fo/p6FcGSisKmQVTcZNf
 uPXLDcHUfMCjhb6np3r9gN2wYTrTdkB3EL9NnzDs8c6AATKpTN7RwXuC+lwxjyfVIEkh
 TzdwiTrkiYf1imai58AnYysl9/11Iz/I/oapn1KQdrJ9YDUXcpUBPeiICllk0TwsxFga
 jitQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103130; x=1734707930;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=2oYrLMZynfGoehZjWa6pbu2oV1B5fji3Vx4MV4wrlhE=;
 b=qMXqgj5Rn6vZWSgsQWejBPyG52dtsr80Zdx705TX7c+rn4A/9uSWr3z0qaJDgh4u0W
 P7LWaJmJ8bufjc79Dc+t4KzvTMtcu4H6ZgLJv2Eij9C5bVvcKTrvNavmrIEj1DMgtvai
 INIQg3IjPqo3dVFND8V1IG/uPio41TTIlRW1frQHC/WUJVbfLcHf7tkys4QzugKHTSG0
 HQJCTR8d6T2j5cf0xD+IQt8dRF3AmFqbkb4rZcvICj3FpWl5UtpCJNulQrK+mAfnDWhe
 S3JCp4C1ig4DPC9y6N0O6q+xZWScHyGPFodQ+6oV8vOUGqaJir0mSEvkD4enW/HMMjgF
 3WyQ==
X-Gm-Message-State: AOJu0YyJ5PpyCdcUlSxNvMHvzDFHRwY0Ju0l7v/nXw5EoOaB23jK1Uo2
 f7Ohx6+0SRx6IizaDO6sPXnszi5eBsauX7P5369sZcN5poZ4Ld6dRd7XV0pD1fnmJIucD5GeMsW
 BPQ==
X-Gm-Gg: ASbGncszjiKHYnWFn610HwBVdyu/lYbXffJk8x5YYzURTBnn6gUHey8+lebxhVV/WA1
 xvLhe5XuPZgs1Yr8BqCDgoP7fovnYWr57/MfEUm/TWQx0/6bihhos8Oe7TCbfF6o6nNHxS59b47
 cWYlgj+NJUnFYVhdzw637SH7uYLc8iYqDwlBvQccBuG6gle+2GnHr3MFpEZsy7TRpTcmAQO0Z1g
 JLJV79AmCpJ9ufekizmS4qcZrZuYZjiWolMAlBFhoNCJ94snoJ65SaiDpzwXIjeB6cpdjb26x8w
 fPDQphStwwtYdMefsQCTaCTAk71G/syP
X-Google-Smtp-Source: 
 AGHT+IG8ENRCwuJy8z2jScJ1HVWKJk6zjhAAgwffuZiUqMjUMw3Tcp083vHfgOBmVWK7PKw1ON9bMA==
X-Received: by 2002:a17:906:6ad1:b0:aab:9257:248d with SMTP id
 a640c23a62f3a-aab92572532mr33295966b.57.1734103130388;
 Fri, 13 Dec 2024 07:18:50 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 07/15] hw/misc/pvpanic: Add MMIO interface
Date: Fri, 13 Dec 2024 16:17:57 +0100
Message-Id: <20241213151821.65748-8-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62b;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62b.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103356912116600

From: Alexander Graf <graf@amazon.com>

In addition to the ISA and PCI variants of pvpanic, let's add an MMIO
platform device that we can use in embedded arm environments.

Signed-off-by: Alexander Graf <graf@amazon.com>
Reviewed-by: Philippe Mathieu-Daud=C3=A9 <philmd@linaro.org>
Tested-by: Philippe Mathieu-Daud=C3=A9 <philmd@linaro.org>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v3:
 * Rebased on upstream, updated a header path

 hw/misc/Kconfig           |  4 +++
 hw/misc/meson.build       |  1 +
 hw/misc/pvpanic-mmio.c    | 61 +++++++++++++++++++++++++++++++++++++++
 include/hw/misc/pvpanic.h |  1 +
 4 files changed, 67 insertions(+)
 create mode 100644 hw/misc/pvpanic-mmio.c

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 1f1baa5dde9..5a6c1603b60 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -145,6 +145,10 @@ config PVPANIC_ISA
     depends on ISA_BUS
     select PVPANIC_COMMON
=20
+config PVPANIC_MMIO
+    bool
+    select PVPANIC_COMMON
+
 config AUX
     bool
     select I2C
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index d02d96e403b..4de4db0a600 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -122,6 +122,7 @@ system_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files=
('armsse-mhu.c'))
=20
 system_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
 system_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
+system_ss.add(when: 'CONFIG_PVPANIC_MMIO', if_true: files('pvpanic-mmio.c'=
))
 system_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
 system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
   'aspeed_hace.c',
diff --git a/hw/misc/pvpanic-mmio.c b/hw/misc/pvpanic-mmio.c
new file mode 100644
index 00000000000..56738efee53
--- /dev/null
+++ b/hw/misc/pvpanic-mmio.c
@@ -0,0 +1,61 @@
+/*
+ * QEMU simulated pvpanic device (MMIO frontend)
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/qdev-properties.h"
+#include "hw/misc/pvpanic.h"
+#include "hw/sysbus.h"
+#include "standard-headers/misc/pvpanic.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(PVPanicMMIOState, PVPANIC_MMIO_DEVICE)
+
+#define PVPANIC_MMIO_SIZE 0x2
+
+struct PVPanicMMIOState {
+    SysBusDevice parent_obj;
+
+    PVPanicState pvpanic;
+};
+
+static void pvpanic_mmio_initfn(Object *obj)
+{
+    PVPanicMMIOState *s =3D PVPANIC_MMIO_DEVICE(obj);
+
+    pvpanic_setup_io(&s->pvpanic, DEVICE(s), PVPANIC_MMIO_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->pvpanic.mr);
+}
+
+static Property pvpanic_mmio_properties[] =3D {
+    DEFINE_PROP_UINT8("events", PVPanicMMIOState, pvpanic.events,
+                      PVPANIC_PANICKED | PVPANIC_CRASH_LOADED),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pvpanic_mmio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, pvpanic_mmio_properties);
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo pvpanic_mmio_info =3D {
+    .name          =3D TYPE_PVPANIC_MMIO_DEVICE,
+    .parent        =3D TYPE_SYS_BUS_DEVICE,
+    .instance_size =3D sizeof(PVPanicMMIOState),
+    .instance_init =3D pvpanic_mmio_initfn,
+    .class_init    =3D pvpanic_mmio_class_init,
+};
+
+static void pvpanic_register_types(void)
+{
+    type_register_static(&pvpanic_mmio_info);
+}
+
+type_init(pvpanic_register_types)
diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h
index 9a71a5ad0d7..049a94c1125 100644
--- a/include/hw/misc/pvpanic.h
+++ b/include/hw/misc/pvpanic.h
@@ -26,6 +26,7 @@
=20
 #define TYPE_PVPANIC_ISA_DEVICE "pvpanic"
 #define TYPE_PVPANIC_PCI_DEVICE "pvpanic-pci"
+#define TYPE_PVPANIC_MMIO_DEVICE "pvpanic-mmio"
=20
 #define PVPANIC_IOPORT_PROP "ioport"
=20
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103503; cv=none;
	d=zohomail.com; s=zohoarc;
	b=E562KpovjCaXotOOTMiLhWOJatoAY0tXA0+vqynCjp5iEJd0bOvZkXkZfsKdqEXz3P0C20wEbhn6JnX/Kw4ZHqU+PIIGem9EiyKH/vjm/e9mnK0ZfRZZuBleM7+/t7iu5YZvJ9LRYix+nmZDzW7zD7Xb+40/m06CERwsokIHaNc=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103503;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=2oYrLMZynfGoehZjWa6pbu2oV1B5fji3Vx4MV4wrlhE=;
	b=O5h3aafAGrCinvSKosdMcR2WR/vrh7SizmpT8BxZg9lWvOyDrNFZI0xxZOfq6joAYBmRYYwxOtCg8i4fg1T3hTuc0WYrTB09c8RBJrhUVOEZvCP+4WwqeYjhqeUprsVznLGVKuVo7ZCMvNMsBjPIZtaVojzXk7xPfbCgg7QeHa4=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103503258407.55603575623604;
 Fri, 13 Dec 2024 07:25:03 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Sp-0006i3-QV; Fri, 13 Dec 2024 10:20:24 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S3-0004h0-L6
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:36 -0500
Received: from mail-ej1-x632.google.com ([2a00:1450:4864:20::632])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rq-0005M3-9W
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:34 -0500
Received: by mail-ej1-x632.google.com with SMTP id
 a640c23a62f3a-aa6aad76beeso281793766b.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:21 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.19
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:20 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103161;
 x=1734707961;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=2oYrLMZynfGoehZjWa6pbu2oV1B5fji3Vx4MV4wrlhE=;
 b=Ac0kufZqOHVxZ3OzK8cWJSWf7fAWI9SaHETMU4oxidxV7Y41IF0m9gmgctkGHIjNS/
 gCP5htd6mYddGhRNDdSx4LCqgQExFeKAcpNX8D1ArKLH0+z19f/DvkmcObwH1zqFisGM
 RM3m6EvG+ftkuOafJKnO7JH3Qlr/46/F1JFfSVhEBgT4LzEIODouEOMMWNYh8VD2LPty
 e2mdvM6ZDnpMV58Ptz3I9TKyqxp8D1NrqiR5K9H21SrjOTZ/7XTWV8YXUiMrruGr8uWr
 4kG7JSD96RVScT/SCDHgNi+zfH2Z4juCsOSyT+QE8vBNU7wU4R+NmyFoPnI4oU64GvOl
 s6yg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103161; x=1734707961;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=2oYrLMZynfGoehZjWa6pbu2oV1B5fji3Vx4MV4wrlhE=;
 b=lwuUg91Ab7LrmiFCSHDDWkFd/H2bbDPROVxjkvkKw7j8xiVdHq0iH0qamjYydz4Pbz
 XXEqDoIx+dH7caWemw4jAUVBlsQBHmyTI3G7y/hAUdJvlag0W9UIEOBA38lIesHxWlWW
 l4S/S2fZbyrgCbXnk6flbabi2wJEbEGQfet41LucUj9YQVdagA4zDYO6qv0k9RPWBn64
 v3MXy4ccewFmZoYxadygYnIE4y+NyXtP91H+KOke0N0tHE2NhAv1LkauOW8UdOLYO0PX
 5MSaEl1Oc+Lu05TbprUBlef5hZZxWdMnNEk6i9u0EMrlmEQmOj+mAuMUHu9bcFakFjXD
 7JRw==
X-Gm-Message-State: AOJu0YxLCJxEWV6+z+taY+e7xTii1wBSN5261HO7N8luhj46T6ulbVH3
 szApPMCmq+dwQRYKbRWV4um2GqK77f4zAxjqMFqxMbDdjbzRP7ZDRZHD+MXIaCVhSRljzBAtI9y
 01A==
X-Gm-Gg: ASbGnctlCPCwRVLwloB0+wprKNOON5zkZVTYBFZYOjtrw5wHPmObAAr2W1Pe0R3ctfO
 NUWxcZ3PV/xMW0AD6VgCRMLUWgdMTJ8XyKRMnnMV6XLFQgzOaE69r935/uFmSJIEFDsyfM+FzBH
 l2wp+zAeiQkRznc6ZanzZg/DnMQtXMO0otIjh8QXRFCI0ra3wIDOFwbh5HwnV5vHohj0bFgCA8n
 drWC0021RPKftbR1kfvZIowUewwp4JJQiic28Ajva/od/ChikDfE7RWB0LnRY36EUNKizg8dOX0
 NIFdc/WZ5V1c7a6lQbwBDfyMyjBjCsC3
X-Google-Smtp-Source: 
 AGHT+IEfGlzW93XmTmvtXRt0w17s9nb+gOhhV6b/RTIMT0/A8y8Oc+wRGF9co2l7d3xuf0CKGI4M3g==
X-Received: by 2002:a17:907:9690:b0:aa6:ac19:7502 with SMTP id
 a640c23a62f3a-aab778e0769mr291075466b.4.1734103160901;
 Fri, 13 Dec 2024 07:19:20 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 07/15] hw/misc/pvpanic: Add MMIO interface
Date: Fri, 13 Dec 2024 16:18:13 +0100
Message-Id: <20241213151821.65748-24-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::632;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x632.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103503603116600

From: Alexander Graf <graf@amazon.com>

In addition to the ISA and PCI variants of pvpanic, let's add an MMIO
platform device that we can use in embedded arm environments.

Signed-off-by: Alexander Graf <graf@amazon.com>
Reviewed-by: Philippe Mathieu-Daud=C3=A9 <philmd@linaro.org>
Tested-by: Philippe Mathieu-Daud=C3=A9 <philmd@linaro.org>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v3:
 * Rebased on upstream, updated a header path

 hw/misc/Kconfig           |  4 +++
 hw/misc/meson.build       |  1 +
 hw/misc/pvpanic-mmio.c    | 61 +++++++++++++++++++++++++++++++++++++++
 include/hw/misc/pvpanic.h |  1 +
 4 files changed, 67 insertions(+)
 create mode 100644 hw/misc/pvpanic-mmio.c

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 1f1baa5dde9..5a6c1603b60 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -145,6 +145,10 @@ config PVPANIC_ISA
     depends on ISA_BUS
     select PVPANIC_COMMON
=20
+config PVPANIC_MMIO
+    bool
+    select PVPANIC_COMMON
+
 config AUX
     bool
     select I2C
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index d02d96e403b..4de4db0a600 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -122,6 +122,7 @@ system_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files=
('armsse-mhu.c'))
=20
 system_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
 system_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
+system_ss.add(when: 'CONFIG_PVPANIC_MMIO', if_true: files('pvpanic-mmio.c'=
))
 system_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
 system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
   'aspeed_hace.c',
diff --git a/hw/misc/pvpanic-mmio.c b/hw/misc/pvpanic-mmio.c
new file mode 100644
index 00000000000..56738efee53
--- /dev/null
+++ b/hw/misc/pvpanic-mmio.c
@@ -0,0 +1,61 @@
+/*
+ * QEMU simulated pvpanic device (MMIO frontend)
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/qdev-properties.h"
+#include "hw/misc/pvpanic.h"
+#include "hw/sysbus.h"
+#include "standard-headers/misc/pvpanic.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(PVPanicMMIOState, PVPANIC_MMIO_DEVICE)
+
+#define PVPANIC_MMIO_SIZE 0x2
+
+struct PVPanicMMIOState {
+    SysBusDevice parent_obj;
+
+    PVPanicState pvpanic;
+};
+
+static void pvpanic_mmio_initfn(Object *obj)
+{
+    PVPanicMMIOState *s =3D PVPANIC_MMIO_DEVICE(obj);
+
+    pvpanic_setup_io(&s->pvpanic, DEVICE(s), PVPANIC_MMIO_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->pvpanic.mr);
+}
+
+static Property pvpanic_mmio_properties[] =3D {
+    DEFINE_PROP_UINT8("events", PVPanicMMIOState, pvpanic.events,
+                      PVPANIC_PANICKED | PVPANIC_CRASH_LOADED),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pvpanic_mmio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, pvpanic_mmio_properties);
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo pvpanic_mmio_info =3D {
+    .name          =3D TYPE_PVPANIC_MMIO_DEVICE,
+    .parent        =3D TYPE_SYS_BUS_DEVICE,
+    .instance_size =3D sizeof(PVPanicMMIOState),
+    .instance_init =3D pvpanic_mmio_initfn,
+    .class_init    =3D pvpanic_mmio_class_init,
+};
+
+static void pvpanic_register_types(void)
+{
+    type_register_static(&pvpanic_mmio_info);
+}
+
+type_init(pvpanic_register_types)
diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h
index 9a71a5ad0d7..049a94c1125 100644
--- a/include/hw/misc/pvpanic.h
+++ b/include/hw/misc/pvpanic.h
@@ -26,6 +26,7 @@
=20
 #define TYPE_PVPANIC_ISA_DEVICE "pvpanic"
 #define TYPE_PVPANIC_PCI_DEVICE "pvpanic-pci"
+#define TYPE_PVPANIC_MMIO_DEVICE "pvpanic-mmio"
=20
 #define PVPANIC_IOPORT_PROP "ioport"
=20
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103752; cv=none;
	d=zohomail.com; s=zohoarc;
	b=Rj4BF3aQvb1sLQWfCdriZ9vmJILOymfEN8+BWmKpb2+rZ50KX38ptiq2/Cyno4V3eoWg0Mg+pDLX3Cwwo9lYtCYOhvox+4f6QpTufmUHfbRoUmwdcjQWPdxfVk38jTIsx+fiN31Po8H3MZrKOh30A7igz9LZA4XPl9zWZD+tRiA=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103752;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=jbiG06Qj2eVtNM1RZ8Zpr4IJcnCvDLdL2ENhuYJnNHE=;
	b=inN4+sYoFcVanyvEtHLVWXUMt1A56C8GyWGgxV0bh2DDPi82mMXIVBu6raRo3g2r7sdx7MgeVTbEV7Z1D7RdqqUVciwx/i1/FB17WNxNoCVeP3f5yj/Rce3eFK7Na+qe54YOzLJmzz/V4CYO3+MaNFh6ttmpIlFPlGyPqzmYQmI=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103752203457.1832806973305;
 Fri, 13 Dec 2024 07:29:12 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SL-00056r-Cn; Fri, 13 Dec 2024 10:19:53 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rg-0004TA-Bj
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:13 -0500
Received: from mail-ed1-x52f.google.com ([2a00:1450:4864:20::52f])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rb-000596-6I
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:11 -0500
Received: by mail-ed1-x52f.google.com with SMTP id
 4fb4d7f45d1cf-5d414b8af7bso3857755a12.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:53 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.50
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:51 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103132;
 x=1734707932;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=jbiG06Qj2eVtNM1RZ8Zpr4IJcnCvDLdL2ENhuYJnNHE=;
 b=Mg/48fs7F5xz9lLSIsD7ur3qb5fJt+LVbDjCqR450zyt+5+xCZwAwqy72LY8/MGdmx
 nYS3kyldjBoum04UNsDV9dM8Pt+XAJP6b4TkcwSNgNTk9PDKyCxTCfo3h8jbyubvv0K9
 tfCa+TFI1Dpg9sSilvRH2PPpRWqdhXFQCMf/Pxq7MLYMVljL8lGLF5NOLv3XhqP6QZiw
 FyvP3cyPgX2zjkqCoxS0zcgYsCW36zFQCVB+MkSKxR1Zt2Xh9LdZMqSEoWziXC7yeQIf
 5KLTK/qT2vKLQAYVi/hY446QDxeBwFfBwvqkK4v+XPd8B3SFtBxU4w1dsCcj8PihMQvn
 aDYw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103132; x=1734707932;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=jbiG06Qj2eVtNM1RZ8Zpr4IJcnCvDLdL2ENhuYJnNHE=;
 b=Ng0G4Ho2dLF5vIKFfsniOpxRWgoLEf/NHW688pIKT7gTzbYxER/5Ve67eaxTjBdWRx
 4XEo37Jap3hPY02KFp7jPWC0hFmaG7V/yMTp1NkvTeoYk9lPWC2cwzGdTUljHux9jQlG
 blX8MwutNyQoN8L58LQfcJEJmaZchludBswpRB4iBEz63uGEWMmAUYdWCO6jAZezrkLt
 tvp0eZWVBBmP6llymc8k7KJPeyu+RJ8t+sHTE7L0oL0UiUn7kVYVa5TP41iN2+lloqjV
 u46A3ONNHw4Qjphz1dAzR8Uh4EtIJNC3z80mMah+QfXeMnjJtXSn26pk5ZFo1K3QwBbG
 2iYQ==
X-Gm-Message-State: AOJu0Yz9IqwQLVy/sWqNzi09V3ieFjazp9ktG4ZgyctRHZ185JpkFHrr
 h0sAdfH3cIUnA9arbmA2dyKcqtWBKpg86PJCKis0sdfAhD5pqRaAIXacFrTA3DRIr+oZnISopqs
 o5A==
X-Gm-Gg: ASbGnct3R7AKdGHG2EfJztF9Ab13/qDYtLNAPTmnm+2a8prJr8caMJ6HsjutRTlAEvV
 FWshJ3NXD/DtvVlCbec1THHAZeK01nCRSu+mUBjUppe1kvAKA/rgVoT+7A8rI1eKfJOoKyWjvuJ
 fg2HUZstb4/4pbFEko6p9e77x6urvQIJ1SRBwKwftH/fhBBrXkbqUB0YEzLUjGbYT16HpJGT/Rr
 VXQPMgr9Dl6HRbfLiUFfA6P2D3MlSt1zWCSiUy6CbLUXVF60JYwdY7b9JpXFLMp3ApPhp0dfyaP
 aTfCJIlzNNZOriTwfcQqF4vwRlN37NJt
X-Google-Smtp-Source: 
 AGHT+IG5bvJo7d8pkfatjbIVYQhMywy7MKrXn/q3FV5D1M66jmhBDg4HL8AFRo+DCOuQKlTU79yJOg==
X-Received: by 2002:a17:907:a08a:b0:aa6:8bb4:503d with SMTP id
 a640c23a62f3a-aab778c9cc3mr328990866b.2.1734103132294;
 Fri, 13 Dec 2024 07:18:52 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 08/15] hvf: arm: Ignore writes to CNTP_CTL_EL0
Date: Fri, 13 Dec 2024 16:17:58 +0100
Message-Id: <20241213151821.65748-9-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::52f;
 envelope-from=phil@philjordan.eu; helo=mail-ed1-x52f.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103752678116600
Content-Type: text/plain; charset="utf-8"

From: Alexander Graf <graf@amazon.com>

MacOS unconditionally disables interrupts of the physical timer on boot
and then continues to use the virtual one. We don't really want to support
a full physical timer emulation, so let's just ignore those writes.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 target/arm/hvf/hvf.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index ca7ea92774a..d75e504dcda 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -11,6 +11,7 @@
=20
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
+#include "qemu/log.h"
=20
 #include "sysemu/runstate.h"
 #include "sysemu/hvf.h"
@@ -184,6 +185,7 @@ void hvf_arm_init_debug(void)
 #define SYSREG_OSLSR_EL1      SYSREG(2, 0, 1, 1, 4)
 #define SYSREG_OSDLR_EL1      SYSREG(2, 0, 1, 3, 4)
 #define SYSREG_CNTPCT_EL0     SYSREG(3, 3, 14, 0, 1)
+#define SYSREG_CNTP_CTL_EL0   SYSREG(3, 3, 14, 2, 1)
 #define SYSREG_PMCR_EL0       SYSREG(3, 3, 9, 12, 0)
 #define SYSREG_PMUSERENR_EL0  SYSREG(3, 3, 9, 14, 0)
 #define SYSREG_PMCNTENSET_EL0 SYSREG(3, 3, 9, 12, 1)
@@ -1620,6 +1622,13 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t =
reg, uint64_t val)
     case SYSREG_OSLAR_EL1:
         env->cp15.oslsr_el1 =3D val & 1;
         return 0;
+    case SYSREG_CNTP_CTL_EL0:
+        /*
+         * Guests should not rely on the physical counter, but macOS emits
+         * disable writes to it. Let it do so, but ignore the requests.
+         */
+        qemu_log_mask(LOG_UNIMP, "Unsupported write to CNTP_CTL_EL0\n");
+        return 0;
     case SYSREG_OSDLR_EL1:
         /* Dummy register */
         return 0;
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103550; cv=none;
	d=zohomail.com; s=zohoarc;
	b=Cz4++qgOTXDnx/UKvRXs/ExCIEs9l5gHBDj5iNAz2dXnDNtezaqyVoI1KWgMu3bI3EuF+2zeMUDMj60w4H79eYII7f9AK2kGCImfH1WYGuxflSuLHn9ZwylKp45ZUcAh1A3PuYctAX/JeAHB74XSyA3RKvJxRXAMPf+0ypsNbOo=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103550;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=jbiG06Qj2eVtNM1RZ8Zpr4IJcnCvDLdL2ENhuYJnNHE=;
	b=VS3yurpTiCateQmJQkstUtEURsD8dt3ydaFm3fwRkMvXMruQ+yQJdcXLZkRj76ZQvieisZ1/CjFwxDfyCPlyS/ULMT/dBpgrIcrgiUKmtD2muDbeYHzn3gXp2f3MsJZYn83y8UJip/yN9nX98QCaF0oc274aQMNyzwVEm9NfUTQ=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103550742646.1339663975873;
 Fri, 13 Dec 2024 07:25:50 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Sd-00065N-Qm; Fri, 13 Dec 2024 10:20:12 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S9-0004qt-Dd
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:41 -0500
Received: from mail-ej1-x633.google.com ([2a00:1450:4864:20::633])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rs-0005Mr-9I
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:40 -0500
Received: by mail-ej1-x633.google.com with SMTP id
 a640c23a62f3a-aa543c4db92so366351166b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:23 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.21
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:22 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103163;
 x=1734707963;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=jbiG06Qj2eVtNM1RZ8Zpr4IJcnCvDLdL2ENhuYJnNHE=;
 b=zDDozi3URzuy3BD/2wxsvWSTPemoukV14WC6mIB2bNeg7qgi0vvK48LE3DqTGwBJuj
 bBayp1K3urSPCRjc2HEa/5WqUgMGVjNrAzHTMyDJgNj58wFPXB/mCfUZ6rI15H1igYuq
 zJVoIGn0ooons/yl4bc11XcV9DIMH6E04CyvQ0PJP381cO2aFDy7Nh4xH1x5zbMIXOhE
 IhGQX1gpdg2hm+tBAHTmipa6+oAk1xvW6piggwMMocPshkQyBqMqkrWLsYB/Ia2OyG6S
 9P0YN8O4ccvd5ms76zDuCiA0/xkPGzqU/npxx/tXr4Gq4qyV4xM0PH/jBXl4zjE5ZKUI
 E1LQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103163; x=1734707963;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=jbiG06Qj2eVtNM1RZ8Zpr4IJcnCvDLdL2ENhuYJnNHE=;
 b=buyCc4t3xqs3ieSNCLbiqiwz6a7QbcP0e8DkbJxV415LrWvplQwl3ShCINwj235GpA
 MKVuimkdDw5XTm+iEbiOKBLgZJvMpGTyFumXugYNZDBlHJ7GyqTH/gX9AiXeurzmnmPz
 1Bo/3uaplutxt7PVaV2Q1fWcssOWSGmBq2eQOOa/fdCVtuOYaNDlCCMEBE2+AUd78cPV
 pdJGE00jjR+3XIUoL6XucRtwDzzmBnC+3TVBe+87fWhwQz1rkIBGMCvzox4lZFti12dh
 1gNcts5DvZX/ZvUf1Z1qbv+k+HX7Y/XU9QBqQYF+WbOOWFU2VANYD8ew5khzkm0YB3g4
 CFxw==
X-Gm-Message-State: AOJu0Yz+5/WRU3QNFbbpvsrtfdAn6ofl9X33uh43FLmFiT+S6gmsFPHB
 jHlmvTku47oH2Tr+dlzR0Zhk2Ttt0CTcvSje9m8xZqVJB9y/R9aGOl+u/0lyM0L7WFApNsTJRKV
 dRg==
X-Gm-Gg: ASbGnctISovv/qRs1b0ulqKCVsKHnLo8/i4pARQGQLyH7UmBIQqTG1DcQHn1L+e4mVh
 sqDvP7TJz89/GBoOV7OAPs3rm24apl8sJTVU5px1OTl8VFy2500NaZqt3bLDMtb4H4Fg6G4kH92
 cjCgoUWabV5cwdy/Zfjby0WleTt1R6nnKBZ437KoBsf84Z2oktc8HH5Ru/2dRCiD4BarBiSLM0x
 jUxuVTK/W7z/DmV8yXb4zj0jLAWBBnfqu75D95aOso5gdxbf0J0vFCFH9wPu7HL+TAp5L8YagCT
 7Aku9BlbH8wT/Krxtjwc0qCxoSuURSPW
X-Google-Smtp-Source: 
 AGHT+IF5PPSX3PcdDyLMno1xB5YKxsDErOLFv9wfZNBM++bTd6w9SsB9zRDRId5ALtwVW3/qmpEZ5Q==
X-Received: by 2002:a17:907:7ba2:b0:aa6:8275:223c with SMTP id
 a640c23a62f3a-aab77e7b67amr342828166b.44.1734103162677;
 Fri, 13 Dec 2024 07:19:22 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 08/15] hvf: arm: Ignore writes to CNTP_CTL_EL0
Date: Fri, 13 Dec 2024 16:18:14 +0100
Message-Id: <20241213151821.65748-25-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::633;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x633.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103551741116600
Content-Type: text/plain; charset="utf-8"

From: Alexander Graf <graf@amazon.com>

MacOS unconditionally disables interrupts of the physical timer on boot
and then continues to use the virtual one. We don't really want to support
a full physical timer emulation, so let's just ignore those writes.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 target/arm/hvf/hvf.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index ca7ea92774a..d75e504dcda 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -11,6 +11,7 @@
=20
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
+#include "qemu/log.h"
=20
 #include "sysemu/runstate.h"
 #include "sysemu/hvf.h"
@@ -184,6 +185,7 @@ void hvf_arm_init_debug(void)
 #define SYSREG_OSLSR_EL1      SYSREG(2, 0, 1, 1, 4)
 #define SYSREG_OSDLR_EL1      SYSREG(2, 0, 1, 3, 4)
 #define SYSREG_CNTPCT_EL0     SYSREG(3, 3, 14, 0, 1)
+#define SYSREG_CNTP_CTL_EL0   SYSREG(3, 3, 14, 2, 1)
 #define SYSREG_PMCR_EL0       SYSREG(3, 3, 9, 12, 0)
 #define SYSREG_PMUSERENR_EL0  SYSREG(3, 3, 9, 14, 0)
 #define SYSREG_PMCNTENSET_EL0 SYSREG(3, 3, 9, 12, 1)
@@ -1620,6 +1622,13 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t =
reg, uint64_t val)
     case SYSREG_OSLAR_EL1:
         env->cp15.oslsr_el1 =3D val & 1;
         return 0;
+    case SYSREG_CNTP_CTL_EL0:
+        /*
+         * Guests should not rely on the physical counter, but macOS emits
+         * disable writes to it. Let it do so, but ignore the requests.
+         */
+        qemu_log_mask(LOG_UNIMP, "Unsupported write to CNTP_CTL_EL0\n");
+        return 0;
     case SYSREG_OSDLR_EL1:
         /* Dummy register */
         return 0;
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103630; cv=none;
	d=zohomail.com; s=zohoarc;
	b=LU5tsJyPIqygeb+witRnmlbhemP+wfwtsx9jNgHKnwig96oM6maxIu513Rmaf3f/5FkBkJgLxkMYtDAXFcKKzkYxM4x/O/7tvd/pON2x6dX0jMV/vV7RiFzzu6Jjv5l5r2tnP+V6cG95KyznGRgbwbJslniOQ9bFdv1bNjs2B48=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103630;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=vE4icFzbUyJwOx4II5Kw3Wy8lfUTjt60Nc/k0y/6lC8=;
	b=dqfgVeunabYyCwjOfpXsWDjz41lRA3Wnf+QL9ifk7Q+j1bBLY1O0dqZ9cu2ffkinQSVe8Ex5AWuLj8HlL77Zpm5Kk6slIHeUyQlE406rjjLaHyG/a9OIZpSM//2quasc+R+kZfq4/zgu5sv76e9xiLv2j5QmRYVKVV7jju+U7Mk=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 17341036306371014.7929587400678;
 Fri, 13 Dec 2024 07:27:10 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Ts-0000Ho-At; Fri, 13 Dec 2024 10:21:29 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S7-0004nc-DT
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:40 -0500
Received: from mail-ej1-x62d.google.com ([2a00:1450:4864:20::62d])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Ru-0005NU-2q
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:39 -0500
Received: by mail-ej1-x62d.google.com with SMTP id
 a640c23a62f3a-aa6997f33e4so279278366b.3
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:25 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.22
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:24 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103164;
 x=1734707964;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=vE4icFzbUyJwOx4II5Kw3Wy8lfUTjt60Nc/k0y/6lC8=;
 b=xpm41llUSYVoIH5rOfgduVT49z+xmLbfmGs5PxouSrXCYva/+lPXRcFrd2GeKQ12SV
 aMIEr/mFjtCTr/W3Ze+zwUfZqdQBM9G97m2rTEU0TUXLBUoYUuwkh/CCO+NSwxFO1fIo
 uiweyecZ00ky+JZ9OHM4Fxd9KhbH2STSQQ96F/bepRdnve6FS4q0EWtAaSQG3ulRNwa3
 RkDZn53OvybPnkg4wH/BkEeUYBAHb4a3SktCAJTyWkMcaS4l4Puq5YCkcVmEWwmaFN9t
 BNE6WNiLt0xXI0cdhI9dv0G2i2qO7GMl/JMKNq8asbX10JxVTei8hAT9N/Lp7eRtSoEG
 TtNw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103164; x=1734707964;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=vE4icFzbUyJwOx4II5Kw3Wy8lfUTjt60Nc/k0y/6lC8=;
 b=Rjl8hafwJmAT/gODZNPWk3LI62eexhGVmTDsPxu/k1FXx/NVqrNxCEyGcj3x1ZyQvm
 QvmYZQ6N8CvX93etOdhsqiAGMjEFrLS8iVmRTJAu00zE7RHPPlcnTCmZC6arWvWWaPsx
 8eWJr+1Mrv2TyAfxM24NDfJ6bNWvWdvLGSaJGR/GLaZplRftLBAWAveqgUmr8+FACULD
 Wq9CBz006O3imZc/mDPy1+MNrcWTkLyE5gO6EsN24bij7Iuj5MuThcKOmCEhy7RvQzcc
 HdqOD7EFR1kFOir2r1IjIh3yrCrvRPMOMU5w37sCZVKPp5JghTiBSWYokmV+Z2zI1esw
 QpnQ==
X-Gm-Message-State: AOJu0YyTUrOzOuNNUdMS2bzRz8+HuR7PJP86DCYIPnzjqKxTPxJM/e6p
 Vs4O+P/pswda3CX5V2/UpgICPTCE3CEy/OUfWdyWu4HypNu7AzZKrMP9Tb4Q5W/cZtThKV4eigp
 aIA==
X-Gm-Gg: ASbGncuYEM8MtKpI+M7cATQdVm6p7ecoX4us8Rrg7rxAeH1Cp+1wJjFD9yQsMnWLsME
 Qng/BlTVX7+DaT6h5mgcE/RuXTljJ8xPNRUCxj41ACCvZVz286E/h5xqGjpffL3nJrXX0Otscto
 Z9nJlHVV4+AGlOHgFUWmLNU/Sp35LNjwCYbBeibSACRGX3iSBr3eoEAk/JaZGQcTyZv+t3TxZ88
 FwUC1hgCDUe47QvtcH2QvN4H7Zcu/G65QsVdJb71ne/jvL/IUtHqOF7wdGquoDk57u7KczZHtFe
 qaS/jiUr/B0I/AO0Jy+FPetEPz4Ht1mE
X-Google-Smtp-Source: 
 AGHT+IFkq0yNpuumLz8D7oDQ5U0DpgvUh0fQW48MFgsBslxQky+yDfrWutauy13rSOh0CtYHPFMlPg==
X-Received: by 2002:a17:906:c106:b0:aa6:ab70:4a78 with SMTP id
 a640c23a62f3a-aab77e8ab51mr264187466b.37.1734103164441;
 Fri, 13 Dec 2024 07:19:24 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 09/15] gpex: Allow more than 4 legacy IRQs
Date: Fri, 13 Dec 2024 16:18:15 +0100
Message-Id: <20241213151821.65748-26-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62d;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62d.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103632355116600
Content-Type: text/plain; charset="utf-8"

From: Alexander Graf <graf@amazon.com>

Some boards such as vmapple don't do real legacy PCI IRQ swizzling.
Instead, they just keep allocating more board IRQ lines for each new
legacy IRQ. Let's support that mode by giving instantiators a new
"nr_irqs" property they can use to support more than 4 legacy IRQ lines.
In this mode, GPEX will export more IRQ lines, one for each device.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Turned pair of IRQ arrays into array of structs.
 * Simplified swizzling logic selection.

v12:

 * Fixed uses of deleted GPEX_NUM_IRQS constant that have been
   added to QEMU since this patch was originally written.

 hw/arm/sbsa-ref.c          |  2 +-
 hw/arm/virt.c              |  2 +-
 hw/i386/microvm.c          |  2 +-
 hw/loongarch/virt.c        | 12 +++++------
 hw/mips/loongson3_virt.c   |  2 +-
 hw/openrisc/virt.c         | 12 +++++------
 hw/pci-host/gpex.c         | 43 ++++++++++++++++++++++++++++++--------
 hw/riscv/virt.c            | 12 +++++------
 hw/xen/xen-pvh-common.c    |  2 +-
 hw/xtensa/virt.c           |  2 +-
 include/hw/pci-host/gpex.h |  7 +++----
 11 files changed, 61 insertions(+), 37 deletions(-)

diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index e3195d54497..7e7322486c2 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -673,7 +673,7 @@ static void create_pcie(SBSAMachineState *sms)
     /* Map IO port space */
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
                            qdev_get_gpio_in(sms->gic, irq + i));
         gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 1a381e9a2bd..8aa22ea3155 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1547,7 +1547,7 @@ static void create_pcie(VirtMachineState *vms)
     /* Map IO port space */
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
                            qdev_get_gpio_in(vms->gic, irq + i));
         gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 86637afa0f3..ce80596c239 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -139,7 +139,7 @@ static void create_gpex(MicrovmMachineState *mms)
                                     mms->gpex.mmio64.base, mmio64_alias);
     }
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
                            x86ms->gsi[mms->gpex.irq + i]);
     }
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 9a635d1d3d3..1d71982c722 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -441,7 +441,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchVi=
rtMachineState *lvms,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 0;
-    uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] =3D {};
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 10] =3D {};
     uint32_t *irq_map =3D full_irq_map;
     const MachineState *ms =3D MACHINE(lvms);
=20
@@ -454,11 +454,11 @@ static void fdt_add_pcie_irq_map_node(const LoongArch=
VirtMachineState *lvms,
      * to wrap to any number of devices.
      */
=20
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev * 0x8;
=20
-        for (pin =3D 0; pin  < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D 16 + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -482,7 +482,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchVi=
rtMachineState *lvms,
=20
=20
     qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
-                     GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+                     PCI_NUM_PINS * PCI_NUM_PINS *
                      irq_map_stride * sizeof(uint32_t));
     qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
                      0x1800, 0, 0, 0x7);
@@ -741,7 +741,7 @@ static void virt_devices_init(DeviceState *pch_pic,
     memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE,
                                 pio_alias);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(d, i,
                            qdev_get_gpio_in(pch_pic, 16 + i));
         gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
index f3b6326cc59..884b5f23a99 100644
--- a/hw/mips/loongson3_virt.c
+++ b/hw/mips/loongson3_virt.c
@@ -458,7 +458,7 @@ static inline void loongson3_virt_devices_init(MachineS=
tate *machine,
                                 virt_memmap[VIRT_PCIE_PIO].base, s->pio_al=
ias);
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].bas=
e);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         irq =3D qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
         gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c
index 47d2c9bd3c7..6f053bf48e0 100644
--- a/hw/openrisc/virt.c
+++ b/hw/openrisc/virt.c
@@ -318,7 +318,7 @@ static void create_pcie_irq_map(void *fdt, char *nodena=
me, int irq_base,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 0;
-    uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] =3D {};
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] =3D {};
     uint32_t *irq_map =3D full_irq_map;
=20
     /*
@@ -330,11 +330,11 @@ static void create_pcie_irq_map(void *fdt, char *node=
name, int irq_base,
      * possible slot) seeing the interrupt-map-mask will allow the table
      * to wrap to any number of devices.
      */
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev << 3;
=20
-        for (pin =3D 0; pin < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_=
IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_P=
INS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -357,7 +357,7 @@ static void create_pcie_irq_map(void *fdt, char *nodena=
me, int irq_base,
     }
=20
     qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
-                     GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+                     PCI_NUM_PINS * PCI_NUM_PINS *
                      irq_map_stride * sizeof(uint32_t));
=20
     qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
@@ -409,7 +409,7 @@ static void openrisc_virt_pcie_init(OR1KVirtState *stat=
e,
     memory_region_add_subregion(get_system_memory(), pio_base, alias);
=20
     /* Connect IRQ lines. */
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         pcie_irq =3D get_per_cpu_irq(cpus, num_cpus, irq_base + i);
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pcie_irq);
diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c
index e9cf455bf52..cd63aa2d3cf 100644
--- a/hw/pci-host/gpex.c
+++ b/hw/pci-host/gpex.c
@@ -32,6 +32,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "hw/irq.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci-host/gpex.h"
 #include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
@@ -41,20 +42,25 @@
  * GPEX host
  */
=20
+struct GPEXIrq {
+    qemu_irq irq;
+    int irq_num;
+};
+
 static void gpex_set_irq(void *opaque, int irq_num, int level)
 {
     GPEXHost *s =3D opaque;
=20
-    qemu_set_irq(s->irq[irq_num], level);
+    qemu_set_irq(s->irq[irq_num].irq, level);
 }
=20
 int gpex_set_irq_num(GPEXHost *s, int index, int gsi)
 {
-    if (index >=3D GPEX_NUM_IRQS) {
+    if (index >=3D s->num_irqs) {
         return -EINVAL;
     }
=20
-    s->irq_num[index] =3D gsi;
+    s->irq[index].irq_num =3D gsi;
     return 0;
 }
=20
@@ -62,7 +68,7 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaq=
ue, int pin)
 {
     PCIINTxRoute route;
     GPEXHost *s =3D opaque;
-    int gsi =3D s->irq_num[pin];
+    int gsi =3D s->irq[pin].irq_num;
=20
     route.irq =3D gsi;
     if (gsi < 0) {
@@ -74,6 +80,13 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opa=
que, int pin)
     return route;
 }
=20
+static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
+{
+    PCIBus *bus =3D pci_device_root_bus(pci_dev);
+
+    return (PCI_SLOT(pci_dev->devfn) + pin) % bus->nirq;
+}
+
 static void gpex_host_realize(DeviceState *dev, Error **errp)
 {
     PCIHostState *pci =3D PCI_HOST_BRIDGE(dev);
@@ -82,6 +95,8 @@ static void gpex_host_realize(DeviceState *dev, Error **e=
rrp)
     PCIExpressHost *pex =3D PCIE_HOST_BRIDGE(dev);
     int i;
=20
+    s->irq =3D g_malloc0_n(s->num_irqs, sizeof(*s->irq));
+
     pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
     sysbus_init_mmio(sbd, &pex->mmio);
=20
@@ -128,19 +143,27 @@ static void gpex_host_realize(DeviceState *dev, Error=
 **errp)
         sysbus_init_mmio(sbd, &s->io_ioport);
     }
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
-        sysbus_init_irq(sbd, &s->irq[i]);
-        s->irq_num[i] =3D -1;
+    for (i =3D 0; i < s->num_irqs; i++) {
+        sysbus_init_irq(sbd, &s->irq[i].irq);
+        s->irq[i].irq_num =3D -1;
     }
=20
     pci->bus =3D pci_register_root_bus(dev, "pcie.0", gpex_set_irq,
-                                     pci_swizzle_map_irq_fn, s, &s->io_mmi=
o,
-                                     &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
+                                     gpex_swizzle_map_irq_fn,
+                                     s, &s->io_mmio, &s->io_ioport, 0,
+                                     s->num_irqs, TYPE_PCIE_BUS);
=20
     pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq);
     qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal);
 }
=20
+static void gpex_host_unrealize(DeviceState *dev)
+{
+    GPEXHost *s =3D GPEX_HOST(dev);
+
+    g_free(s->irq);
+}
+
 static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
                                           PCIBus *rootbus)
 {
@@ -166,6 +189,7 @@ static Property gpex_host_properties[] =3D {
                        gpex_cfg.mmio64.base, 0),
     DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost,
                      gpex_cfg.mmio64.size, 0),
+    DEFINE_PROP_UINT8("num-irqs", GPEXHost, num_irqs, PCI_NUM_PINS),
     DEFINE_PROP_END_OF_LIST(),
 };
=20
@@ -176,6 +200,7 @@ static void gpex_host_class_init(ObjectClass *klass, vo=
id *data)
=20
     hc->root_bus_path =3D gpex_host_root_bus_path;
     dc->realize =3D gpex_host_realize;
+    dc->unrealize =3D gpex_host_unrealize;
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
     dc->fw_name =3D "pci";
     device_class_set_props(dc, gpex_host_properties);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 45a8c4f8190..567fe92a136 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -168,7 +168,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void=
 *fdt, char *nodename,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 0;
-    uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
                           FDT_MAX_INT_MAP_WIDTH] =3D {};
     uint32_t *irq_map =3D full_irq_map;
=20
@@ -180,11 +180,11 @@ static void create_pcie_irq_map(RISCVVirtState *s, vo=
id *fdt, char *nodename,
      * possible slot) seeing the interrupt-map-mask will allow the table
      * to wrap to any number of devices.
      */
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev * 0x8;
=20
-        for (pin =3D 0; pin < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_=
IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_P=
INS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -210,7 +210,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void=
 *fdt, char *nodename,
     }
=20
     qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
-                     GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+                     PCI_NUM_PINS * PCI_NUM_PINS *
                      irq_map_stride * sizeof(uint32_t));
=20
     qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
@@ -1182,7 +1182,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegio=
n *sys_mem,
=20
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         irq =3D qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
diff --git a/hw/xen/xen-pvh-common.c b/hw/xen/xen-pvh-common.c
index 218ac851cf7..9143b54d826 100644
--- a/hw/xen/xen-pvh-common.c
+++ b/hw/xen/xen-pvh-common.c
@@ -169,7 +169,7 @@ static inline void xenpvh_gpex_init(XenPVHMachineState =
*s,
      */
     assert(xpc->set_pci_intx_irq);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         qemu_irq irq =3D qemu_allocate_irq(xpc->set_pci_intx_irq, s, i);
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c
index 5310a888613..8f5c2009d29 100644
--- a/hw/xtensa/virt.c
+++ b/hw/xtensa/virt.c
@@ -93,7 +93,7 @@ static void create_pcie(MachineState *ms, CPUXtensaState =
*env, int irq_base,
     /* Connect IRQ lines. */
     extints =3D xtensa_get_extints(env);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         void *q =3D extints[irq_base + i];
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, q);
diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h
index dce883573ba..84471533af0 100644
--- a/include/hw/pci-host/gpex.h
+++ b/include/hw/pci-host/gpex.h
@@ -32,8 +32,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(GPEXHost, GPEX_HOST)
 #define TYPE_GPEX_ROOT_DEVICE "gpex-root"
 OBJECT_DECLARE_SIMPLE_TYPE(GPEXRootState, GPEX_ROOT_DEVICE)
=20
-#define GPEX_NUM_IRQS 4
-
 struct GPEXRootState {
     /*< private >*/
     PCIDevice parent_obj;
@@ -49,6 +47,7 @@ struct GPEXConfig {
     PCIBus      *bus;
 };
=20
+typedef struct GPEXIrq GPEXIrq;
 struct GPEXHost {
     /*< private >*/
     PCIExpressHost parent_obj;
@@ -60,8 +59,8 @@ struct GPEXHost {
     MemoryRegion io_mmio;
     MemoryRegion io_ioport_window;
     MemoryRegion io_mmio_window;
-    qemu_irq irq[GPEX_NUM_IRQS];
-    int irq_num[GPEX_NUM_IRQS];
+    GPEXIrq *irq;
+    uint8_t num_irqs;
=20
     bool allow_unmapped_accesses;
=20
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103270; cv=none;
	d=zohomail.com; s=zohoarc;
	b=nMhGROjWsALZ8QnRN4hkisc0aGPe4rwMYZs5ZJv4joCkTk76Dtr/rdYvtMRS3s4CwCC0eEwfQCssf/9+hdmyLr6cEpSXYrzWp1COvPVoqwaou1WBLKQI5ZHqcF25r4Er0vJHArqkWwvxU28D8vgbcw84x6FQAd02Sxt+mCduEsA=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103270;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=vE4icFzbUyJwOx4II5Kw3Wy8lfUTjt60Nc/k0y/6lC8=;
	b=DIDsfBjaWprKvj/dTlDHeyJAsiqG+MfH6assYBUHgkRpTw0ZB1yzSsNOXOgoWwgSQ9u5xris4mbEUa4qS0Ib47kRNSKGseUVlgYKchJlkG7RaMKNEQ4zS0w1fiLU8gcGy5p9qSnpemnKIn1DkvAeVHyj2fIllIutU8WrwGjqeg4=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103270701449.28793744314623;
 Fri, 13 Dec 2024 07:21:10 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SP-0005Al-3z; Fri, 13 Dec 2024 10:19:57 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rl-0004VW-Ou
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:18 -0500
Received: from mail-ej1-x62d.google.com ([2a00:1450:4864:20::62d])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Re-00059f-Gi
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:17 -0500
Received: by mail-ej1-x62d.google.com with SMTP id
 a640c23a62f3a-aa6a92f863cso369480666b.1
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:56 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.52
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:53 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103134;
 x=1734707934;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=vE4icFzbUyJwOx4II5Kw3Wy8lfUTjt60Nc/k0y/6lC8=;
 b=ItWQOt3JbhFneGrZDyUDF+d8yOESO3fPB2qFj/KM3W7AbUXBOooeLauMwzZHbhBkjN
 poz8eISlHBsiEg8hjKOcQApL42TzFrtLrWLwxF8jTvEX6Pwlg0ADFcylvAK58zLfiLEY
 ehZGU1K2gKkgaWckUoLGxuy1V/Nfp9GWpCTe8pDKQbSC3ty9seVUJGNi8Gbn8l/g4qfL
 wcYSKuc3YvwtSk1qY8+1YLEySDEUYeS02+oxPotV59ln0M1ydGu56YdqxTwxrRvS65gF
 cSpTC8UUBd9V+rNfE3C6vKiRe4ZwvhwIUeUKxyBzIJK96OjHPT8JhwmaXb5qIF+urWDe
 i93A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103134; x=1734707934;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=vE4icFzbUyJwOx4II5Kw3Wy8lfUTjt60Nc/k0y/6lC8=;
 b=uPjY96njB+fhOKt6f9q2DL4gOuWRbHOK/qPLb2RjGZ9pb462eFul7wZOnTs6hB0Sf6
 WzRPm4Rtiau1ntVRN2PUVCQPPp7LRMpFVmYOJ+JzzvIj/VJNG67FCUUqh1Vz+VxZu0AI
 qqenOy5p81/YB7nG/i231AZP2Tg/Jk0gz2T6F/sYE2MG+XHe9Zzjul8uf8oipzlECYjp
 T/VQ/REQ/wFOWAT04XvBvndjGXN5knjQO/2Udxj1rB/Dv4Wz1QQlcjcx7jAQrXpOTuOL
 4kObG8+8noSlZ20q0CxSelJm0GY8L4x1D1OyITxJUh4JlzG/elFL2XDXOO7khHB+s8aS
 NwWA==
X-Gm-Message-State: AOJu0YyWb61yJN0zIy9jW+/005f+py9Z3pa9rq/7XCBb9vYzYaUZt1S0
 mTVVMsgWae1VwD3cFLR6Z4PDuxNUD2kBIzwxZAMlkdtQVCltwgfRDSqEWA1zACDe25dkXwPmXNj
 e1g==
X-Gm-Gg: ASbGnctQ5J5Abzc4CBA8lBuIvAra3Uyl86DRaIr41lwzpoWk9cODcsnv+I2TIdRDldm
 JrIZUH9mBXtoglT4CeW6LmGPsPzHzPGtXF2ULr7Og+YMmwLkRuB3s30CiDJ+BPk7SpFjNHXMsSX
 GZYyUKu/xoFKFu0wN2O3QjoomU7RI/ZDCl2OP+F27FjiqAEau5HM9x3xFD5chmeJQIh3IgYZHGa
 7sN/MuJn3L+0urlQwH2kcDVSdk02tkJlRrz8yHwlslD84Aiy8wIZciJHC17FrQq49hvM1ymm3PJ
 hoNx2XgCtZo/IOSl2kDTRwA4lEP21RJU
X-Google-Smtp-Source: 
 AGHT+IF9loGZX3J9ajpNB7oRpExfNYh43F2RCVrY0GyiWqyBhwy769POfcuensOhB66Jwz3LxCUorQ==
X-Received: by 2002:a17:906:311b:b0:aa6:80fa:f692 with SMTP id
 a640c23a62f3a-aab77eab25dmr294714166b.49.1734103134274;
 Fri, 13 Dec 2024 07:18:54 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 09/15] gpex: Allow more than 4 legacy IRQs
Date: Fri, 13 Dec 2024 16:17:59 +0100
Message-Id: <20241213151821.65748-10-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62d;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62d.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103272621116600
Content-Type: text/plain; charset="utf-8"

From: Alexander Graf <graf@amazon.com>

Some boards such as vmapple don't do real legacy PCI IRQ swizzling.
Instead, they just keep allocating more board IRQ lines for each new
legacy IRQ. Let's support that mode by giving instantiators a new
"nr_irqs" property they can use to support more than 4 legacy IRQ lines.
In this mode, GPEX will export more IRQ lines, one for each device.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Turned pair of IRQ arrays into array of structs.
 * Simplified swizzling logic selection.

v12:

 * Fixed uses of deleted GPEX_NUM_IRQS constant that have been
   added to QEMU since this patch was originally written.

 hw/arm/sbsa-ref.c          |  2 +-
 hw/arm/virt.c              |  2 +-
 hw/i386/microvm.c          |  2 +-
 hw/loongarch/virt.c        | 12 +++++------
 hw/mips/loongson3_virt.c   |  2 +-
 hw/openrisc/virt.c         | 12 +++++------
 hw/pci-host/gpex.c         | 43 ++++++++++++++++++++++++++++++--------
 hw/riscv/virt.c            | 12 +++++------
 hw/xen/xen-pvh-common.c    |  2 +-
 hw/xtensa/virt.c           |  2 +-
 include/hw/pci-host/gpex.h |  7 +++----
 11 files changed, 61 insertions(+), 37 deletions(-)

diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index e3195d54497..7e7322486c2 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -673,7 +673,7 @@ static void create_pcie(SBSAMachineState *sms)
     /* Map IO port space */
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
                            qdev_get_gpio_in(sms->gic, irq + i));
         gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 1a381e9a2bd..8aa22ea3155 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1547,7 +1547,7 @@ static void create_pcie(VirtMachineState *vms)
     /* Map IO port space */
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
                            qdev_get_gpio_in(vms->gic, irq + i));
         gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 86637afa0f3..ce80596c239 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -139,7 +139,7 @@ static void create_gpex(MicrovmMachineState *mms)
                                     mms->gpex.mmio64.base, mmio64_alias);
     }
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
                            x86ms->gsi[mms->gpex.irq + i]);
     }
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 9a635d1d3d3..1d71982c722 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -441,7 +441,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchVi=
rtMachineState *lvms,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 0;
-    uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] =3D {};
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 10] =3D {};
     uint32_t *irq_map =3D full_irq_map;
     const MachineState *ms =3D MACHINE(lvms);
=20
@@ -454,11 +454,11 @@ static void fdt_add_pcie_irq_map_node(const LoongArch=
VirtMachineState *lvms,
      * to wrap to any number of devices.
      */
=20
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev * 0x8;
=20
-        for (pin =3D 0; pin  < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D 16 + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -482,7 +482,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchVi=
rtMachineState *lvms,
=20
=20
     qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
-                     GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+                     PCI_NUM_PINS * PCI_NUM_PINS *
                      irq_map_stride * sizeof(uint32_t));
     qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
                      0x1800, 0, 0, 0x7);
@@ -741,7 +741,7 @@ static void virt_devices_init(DeviceState *pch_pic,
     memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE,
                                 pio_alias);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         sysbus_connect_irq(d, i,
                            qdev_get_gpio_in(pch_pic, 16 + i));
         gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
index f3b6326cc59..884b5f23a99 100644
--- a/hw/mips/loongson3_virt.c
+++ b/hw/mips/loongson3_virt.c
@@ -458,7 +458,7 @@ static inline void loongson3_virt_devices_init(MachineS=
tate *machine,
                                 virt_memmap[VIRT_PCIE_PIO].base, s->pio_al=
ias);
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].bas=
e);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         irq =3D qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
         gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c
index 47d2c9bd3c7..6f053bf48e0 100644
--- a/hw/openrisc/virt.c
+++ b/hw/openrisc/virt.c
@@ -318,7 +318,7 @@ static void create_pcie_irq_map(void *fdt, char *nodena=
me, int irq_base,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 0;
-    uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] =3D {};
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] =3D {};
     uint32_t *irq_map =3D full_irq_map;
=20
     /*
@@ -330,11 +330,11 @@ static void create_pcie_irq_map(void *fdt, char *node=
name, int irq_base,
      * possible slot) seeing the interrupt-map-mask will allow the table
      * to wrap to any number of devices.
      */
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev << 3;
=20
-        for (pin =3D 0; pin < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_=
IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_P=
INS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -357,7 +357,7 @@ static void create_pcie_irq_map(void *fdt, char *nodena=
me, int irq_base,
     }
=20
     qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
-                     GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+                     PCI_NUM_PINS * PCI_NUM_PINS *
                      irq_map_stride * sizeof(uint32_t));
=20
     qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
@@ -409,7 +409,7 @@ static void openrisc_virt_pcie_init(OR1KVirtState *stat=
e,
     memory_region_add_subregion(get_system_memory(), pio_base, alias);
=20
     /* Connect IRQ lines. */
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         pcie_irq =3D get_per_cpu_irq(cpus, num_cpus, irq_base + i);
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pcie_irq);
diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c
index e9cf455bf52..cd63aa2d3cf 100644
--- a/hw/pci-host/gpex.c
+++ b/hw/pci-host/gpex.c
@@ -32,6 +32,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "hw/irq.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci-host/gpex.h"
 #include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
@@ -41,20 +42,25 @@
  * GPEX host
  */
=20
+struct GPEXIrq {
+    qemu_irq irq;
+    int irq_num;
+};
+
 static void gpex_set_irq(void *opaque, int irq_num, int level)
 {
     GPEXHost *s =3D opaque;
=20
-    qemu_set_irq(s->irq[irq_num], level);
+    qemu_set_irq(s->irq[irq_num].irq, level);
 }
=20
 int gpex_set_irq_num(GPEXHost *s, int index, int gsi)
 {
-    if (index >=3D GPEX_NUM_IRQS) {
+    if (index >=3D s->num_irqs) {
         return -EINVAL;
     }
=20
-    s->irq_num[index] =3D gsi;
+    s->irq[index].irq_num =3D gsi;
     return 0;
 }
=20
@@ -62,7 +68,7 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaq=
ue, int pin)
 {
     PCIINTxRoute route;
     GPEXHost *s =3D opaque;
-    int gsi =3D s->irq_num[pin];
+    int gsi =3D s->irq[pin].irq_num;
=20
     route.irq =3D gsi;
     if (gsi < 0) {
@@ -74,6 +80,13 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opa=
que, int pin)
     return route;
 }
=20
+static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
+{
+    PCIBus *bus =3D pci_device_root_bus(pci_dev);
+
+    return (PCI_SLOT(pci_dev->devfn) + pin) % bus->nirq;
+}
+
 static void gpex_host_realize(DeviceState *dev, Error **errp)
 {
     PCIHostState *pci =3D PCI_HOST_BRIDGE(dev);
@@ -82,6 +95,8 @@ static void gpex_host_realize(DeviceState *dev, Error **e=
rrp)
     PCIExpressHost *pex =3D PCIE_HOST_BRIDGE(dev);
     int i;
=20
+    s->irq =3D g_malloc0_n(s->num_irqs, sizeof(*s->irq));
+
     pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
     sysbus_init_mmio(sbd, &pex->mmio);
=20
@@ -128,19 +143,27 @@ static void gpex_host_realize(DeviceState *dev, Error=
 **errp)
         sysbus_init_mmio(sbd, &s->io_ioport);
     }
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
-        sysbus_init_irq(sbd, &s->irq[i]);
-        s->irq_num[i] =3D -1;
+    for (i =3D 0; i < s->num_irqs; i++) {
+        sysbus_init_irq(sbd, &s->irq[i].irq);
+        s->irq[i].irq_num =3D -1;
     }
=20
     pci->bus =3D pci_register_root_bus(dev, "pcie.0", gpex_set_irq,
-                                     pci_swizzle_map_irq_fn, s, &s->io_mmi=
o,
-                                     &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
+                                     gpex_swizzle_map_irq_fn,
+                                     s, &s->io_mmio, &s->io_ioport, 0,
+                                     s->num_irqs, TYPE_PCIE_BUS);
=20
     pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq);
     qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal);
 }
=20
+static void gpex_host_unrealize(DeviceState *dev)
+{
+    GPEXHost *s =3D GPEX_HOST(dev);
+
+    g_free(s->irq);
+}
+
 static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
                                           PCIBus *rootbus)
 {
@@ -166,6 +189,7 @@ static Property gpex_host_properties[] =3D {
                        gpex_cfg.mmio64.base, 0),
     DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost,
                      gpex_cfg.mmio64.size, 0),
+    DEFINE_PROP_UINT8("num-irqs", GPEXHost, num_irqs, PCI_NUM_PINS),
     DEFINE_PROP_END_OF_LIST(),
 };
=20
@@ -176,6 +200,7 @@ static void gpex_host_class_init(ObjectClass *klass, vo=
id *data)
=20
     hc->root_bus_path =3D gpex_host_root_bus_path;
     dc->realize =3D gpex_host_realize;
+    dc->unrealize =3D gpex_host_unrealize;
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
     dc->fw_name =3D "pci";
     device_class_set_props(dc, gpex_host_properties);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 45a8c4f8190..567fe92a136 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -168,7 +168,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void=
 *fdt, char *nodename,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 0;
-    uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
                           FDT_MAX_INT_MAP_WIDTH] =3D {};
     uint32_t *irq_map =3D full_irq_map;
=20
@@ -180,11 +180,11 @@ static void create_pcie_irq_map(RISCVVirtState *s, vo=
id *fdt, char *nodename,
      * possible slot) seeing the interrupt-map-mask will allow the table
      * to wrap to any number of devices.
      */
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev * 0x8;
=20
-        for (pin =3D 0; pin < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_=
IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_P=
INS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -210,7 +210,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void=
 *fdt, char *nodename,
     }
=20
     qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
-                     GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+                     PCI_NUM_PINS * PCI_NUM_PINS *
                      irq_map_stride * sizeof(uint32_t));
=20
     qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
@@ -1182,7 +1182,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegio=
n *sys_mem,
=20
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         irq =3D qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
diff --git a/hw/xen/xen-pvh-common.c b/hw/xen/xen-pvh-common.c
index 218ac851cf7..9143b54d826 100644
--- a/hw/xen/xen-pvh-common.c
+++ b/hw/xen/xen-pvh-common.c
@@ -169,7 +169,7 @@ static inline void xenpvh_gpex_init(XenPVHMachineState =
*s,
      */
     assert(xpc->set_pci_intx_irq);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         qemu_irq irq =3D qemu_allocate_irq(xpc->set_pci_intx_irq, s, i);
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c
index 5310a888613..8f5c2009d29 100644
--- a/hw/xtensa/virt.c
+++ b/hw/xtensa/virt.c
@@ -93,7 +93,7 @@ static void create_pcie(MachineState *ms, CPUXtensaState =
*env, int irq_base,
     /* Connect IRQ lines. */
     extints =3D xtensa_get_extints(env);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         void *q =3D extints[irq_base + i];
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, q);
diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h
index dce883573ba..84471533af0 100644
--- a/include/hw/pci-host/gpex.h
+++ b/include/hw/pci-host/gpex.h
@@ -32,8 +32,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(GPEXHost, GPEX_HOST)
 #define TYPE_GPEX_ROOT_DEVICE "gpex-root"
 OBJECT_DECLARE_SIMPLE_TYPE(GPEXRootState, GPEX_ROOT_DEVICE)
=20
-#define GPEX_NUM_IRQS 4
-
 struct GPEXRootState {
     /*< private >*/
     PCIDevice parent_obj;
@@ -49,6 +47,7 @@ struct GPEXConfig {
     PCIBus      *bus;
 };
=20
+typedef struct GPEXIrq GPEXIrq;
 struct GPEXHost {
     /*< private >*/
     PCIExpressHost parent_obj;
@@ -60,8 +59,8 @@ struct GPEXHost {
     MemoryRegion io_mmio;
     MemoryRegion io_ioport_window;
     MemoryRegion io_mmio_window;
-    qemu_irq irq[GPEX_NUM_IRQS];
-    int irq_num[GPEX_NUM_IRQS];
+    GPEXIrq *irq;
+    uint8_t num_irqs;
=20
     bool allow_unmapped_accesses;
=20
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103368; cv=none;
	d=zohomail.com; s=zohoarc;
	b=L0AQjG2lRddWgXzxylEnF1JYQqtDxTxcvSSK4aquxYOo4bdhNOLG7IhVYA2vGR8N/nJapFqWNutAWNdl6wGqxwSFvcfwsPTWwY3vYPxEm3SELlvTQgWDilQt+5MNHuYaKkegvW9O607VY5KG+EVNDcmemsDydCvGS7nt6MvWbPw=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103368;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=4ANpAZDxL+OlxYTkY1W/N1GGxtnwlFqD0+mbtvmm/Y4=;
	b=VBitw25kPH7HACY+Ci53DWWzOJrQ0jgNo9foNjmq5nOWXm0tof+NWyhyn6yGExAZC9ENq7ZqOn2tLfelRT7Bh+jbTw4ZR7xyHL2T4Ye2DL15xtC44YJaX36FYK6KyTfLLMeicx/mCMYy0p6z7b4lU9JirBG8DdKnSAf+Pdw8slU=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103368089347.6433357274327;
 Fri, 13 Dec 2024 07:22:48 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7TF-0007d4-Sb; Fri, 13 Dec 2024 10:20:50 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7SB-0004uy-FZ
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:43 -0500
Received: from mail-ej1-x633.google.com ([2a00:1450:4864:20::633])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rz-0005O6-DM
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:43 -0500
Received: by mail-ej1-x633.google.com with SMTP id
 a640c23a62f3a-a9a68480164so304360566b.3
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:27 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.24
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:25 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103166;
 x=1734707966;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=4ANpAZDxL+OlxYTkY1W/N1GGxtnwlFqD0+mbtvmm/Y4=;
 b=J05IJt4jhXB+8G9i7VOUpFXaJDL0D3oQG4wPg1c0jQes8JzoG6oOqxh2BMSQ1Ed4CG
 Rpf2ttvt+yrYTHry5jKBePq2zjIQc+TjFSKuHWdwZ3pAvTi2rEH5TvWUkZrZ5R5KJtWV
 eZxst2GX5sf0GqRaA3IYaGzvnxB0Rt2S7FlXae3O0X2mEGZkfcf5SYMdzo2kacAiQ/eL
 YESHJN2UHBVIFJFFgbmJMcCLCUWr3+WULhDqD8HYz1Unvo4QqXD/OFgi10lW2AZ+/k40
 ujmtOOlckR1nKqIqSu7nj8Y4M2M6uQ1CxEpvp6RifHC8rWRy7iFtNS7JFwQAyqorbn3M
 kNMw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103166; x=1734707966;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=4ANpAZDxL+OlxYTkY1W/N1GGxtnwlFqD0+mbtvmm/Y4=;
 b=NkpLKMFJ97G423Z3esYs1dFbXjZvikeLbBqRu6xml7ZLdivcwTzCbRFaJ9Q1e74lLV
 MOxowgnOgcY3jyYfAkNMxKaBQaLyAuJIhnUZDWULwx9YAviN2MI199xDiRcub3a6woDW
 sayVRRHXacD+76OTW/DWEcOdskzEwbEHjZixOa/5qV5oAutvq9bUvgtGPhlNHFtvIHFa
 o/Ndw+rgsunLqsAGtlRhYr1qZvr61K/SR7vCHtQTeAWUjJWcRvvGdQuo+8KUp9Oj9j80
 aSfYhA8HoiVi+xnbksmZvswR138lRsN3NF4dqoD5Bc5WRjFzAX4l5tB+2jKfAwYuIyZJ
 Komg==
X-Gm-Message-State: AOJu0Yx+zCcAp83WuZ2yKWyNIS/4nexTWFfIfU3t1dxyT7fvnVL71A+7
 SDyOETR1zW6AqsNTGBFanCGXC2uHaEx6xzbcJWZ9MfveuqrFKUm3DmW56tvHnEBXhOxTJU2dXeR
 Teg==
X-Gm-Gg: ASbGnct/GxWhT87PplbZZHh6YlFMUUIUpFqGhwhadlvyTzqHhGUHlDW58I93yqmQJei
 YZmSwgpoW6nvlRZGESIoCq+9TIJ1DjgM5i57NTcviJxcTIjyq1clfb1nxC3tblqTBSPE5IigSWO
 efsW3z1JD81g26RhSNo2u80sPKTRPFb7YMc1eMfFu+HnMsLRUz+mDxK3KvpQQTFK0eolhua33zW
 QMIyofkfb5FUlRS3ik4ObaqEJdQIHO2W2TZyv0FkCFpRcp/O49NgNJFv+C6Zdy8/WEsbZJpFfwg
 19lNC8cm661bQEMMYM8LbnKW8vL9weK9
X-Google-Smtp-Source: 
 AGHT+IHtx8FwN3CIq5LTolQD1hp+oSEOKMVSpF/hLMWJAWdrlPUsFDZDylk3zS3unDpfLsVnt9TTLQ==
X-Received: by 2002:a17:907:c24:b0:aa6:9599:a9af with SMTP id
 a640c23a62f3a-aab77ebc858mr369417766b.53.1734103166383;
 Fri, 13 Dec 2024 07:19:26 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 10/15] hw/vmapple/aes: Introduce aes engine
Date: Fri, 13 Dec 2024 16:18:16 +0100
Message-Id: <20241213151821.65748-27-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::633;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x633.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103369174116600

From: Alexander Graf <graf@amazon.com>

VMApple contains an "aes" engine device that it uses to encrypt and
decrypt its nvram. It has trivial hard coded keys it uses for that
purpose.

Add device emulation for this device model.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v3:

 * Rebased on latest upstream and fixed minor breakages.
 * Replaced legacy device reset method with Resettable method

v4:

 * Improved logging of unimplemented functions and guest errors.
 * Better adherence to naming and coding conventions.
 * Cleaner error handling and recovery, including using g_autoptr

v5:

 * More logging improvements
 * Use xxx64_overflow() functions for hexdump buffer size calculations.

v7:

 * Coding style tweaks.

v8:

 * Further improved logging of guest errors.

v9:

 * Replaced a use of cpu_physical_memory_write with dma_memory_write.
 * Dropped unnecessary use of ternary operator for bool -> 0/1.

v10:

 * Code style and comment improvements.

 hw/vmapple/Kconfig           |   2 +
 hw/vmapple/aes.c             | 581 +++++++++++++++++++++++++++++++++++
 hw/vmapple/meson.build       |   1 +
 hw/vmapple/trace-events      |  14 +
 include/hw/vmapple/vmapple.h |  17 +
 include/qemu/cutils.h        |  15 +
 util/hexdump.c               |  18 ++
 7 files changed, 648 insertions(+)
 create mode 100644 hw/vmapple/aes.c
 create mode 100644 include/hw/vmapple/vmapple.h

diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index 8b137891791..a73504d5999 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -1 +1,3 @@
+config VMAPPLE_AES
+    bool
=20
diff --git a/hw/vmapple/aes.c b/hw/vmapple/aes.c
new file mode 100644
index 00000000000..3759dae11ba
--- /dev/null
+++ b/hw/vmapple/aes.c
@@ -0,0 +1,581 @@
+/*
+ * QEMU Apple AES device emulation
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "trace.h"
+#include "crypto/hash.h"
+#include "crypto/aes.h"
+#include "crypto/cipher.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "hw/vmapple/vmapple.h"
+#include "migration/vmstate.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "sysemu/dma.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(AESState, APPLE_AES)
+
+#define MAX_FIFO_SIZE     9
+
+#define CMD_KEY           0x1
+#define CMD_KEY_CONTEXT_SHIFT    27
+#define CMD_KEY_CONTEXT_MASK     (0x1 << CMD_KEY_CONTEXT_SHIFT)
+#define CMD_KEY_SELECT_MAX_IDX   0x7
+#define CMD_KEY_SELECT_SHIFT     24
+#define CMD_KEY_SELECT_MASK      (CMD_KEY_SELECT_MAX_IDX << CMD_KEY_SELECT=
_SHIFT)
+#define CMD_KEY_KEY_LEN_NUM      4u
+#define CMD_KEY_KEY_LEN_SHIFT    22
+#define CMD_KEY_KEY_LEN_MASK     ((CMD_KEY_KEY_LEN_NUM - 1u) << CMD_KEY_KE=
Y_LEN_SHIFT)
+#define CMD_KEY_ENCRYPT_SHIFT    20
+#define CMD_KEY_ENCRYPT_MASK     (0x1 << CMD_KEY_ENCRYPT_SHIFT)
+#define CMD_KEY_BLOCK_MODE_SHIFT 16
+#define CMD_KEY_BLOCK_MODE_MASK  (0x3 << CMD_KEY_BLOCK_MODE_SHIFT)
+#define CMD_IV            0x2
+#define CMD_IV_CONTEXT_SHIFT     26
+#define CMD_IV_CONTEXT_MASK      (0x3 << CMD_KEY_CONTEXT_SHIFT)
+#define CMD_DSB           0x3
+#define CMD_SKG           0x4
+#define CMD_DATA          0x5
+#define CMD_DATA_KEY_CTX_SHIFT   27
+#define CMD_DATA_KEY_CTX_MASK    (0x1 << CMD_DATA_KEY_CTX_SHIFT)
+#define CMD_DATA_IV_CTX_SHIFT    25
+#define CMD_DATA_IV_CTX_MASK     (0x3 << CMD_DATA_IV_CTX_SHIFT)
+#define CMD_DATA_LEN_MASK        0xffffff
+#define CMD_STORE_IV      0x6
+#define CMD_STORE_IV_ADDR_MASK   0xffffff
+#define CMD_WRITE_REG     0x7
+#define CMD_FLAG          0x8
+#define CMD_FLAG_STOP_MASK       BIT(26)
+#define CMD_FLAG_RAISE_IRQ_MASK  BIT(27)
+#define CMD_FLAG_INFO_MASK       0xff
+#define CMD_MAX           0x10
+
+#define CMD_SHIFT         28
+
+#define REG_STATUS            0xc
+#define REG_STATUS_DMA_READ_RUNNING     BIT(0)
+#define REG_STATUS_DMA_READ_PENDING     BIT(1)
+#define REG_STATUS_DMA_WRITE_RUNNING    BIT(2)
+#define REG_STATUS_DMA_WRITE_PENDING    BIT(3)
+#define REG_STATUS_BUSY                 BIT(4)
+#define REG_STATUS_EXECUTING            BIT(5)
+#define REG_STATUS_READY                BIT(6)
+#define REG_STATUS_TEXT_DPA_SEEDED      BIT(7)
+#define REG_STATUS_UNWRAP_DPA_SEEDED    BIT(8)
+
+#define REG_IRQ_STATUS        0x18
+#define REG_IRQ_STATUS_INVALID_CMD      BIT(2)
+#define REG_IRQ_STATUS_FLAG             BIT(5)
+#define REG_IRQ_ENABLE        0x1c
+#define REG_WATERMARK         0x20
+#define REG_Q_STATUS          0x24
+#define REG_FLAG_INFO         0x30
+#define REG_FIFO              0x200
+
+static const uint32_t key_lens[CMD_KEY_KEY_LEN_NUM] =3D {
+    [0] =3D 16,
+    [1] =3D 24,
+    [2] =3D 32,
+    [3] =3D 64,
+};
+
+typedef struct Key {
+    uint32_t key_len;
+    uint8_t key[32];
+} Key;
+
+typedef struct IV {
+    uint32_t iv[4];
+} IV;
+
+static Key builtin_keys[CMD_KEY_SELECT_MAX_IDX + 1] =3D {
+    [1] =3D {
+        .key_len =3D 32,
+        .key =3D { 0x1 },
+    },
+    [2] =3D {
+        .key_len =3D 32,
+        .key =3D { 0x2 },
+    },
+    [3] =3D {
+        .key_len =3D 32,
+        .key =3D { 0x3 },
+    }
+};
+
+struct AESState {
+    SysBusDevice parent_obj;
+
+    qemu_irq irq;
+    MemoryRegion iomem1;
+    MemoryRegion iomem2;
+    AddressSpace *as;
+
+    uint32_t status;
+    uint32_t q_status;
+    uint32_t irq_status;
+    uint32_t irq_enable;
+    uint32_t watermark;
+    uint32_t flag_info;
+    uint32_t fifo[MAX_FIFO_SIZE];
+    uint32_t fifo_idx;
+    Key key[2];
+    IV iv[4];
+    bool is_encrypt;
+    QCryptoCipherMode block_mode;
+};
+
+static void aes_update_irq(AESState *s)
+{
+    qemu_set_irq(s->irq, !!(s->irq_status & s->irq_enable));
+}
+
+static uint64_t aes1_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AESState *s =3D opaque;
+    uint64_t res =3D 0;
+
+    switch (offset) {
+    case REG_STATUS:
+        res =3D s->status;
+        break;
+    case REG_IRQ_STATUS:
+        res =3D s->irq_status;
+        break;
+    case REG_IRQ_ENABLE:
+        res =3D s->irq_enable;
+        break;
+    case REG_WATERMARK:
+        res =3D s->watermark;
+        break;
+    case REG_Q_STATUS:
+        res =3D s->q_status;
+        break;
+    case REG_FLAG_INFO:
+        res =3D s->flag_info;
+        break;
+
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: Unknown AES MMIO offset %" PRIx64 "\=
n",
+                      __func__, offset);
+        break;
+    }
+
+    trace_aes_read(offset, res);
+
+    return res;
+}
+
+static void fifo_append(AESState *s, uint64_t val)
+{
+    if (s->fifo_idx =3D=3D MAX_FIFO_SIZE) {
+        /* Exceeded the FIFO. Bail out */
+        return;
+    }
+
+    s->fifo[s->fifo_idx++] =3D val;
+}
+
+static bool has_payload(AESState *s, uint32_t elems)
+{
+    return s->fifo_idx >=3D elems + 1;
+}
+
+static bool cmd_key(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t key_select =3D (cmd & CMD_KEY_SELECT_MASK) >> CMD_KEY_SELECT_=
SHIFT;
+    uint32_t ctxt =3D (cmd & CMD_KEY_CONTEXT_MASK) >> CMD_KEY_CONTEXT_SHIF=
T;
+    uint32_t key_len;
+
+    switch ((cmd & CMD_KEY_BLOCK_MODE_MASK) >> CMD_KEY_BLOCK_MODE_SHIFT) {
+    case 0:
+        s->block_mode =3D QCRYPTO_CIPHER_MODE_ECB;
+        break;
+    case 1:
+        s->block_mode =3D QCRYPTO_CIPHER_MODE_CBC;
+        break;
+    default:
+        return false;
+    }
+
+    s->is_encrypt =3D cmd & CMD_KEY_ENCRYPT_MASK;
+    key_len =3D key_lens[(cmd & CMD_KEY_KEY_LEN_MASK) >> CMD_KEY_KEY_LEN_S=
HIFT];
+
+    if (key_select) {
+        trace_aes_cmd_key_select_builtin(ctxt, key_select,
+                                         s->is_encrypt ? "en" : "de",
+                                         QCryptoCipherMode_str(s->block_mo=
de));
+        s->key[ctxt] =3D builtin_keys[key_select];
+    } else {
+        trace_aes_cmd_key_select_new(ctxt, key_len,
+                                     s->is_encrypt ? "en" : "de",
+                                     QCryptoCipherMode_str(s->block_mode));
+        if (key_len > sizeof(s->key[ctxt].key)) {
+            return false;
+        }
+        if (!has_payload(s, key_len / sizeof(uint32_t))) {
+            /* wait for payload */
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+            return false;
+        }
+        memcpy(&s->key[ctxt].key, &s->fifo[1], key_len);
+        s->key[ctxt].key_len =3D key_len;
+    }
+
+    return true;
+}
+
+static bool cmd_iv(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t ctxt =3D (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
+
+    if (!has_payload(s, 4)) {
+        /* wait for payload */
+        return false;
+    }
+    memcpy(&s->iv[ctxt].iv, &s->fifo[1], sizeof(s->iv[ctxt].iv));
+    trace_aes_cmd_iv(ctxt, s->fifo[1], s->fifo[2], s->fifo[3], s->fifo[4]);
+
+    return true;
+}
+
+static void dump_data(const char *desc, const void *p, size_t len)
+{
+    static const size_t MAX_LEN =3D 0x1000;
+    char hex[MAX_LEN * 2 + 1] =3D "";
+
+    if (len > MAX_LEN) {
+        return;
+    }
+
+    qemu_hexdump_to_buffer(hex, sizeof(hex), p, len);
+    trace_aes_dump_data(desc, hex);
+}
+
+static bool cmd_data(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t ctxt_iv =3D 0;
+    uint32_t ctxt_key =3D (cmd & CMD_DATA_KEY_CTX_MASK) >> CMD_DATA_KEY_CT=
X_SHIFT;
+    uint32_t len =3D cmd & CMD_DATA_LEN_MASK;
+    uint64_t src_addr =3D s->fifo[2];
+    uint64_t dst_addr =3D s->fifo[3];
+    QCryptoCipherAlgo alg;
+    g_autoptr(QCryptoCipher) cipher =3D NULL;
+    g_autoptr(GByteArray) src =3D NULL;
+    g_autoptr(GByteArray) dst =3D NULL;
+    MemTxResult r;
+
+    src_addr |=3D ((uint64_t)s->fifo[1] << 16) & 0xffff00000000ULL;
+    dst_addr |=3D ((uint64_t)s->fifo[1] << 32) & 0xffff00000000ULL;
+
+    trace_aes_cmd_data(ctxt_key, ctxt_iv, src_addr, dst_addr, len);
+
+    if (!has_payload(s, 3)) {
+        /* wait for payload */
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+        return false;
+    }
+
+    if (ctxt_key >=3D ARRAY_SIZE(s->key) ||
+        ctxt_iv >=3D ARRAY_SIZE(s->iv)) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key or iv\n", __func__=
);
+        return false;
+    }
+
+    src =3D g_byte_array_sized_new(len);
+    g_byte_array_set_size(src, len);
+    dst =3D g_byte_array_sized_new(len);
+    g_byte_array_set_size(dst, len);
+
+    r =3D dma_memory_read(s->as, src_addr, src->data, len, MEMTXATTRS_UNSP=
ECIFIED);
+    if (r !=3D MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA read of %"PRIu32" bytes "
+                      "from 0x%"PRIx64" failed. (r=3D%d)\n",
+                      __func__, len, src_addr, r);
+        return false;
+    }
+
+    dump_data("cmd_data(): src_data=3D", src->data, len);
+
+    switch (s->key[ctxt_key].key_len) {
+    case 128 / 8:
+        alg =3D QCRYPTO_CIPHER_ALGO_AES_128;
+        break;
+    case 192 / 8:
+        alg =3D QCRYPTO_CIPHER_ALGO_AES_192;
+        break;
+    case 256 / 8:
+        alg =3D QCRYPTO_CIPHER_ALGO_AES_256;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key length\n", __func_=
_);
+        return false;
+    }
+    cipher =3D qcrypto_cipher_new(alg, s->block_mode,
+                                s->key[ctxt_key].key,
+                                s->key[ctxt_key].key_len, NULL);
+    if (!cipher) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to create cipher object=
\n",
+                      __func__);
+        return false;
+    }
+    if (s->block_mode !=3D QCRYPTO_CIPHER_MODE_ECB) {
+        if (qcrypto_cipher_setiv(cipher, (void *)s->iv[ctxt_iv].iv,
+                                 sizeof(s->iv[ctxt_iv].iv), NULL) !=3D 0) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to set IV\n", __fun=
c__);
+            return false;
+        }
+    }
+    if (s->is_encrypt) {
+        if (qcrypto_cipher_encrypt(cipher, src->data, dst->data, len, NULL=
) !=3D 0) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Encryption failed\n", __fu=
nc__);
+            return false;
+        }
+    } else {
+        if (qcrypto_cipher_decrypt(cipher, src->data, dst->data, len, NULL=
) !=3D 0) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Decryption failed\n", __fu=
nc__);
+            return false;
+        }
+    }
+
+    dump_data("cmd_data(): dst_data=3D", dst->data, len);
+    r =3D dma_memory_write(s->as, dst_addr, dst->data, len, MEMTXATTRS_UNS=
PECIFIED);
+    if (r !=3D MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA write of %"PRIu32" bytes "
+                      "to 0x%"PRIx64" failed. (r=3D%d)\n",
+                      __func__, len, src_addr, r);
+        return false;
+    }
+
+    return true;
+}
+
+static bool cmd_store_iv(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t ctxt =3D (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
+    uint64_t addr =3D s->fifo[1];
+    MemTxResult dma_result;
+
+    if (!has_payload(s, 1)) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+        return false;
+    }
+
+    if (ctxt >=3D ARRAY_SIZE(s->iv)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Invalid context. ctxt =3D %u, allowed: 0..%zu\n=
",
+                      __func__, ctxt, ARRAY_SIZE(s->iv) - 1);
+        return false;
+    }
+
+    addr |=3D ((uint64_t)cmd << 32) & 0xff00000000ULL;
+    dma_result =3D dma_memory_write(&address_space_memory, addr,
+                                  &s->iv[ctxt].iv, sizeof(s->iv[ctxt].iv),
+                                  MEMTXATTRS_UNSPECIFIED);
+
+    trace_aes_cmd_store_iv(ctxt, addr, s->iv[ctxt].iv[0], s->iv[ctxt].iv[1=
],
+                           s->iv[ctxt].iv[2], s->iv[ctxt].iv[3]);
+
+    return dma_result =3D=3D MEMTX_OK;
+}
+
+static bool cmd_flag(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t raise_irq =3D cmd & CMD_FLAG_RAISE_IRQ_MASK;
+
+    /* We always process data when it's coming in, so fire an IRQ immediat=
ely */
+    if (raise_irq) {
+        s->irq_status |=3D REG_IRQ_STATUS_FLAG;
+    }
+
+    s->flag_info =3D cmd & CMD_FLAG_INFO_MASK;
+
+    trace_aes_cmd_flag(!!raise_irq, s->flag_info);
+
+    return true;
+}
+
+static void fifo_process(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0] >> CMD_SHIFT;
+    bool success =3D false;
+
+    if (!s->fifo_idx) {
+        return;
+    }
+
+    switch (cmd) {
+    case CMD_KEY:
+        success =3D cmd_key(s);
+        break;
+    case CMD_IV:
+        success =3D cmd_iv(s);
+        break;
+    case CMD_DATA:
+        success =3D cmd_data(s);
+        break;
+    case CMD_STORE_IV:
+        success =3D cmd_store_iv(s);
+        break;
+    case CMD_FLAG:
+        success =3D cmd_flag(s);
+        break;
+    default:
+        s->irq_status |=3D REG_IRQ_STATUS_INVALID_CMD;
+        break;
+    }
+
+    if (success) {
+        s->fifo_idx =3D 0;
+    }
+
+    trace_aes_fifo_process(cmd, success);
+}
+
+static void aes1_write(void *opaque, hwaddr offset, uint64_t val, unsigned=
 size)
+{
+    AESState *s =3D opaque;
+
+    trace_aes_write(offset, val);
+
+    switch (offset) {
+    case REG_IRQ_STATUS:
+        s->irq_status &=3D ~val;
+        break;
+    case REG_IRQ_ENABLE:
+        s->irq_enable =3D val;
+        break;
+    case REG_FIFO:
+        fifo_append(s, val);
+        fifo_process(s);
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Unknown AES MMIO offset %"PRIx64", data %"PRIx6=
4"\n",
+                      __func__, offset, val);
+        return;
+    }
+
+    aes_update_irq(s);
+}
+
+static const MemoryRegionOps aes1_ops =3D {
+    .read =3D aes1_read,
+    .write =3D aes1_write,
+    .endianness =3D DEVICE_NATIVE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 4,
+    },
+};
+
+static uint64_t aes2_read(void *opaque, hwaddr offset, unsigned size)
+{
+    uint64_t res =3D 0;
+
+    switch (offset) {
+    case 0:
+        res =3D 0;
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Unknown AES MMIO 2 offset %"PRIx64"\n",
+                      __func__, offset);
+        break;
+    }
+
+    trace_aes_2_read(offset, res);
+
+    return res;
+}
+
+static void aes2_write(void *opaque, hwaddr offset, uint64_t val, unsigned=
 size)
+{
+    trace_aes_2_write(offset, val);
+
+    switch (offset) {
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Unknown AES MMIO 2 offset %"PRIx64", data %"PRI=
x64"\n",
+                      __func__, offset, val);
+        return;
+    }
+}
+
+static const MemoryRegionOps aes2_ops =3D {
+    .read =3D aes2_read,
+    .write =3D aes2_write,
+    .endianness =3D DEVICE_NATIVE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 4,
+    },
+};
+
+static void aes_reset(Object *obj, ResetType type)
+{
+    AESState *s =3D APPLE_AES(obj);
+
+    s->status =3D 0x3f80;
+    s->q_status =3D 2;
+    s->irq_status =3D 0;
+    s->irq_enable =3D 0;
+    s->watermark =3D 0;
+}
+
+static void aes_init(Object *obj)
+{
+    AESState *s =3D APPLE_AES(obj);
+
+    memory_region_init_io(&s->iomem1, obj, &aes1_ops, s, TYPE_APPLE_AES, 0=
x4000);
+    memory_region_init_io(&s->iomem2, obj, &aes2_ops, s, TYPE_APPLE_AES, 0=
x4000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem1);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem2);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
+    s->as =3D &address_space_memory;
+}
+
+static void aes_class_init(ObjectClass *klass, void *data)
+{
+    ResettableClass *rc =3D RESETTABLE_CLASS(klass);
+
+    rc->phases.hold =3D aes_reset;
+}
+
+static const TypeInfo aes_info =3D {
+    .name          =3D TYPE_APPLE_AES,
+    .parent        =3D TYPE_SYS_BUS_DEVICE,
+    .instance_size =3D sizeof(AESState),
+    .class_init    =3D aes_class_init,
+    .instance_init =3D aes_init,
+};
+
+static void aes_register_types(void)
+{
+    type_register_static(&aes_info);
+}
+
+type_init(aes_register_types)
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index e69de29bb2d..bcd4dcb28d2 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -0,0 +1 @@
+system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('aes.c'))
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
index 9ccc5790487..0d4a73d7d1c 100644
--- a/hw/vmapple/trace-events
+++ b/hw/vmapple/trace-events
@@ -1,2 +1,16 @@
 # See docs/devel/tracing.rst for syntax documentation.
=20
+# aes.c
+aes_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRIx64" res=3D0x%"PR=
Ix64
+aes_cmd_key_select_builtin(uint32_t ctx, uint32_t key_id, const char *dire=
ction, const char *cipher) "[%d] Selecting builtin key %d to %scrypt with %=
s"
+aes_cmd_key_select_new(uint32_t ctx, uint32_t key_len, const char *directi=
on, const char *cipher) "[%d] Selecting new key size=3D%d to %scrypt with %=
s"
+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"
+aes_cmd_data(uint32_t key, uint32_t iv, uint64_t src, uint64_t dst, uint32=
_t len) "[key=3D%d iv=3D%d] src=3D0x%"PRIx64" dst=3D0x%"PRIx64" len=3D0x%x"
+aes_cmd_store_iv(uint32_t ctx, uint64_t addr, uint32_t iv0, uint32_t iv1, =
uint32_t iv2, uint32_t iv3) "[%d] addr=3D0x%"PRIx64"x -> 0x%08x 0x%08x 0x%0=
8x 0x%08x"
+aes_cmd_flag(uint32_t raise, uint32_t flag_info) "raise=3D%d flag_info=3D0=
x%x"
+aes_fifo_process(uint32_t cmd, bool success) "cmd=3D%d success=3D%d"
+aes_write(uint64_t offset, uint64_t val) "offset=3D0x%"PRIx64" val=3D0x%"P=
RIx64
+aes_2_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRIx64" res=3D0x%"=
PRIx64
+aes_2_write(uint64_t offset, uint64_t val) "offset=3D0x%"PRIx64" val=3D0x%=
"PRIx64
+aes_dump_data(const char *desc, const char *hex) "%s%s"
+
diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
new file mode 100644
index 00000000000..6762b6c869f
--- /dev/null
+++ b/include/hw/vmapple/vmapple.h
@@ -0,0 +1,17 @@
+/*
+ * Devices specific to the VMApple machine type
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VMAPPLE_VMAPPLE_H
+#define HW_VMAPPLE_VMAPPLE_H
+
+#define TYPE_APPLE_AES "apple-aes"
+
+#endif /* HW_VMAPPLE_VMAPPLE_H */
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index 34a9b9b2204..36c68ce86c5 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -302,4 +302,19 @@ GString *qemu_hexdump_line(GString *str, const void *b=
uf, size_t len,
 void qemu_hexdump(FILE *fp, const char *prefix,
                   const void *bufptr, size_t size);
=20
+/**
+ * qemu_hexdump_to_buffer:
+ * @buffer: output string buffer
+ * @buffer_size: amount of available space in buffer. Must be at least
+ *               data_size*2+1.
+ * @data: input bytes
+ * @data_size: number of bytes in data
+ *
+ * Converts the @data_size bytes in @data into hex digit pairs, writing th=
em to
+ * @buffer. Finally, a nul terminating character is written; @buffer there=
fore
+ * needs space for (data_size*2+1) chars.
+ */
+void qemu_hexdump_to_buffer(char *restrict buffer, size_t buffer_size,
+                            const uint8_t *restrict data, size_t data_size=
);
+
 #endif
diff --git a/util/hexdump.c b/util/hexdump.c
index ae0d4992dcf..f29ffceb746 100644
--- a/util/hexdump.c
+++ b/util/hexdump.c
@@ -15,6 +15,7 @@
=20
 #include "qemu/osdep.h"
 #include "qemu/cutils.h"
+#include "qemu/host-utils.h"
=20
 static inline char hexdump_nibble(unsigned x)
 {
@@ -97,3 +98,20 @@ void qemu_hexdump(FILE *fp, const char *prefix,
     }
=20
 }
+
+void qemu_hexdump_to_buffer(char *restrict buffer, size_t buffer_size,
+                            const uint8_t *restrict data, size_t data_size)
+{
+    size_t i;
+    uint64_t required_buffer_size;
+    bool overflow =3D umul64_overflow(data_size, 2, &required_buffer_size);
+    overflow |=3D uadd64_overflow(required_buffer_size, 1, &required_buffe=
r_size);
+    assert(!overflow && buffer_size >=3D required_buffer_size);
+
+    for (i =3D 0; i < data_size; i++) {
+        uint8_t val =3D data[i];
+        *(buffer++) =3D hexdump_nibble(val >> 4);
+        *(buffer++) =3D hexdump_nibble(val & 0xf);
+    }
+    *buffer =3D '\0';
+}
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103469; cv=none;
	d=zohomail.com; s=zohoarc;
	b=EYr/luPfCNd99e294WQR91UYAcX1vpyxyjfxMe3D4CoLlCeCbkwlqA8/yJH2g6ePOTVBElhC7nsU1Bd2eHfedejI4XX4K9Ic/PXO92pCOcWyIf5Cf0YpiMuZmKQQ0lhzLnos0VbLtlmdSG+ppRRi6RLRcYBCZKpALZDvK8ohDeQ=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103469;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=4ANpAZDxL+OlxYTkY1W/N1GGxtnwlFqD0+mbtvmm/Y4=;
	b=buSX5UrTvNKe2mE+Q/VCIXUGf874fA7FsqiSFfORDcv4CcrS7i1ZGI3hWZkhB76kh9FZ2y6JkQj/rtP6TILmp8ivXoALXzJdspfNMcvINj0bhbkXS8aqSLSIBiiIBQONn2eltEN0hh7Pp7Gup1M63c8epy5rY3aoDgect43N5LQ=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103469924149.75830923731792;
 Fri, 13 Dec 2024 07:24:29 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Sb-0005wL-6n; Fri, 13 Dec 2024 10:20:09 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rm-0004bK-TD
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:22 -0500
Received: from mail-ej1-x62a.google.com ([2a00:1450:4864:20::62a])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Re-0005Ab-Ij
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:18 -0500
Received: by mail-ej1-x62a.google.com with SMTP id
 a640c23a62f3a-aab925654d9so21312066b.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:58 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.54
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:55 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103136;
 x=1734707936;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=4ANpAZDxL+OlxYTkY1W/N1GGxtnwlFqD0+mbtvmm/Y4=;
 b=A/h2joBSOMQK2K9bLwpzD1lz1dPJRg6nfa6rfMX5ONBmZAhYOSL7u1kHQHGDB4T55k
 dQ04C6QOTEA+80W70ddpT5wCL2uXvV8gRC9ZPR1mMZZ3lrXoex+pOEec9IMH8AaGOVAH
 0yRcza1x4os55rWTwn2F8D+mrifX9iMUQKdq3Ntm3H6wxupuMIrdlfm+jwkDqOchOBRT
 WNufrXHds4NDnAhKzIZZB1zOKM9mht866HBQqky4ijveSqdocp17X4xRVgiS/BfFIZ7I
 f8+8W7duPNKxKUsNEOR2tiG6oKW/IEumjbUwgRYO9C0G0vFmq4oHtSTLVHgXZ7BEv82s
 K/sg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103136; x=1734707936;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=4ANpAZDxL+OlxYTkY1W/N1GGxtnwlFqD0+mbtvmm/Y4=;
 b=sN7JfLdaUyneiRko1akFMV7kXacb/6O33IlQeZXt+76BnQqMCIT6EiGHWZvW41IboA
 MUTUgtzPIE8vFSYzkPzHFzBq6BO8acazmV1p9HELfwf9eXJuk20f/oOVy1QTNKpgW7wf
 IQcX3hCB1QH5SrcL9fz+9jwIlAAeFDI0s7kFYqLuj0r1wHlfEbAXzhQDPlMUIrJeP2YM
 6eciTWhmrfj8O0cOkTvIkvPr8YBijDCTnN1giLmomCIKXj7Avr2AoCHUgDVhiFaO2Pfk
 xtYaobc6W45+cPoBNqynltnou9EN2MPZ0QS6z0uX+wfsn6K7/grhL6CbcRJEB64kOpm5
 uvaA==
X-Gm-Message-State: AOJu0YwVxofKD9uV64TtB/46s6PxU/PqBdMWXRvQJQQ4dqRl9NtIuTQT
 gu+v4BprYkotX76X6+cAuGcyaKKFsVSWt+6EEp2V46HPrRpxVtgizXNz6RQwlZaOI29zQnjNBzy
 Gsw==
X-Gm-Gg: ASbGncuzP9vY467z5rPWBBh+tCP1j28PpEtaqEh4jy6ge2EPh+OhiDolNTJ8T7/uPOZ
 KSStHM+oPJVhq5lkF5Tz1HFaPKvNfCAU3bwhGwnMiNADYW/9P+bkqEsLJK440gU2+LeJBSLHQp3
 Z8LzjP2dxlK1QNbjtS0wn4Tm2VXMEBbg5h1jOpr7NmfiS/W6Y4qWkQ55ejv3TUiUU5YHdP0mUCx
 FB6s+0RDZEfCQAv+ILf764I7r6vNf+yGND7DXKJYX9t7WjT46IxQj9J/Dv6CkCTWzzsNKUo/TCx
 19x0eeZbHFDlODAp9MFkpQBsJxAEsh5O
X-Google-Smtp-Source: 
 AGHT+IHeilLPfX3OLdhGNd4cdfIbrU9St10BEfg/yPigG0fzamQmdZeWZXkl7O7VLk0mbkWvZNrchQ==
X-Received: by 2002:a17:907:3fa0:b0:aa6:832b:8d75 with SMTP id
 a640c23a62f3a-aab7792d012mr304853966b.17.1734103136182;
 Fri, 13 Dec 2024 07:18:56 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 10/15] hw/vmapple/aes: Introduce aes engine
Date: Fri, 13 Dec 2024 16:18:00 +0100
Message-Id: <20241213151821.65748-11-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62a;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62a.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103471560116600

From: Alexander Graf <graf@amazon.com>

VMApple contains an "aes" engine device that it uses to encrypt and
decrypt its nvram. It has trivial hard coded keys it uses for that
purpose.

Add device emulation for this device model.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v3:

 * Rebased on latest upstream and fixed minor breakages.
 * Replaced legacy device reset method with Resettable method

v4:

 * Improved logging of unimplemented functions and guest errors.
 * Better adherence to naming and coding conventions.
 * Cleaner error handling and recovery, including using g_autoptr

v5:

 * More logging improvements
 * Use xxx64_overflow() functions for hexdump buffer size calculations.

v7:

 * Coding style tweaks.

v8:

 * Further improved logging of guest errors.

v9:

 * Replaced a use of cpu_physical_memory_write with dma_memory_write.
 * Dropped unnecessary use of ternary operator for bool -> 0/1.

v10:

 * Code style and comment improvements.

 hw/vmapple/Kconfig           |   2 +
 hw/vmapple/aes.c             | 581 +++++++++++++++++++++++++++++++++++
 hw/vmapple/meson.build       |   1 +
 hw/vmapple/trace-events      |  14 +
 include/hw/vmapple/vmapple.h |  17 +
 include/qemu/cutils.h        |  15 +
 util/hexdump.c               |  18 ++
 7 files changed, 648 insertions(+)
 create mode 100644 hw/vmapple/aes.c
 create mode 100644 include/hw/vmapple/vmapple.h

diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index 8b137891791..a73504d5999 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -1 +1,3 @@
+config VMAPPLE_AES
+    bool
=20
diff --git a/hw/vmapple/aes.c b/hw/vmapple/aes.c
new file mode 100644
index 00000000000..3759dae11ba
--- /dev/null
+++ b/hw/vmapple/aes.c
@@ -0,0 +1,581 @@
+/*
+ * QEMU Apple AES device emulation
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "trace.h"
+#include "crypto/hash.h"
+#include "crypto/aes.h"
+#include "crypto/cipher.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "hw/vmapple/vmapple.h"
+#include "migration/vmstate.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "sysemu/dma.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(AESState, APPLE_AES)
+
+#define MAX_FIFO_SIZE     9
+
+#define CMD_KEY           0x1
+#define CMD_KEY_CONTEXT_SHIFT    27
+#define CMD_KEY_CONTEXT_MASK     (0x1 << CMD_KEY_CONTEXT_SHIFT)
+#define CMD_KEY_SELECT_MAX_IDX   0x7
+#define CMD_KEY_SELECT_SHIFT     24
+#define CMD_KEY_SELECT_MASK      (CMD_KEY_SELECT_MAX_IDX << CMD_KEY_SELECT=
_SHIFT)
+#define CMD_KEY_KEY_LEN_NUM      4u
+#define CMD_KEY_KEY_LEN_SHIFT    22
+#define CMD_KEY_KEY_LEN_MASK     ((CMD_KEY_KEY_LEN_NUM - 1u) << CMD_KEY_KE=
Y_LEN_SHIFT)
+#define CMD_KEY_ENCRYPT_SHIFT    20
+#define CMD_KEY_ENCRYPT_MASK     (0x1 << CMD_KEY_ENCRYPT_SHIFT)
+#define CMD_KEY_BLOCK_MODE_SHIFT 16
+#define CMD_KEY_BLOCK_MODE_MASK  (0x3 << CMD_KEY_BLOCK_MODE_SHIFT)
+#define CMD_IV            0x2
+#define CMD_IV_CONTEXT_SHIFT     26
+#define CMD_IV_CONTEXT_MASK      (0x3 << CMD_KEY_CONTEXT_SHIFT)
+#define CMD_DSB           0x3
+#define CMD_SKG           0x4
+#define CMD_DATA          0x5
+#define CMD_DATA_KEY_CTX_SHIFT   27
+#define CMD_DATA_KEY_CTX_MASK    (0x1 << CMD_DATA_KEY_CTX_SHIFT)
+#define CMD_DATA_IV_CTX_SHIFT    25
+#define CMD_DATA_IV_CTX_MASK     (0x3 << CMD_DATA_IV_CTX_SHIFT)
+#define CMD_DATA_LEN_MASK        0xffffff
+#define CMD_STORE_IV      0x6
+#define CMD_STORE_IV_ADDR_MASK   0xffffff
+#define CMD_WRITE_REG     0x7
+#define CMD_FLAG          0x8
+#define CMD_FLAG_STOP_MASK       BIT(26)
+#define CMD_FLAG_RAISE_IRQ_MASK  BIT(27)
+#define CMD_FLAG_INFO_MASK       0xff
+#define CMD_MAX           0x10
+
+#define CMD_SHIFT         28
+
+#define REG_STATUS            0xc
+#define REG_STATUS_DMA_READ_RUNNING     BIT(0)
+#define REG_STATUS_DMA_READ_PENDING     BIT(1)
+#define REG_STATUS_DMA_WRITE_RUNNING    BIT(2)
+#define REG_STATUS_DMA_WRITE_PENDING    BIT(3)
+#define REG_STATUS_BUSY                 BIT(4)
+#define REG_STATUS_EXECUTING            BIT(5)
+#define REG_STATUS_READY                BIT(6)
+#define REG_STATUS_TEXT_DPA_SEEDED      BIT(7)
+#define REG_STATUS_UNWRAP_DPA_SEEDED    BIT(8)
+
+#define REG_IRQ_STATUS        0x18
+#define REG_IRQ_STATUS_INVALID_CMD      BIT(2)
+#define REG_IRQ_STATUS_FLAG             BIT(5)
+#define REG_IRQ_ENABLE        0x1c
+#define REG_WATERMARK         0x20
+#define REG_Q_STATUS          0x24
+#define REG_FLAG_INFO         0x30
+#define REG_FIFO              0x200
+
+static const uint32_t key_lens[CMD_KEY_KEY_LEN_NUM] =3D {
+    [0] =3D 16,
+    [1] =3D 24,
+    [2] =3D 32,
+    [3] =3D 64,
+};
+
+typedef struct Key {
+    uint32_t key_len;
+    uint8_t key[32];
+} Key;
+
+typedef struct IV {
+    uint32_t iv[4];
+} IV;
+
+static Key builtin_keys[CMD_KEY_SELECT_MAX_IDX + 1] =3D {
+    [1] =3D {
+        .key_len =3D 32,
+        .key =3D { 0x1 },
+    },
+    [2] =3D {
+        .key_len =3D 32,
+        .key =3D { 0x2 },
+    },
+    [3] =3D {
+        .key_len =3D 32,
+        .key =3D { 0x3 },
+    }
+};
+
+struct AESState {
+    SysBusDevice parent_obj;
+
+    qemu_irq irq;
+    MemoryRegion iomem1;
+    MemoryRegion iomem2;
+    AddressSpace *as;
+
+    uint32_t status;
+    uint32_t q_status;
+    uint32_t irq_status;
+    uint32_t irq_enable;
+    uint32_t watermark;
+    uint32_t flag_info;
+    uint32_t fifo[MAX_FIFO_SIZE];
+    uint32_t fifo_idx;
+    Key key[2];
+    IV iv[4];
+    bool is_encrypt;
+    QCryptoCipherMode block_mode;
+};
+
+static void aes_update_irq(AESState *s)
+{
+    qemu_set_irq(s->irq, !!(s->irq_status & s->irq_enable));
+}
+
+static uint64_t aes1_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AESState *s =3D opaque;
+    uint64_t res =3D 0;
+
+    switch (offset) {
+    case REG_STATUS:
+        res =3D s->status;
+        break;
+    case REG_IRQ_STATUS:
+        res =3D s->irq_status;
+        break;
+    case REG_IRQ_ENABLE:
+        res =3D s->irq_enable;
+        break;
+    case REG_WATERMARK:
+        res =3D s->watermark;
+        break;
+    case REG_Q_STATUS:
+        res =3D s->q_status;
+        break;
+    case REG_FLAG_INFO:
+        res =3D s->flag_info;
+        break;
+
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: Unknown AES MMIO offset %" PRIx64 "\=
n",
+                      __func__, offset);
+        break;
+    }
+
+    trace_aes_read(offset, res);
+
+    return res;
+}
+
+static void fifo_append(AESState *s, uint64_t val)
+{
+    if (s->fifo_idx =3D=3D MAX_FIFO_SIZE) {
+        /* Exceeded the FIFO. Bail out */
+        return;
+    }
+
+    s->fifo[s->fifo_idx++] =3D val;
+}
+
+static bool has_payload(AESState *s, uint32_t elems)
+{
+    return s->fifo_idx >=3D elems + 1;
+}
+
+static bool cmd_key(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t key_select =3D (cmd & CMD_KEY_SELECT_MASK) >> CMD_KEY_SELECT_=
SHIFT;
+    uint32_t ctxt =3D (cmd & CMD_KEY_CONTEXT_MASK) >> CMD_KEY_CONTEXT_SHIF=
T;
+    uint32_t key_len;
+
+    switch ((cmd & CMD_KEY_BLOCK_MODE_MASK) >> CMD_KEY_BLOCK_MODE_SHIFT) {
+    case 0:
+        s->block_mode =3D QCRYPTO_CIPHER_MODE_ECB;
+        break;
+    case 1:
+        s->block_mode =3D QCRYPTO_CIPHER_MODE_CBC;
+        break;
+    default:
+        return false;
+    }
+
+    s->is_encrypt =3D cmd & CMD_KEY_ENCRYPT_MASK;
+    key_len =3D key_lens[(cmd & CMD_KEY_KEY_LEN_MASK) >> CMD_KEY_KEY_LEN_S=
HIFT];
+
+    if (key_select) {
+        trace_aes_cmd_key_select_builtin(ctxt, key_select,
+                                         s->is_encrypt ? "en" : "de",
+                                         QCryptoCipherMode_str(s->block_mo=
de));
+        s->key[ctxt] =3D builtin_keys[key_select];
+    } else {
+        trace_aes_cmd_key_select_new(ctxt, key_len,
+                                     s->is_encrypt ? "en" : "de",
+                                     QCryptoCipherMode_str(s->block_mode));
+        if (key_len > sizeof(s->key[ctxt].key)) {
+            return false;
+        }
+        if (!has_payload(s, key_len / sizeof(uint32_t))) {
+            /* wait for payload */
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+            return false;
+        }
+        memcpy(&s->key[ctxt].key, &s->fifo[1], key_len);
+        s->key[ctxt].key_len =3D key_len;
+    }
+
+    return true;
+}
+
+static bool cmd_iv(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t ctxt =3D (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
+
+    if (!has_payload(s, 4)) {
+        /* wait for payload */
+        return false;
+    }
+    memcpy(&s->iv[ctxt].iv, &s->fifo[1], sizeof(s->iv[ctxt].iv));
+    trace_aes_cmd_iv(ctxt, s->fifo[1], s->fifo[2], s->fifo[3], s->fifo[4]);
+
+    return true;
+}
+
+static void dump_data(const char *desc, const void *p, size_t len)
+{
+    static const size_t MAX_LEN =3D 0x1000;
+    char hex[MAX_LEN * 2 + 1] =3D "";
+
+    if (len > MAX_LEN) {
+        return;
+    }
+
+    qemu_hexdump_to_buffer(hex, sizeof(hex), p, len);
+    trace_aes_dump_data(desc, hex);
+}
+
+static bool cmd_data(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t ctxt_iv =3D 0;
+    uint32_t ctxt_key =3D (cmd & CMD_DATA_KEY_CTX_MASK) >> CMD_DATA_KEY_CT=
X_SHIFT;
+    uint32_t len =3D cmd & CMD_DATA_LEN_MASK;
+    uint64_t src_addr =3D s->fifo[2];
+    uint64_t dst_addr =3D s->fifo[3];
+    QCryptoCipherAlgo alg;
+    g_autoptr(QCryptoCipher) cipher =3D NULL;
+    g_autoptr(GByteArray) src =3D NULL;
+    g_autoptr(GByteArray) dst =3D NULL;
+    MemTxResult r;
+
+    src_addr |=3D ((uint64_t)s->fifo[1] << 16) & 0xffff00000000ULL;
+    dst_addr |=3D ((uint64_t)s->fifo[1] << 32) & 0xffff00000000ULL;
+
+    trace_aes_cmd_data(ctxt_key, ctxt_iv, src_addr, dst_addr, len);
+
+    if (!has_payload(s, 3)) {
+        /* wait for payload */
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+        return false;
+    }
+
+    if (ctxt_key >=3D ARRAY_SIZE(s->key) ||
+        ctxt_iv >=3D ARRAY_SIZE(s->iv)) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key or iv\n", __func__=
);
+        return false;
+    }
+
+    src =3D g_byte_array_sized_new(len);
+    g_byte_array_set_size(src, len);
+    dst =3D g_byte_array_sized_new(len);
+    g_byte_array_set_size(dst, len);
+
+    r =3D dma_memory_read(s->as, src_addr, src->data, len, MEMTXATTRS_UNSP=
ECIFIED);
+    if (r !=3D MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA read of %"PRIu32" bytes "
+                      "from 0x%"PRIx64" failed. (r=3D%d)\n",
+                      __func__, len, src_addr, r);
+        return false;
+    }
+
+    dump_data("cmd_data(): src_data=3D", src->data, len);
+
+    switch (s->key[ctxt_key].key_len) {
+    case 128 / 8:
+        alg =3D QCRYPTO_CIPHER_ALGO_AES_128;
+        break;
+    case 192 / 8:
+        alg =3D QCRYPTO_CIPHER_ALGO_AES_192;
+        break;
+    case 256 / 8:
+        alg =3D QCRYPTO_CIPHER_ALGO_AES_256;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key length\n", __func_=
_);
+        return false;
+    }
+    cipher =3D qcrypto_cipher_new(alg, s->block_mode,
+                                s->key[ctxt_key].key,
+                                s->key[ctxt_key].key_len, NULL);
+    if (!cipher) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to create cipher object=
\n",
+                      __func__);
+        return false;
+    }
+    if (s->block_mode !=3D QCRYPTO_CIPHER_MODE_ECB) {
+        if (qcrypto_cipher_setiv(cipher, (void *)s->iv[ctxt_iv].iv,
+                                 sizeof(s->iv[ctxt_iv].iv), NULL) !=3D 0) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to set IV\n", __fun=
c__);
+            return false;
+        }
+    }
+    if (s->is_encrypt) {
+        if (qcrypto_cipher_encrypt(cipher, src->data, dst->data, len, NULL=
) !=3D 0) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Encryption failed\n", __fu=
nc__);
+            return false;
+        }
+    } else {
+        if (qcrypto_cipher_decrypt(cipher, src->data, dst->data, len, NULL=
) !=3D 0) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Decryption failed\n", __fu=
nc__);
+            return false;
+        }
+    }
+
+    dump_data("cmd_data(): dst_data=3D", dst->data, len);
+    r =3D dma_memory_write(s->as, dst_addr, dst->data, len, MEMTXATTRS_UNS=
PECIFIED);
+    if (r !=3D MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA write of %"PRIu32" bytes "
+                      "to 0x%"PRIx64" failed. (r=3D%d)\n",
+                      __func__, len, src_addr, r);
+        return false;
+    }
+
+    return true;
+}
+
+static bool cmd_store_iv(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t ctxt =3D (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
+    uint64_t addr =3D s->fifo[1];
+    MemTxResult dma_result;
+
+    if (!has_payload(s, 1)) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+        return false;
+    }
+
+    if (ctxt >=3D ARRAY_SIZE(s->iv)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Invalid context. ctxt =3D %u, allowed: 0..%zu\n=
",
+                      __func__, ctxt, ARRAY_SIZE(s->iv) - 1);
+        return false;
+    }
+
+    addr |=3D ((uint64_t)cmd << 32) & 0xff00000000ULL;
+    dma_result =3D dma_memory_write(&address_space_memory, addr,
+                                  &s->iv[ctxt].iv, sizeof(s->iv[ctxt].iv),
+                                  MEMTXATTRS_UNSPECIFIED);
+
+    trace_aes_cmd_store_iv(ctxt, addr, s->iv[ctxt].iv[0], s->iv[ctxt].iv[1=
],
+                           s->iv[ctxt].iv[2], s->iv[ctxt].iv[3]);
+
+    return dma_result =3D=3D MEMTX_OK;
+}
+
+static bool cmd_flag(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0];
+    uint32_t raise_irq =3D cmd & CMD_FLAG_RAISE_IRQ_MASK;
+
+    /* We always process data when it's coming in, so fire an IRQ immediat=
ely */
+    if (raise_irq) {
+        s->irq_status |=3D REG_IRQ_STATUS_FLAG;
+    }
+
+    s->flag_info =3D cmd & CMD_FLAG_INFO_MASK;
+
+    trace_aes_cmd_flag(!!raise_irq, s->flag_info);
+
+    return true;
+}
+
+static void fifo_process(AESState *s)
+{
+    uint32_t cmd =3D s->fifo[0] >> CMD_SHIFT;
+    bool success =3D false;
+
+    if (!s->fifo_idx) {
+        return;
+    }
+
+    switch (cmd) {
+    case CMD_KEY:
+        success =3D cmd_key(s);
+        break;
+    case CMD_IV:
+        success =3D cmd_iv(s);
+        break;
+    case CMD_DATA:
+        success =3D cmd_data(s);
+        break;
+    case CMD_STORE_IV:
+        success =3D cmd_store_iv(s);
+        break;
+    case CMD_FLAG:
+        success =3D cmd_flag(s);
+        break;
+    default:
+        s->irq_status |=3D REG_IRQ_STATUS_INVALID_CMD;
+        break;
+    }
+
+    if (success) {
+        s->fifo_idx =3D 0;
+    }
+
+    trace_aes_fifo_process(cmd, success);
+}
+
+static void aes1_write(void *opaque, hwaddr offset, uint64_t val, unsigned=
 size)
+{
+    AESState *s =3D opaque;
+
+    trace_aes_write(offset, val);
+
+    switch (offset) {
+    case REG_IRQ_STATUS:
+        s->irq_status &=3D ~val;
+        break;
+    case REG_IRQ_ENABLE:
+        s->irq_enable =3D val;
+        break;
+    case REG_FIFO:
+        fifo_append(s, val);
+        fifo_process(s);
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Unknown AES MMIO offset %"PRIx64", data %"PRIx6=
4"\n",
+                      __func__, offset, val);
+        return;
+    }
+
+    aes_update_irq(s);
+}
+
+static const MemoryRegionOps aes1_ops =3D {
+    .read =3D aes1_read,
+    .write =3D aes1_write,
+    .endianness =3D DEVICE_NATIVE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 4,
+    },
+};
+
+static uint64_t aes2_read(void *opaque, hwaddr offset, unsigned size)
+{
+    uint64_t res =3D 0;
+
+    switch (offset) {
+    case 0:
+        res =3D 0;
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Unknown AES MMIO 2 offset %"PRIx64"\n",
+                      __func__, offset);
+        break;
+    }
+
+    trace_aes_2_read(offset, res);
+
+    return res;
+}
+
+static void aes2_write(void *opaque, hwaddr offset, uint64_t val, unsigned=
 size)
+{
+    trace_aes_2_write(offset, val);
+
+    switch (offset) {
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Unknown AES MMIO 2 offset %"PRIx64", data %"PRI=
x64"\n",
+                      __func__, offset, val);
+        return;
+    }
+}
+
+static const MemoryRegionOps aes2_ops =3D {
+    .read =3D aes2_read,
+    .write =3D aes2_write,
+    .endianness =3D DEVICE_NATIVE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 4,
+        .max_access_size =3D 4,
+    },
+};
+
+static void aes_reset(Object *obj, ResetType type)
+{
+    AESState *s =3D APPLE_AES(obj);
+
+    s->status =3D 0x3f80;
+    s->q_status =3D 2;
+    s->irq_status =3D 0;
+    s->irq_enable =3D 0;
+    s->watermark =3D 0;
+}
+
+static void aes_init(Object *obj)
+{
+    AESState *s =3D APPLE_AES(obj);
+
+    memory_region_init_io(&s->iomem1, obj, &aes1_ops, s, TYPE_APPLE_AES, 0=
x4000);
+    memory_region_init_io(&s->iomem2, obj, &aes2_ops, s, TYPE_APPLE_AES, 0=
x4000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem1);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem2);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
+    s->as =3D &address_space_memory;
+}
+
+static void aes_class_init(ObjectClass *klass, void *data)
+{
+    ResettableClass *rc =3D RESETTABLE_CLASS(klass);
+
+    rc->phases.hold =3D aes_reset;
+}
+
+static const TypeInfo aes_info =3D {
+    .name          =3D TYPE_APPLE_AES,
+    .parent        =3D TYPE_SYS_BUS_DEVICE,
+    .instance_size =3D sizeof(AESState),
+    .class_init    =3D aes_class_init,
+    .instance_init =3D aes_init,
+};
+
+static void aes_register_types(void)
+{
+    type_register_static(&aes_info);
+}
+
+type_init(aes_register_types)
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index e69de29bb2d..bcd4dcb28d2 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -0,0 +1 @@
+system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('aes.c'))
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
index 9ccc5790487..0d4a73d7d1c 100644
--- a/hw/vmapple/trace-events
+++ b/hw/vmapple/trace-events
@@ -1,2 +1,16 @@
 # See docs/devel/tracing.rst for syntax documentation.
=20
+# aes.c
+aes_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRIx64" res=3D0x%"PR=
Ix64
+aes_cmd_key_select_builtin(uint32_t ctx, uint32_t key_id, const char *dire=
ction, const char *cipher) "[%d] Selecting builtin key %d to %scrypt with %=
s"
+aes_cmd_key_select_new(uint32_t ctx, uint32_t key_len, const char *directi=
on, const char *cipher) "[%d] Selecting new key size=3D%d to %scrypt with %=
s"
+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"
+aes_cmd_data(uint32_t key, uint32_t iv, uint64_t src, uint64_t dst, uint32=
_t len) "[key=3D%d iv=3D%d] src=3D0x%"PRIx64" dst=3D0x%"PRIx64" len=3D0x%x"
+aes_cmd_store_iv(uint32_t ctx, uint64_t addr, uint32_t iv0, uint32_t iv1, =
uint32_t iv2, uint32_t iv3) "[%d] addr=3D0x%"PRIx64"x -> 0x%08x 0x%08x 0x%0=
8x 0x%08x"
+aes_cmd_flag(uint32_t raise, uint32_t flag_info) "raise=3D%d flag_info=3D0=
x%x"
+aes_fifo_process(uint32_t cmd, bool success) "cmd=3D%d success=3D%d"
+aes_write(uint64_t offset, uint64_t val) "offset=3D0x%"PRIx64" val=3D0x%"P=
RIx64
+aes_2_read(uint64_t offset, uint64_t res) "offset=3D0x%"PRIx64" res=3D0x%"=
PRIx64
+aes_2_write(uint64_t offset, uint64_t val) "offset=3D0x%"PRIx64" val=3D0x%=
"PRIx64
+aes_dump_data(const char *desc, const char *hex) "%s%s"
+
diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
new file mode 100644
index 00000000000..6762b6c869f
--- /dev/null
+++ b/include/hw/vmapple/vmapple.h
@@ -0,0 +1,17 @@
+/*
+ * Devices specific to the VMApple machine type
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VMAPPLE_VMAPPLE_H
+#define HW_VMAPPLE_VMAPPLE_H
+
+#define TYPE_APPLE_AES "apple-aes"
+
+#endif /* HW_VMAPPLE_VMAPPLE_H */
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index 34a9b9b2204..36c68ce86c5 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -302,4 +302,19 @@ GString *qemu_hexdump_line(GString *str, const void *b=
uf, size_t len,
 void qemu_hexdump(FILE *fp, const char *prefix,
                   const void *bufptr, size_t size);
=20
+/**
+ * qemu_hexdump_to_buffer:
+ * @buffer: output string buffer
+ * @buffer_size: amount of available space in buffer. Must be at least
+ *               data_size*2+1.
+ * @data: input bytes
+ * @data_size: number of bytes in data
+ *
+ * Converts the @data_size bytes in @data into hex digit pairs, writing th=
em to
+ * @buffer. Finally, a nul terminating character is written; @buffer there=
fore
+ * needs space for (data_size*2+1) chars.
+ */
+void qemu_hexdump_to_buffer(char *restrict buffer, size_t buffer_size,
+                            const uint8_t *restrict data, size_t data_size=
);
+
 #endif
diff --git a/util/hexdump.c b/util/hexdump.c
index ae0d4992dcf..f29ffceb746 100644
--- a/util/hexdump.c
+++ b/util/hexdump.c
@@ -15,6 +15,7 @@
=20
 #include "qemu/osdep.h"
 #include "qemu/cutils.h"
+#include "qemu/host-utils.h"
=20
 static inline char hexdump_nibble(unsigned x)
 {
@@ -97,3 +98,20 @@ void qemu_hexdump(FILE *fp, const char *prefix,
     }
=20
 }
+
+void qemu_hexdump_to_buffer(char *restrict buffer, size_t buffer_size,
+                            const uint8_t *restrict data, size_t data_size)
+{
+    size_t i;
+    uint64_t required_buffer_size;
+    bool overflow =3D umul64_overflow(data_size, 2, &required_buffer_size);
+    overflow |=3D uadd64_overflow(required_buffer_size, 1, &required_buffe=
r_size);
+    assert(!overflow && buffer_size >=3D required_buffer_size);
+
+    for (i =3D 0; i < data_size; i++) {
+        uint8_t val =3D data[i];
+        *(buffer++) =3D hexdump_nibble(val >> 4);
+        *(buffer++) =3D hexdump_nibble(val & 0xf);
+    }
+    *buffer =3D '\0';
+}
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103522; cv=none;
	d=zohomail.com; s=zohoarc;
	b=ba3nyv7XG+0w9p4PNEWQvMz9XLMBKuuOm8/pVQUy/49UHrSwy2Ndki20jin07H8YMRzIXo0w9NUO4xmNTa/Ocs7+s4uElZuPxk2hlQrMOE2b7CdBD7Pd9mNrXL/AALxogczCQbLs3691jpwYgs1iJIjepGm3YRPqlNnXkDJc3nE=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103522;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=sWBVtN/MtB7QwyvqivaPQCEjkPZnM9/4icL1W2D0Ipw=;
	b=VcBCOJtk3CyCYdNyGZEWywNNNCAnlYWT0NmML6BJGNPEhoBPnBt1CNea/kMV44by3TgHjBLh8YA+nnzxkM5cCRay6XdyGwKHEFLyZZwgMyg5fJlFtlaxOMDfhdARR0R5bNxvmPHhjrUdzsIFksCakuYNBqebZDNNX62WcoNxArg=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103522169129.28508880276615;
 Fri, 13 Dec 2024 07:25:22 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SJ-00054Y-6t; Fri, 13 Dec 2024 10:19:51 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Re-0004Se-FH
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:13 -0500
Received: from mail-ej1-x62c.google.com ([2a00:1450:4864:20::62c])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7RW-0005Aw-AM
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:06 -0500
Received: by mail-ej1-x62c.google.com with SMTP id
 a640c23a62f3a-aa67f31a858so345424366b.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:18:59 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.56
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:57 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103138;
 x=1734707938;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=sWBVtN/MtB7QwyvqivaPQCEjkPZnM9/4icL1W2D0Ipw=;
 b=b09Wm2Iwd+AFViDEBIqrmKNXPtraeMa3UjR88r17GEavZES/n6d2gLBO631qOKsUx7
 qpI2TU+ZcR2E6lynX8cRJedvfHf6QR/K1qXCKA2trPD14FSa9Oh8XqkdBELW00ehc5Gi
 J1JNBusT0lndDvZHnhKJqVhctkNTEvBR1os71nFURnCk8reuaLcHFAkP6urlEXnJ3NOP
 SnxJ6O3c1TPP5VisjSG7agEpSt90zqAMRD3VhCrz+m22ucXXbPMZB8JyY5Qp/4X58HyK
 2/cuKA/QuYQClzskoFxv0fRJQE7dNZFqAnf+YrEE1cOmBLER5uAUu6W63sPHmThShAgE
 FOXw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103138; x=1734707938;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=sWBVtN/MtB7QwyvqivaPQCEjkPZnM9/4icL1W2D0Ipw=;
 b=Fs9R9n4slAo7CIiyt9Xy0g5HGTgqRokLjbnRCg5HHv+A86UGz4Pn9N7Jt2jiS92VF6
 RTI/h7snutp9W8T5axn5JDsSl+kjpNaEBUCEJjcigbrS4IfkkQlxtsCC05yxpMeepHEa
 TOT7/UA7ZaS3cJGmeLIGTIjmVNXq32FAOFJ7Yt16u6Z4Ble+vEyJ5vuJqJXu5RCYrq94
 rhb+cSHX/vHcc799xwQp/7fOFB25TFY17OYfyb9Dm3LbcPKBue+2PHoCIKdvExnZcQ/M
 WT+x20A5PyTNAhtSIInuxigR/w2zLm82ktvO1P6yrgcxJpqR3pLhRDkrw3pDdMHRIvg0
 VHsw==
X-Gm-Message-State: AOJu0YzrwlSzAo8d4D1VaqgEW71EprCmwTysBSlqMD6XLtVQxpXmqaxS
 NyDsLxK0rusnZXK8O5ccGCkdR+swtQ1lveuvCZC4ckGNMNuTWIlBdZf785mmM0TDjLe3nt3gadn
 J5g==
X-Gm-Gg: ASbGncskYzEb9H9OvktE+0FcOHdjSN2XemBoBHEVbgibePLq15g2r8bd8X9VflL88AE
 +hLXGv5IG9IPN04IoePoYvf3v9iPOwfRqOK3GkTrto+4PcYFt/xfzkFthWX+24TlbySGND3lVya
 2yZ/RTAI1EVqEo5T/8+NM5ODTQNL9N7clyCRhbMh/umkpsELD4XhjVcadRVU97ikm3NH82cg2tz
 to3lXbEM43wRch9sM1bu1aRSTKB3o1CqKVCjyreiMLpxaWEKxoiarhe6P3EJEywWxfZvZ2bENwl
 8svDCwff8SGY6GwVWwYaF2I9/VjS61Ol
X-Google-Smtp-Source: 
 AGHT+IGm/ufWUpIUETBHJBYsrjhjOuR8QKCif/7RiIYCU80/baRdAh3nT4hnv4nzeUis9sUjTB1pug==
X-Received: by 2002:a17:906:3152:b0:aa6:8160:8495 with SMTP id
 a640c23a62f3a-aab77e9705emr304650166b.42.1734103138176;
 Fri, 13 Dec 2024 07:18:58 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 11/15] hw/vmapple/bdif: Introduce vmapple backdoor
 interface
Date: Fri, 13 Dec 2024 16:18:01 +0100
Message-Id: <20241213151821.65748-12-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62c;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62c.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103523903116600

From: Alexander Graf <graf@amazon.com>

The VMApple machine exposes AUX and ROOT block devices (as well as USB OTG
emulation) via virtio-pci as well as a special, simple backdoor platform
device.

This patch implements this backdoor platform device to the best of my
understanding. I left out any USB OTG parts; they're only needed for
guest recovery and I don't understand the protocol yet.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Moved most header code to .c, rest to vmapple.h
 * Better compliance with coding, naming, and formatting conventions.

v8:

 * Replaced uses of cpu_physical_memory_read with dma_memory_read.
 * Replaced an instance of g_free with g_autofree.

v9:

 * Replaced uses of cpu_physical_memory_write with dma_memory_write.
=20
 hw/vmapple/Kconfig           |   3 +
 hw/vmapple/bdif.c            | 275 +++++++++++++++++++++++++++++++++++
 hw/vmapple/meson.build       |   1 +
 hw/vmapple/trace-events      |   5 +
 include/hw/vmapple/vmapple.h |   2 +
 5 files changed, 286 insertions(+)
 create mode 100644 hw/vmapple/bdif.c

diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index a73504d5999..68f88876eb9 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -1,3 +1,6 @@
 config VMAPPLE_AES
     bool
=20
+config VMAPPLE_BDIF
+    bool
+
diff --git a/hw/vmapple/bdif.c b/hw/vmapple/bdif.c
new file mode 100644
index 00000000000..d7b6b7a25a4
--- /dev/null
+++ b/hw/vmapple/bdif.c
@@ -0,0 +1,275 @@
+/*
+ * VMApple Backdoor Interface
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "trace.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/sysbus.h"
+#include "hw/block/block.h"
+#include "qapi/error.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/dma.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleBdifState, VMAPPLE_BDIF)
+
+struct VMAppleBdifState {
+    SysBusDevice parent_obj;
+
+    BlockBackend *aux;
+    BlockBackend *root;
+    MemoryRegion mmio;
+};
+
+#define VMAPPLE_BDIF_SIZE   0x00200000
+
+#define REG_DEVID_MASK      0xffff0000
+#define DEVID_ROOT          0x00000000
+#define DEVID_AUX           0x00010000
+#define DEVID_USB           0x00100000
+
+#define REG_STATUS          0x0
+#define REG_STATUS_ACTIVE     BIT(0)
+#define REG_CFG             0x4
+#define REG_CFG_ACTIVE        BIT(1)
+#define REG_UNK1            0x8
+#define REG_BUSY            0x10
+#define REG_BUSY_READY        BIT(0)
+#define REG_UNK2            0x400
+#define REG_CMD             0x408
+#define REG_NEXT_DEVICE     0x420
+#define REG_UNK3            0x434
+
+typedef struct VblkSector {
+    uint32_t pad;
+    uint32_t pad2;
+    uint32_t sector;
+    uint32_t pad3;
+} VblkSector;
+
+typedef struct VblkReqCmd {
+    uint64_t addr;
+    uint32_t len;
+    uint32_t flags;
+} VblkReqCmd;
+
+typedef struct VblkReq {
+    VblkReqCmd sector;
+    VblkReqCmd data;
+    VblkReqCmd retval;
+} VblkReq;
+
+#define VBLK_DATA_FLAGS_READ  0x00030001
+#define VBLK_DATA_FLAGS_WRITE 0x00010001
+
+#define VBLK_RET_SUCCESS  0
+#define VBLK_RET_FAILED   1
+
+static uint64_t bdif_read(void *opaque, hwaddr offset, unsigned size)
+{
+    uint64_t ret =3D -1;
+    uint64_t devid =3D offset & REG_DEVID_MASK;
+
+    switch (offset & ~REG_DEVID_MASK) {
+    case REG_STATUS:
+        ret =3D REG_STATUS_ACTIVE;
+        break;
+    case REG_CFG:
+        ret =3D REG_CFG_ACTIVE;
+        break;
+    case REG_UNK1:
+        ret =3D 0x420;
+        break;
+    case REG_BUSY:
+        ret =3D REG_BUSY_READY;
+        break;
+    case REG_UNK2:
+        ret =3D 0x1;
+        break;
+    case REG_UNK3:
+        ret =3D 0x0;
+        break;
+    case REG_NEXT_DEVICE:
+        switch (devid) {
+        case DEVID_ROOT:
+            ret =3D 0x8000000;
+            break;
+        case DEVID_AUX:
+            ret =3D 0x10000;
+            break;
+        }
+        break;
+    }
+
+    trace_bdif_read(offset, size, ret);
+    return ret;
+}
+
+static void le2cpu_sector(VblkSector *sector)
+{
+    sector->sector =3D le32_to_cpu(sector->sector);
+}
+
+static void le2cpu_reqcmd(VblkReqCmd *cmd)
+{
+    cmd->addr =3D le64_to_cpu(cmd->addr);
+    cmd->len =3D le32_to_cpu(cmd->len);
+    cmd->flags =3D le32_to_cpu(cmd->flags);
+}
+
+static void le2cpu_req(VblkReq *req)
+{
+    le2cpu_reqcmd(&req->sector);
+    le2cpu_reqcmd(&req->data);
+    le2cpu_reqcmd(&req->retval);
+}
+
+static void vblk_cmd(uint64_t devid, BlockBackend *blk, uint64_t gp_addr,
+                     uint64_t static_off)
+{
+    VblkReq req;
+    VblkSector sector;
+    uint64_t off =3D 0;
+    g_autofree char *buf =3D NULL;
+    uint8_t ret =3D VBLK_RET_FAILED;
+    int r;
+    MemTxResult dma_result;
+
+    dma_result =3D dma_memory_read(&address_space_memory, gp_addr,
+                                 &req, sizeof(req), MEMTXATTRS_UNSPECIFIED=
);
+    if (dma_result !=3D MEMTX_OK) {
+        goto out;
+    }
+
+    le2cpu_req(&req);
+
+    if (req.sector.len !=3D sizeof(sector)) {
+        goto out;
+    }
+
+    /* Read the vblk command */
+    dma_result =3D dma_memory_read(&address_space_memory, req.sector.addr,
+                                 &sector, sizeof(sector),
+                                 MEMTXATTRS_UNSPECIFIED);
+    if (dma_result !=3D MEMTX_OK) {
+        goto out;
+    }
+    le2cpu_sector(&sector);
+
+    off =3D sector.sector * 512ULL + static_off;
+
+    /* Sanity check that we're not allocating bogus sizes */
+    if (req.data.len > 128 * MiB) {
+        goto out;
+    }
+
+    buf =3D g_malloc0(req.data.len);
+    switch (req.data.flags) {
+    case VBLK_DATA_FLAGS_READ:
+        r =3D blk_pread(blk, off, req.data.len, buf, 0);
+        trace_bdif_vblk_read(devid =3D=3D DEVID_AUX ? "aux" : "root",
+                             req.data.addr, off, req.data.len, r);
+        if (r < 0) {
+            goto out;
+        }
+        dma_result =3D dma_memory_write(&address_space_memory, req.data.ad=
dr, buf,
+                                      req.data.len, MEMTXATTRS_UNSPECIFIED=
);
+        if (dma_result =3D=3D MEMTX_OK) {
+            ret =3D VBLK_RET_SUCCESS;
+        }
+        break;
+    case VBLK_DATA_FLAGS_WRITE:
+        /* Not needed, iBoot only reads */
+        break;
+    default:
+        break;
+    }
+
+out:
+    dma_memory_write(&address_space_memory, req.retval.addr, &ret, 1,
+                     MEMTXATTRS_UNSPECIFIED);
+}
+
+static void bdif_write(void *opaque, hwaddr offset,
+                       uint64_t value, unsigned size)
+{
+    VMAppleBdifState *s =3D opaque;
+    uint64_t devid =3D (offset & REG_DEVID_MASK);
+
+    trace_bdif_write(offset, size, value);
+
+    switch (offset & ~REG_DEVID_MASK) {
+    case REG_CMD:
+        switch (devid) {
+        case DEVID_ROOT:
+            vblk_cmd(devid, s->root, value, 0x0);
+            break;
+        case DEVID_AUX:
+            vblk_cmd(devid, s->aux, value, 0x0);
+            break;
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps bdif_ops =3D {
+    .read =3D bdif_read,
+    .write =3D bdif_write,
+    .endianness =3D DEVICE_NATIVE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 1,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 1,
+        .max_access_size =3D 8,
+    },
+};
+
+static void bdif_init(Object *obj)
+{
+    VMAppleBdifState *s =3D VMAPPLE_BDIF(obj);
+
+    memory_region_init_io(&s->mmio, obj, &bdif_ops, obj,
+                         "VMApple Backdoor Interface", VMAPPLE_BDIF_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static Property bdif_properties[] =3D {
+    DEFINE_PROP_DRIVE("aux", VMAppleBdifState, aux),
+    DEFINE_PROP_DRIVE("root", VMAppleBdifState, root),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void bdif_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+
+    dc->desc =3D "VMApple Backdoor Interface";
+    device_class_set_props(dc, bdif_properties);
+}
+
+static const TypeInfo bdif_info =3D {
+    .name          =3D TYPE_VMAPPLE_BDIF,
+    .parent        =3D TYPE_SYS_BUS_DEVICE,
+    .instance_size =3D sizeof(VMAppleBdifState),
+    .instance_init =3D bdif_init,
+    .class_init    =3D bdif_class_init,
+};
+
+static void bdif_register_types(void)
+{
+    type_register_static(&bdif_info);
+}
+
+type_init(bdif_register_types)
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index bcd4dcb28d2..d4624713deb 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -1 +1,2 @@
 system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('aes.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
index 0d4a73d7d1c..d86f64d50fe 100644
--- a/hw/vmapple/trace-events
+++ b/hw/vmapple/trace-events
@@ -14,3 +14,8 @@ aes_2_read(uint64_t offset, uint64_t res) "offset=3D0x%"P=
RIx64" res=3D0x%"PRIx64
 aes_2_write(uint64_t offset, uint64_t val) "offset=3D0x%"PRIx64" val=3D0x%=
"PRIx64
 aes_dump_data(const char *desc, const char *hex) "%s%s"
=20
+# bdif.c
+bdif_read(uint64_t offset, uint32_t size, uint64_t value) "offset=3D0x%"PR=
Ix64" size=3D0x%x value=3D0x%"PRIx64
+bdif_write(uint64_t offset, uint32_t size, uint64_t value) "offset=3D0x%"P=
RIx64" size=3D0x%x value=3D0x%"PRIx64
+bdif_vblk_read(const char *dev, uint64_t addr, uint64_t offset, uint32_t l=
en, int r) "dev=3D%s addr=3D0x%"PRIx64" off=3D0x%"PRIx64" size=3D0x%x r=3D%=
d"
+
diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
index 6762b6c869f..9090e9c5ac8 100644
--- a/include/hw/vmapple/vmapple.h
+++ b/include/hw/vmapple/vmapple.h
@@ -14,4 +14,6 @@
=20
 #define TYPE_APPLE_AES "apple-aes"
=20
+#define TYPE_VMAPPLE_BDIF "vmapple-bdif"
+
 #endif /* HW_VMAPPLE_VMAPPLE_H */
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103282; cv=none;
	d=zohomail.com; s=zohoarc;
	b=COY6FCRm9cvcGS8bZ7/QQseXFCtg6HcqhXd2o2thf84UpY5X/fQyNfROc4Nuyd8+8x7RlRXdacfbPi/CddR2BrV3B4BZ6peJMnyzlmmrYCUPLQqmKgfXC7LoU0nJb/+EJ76X0xVDDYatMq9E+cqWnc0e/jVomGWWe0pMHeKM8zE=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103282;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=sWBVtN/MtB7QwyvqivaPQCEjkPZnM9/4icL1W2D0Ipw=;
	b=TD4cWX62HxQKZ719dSoUeW+rrQs9H7uh2uVKIN60e4roslFh8Oj94qs9iNwHaLQI7KLAsHYOsHlcKbQoL74duKfqYeV7xXJImVRCxp4yEeuqzPv+V3aoHYtj0cjCYJzm4gybNltNiSW7rhOudxu/ddAUu4QcGAxaLw7Ozua9JFE=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103282482531.6557102133149;
 Fri, 13 Dec 2024 07:21:22 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7TB-0007UB-ND; Fri, 13 Dec 2024 10:20:46 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7SB-0004ug-7o
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:43 -0500
Received: from mail-ed1-x533.google.com ([2a00:1450:4864:20::533])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S1-0005OT-4t
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:42 -0500
Received: by mail-ed1-x533.google.com with SMTP id
 4fb4d7f45d1cf-5d3f28a4fccso2889357a12.2
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:29 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.26
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:27 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103168;
 x=1734707968;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=sWBVtN/MtB7QwyvqivaPQCEjkPZnM9/4icL1W2D0Ipw=;
 b=gxS8iRyMwEm4/ZF11x8/2rh+1vuhedYawD8+0H88uVmqf5RgQjm0SpmIbXhIeNaeGM
 MI5SWUXQkXNdLqtGlAuN1cFlEnN6yTTF5py2Gl9g1EsQMLS/8/bsxjyPgiPX42aBybhH
 3pzuyQy1f/CvztOPj6a5L4YhWVkrNDtRp5lmYghrLML8UzZS07yUqifcwqMhVCTUUgUY
 kjt4iGnn8J00l67rExXqw+Gg+fiREytH79E5Rbs6IgSTbdKBNNtC0swakbgyOSS1/BKp
 onFssm9gYLHqTEbTh6t0eZTTJKT/fYPR6OtEX4FvPc0VyhVwrw8ZzIUKE5Z9nLdgVTmR
 Dd8g==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103168; x=1734707968;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=sWBVtN/MtB7QwyvqivaPQCEjkPZnM9/4icL1W2D0Ipw=;
 b=BASb+vRPJszvEQDOh5XUe80rRVCYGKJh1ovVfwCD30Z13T+t4FIvPs7nkCs99OBKAh
 /210A6OtuuzEnOowY1OUkcXDwXMRGSM7xXO4kp1+PF5Z9/5+Zj+8gyZqwdoeIOb7S5GB
 OkcbshekZD51gQ4XEBqc5teRdsE29ePe0Dex4yK0MJQn8rcrMjjSBndJ7l/mLTbjx5le
 cXjSPZW2dJmTijG2Rg8BkXWCd/dZY1vCLoi/Tx40NXOxM4+cdo8MoU8JTSZxvgCXMToC
 4YxiiDxY+v6o+mrz14eRDrdwC09GZOxtAsoHnZH/Sloq8cneV/xZTxxRLi5vW/sEveKM
 vMBw==
X-Gm-Message-State: AOJu0YyOxGq7F7lhECN79IlwI8KruKbgK5F6IZuPz8bvEF0eIsqEySk9
 85HsX7/p8lprCVhvoolKbg1rdm1Mxg1hTk4J4hPnK5ZIWHqMTUpQ6vlujXQjjkNKFIpV5gSckZz
 L5g==
X-Gm-Gg: ASbGncvtv8WCNyI7a5VZNzg9bFx8pq0b2fsUwkF2eIagrsA0PtAAadodkZGaB6Zh0Gt
 O34o+pBkq6f/6pjR3UAi1kGPfh+US4DwxqAkxvSDQBAYWJ7jtMm421S4lgpNZWeoKejlrfaZpB6
 b3qzqt5R/WA06qf6XomurlIbHrgOUp4THjhBu8bnEqR3uSwKus6WFgT2B+Rkm8fVKCeTNx4QUwQ
 5n8kE+Vv9oTpmPIb2HWbUhLBXbFm4eml1HhqDWvdeF2TCxLyJAdF7U6U4CfNfzwQiHBXyGd+5S+
 IqNCslrvvLGPK67p6/aj6R9iq6bvSbrp
X-Google-Smtp-Source: 
 AGHT+IGRYNYi6txM8q4CZKwmYUaqHQDnbJAZRCBg37crVDN0mXck2vBJgzRDJSe40i3AHZVwoCgHCw==
X-Received: by 2002:a17:906:478f:b0:aa6:b926:bfb2 with SMTP id
 a640c23a62f3a-aab779b04e2mr322689766b.24.1734103168245;
 Fri, 13 Dec 2024 07:19:28 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 11/15] hw/vmapple/bdif: Introduce vmapple backdoor
 interface
Date: Fri, 13 Dec 2024 16:18:17 +0100
Message-Id: <20241213151821.65748-28-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::533;
 envelope-from=phil@philjordan.eu; helo=mail-ed1-x533.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103284964116600

From: Alexander Graf <graf@amazon.com>

The VMApple machine exposes AUX and ROOT block devices (as well as USB OTG
emulation) via virtio-pci as well as a special, simple backdoor platform
device.

This patch implements this backdoor platform device to the best of my
understanding. I left out any USB OTG parts; they're only needed for
guest recovery and I don't understand the protocol yet.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Moved most header code to .c, rest to vmapple.h
 * Better compliance with coding, naming, and formatting conventions.

v8:

 * Replaced uses of cpu_physical_memory_read with dma_memory_read.
 * Replaced an instance of g_free with g_autofree.

v9:

 * Replaced uses of cpu_physical_memory_write with dma_memory_write.
=20
 hw/vmapple/Kconfig           |   3 +
 hw/vmapple/bdif.c            | 275 +++++++++++++++++++++++++++++++++++
 hw/vmapple/meson.build       |   1 +
 hw/vmapple/trace-events      |   5 +
 include/hw/vmapple/vmapple.h |   2 +
 5 files changed, 286 insertions(+)
 create mode 100644 hw/vmapple/bdif.c

diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index a73504d5999..68f88876eb9 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -1,3 +1,6 @@
 config VMAPPLE_AES
     bool
=20
+config VMAPPLE_BDIF
+    bool
+
diff --git a/hw/vmapple/bdif.c b/hw/vmapple/bdif.c
new file mode 100644
index 00000000000..d7b6b7a25a4
--- /dev/null
+++ b/hw/vmapple/bdif.c
@@ -0,0 +1,275 @@
+/*
+ * VMApple Backdoor Interface
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "trace.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/sysbus.h"
+#include "hw/block/block.h"
+#include "qapi/error.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/dma.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleBdifState, VMAPPLE_BDIF)
+
+struct VMAppleBdifState {
+    SysBusDevice parent_obj;
+
+    BlockBackend *aux;
+    BlockBackend *root;
+    MemoryRegion mmio;
+};
+
+#define VMAPPLE_BDIF_SIZE   0x00200000
+
+#define REG_DEVID_MASK      0xffff0000
+#define DEVID_ROOT          0x00000000
+#define DEVID_AUX           0x00010000
+#define DEVID_USB           0x00100000
+
+#define REG_STATUS          0x0
+#define REG_STATUS_ACTIVE     BIT(0)
+#define REG_CFG             0x4
+#define REG_CFG_ACTIVE        BIT(1)
+#define REG_UNK1            0x8
+#define REG_BUSY            0x10
+#define REG_BUSY_READY        BIT(0)
+#define REG_UNK2            0x400
+#define REG_CMD             0x408
+#define REG_NEXT_DEVICE     0x420
+#define REG_UNK3            0x434
+
+typedef struct VblkSector {
+    uint32_t pad;
+    uint32_t pad2;
+    uint32_t sector;
+    uint32_t pad3;
+} VblkSector;
+
+typedef struct VblkReqCmd {
+    uint64_t addr;
+    uint32_t len;
+    uint32_t flags;
+} VblkReqCmd;
+
+typedef struct VblkReq {
+    VblkReqCmd sector;
+    VblkReqCmd data;
+    VblkReqCmd retval;
+} VblkReq;
+
+#define VBLK_DATA_FLAGS_READ  0x00030001
+#define VBLK_DATA_FLAGS_WRITE 0x00010001
+
+#define VBLK_RET_SUCCESS  0
+#define VBLK_RET_FAILED   1
+
+static uint64_t bdif_read(void *opaque, hwaddr offset, unsigned size)
+{
+    uint64_t ret =3D -1;
+    uint64_t devid =3D offset & REG_DEVID_MASK;
+
+    switch (offset & ~REG_DEVID_MASK) {
+    case REG_STATUS:
+        ret =3D REG_STATUS_ACTIVE;
+        break;
+    case REG_CFG:
+        ret =3D REG_CFG_ACTIVE;
+        break;
+    case REG_UNK1:
+        ret =3D 0x420;
+        break;
+    case REG_BUSY:
+        ret =3D REG_BUSY_READY;
+        break;
+    case REG_UNK2:
+        ret =3D 0x1;
+        break;
+    case REG_UNK3:
+        ret =3D 0x0;
+        break;
+    case REG_NEXT_DEVICE:
+        switch (devid) {
+        case DEVID_ROOT:
+            ret =3D 0x8000000;
+            break;
+        case DEVID_AUX:
+            ret =3D 0x10000;
+            break;
+        }
+        break;
+    }
+
+    trace_bdif_read(offset, size, ret);
+    return ret;
+}
+
+static void le2cpu_sector(VblkSector *sector)
+{
+    sector->sector =3D le32_to_cpu(sector->sector);
+}
+
+static void le2cpu_reqcmd(VblkReqCmd *cmd)
+{
+    cmd->addr =3D le64_to_cpu(cmd->addr);
+    cmd->len =3D le32_to_cpu(cmd->len);
+    cmd->flags =3D le32_to_cpu(cmd->flags);
+}
+
+static void le2cpu_req(VblkReq *req)
+{
+    le2cpu_reqcmd(&req->sector);
+    le2cpu_reqcmd(&req->data);
+    le2cpu_reqcmd(&req->retval);
+}
+
+static void vblk_cmd(uint64_t devid, BlockBackend *blk, uint64_t gp_addr,
+                     uint64_t static_off)
+{
+    VblkReq req;
+    VblkSector sector;
+    uint64_t off =3D 0;
+    g_autofree char *buf =3D NULL;
+    uint8_t ret =3D VBLK_RET_FAILED;
+    int r;
+    MemTxResult dma_result;
+
+    dma_result =3D dma_memory_read(&address_space_memory, gp_addr,
+                                 &req, sizeof(req), MEMTXATTRS_UNSPECIFIED=
);
+    if (dma_result !=3D MEMTX_OK) {
+        goto out;
+    }
+
+    le2cpu_req(&req);
+
+    if (req.sector.len !=3D sizeof(sector)) {
+        goto out;
+    }
+
+    /* Read the vblk command */
+    dma_result =3D dma_memory_read(&address_space_memory, req.sector.addr,
+                                 &sector, sizeof(sector),
+                                 MEMTXATTRS_UNSPECIFIED);
+    if (dma_result !=3D MEMTX_OK) {
+        goto out;
+    }
+    le2cpu_sector(&sector);
+
+    off =3D sector.sector * 512ULL + static_off;
+
+    /* Sanity check that we're not allocating bogus sizes */
+    if (req.data.len > 128 * MiB) {
+        goto out;
+    }
+
+    buf =3D g_malloc0(req.data.len);
+    switch (req.data.flags) {
+    case VBLK_DATA_FLAGS_READ:
+        r =3D blk_pread(blk, off, req.data.len, buf, 0);
+        trace_bdif_vblk_read(devid =3D=3D DEVID_AUX ? "aux" : "root",
+                             req.data.addr, off, req.data.len, r);
+        if (r < 0) {
+            goto out;
+        }
+        dma_result =3D dma_memory_write(&address_space_memory, req.data.ad=
dr, buf,
+                                      req.data.len, MEMTXATTRS_UNSPECIFIED=
);
+        if (dma_result =3D=3D MEMTX_OK) {
+            ret =3D VBLK_RET_SUCCESS;
+        }
+        break;
+    case VBLK_DATA_FLAGS_WRITE:
+        /* Not needed, iBoot only reads */
+        break;
+    default:
+        break;
+    }
+
+out:
+    dma_memory_write(&address_space_memory, req.retval.addr, &ret, 1,
+                     MEMTXATTRS_UNSPECIFIED);
+}
+
+static void bdif_write(void *opaque, hwaddr offset,
+                       uint64_t value, unsigned size)
+{
+    VMAppleBdifState *s =3D opaque;
+    uint64_t devid =3D (offset & REG_DEVID_MASK);
+
+    trace_bdif_write(offset, size, value);
+
+    switch (offset & ~REG_DEVID_MASK) {
+    case REG_CMD:
+        switch (devid) {
+        case DEVID_ROOT:
+            vblk_cmd(devid, s->root, value, 0x0);
+            break;
+        case DEVID_AUX:
+            vblk_cmd(devid, s->aux, value, 0x0);
+            break;
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps bdif_ops =3D {
+    .read =3D bdif_read,
+    .write =3D bdif_write,
+    .endianness =3D DEVICE_NATIVE_ENDIAN,
+    .valid =3D {
+        .min_access_size =3D 1,
+        .max_access_size =3D 8,
+    },
+    .impl =3D {
+        .min_access_size =3D 1,
+        .max_access_size =3D 8,
+    },
+};
+
+static void bdif_init(Object *obj)
+{
+    VMAppleBdifState *s =3D VMAPPLE_BDIF(obj);
+
+    memory_region_init_io(&s->mmio, obj, &bdif_ops, obj,
+                         "VMApple Backdoor Interface", VMAPPLE_BDIF_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static Property bdif_properties[] =3D {
+    DEFINE_PROP_DRIVE("aux", VMAppleBdifState, aux),
+    DEFINE_PROP_DRIVE("root", VMAppleBdifState, root),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void bdif_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+
+    dc->desc =3D "VMApple Backdoor Interface";
+    device_class_set_props(dc, bdif_properties);
+}
+
+static const TypeInfo bdif_info =3D {
+    .name          =3D TYPE_VMAPPLE_BDIF,
+    .parent        =3D TYPE_SYS_BUS_DEVICE,
+    .instance_size =3D sizeof(VMAppleBdifState),
+    .instance_init =3D bdif_init,
+    .class_init    =3D bdif_class_init,
+};
+
+static void bdif_register_types(void)
+{
+    type_register_static(&bdif_info);
+}
+
+type_init(bdif_register_types)
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index bcd4dcb28d2..d4624713deb 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -1 +1,2 @@
 system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('aes.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
index 0d4a73d7d1c..d86f64d50fe 100644
--- a/hw/vmapple/trace-events
+++ b/hw/vmapple/trace-events
@@ -14,3 +14,8 @@ aes_2_read(uint64_t offset, uint64_t res) "offset=3D0x%"P=
RIx64" res=3D0x%"PRIx64
 aes_2_write(uint64_t offset, uint64_t val) "offset=3D0x%"PRIx64" val=3D0x%=
"PRIx64
 aes_dump_data(const char *desc, const char *hex) "%s%s"
=20
+# bdif.c
+bdif_read(uint64_t offset, uint32_t size, uint64_t value) "offset=3D0x%"PR=
Ix64" size=3D0x%x value=3D0x%"PRIx64
+bdif_write(uint64_t offset, uint32_t size, uint64_t value) "offset=3D0x%"P=
RIx64" size=3D0x%x value=3D0x%"PRIx64
+bdif_vblk_read(const char *dev, uint64_t addr, uint64_t offset, uint32_t l=
en, int r) "dev=3D%s addr=3D0x%"PRIx64" off=3D0x%"PRIx64" size=3D0x%x r=3D%=
d"
+
diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
index 6762b6c869f..9090e9c5ac8 100644
--- a/include/hw/vmapple/vmapple.h
+++ b/include/hw/vmapple/vmapple.h
@@ -14,4 +14,6 @@
=20
 #define TYPE_APPLE_AES "apple-aes"
=20
+#define TYPE_VMAPPLE_BDIF "vmapple-bdif"
+
 #endif /* HW_VMAPPLE_VMAPPLE_H */
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103735; cv=none;
	d=zohomail.com; s=zohoarc;
	b=DVx+nU3A3CnEpseNt3/anE/wK9RybnaeVukt6nykYTlLjp4fNxGCmR2tpJYF631ENOmknRzextrDbZTlqw3pss2/edCancIoM+PqyelBAgIOQzQqffKjHdOEaX1Of1/NfO1aAVId1H+Q1VQaoNWrqFIJKOckkf29TebI+ZiuThY=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103735;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=f6qmM77CeqmQoXZkjlgnGto2UvZTwvtgaL7LFgK5WK0=;
	b=m2AmC6XGy13xuy3JItdxIGyTuWHW0aDYu/28PBU5BZ4TJFOW2d1sPlwRjpvr0zmVH8Y1+snDvrdbRvblYZtHJm4oF86A5yxUmv2JhBmTgayd8OSPvhwIyxs4G33utlyTONd1e+EwL4hBJCQqJcVn+ybokcvJ62ih9ZnLwQU4C/E=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 17341037353541007.6345193165242;
 Fri, 13 Dec 2024 07:28:55 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Tm-0000EB-Hi; Fri, 13 Dec 2024 10:21:26 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7SG-00050u-De
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:48 -0500
Received: from mail-ed1-x536.google.com ([2a00:1450:4864:20::536])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S1-0005P9-BW
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:48 -0500
Received: by mail-ed1-x536.google.com with SMTP id
 4fb4d7f45d1cf-5cec9609303so2540900a12.1
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:31 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.28
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:29 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103170;
 x=1734707970;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=f6qmM77CeqmQoXZkjlgnGto2UvZTwvtgaL7LFgK5WK0=;
 b=k8VaYwRoVoYlPWEbD+BTUPqI4M4Uos5cl6g3nRKFZG1I3tuU+HDAjHIgxWTPlX1fDc
 UC3JOwWR+Q5wTKpwB43wrgx/CHDrekYlpLVhtU9MfEMHQf3Bstxma/c7vKJ43F5H/BAJ
 3LivQ50T8m8YBWeo+EMRxBtRiJQaW7ZDpkGs0PTXkGV8RA1TTfluJRSPu1BLXIgDS4Ng
 A4wxQGH4UZ4PEOMdGZKr/y+NyRAvNGcWYiK3RXIGPWcCUBeeEqHzEiweRGTN8o/Eehli
 wgMNvFK+neR4Lu1lgZg6gAXLzlS6F1CNciTjMnqfsl2bwq3SZ7wii3/Opp78Ow3So6i0
 lwRQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103170; x=1734707970;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=f6qmM77CeqmQoXZkjlgnGto2UvZTwvtgaL7LFgK5WK0=;
 b=HNYiEKC9ICcjbc2c/7dpTm2Onq0bL4jGSp3qsm6MciP4/L6QTU4vNYFBfFxIEtnh1z
 NYW+/zl8+8lUx8ddKHB8Ocv2MIQ6aFt9r2K6FwU3cQhgecHUgP0w6cBhTgxdTcLYVna2
 EmQOxafBgpc1BTtJvGjbZJP3YDDORk8sNGIOyu67YJeuMfgI/C8lV+kNDGvAZYgSAGZA
 IgurVzuRDhr3f6SFRLesCDFg+gU8eKgxm0cH7bXfuF5yxCkYTAj4uoLwDV+evrBxNHt4
 DXsmFwKJD8nFqQOK3lUEgBH4qUvWg2IDvNB4MIYr+fuVycp2/zdlu1GdUzzFZQKkGWsy
 Wqnw==
X-Gm-Message-State: AOJu0YzBwirpJl2Rwbp6xUA9qgibY0QiKzwCRQwCnhTo9RmCkn2BFC1q
 dhxadCslzMa1ed2PmRi7j6dlJNVWjexW355EZ9lE9fVcswZcqMhPKp8hjp8X93jIx/4NBehWHcw
 OlA==
X-Gm-Gg: ASbGncsqqhHkWPMoLtCGFC1pQVn64WCAUbv0nrweJaDuzetmFT16nBFBdgRCEWODaxR
 V6nRUUVBKxRx5R8vwuzafDUqLJeuTaiVdgWl7dxNOTM+E9yzfwRagb4sqOALzcmLSAk3klOMETV
 pVJ/LUAS00YIjGqAOy97vvnew6ucYfViBzTMoXGeMPzi5Ytkb+x1bZPdgnCf2hO8Vv6TcNWSjmG
 iiFPu28IJt/D7Tnd+Z7kw+KU8xLMHaf5sh3+0XpKmPOfhMHVP/nyL5ydLwCthEoQQvA57PWST50
 x9vMQZ9KDsKhhO68DnufSX07IAzjcOX+
X-Google-Smtp-Source: 
 AGHT+IFS4aSrgPkCE0Rgrsy/WqEdaXs6aDAumXm6WNRYwKAi+L+bvVuP9uadeKLfyO91NP8KRkD5Fw==
X-Received: by 2002:a17:907:94c1:b0:aa6:ac33:90cf with SMTP id
 a640c23a62f3a-aab778c1f3amr272680966b.2.1734103170017;
 Fri, 13 Dec 2024 07:19:30 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 12/15] hw/vmapple/cfg: Introduce vmapple cfg region
Date: Fri, 13 Dec 2024 16:18:18 +0100
Message-Id: <20241213151821.65748-29-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::536;
 envelope-from=phil@philjordan.eu; helo=mail-ed1-x536.google.com
X-Spam_score_int: -18
X-Spam_score: -1.9
X-Spam_bar: -
X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 T_SPF_TEMPERROR=0.01 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103736823116600

From: Alexander Graf <graf@amazon.com>

Instead of device tree or other more standardized means, VMApple passes
platform configuration to the first stage boot loader in a binary encoded
format that resides at a dedicated RAM region in physical address space.

This patch models this configuration space as a qdev device which we can
then map at the fixed location in the address space. That way, we can
influence and annotate all configuration fields easily.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v3:

 * Replaced legacy device reset method with Resettable method

v4:

 * Fixed initialisation of default values for properties
 * Dropped superfluous endianness conversions
 * Moved most header code to .c, device name #define goes in vmapple.h

v5:

 * Improved error reporting in case of string property buffer overflow.

v7:

 * Changed error messages for overrun of properties with
   fixed-length strings to be more useful to users than developers.

v8:

 * Consistent parenthesising of macro arguments for better safety.

v10:

 * Slightly tidier error reporting for overlong property values.

 hw/vmapple/Kconfig           |   3 +
 hw/vmapple/cfg.c             | 196 +++++++++++++++++++++++++++++++++++
 hw/vmapple/meson.build       |   1 +
 include/hw/vmapple/vmapple.h |   2 +
 4 files changed, 202 insertions(+)
 create mode 100644 hw/vmapple/cfg.c

diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index 68f88876eb9..8bbeb9a9237 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -4,3 +4,6 @@ config VMAPPLE_AES
 config VMAPPLE_BDIF
     bool
=20
+config VMAPPLE_CFG
+    bool
+
diff --git a/hw/vmapple/cfg.c b/hw/vmapple/cfg.c
new file mode 100644
index 00000000000..d854b49269b
--- /dev/null
+++ b/hw/vmapple/cfg.c
@@ -0,0 +1,196 @@
+/*
+ * VMApple Configuration Region
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/sysbus.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "net/net.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleCfgState, VMAPPLE_CFG)
+
+#define VMAPPLE_CFG_SIZE 0x00010000
+
+typedef struct VMAppleCfg {
+    uint32_t version;         /* 0x000 */
+    uint32_t nr_cpus;         /* 0x004 */
+    uint32_t unk1;            /* 0x008 */
+    uint32_t unk2;            /* 0x00c */
+    uint32_t unk3;            /* 0x010 */
+    uint32_t unk4;            /* 0x014 */
+    uint64_t ecid;            /* 0x018 */
+    uint64_t ram_size;        /* 0x020 */
+    uint32_t run_installer1;  /* 0x028 */
+    uint32_t unk5;            /* 0x02c */
+    uint32_t unk6;            /* 0x030 */
+    uint32_t run_installer2;  /* 0x034 */
+    uint32_t rnd;             /* 0x038 */
+    uint32_t unk7;            /* 0x03c */
+    MACAddr mac_en0;          /* 0x040 */
+    uint8_t pad1[2];
+    MACAddr mac_en1;          /* 0x048 */
+    uint8_t pad2[2];
+    MACAddr mac_wifi0;        /* 0x050 */
+    uint8_t pad3[2];
+    MACAddr mac_bt0;          /* 0x058 */
+    uint8_t pad4[2];
+    uint8_t reserved[0xa0];   /* 0x060 */
+    uint32_t cpu_ids[0x80];   /* 0x100 */
+    uint8_t scratch[0x200];   /* 0x180 */
+    char serial[32];          /* 0x380 */
+    char unk8[32];            /* 0x3a0 */
+    char model[32];           /* 0x3c0 */
+    uint8_t unk9[32];         /* 0x3e0 */
+    uint32_t unk10;           /* 0x400 */
+    char soc_name[32];        /* 0x404 */
+} VMAppleCfg;
+
+struct VMAppleCfgState {
+    SysBusDevice parent_obj;
+    VMAppleCfg cfg;
+
+    MemoryRegion mem;
+    char *serial;
+    char *model;
+    char *soc_name;
+};
+
+static void vmapple_cfg_reset(Object *obj, ResetType type)
+{
+    VMAppleCfgState *s =3D VMAPPLE_CFG(obj);
+    VMAppleCfg *cfg;
+
+    cfg =3D memory_region_get_ram_ptr(&s->mem);
+    memset(cfg, 0, VMAPPLE_CFG_SIZE);
+    *cfg =3D s->cfg;
+}
+
+static bool set_fixlen_property_or_error(char *restrict dst,
+                                         const char *restrict src,
+                                         size_t dst_size, Error **errp,
+                                         const char *property_name)
+{
+    ERRP_GUARD();
+    size_t len;
+
+    len =3D g_strlcpy(dst, src, dst_size);
+    if (len < dst_size) { /* len does not count nul terminator */
+        return true;
+    }
+
+    error_setg(errp, "Provided value too long for property '%s'", property=
_name);
+    error_append_hint(errp, "length (%zu) exceeds maximum of %zu\n",
+                      len, dst_size - 1);
+    return false;
+}
+
+#define set_fixlen_property_or_return(dst_array, src, errp, property_name)=
 \
+    do { \
+        if (!set_fixlen_property_or_error((dst_array), (src), \
+                                          ARRAY_SIZE(dst_array), \
+                                          (errp), (property_name))) { \
+            return; \
+        } \
+    } while (0)
+
+static void vmapple_cfg_realize(DeviceState *dev, Error **errp)
+{
+    VMAppleCfgState *s =3D VMAPPLE_CFG(dev);
+    uint32_t i;
+
+    if (!s->serial) {
+        s->serial =3D g_strdup("1234");
+    }
+    if (!s->model) {
+        s->model =3D g_strdup("VM0001");
+    }
+    if (!s->soc_name) {
+        s->soc_name =3D g_strdup("Apple M1 (Virtual)");
+    }
+
+    set_fixlen_property_or_return(s->cfg.serial, s->serial, errp, "serial"=
);
+    set_fixlen_property_or_return(s->cfg.model, s->model, errp, "model");
+    set_fixlen_property_or_return(s->cfg.soc_name, s->soc_name, errp, "soc=
_name");
+    set_fixlen_property_or_return(s->cfg.unk8, "D/A", errp, "unk8");
+    s->cfg.version =3D 2;
+    s->cfg.unk1 =3D 1;
+    s->cfg.unk2 =3D 1;
+    s->cfg.unk3 =3D 0x20;
+    s->cfg.unk4 =3D 0;
+    s->cfg.unk5 =3D 1;
+    s->cfg.unk6 =3D 1;
+    s->cfg.unk7 =3D 0;
+    s->cfg.unk10 =3D 1;
+
+    if (s->cfg.nr_cpus > ARRAY_SIZE(s->cfg.cpu_ids)) {
+        error_setg(errp,
+                   "Failed to create %u CPUs, vmapple machine supports %zu=
 max",
+                   s->cfg.nr_cpus, ARRAY_SIZE(s->cfg.cpu_ids));
+        return;
+    }
+    for (i =3D 0; i < s->cfg.nr_cpus; i++) {
+        s->cfg.cpu_ids[i] =3D i;
+    }
+}
+
+static void vmapple_cfg_init(Object *obj)
+{
+    VMAppleCfgState *s =3D VMAPPLE_CFG(obj);
+
+    memory_region_init_ram(&s->mem, obj, "VMApple Config", VMAPPLE_CFG_SIZ=
E,
+                           &error_fatal);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mem);
+}
+
+static Property vmapple_cfg_properties[] =3D {
+    DEFINE_PROP_UINT32("nr-cpus", VMAppleCfgState, cfg.nr_cpus, 1),
+    DEFINE_PROP_UINT64("ecid", VMAppleCfgState, cfg.ecid, 0),
+    DEFINE_PROP_UINT64("ram-size", VMAppleCfgState, cfg.ram_size, 0),
+    DEFINE_PROP_UINT32("run_installer1", VMAppleCfgState, cfg.run_installe=
r1, 0),
+    DEFINE_PROP_UINT32("run_installer2", VMAppleCfgState, cfg.run_installe=
r2, 0),
+    DEFINE_PROP_UINT32("rnd", VMAppleCfgState, cfg.rnd, 0),
+    DEFINE_PROP_MACADDR("mac-en0", VMAppleCfgState, cfg.mac_en0),
+    DEFINE_PROP_MACADDR("mac-en1", VMAppleCfgState, cfg.mac_en1),
+    DEFINE_PROP_MACADDR("mac-wifi0", VMAppleCfgState, cfg.mac_wifi0),
+    DEFINE_PROP_MACADDR("mac-bt0", VMAppleCfgState, cfg.mac_bt0),
+    DEFINE_PROP_STRING("serial", VMAppleCfgState, serial),
+    DEFINE_PROP_STRING("model", VMAppleCfgState, model),
+    DEFINE_PROP_STRING("soc_name", VMAppleCfgState, soc_name),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmapple_cfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+    ResettableClass *rc =3D RESETTABLE_CLASS(klass);
+
+    dc->realize =3D vmapple_cfg_realize;
+    dc->desc =3D "VMApple Configuration Region";
+    device_class_set_props(dc, vmapple_cfg_properties);
+    rc->phases.hold =3D vmapple_cfg_reset;
+}
+
+static const TypeInfo vmapple_cfg_info =3D {
+    .name          =3D TYPE_VMAPPLE_CFG,
+    .parent        =3D TYPE_SYS_BUS_DEVICE,
+    .instance_size =3D sizeof(VMAppleCfgState),
+    .instance_init =3D vmapple_cfg_init,
+    .class_init    =3D vmapple_cfg_class_init,
+};
+
+static void vmapple_cfg_register_types(void)
+{
+    type_register_static(&vmapple_cfg_info);
+}
+
+type_init(vmapple_cfg_register_types)
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index d4624713deb..64b78693a31 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -1,2 +1,3 @@
 system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('aes.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_CFG',  if_true: files('cfg.c'))
diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
index 9090e9c5ac8..3bba59f5ec7 100644
--- a/include/hw/vmapple/vmapple.h
+++ b/include/hw/vmapple/vmapple.h
@@ -16,4 +16,6 @@
=20
 #define TYPE_VMAPPLE_BDIF "vmapple-bdif"
=20
+#define TYPE_VMAPPLE_CFG "vmapple-cfg"
+
 #endif /* HW_VMAPPLE_VMAPPLE_H */
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103405; cv=none;
	d=zohomail.com; s=zohoarc;
	b=Uz/Zob9Srm2I4RVAQJBuum0T2xGFYVRgokvzPmcjkBwVFWbvluOjI6O51ijzeA9LMb+V5Z/g/cZwBi7F5Utir1Mx4zossJdTwIQu8/VZWpo6Dziw93CtSKGWN573t3OUAt1uCGkRBVtUtzQQbICjMkDmoRHT4cQdQ1vyaVIPS0E=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103405;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=f6qmM77CeqmQoXZkjlgnGto2UvZTwvtgaL7LFgK5WK0=;
	b=dnELvVwAUG33EoHgHiExqJJHGMBvO2fTBhkOg8I6cHzLlavlZkOyIzkIh/u+KVUWRTg+GWimePGBK35i/K9ObaqAYpbrL/+wyw1KYww55YlpkE2Daj6veS1Ows468m2IIWmwVDRlsAq3Ub9TFX/VXd2/ya9pEZxGdCOVaX+S4lk=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103405037475.7633777005027;
 Fri, 13 Dec 2024 07:23:25 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SN-0005AC-Q7; Fri, 13 Dec 2024 10:19:56 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rl-0004VS-BX
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:18 -0500
Received: from mail-ej1-x62a.google.com ([2a00:1450:4864:20::62a])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Re-0005Bk-Gv
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:16 -0500
Received: by mail-ej1-x62a.google.com with SMTP id
 a640c23a62f3a-a9f1d76dab1so378095166b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:01 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.18.58
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:18:59 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103140;
 x=1734707940;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=f6qmM77CeqmQoXZkjlgnGto2UvZTwvtgaL7LFgK5WK0=;
 b=KKwWq7IWwx3AJYePlDGOrg3wBAyVW2nH7x1TvEvhDLFLXb2Z2rJRgIsMQSuNRqc4SV
 Cqzk3y0+esFrnyB0h1JimDZ01V2/cGWQhbCGHVdpS9EdtPN5AJDeVkYrpwk/OHyv8ojd
 ls4W7k+6CAwnR4TEthFD42lQqEHu9LkN4I9BdIayZv7Y8dire0xyIRR3eL/KbkY3QBdm
 IW0D33Nb5JwNqmorKZIr//FsySEEGpgQVrqW7FZXN8RPrP/xvpY5fDpmX1jIBSaX0yN2
 sxfO5+Oa7/LLcrm9nzkn4boRA3uKi9/DXM1p8eEwbMl9JbhYh1NnLqpBl+cxGb46/WLt
 vfZg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103140; x=1734707940;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=f6qmM77CeqmQoXZkjlgnGto2UvZTwvtgaL7LFgK5WK0=;
 b=okfyynrPomckzneKLtQ4iAdwjp1ng4ZNeQJJ1k36H5B/K5LvWMwbOmiOFnWispFNKU
 wlPdItn2rthE954I/Q/ArRIvNmQ6Yyv9GqVO/LuWHn+bQrDcVUePvck7AiWZOMOEbyh5
 RB3qUKT45L5AeBAuEXypPA6ZPU4uUP8kPeVd58+b7A3jiv/z95Pgc8HsIzk/t3JCvZtW
 Gs5mKVANPfkNrPmgjMo8vNz2fTy9hQL+om5MQPlPWPM+DWD+cjQ6ctlJCfsKvvUXnykq
 3AKv1VRKXPADcSqnLrMG2/f3Q/pkKtxk8Zc8e1rCgCWmV6WlbJyAos2yUmKSU7gRwdxY
 We6Q==
X-Gm-Message-State: AOJu0YwULb/fRiDv3O7g/afnz41Ji8CVSl6YT45NvKk6E2BdmIWhX0d6
 OoMECxx4igB5p2B6QAEzdFWlELhQUPs9hGWUVaXoJAl67ZySa2PQojBxSSRb3of956769pL++iQ
 FuA==
X-Gm-Gg: ASbGncvTtU8h104Vm7ZPkEwn7wrVNHl2ChoIwzWPDPVbq6u9ZVC9CvHnbIfyJdR2fDy
 L1GrerqEGQWGUjuMY3S1fXuWyzHQqtWK3XKPD4bDibnWz3ossFCRFrDq4COaj+enxWrTzbEtrwi
 SQZYrhYbGrjs/NUFGpctplo9rZzAjM9w44Fd91EWDR2+NDxlFHL4FVYzvdTvFBdqiZ+R4bGlWnZ
 yaVteAATQFYqZO/AXnWTSBrN8E35MFgjPtZAzTaABz4sgpWUM/iwkeYbhl/1CH0e7XhhaxH7Js/
 WstBT2BAFK3aZ7lzp9Ddf0WgkgQ6ye7k
X-Google-Smtp-Source: 
 AGHT+IHh+QdmKKdjLYvd4R7y3B9Aerw98CsnivRQ6RZ1B7ReeS6ulKUY/yoPEmKEWVftYhPj7SlFdw==
X-Received: by 2002:a17:906:c14c:b0:aa6:bcc2:4e5f with SMTP id
 a640c23a62f3a-aab77e8a872mr281895966b.44.1734103140105;
 Fri, 13 Dec 2024 07:19:00 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 12/15] hw/vmapple/cfg: Introduce vmapple cfg region
Date: Fri, 13 Dec 2024 16:18:02 +0100
Message-Id: <20241213151821.65748-13-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62a;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62a.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103407282116600

From: Alexander Graf <graf@amazon.com>

Instead of device tree or other more standardized means, VMApple passes
platform configuration to the first stage boot loader in a binary encoded
format that resides at a dedicated RAM region in physical address space.

This patch models this configuration space as a qdev device which we can
then map at the fixed location in the address space. That way, we can
influence and annotate all configuration fields easily.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v3:

 * Replaced legacy device reset method with Resettable method

v4:

 * Fixed initialisation of default values for properties
 * Dropped superfluous endianness conversions
 * Moved most header code to .c, device name #define goes in vmapple.h

v5:

 * Improved error reporting in case of string property buffer overflow.

v7:

 * Changed error messages for overrun of properties with
   fixed-length strings to be more useful to users than developers.

v8:

 * Consistent parenthesising of macro arguments for better safety.

v10:

 * Slightly tidier error reporting for overlong property values.

 hw/vmapple/Kconfig           |   3 +
 hw/vmapple/cfg.c             | 196 +++++++++++++++++++++++++++++++++++
 hw/vmapple/meson.build       |   1 +
 include/hw/vmapple/vmapple.h |   2 +
 4 files changed, 202 insertions(+)
 create mode 100644 hw/vmapple/cfg.c

diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index 68f88876eb9..8bbeb9a9237 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -4,3 +4,6 @@ config VMAPPLE_AES
 config VMAPPLE_BDIF
     bool
=20
+config VMAPPLE_CFG
+    bool
+
diff --git a/hw/vmapple/cfg.c b/hw/vmapple/cfg.c
new file mode 100644
index 00000000000..d854b49269b
--- /dev/null
+++ b/hw/vmapple/cfg.c
@@ -0,0 +1,196 @@
+/*
+ * VMApple Configuration Region
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/sysbus.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "net/net.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleCfgState, VMAPPLE_CFG)
+
+#define VMAPPLE_CFG_SIZE 0x00010000
+
+typedef struct VMAppleCfg {
+    uint32_t version;         /* 0x000 */
+    uint32_t nr_cpus;         /* 0x004 */
+    uint32_t unk1;            /* 0x008 */
+    uint32_t unk2;            /* 0x00c */
+    uint32_t unk3;            /* 0x010 */
+    uint32_t unk4;            /* 0x014 */
+    uint64_t ecid;            /* 0x018 */
+    uint64_t ram_size;        /* 0x020 */
+    uint32_t run_installer1;  /* 0x028 */
+    uint32_t unk5;            /* 0x02c */
+    uint32_t unk6;            /* 0x030 */
+    uint32_t run_installer2;  /* 0x034 */
+    uint32_t rnd;             /* 0x038 */
+    uint32_t unk7;            /* 0x03c */
+    MACAddr mac_en0;          /* 0x040 */
+    uint8_t pad1[2];
+    MACAddr mac_en1;          /* 0x048 */
+    uint8_t pad2[2];
+    MACAddr mac_wifi0;        /* 0x050 */
+    uint8_t pad3[2];
+    MACAddr mac_bt0;          /* 0x058 */
+    uint8_t pad4[2];
+    uint8_t reserved[0xa0];   /* 0x060 */
+    uint32_t cpu_ids[0x80];   /* 0x100 */
+    uint8_t scratch[0x200];   /* 0x180 */
+    char serial[32];          /* 0x380 */
+    char unk8[32];            /* 0x3a0 */
+    char model[32];           /* 0x3c0 */
+    uint8_t unk9[32];         /* 0x3e0 */
+    uint32_t unk10;           /* 0x400 */
+    char soc_name[32];        /* 0x404 */
+} VMAppleCfg;
+
+struct VMAppleCfgState {
+    SysBusDevice parent_obj;
+    VMAppleCfg cfg;
+
+    MemoryRegion mem;
+    char *serial;
+    char *model;
+    char *soc_name;
+};
+
+static void vmapple_cfg_reset(Object *obj, ResetType type)
+{
+    VMAppleCfgState *s =3D VMAPPLE_CFG(obj);
+    VMAppleCfg *cfg;
+
+    cfg =3D memory_region_get_ram_ptr(&s->mem);
+    memset(cfg, 0, VMAPPLE_CFG_SIZE);
+    *cfg =3D s->cfg;
+}
+
+static bool set_fixlen_property_or_error(char *restrict dst,
+                                         const char *restrict src,
+                                         size_t dst_size, Error **errp,
+                                         const char *property_name)
+{
+    ERRP_GUARD();
+    size_t len;
+
+    len =3D g_strlcpy(dst, src, dst_size);
+    if (len < dst_size) { /* len does not count nul terminator */
+        return true;
+    }
+
+    error_setg(errp, "Provided value too long for property '%s'", property=
_name);
+    error_append_hint(errp, "length (%zu) exceeds maximum of %zu\n",
+                      len, dst_size - 1);
+    return false;
+}
+
+#define set_fixlen_property_or_return(dst_array, src, errp, property_name)=
 \
+    do { \
+        if (!set_fixlen_property_or_error((dst_array), (src), \
+                                          ARRAY_SIZE(dst_array), \
+                                          (errp), (property_name))) { \
+            return; \
+        } \
+    } while (0)
+
+static void vmapple_cfg_realize(DeviceState *dev, Error **errp)
+{
+    VMAppleCfgState *s =3D VMAPPLE_CFG(dev);
+    uint32_t i;
+
+    if (!s->serial) {
+        s->serial =3D g_strdup("1234");
+    }
+    if (!s->model) {
+        s->model =3D g_strdup("VM0001");
+    }
+    if (!s->soc_name) {
+        s->soc_name =3D g_strdup("Apple M1 (Virtual)");
+    }
+
+    set_fixlen_property_or_return(s->cfg.serial, s->serial, errp, "serial"=
);
+    set_fixlen_property_or_return(s->cfg.model, s->model, errp, "model");
+    set_fixlen_property_or_return(s->cfg.soc_name, s->soc_name, errp, "soc=
_name");
+    set_fixlen_property_or_return(s->cfg.unk8, "D/A", errp, "unk8");
+    s->cfg.version =3D 2;
+    s->cfg.unk1 =3D 1;
+    s->cfg.unk2 =3D 1;
+    s->cfg.unk3 =3D 0x20;
+    s->cfg.unk4 =3D 0;
+    s->cfg.unk5 =3D 1;
+    s->cfg.unk6 =3D 1;
+    s->cfg.unk7 =3D 0;
+    s->cfg.unk10 =3D 1;
+
+    if (s->cfg.nr_cpus > ARRAY_SIZE(s->cfg.cpu_ids)) {
+        error_setg(errp,
+                   "Failed to create %u CPUs, vmapple machine supports %zu=
 max",
+                   s->cfg.nr_cpus, ARRAY_SIZE(s->cfg.cpu_ids));
+        return;
+    }
+    for (i =3D 0; i < s->cfg.nr_cpus; i++) {
+        s->cfg.cpu_ids[i] =3D i;
+    }
+}
+
+static void vmapple_cfg_init(Object *obj)
+{
+    VMAppleCfgState *s =3D VMAPPLE_CFG(obj);
+
+    memory_region_init_ram(&s->mem, obj, "VMApple Config", VMAPPLE_CFG_SIZ=
E,
+                           &error_fatal);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mem);
+}
+
+static Property vmapple_cfg_properties[] =3D {
+    DEFINE_PROP_UINT32("nr-cpus", VMAppleCfgState, cfg.nr_cpus, 1),
+    DEFINE_PROP_UINT64("ecid", VMAppleCfgState, cfg.ecid, 0),
+    DEFINE_PROP_UINT64("ram-size", VMAppleCfgState, cfg.ram_size, 0),
+    DEFINE_PROP_UINT32("run_installer1", VMAppleCfgState, cfg.run_installe=
r1, 0),
+    DEFINE_PROP_UINT32("run_installer2", VMAppleCfgState, cfg.run_installe=
r2, 0),
+    DEFINE_PROP_UINT32("rnd", VMAppleCfgState, cfg.rnd, 0),
+    DEFINE_PROP_MACADDR("mac-en0", VMAppleCfgState, cfg.mac_en0),
+    DEFINE_PROP_MACADDR("mac-en1", VMAppleCfgState, cfg.mac_en1),
+    DEFINE_PROP_MACADDR("mac-wifi0", VMAppleCfgState, cfg.mac_wifi0),
+    DEFINE_PROP_MACADDR("mac-bt0", VMAppleCfgState, cfg.mac_bt0),
+    DEFINE_PROP_STRING("serial", VMAppleCfgState, serial),
+    DEFINE_PROP_STRING("model", VMAppleCfgState, model),
+    DEFINE_PROP_STRING("soc_name", VMAppleCfgState, soc_name),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmapple_cfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+    ResettableClass *rc =3D RESETTABLE_CLASS(klass);
+
+    dc->realize =3D vmapple_cfg_realize;
+    dc->desc =3D "VMApple Configuration Region";
+    device_class_set_props(dc, vmapple_cfg_properties);
+    rc->phases.hold =3D vmapple_cfg_reset;
+}
+
+static const TypeInfo vmapple_cfg_info =3D {
+    .name          =3D TYPE_VMAPPLE_CFG,
+    .parent        =3D TYPE_SYS_BUS_DEVICE,
+    .instance_size =3D sizeof(VMAppleCfgState),
+    .instance_init =3D vmapple_cfg_init,
+    .class_init    =3D vmapple_cfg_class_init,
+};
+
+static void vmapple_cfg_register_types(void)
+{
+    type_register_static(&vmapple_cfg_info);
+}
+
+type_init(vmapple_cfg_register_types)
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index d4624713deb..64b78693a31 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -1,2 +1,3 @@
 system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('aes.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_CFG',  if_true: files('cfg.c'))
diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
index 9090e9c5ac8..3bba59f5ec7 100644
--- a/include/hw/vmapple/vmapple.h
+++ b/include/hw/vmapple/vmapple.h
@@ -16,4 +16,6 @@
=20
 #define TYPE_VMAPPLE_BDIF "vmapple-bdif"
=20
+#define TYPE_VMAPPLE_CFG "vmapple-cfg"
+
 #endif /* HW_VMAPPLE_VMAPPLE_H */
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103597; cv=none;
	d=zohomail.com; s=zohoarc;
	b=ET22TZL2SNOZ3aG1hAQeLQDDBi9JZ2GN5tV4RPz7sXxyENrx6hSJduPYuzi68ZBamznXe/dzEHILLtzT00KxdXbm4PvJ2y74Z35fmjK1yamAp2I0fLCwRyq5TCEcAvJRbnBAkQCpyzceeO0GwzP3+caukMAHku2pj2SOdoF3YiU=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103597;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=mJRB2wtK4bqp5QasoGeSFB3JeRDBMHdwYrZnWTkgUnQ=;
	b=bTPCMSDarQOP4fnaYq1hZyzoMNvdLG+lVUfx4Jw+4DIV2AGbSjZmsNNnkCguWR8fHP9Ne7tQg7RTIgLrGnygq9Y3lzwA5FaGv3I4opSUmmrdkhr+MA3vuj0GSkRjz6gJ79vLOtf6EjvWVdLNh/zwn3KsP3C+kqClg3ZkpLmHGBk=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103597809862.1654004662141;
 Fri, 13 Dec 2024 07:26:37 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7UO-0001Se-MT; Fri, 13 Dec 2024 10:22:02 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7SG-00051O-Pw
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:49 -0500
Received: from mail-ej1-x634.google.com ([2a00:1450:4864:20::634])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S4-0005QU-Lw
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:48 -0500
Received: by mail-ej1-x634.google.com with SMTP id
 a640c23a62f3a-a9a68480164so304380166b.3
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:33 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.30
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:31 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103172;
 x=1734707972;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=mJRB2wtK4bqp5QasoGeSFB3JeRDBMHdwYrZnWTkgUnQ=;
 b=wjwrjPdmStXeQyyhkR/i2v8kAY8S9F4Dn/SABBWuHqwO7GzK3OPOx2x4fDpLQ72Ejq
 de5bhpwr8jMQUIDYKue9oZpjH2YQz03/TzTDus1RiD/GNM/yr0mVonoUJWLiN3Im69KJ
 gkJmsU+QMuzWpOUI4I1/rNz5WY67rZkS+p16dO61Cn3QnEE1hW4NSRyXOCUM15ReLM3U
 HOfTMAiVPrfUENBD6exWWsbPnEnv0THoMS1TMdcPTisb8N2Y/99TtCZPrDfAn/RgSHVy
 ngbJpVwZfLSvkYCWNb4QH0KFdcHD1XSXo2SpjNFGWKKI/gSix/zibyLKpOgjTKeaRGLi
 fMOA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103172; x=1734707972;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=mJRB2wtK4bqp5QasoGeSFB3JeRDBMHdwYrZnWTkgUnQ=;
 b=X5U/gopEfsFinMUeAbxIaKRW6e+ncAr/KXc3QTj1uYkM6iBbJSSpk6XmrQTaa8xPyz
 WQfFr+x661tETnvaG8yYmWdTh8gTouVOQgJq0QccFGeLZEu5ITlwSZ+tSUfjpCOTIw9f
 CbzSgUBI79dkkXyWaopWCipqEZqw36dN8fIaMpOLkCIocN9I4ZJivnWKrDAGpMhA1cVl
 9Jf5yxCbGsk7fmHLu2zgA5RnIcmAKeZPQOsKshiY7WmbuJbafhDKOz4Pn6zn9mMl5ABS
 pdwCi6wOAfOK60GToZDqLd9GB2KL1DVTQ89AN9HT5SKRbg/sExDY2cyaAKkwl1a7FOIK
 l7YA==
X-Gm-Message-State: AOJu0YwaAR936Bk1Y9ryH3uq0h+DbUu1G77jIuZHaQ4sdER0mR6nMOaW
 3bu9POygHyR0rxGA44eBbM0X5helil1tCcF1MQtmQ+fqejxaBvveATbwd6iVDeEPC5dy+vO9OHW
 NsA==
X-Gm-Gg: ASbGncszRrJ7CYk1qWJ6ZF+flumf3F2EMuK8hXdJQBIXciD5XXHFyV8AwHGa4FNOteE
 bCl1u65eyEKU2YkSbwTXhhyCtxNOdWQCdL0e8rt0P0988rlN9hkvSqBvzH/uYbyKrCAs2mRuBOd
 vf0u94shKAIfpiaND3eaxBHyrGDIRA74AMdACaSjMhKQ15cf1ScGdwUyo+o0Ig8uMQsESg5aPlj
 UPSGf0SdzbclX+SA1xnyOWx1JRF8GrZgOY00lWh6JsoqGXPR+m7g0lLtPi0CAPIGbAmuyPw074R
 4MdR8qIfwpi7edvu4LhCjV8cuvsgYIGk
X-Google-Smtp-Source: 
 AGHT+IHMgYBcBuKEVbfNnqFCdZ/e0tB/tYjiGtfW3xq2l+4ZpX3aTUwWIUnpZ0TVSlu9DT0Gvaj1Ew==
X-Received: by 2002:a17:906:6ad1:b0:aab:9257:248d with SMTP id
 a640c23a62f3a-aab92572532mr33608066b.57.1734103171839;
 Fri, 13 Dec 2024 07:19:31 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 13/15] hw/vmapple/virtio-blk: Add support for apple
 virtio-blk
Date: Fri, 13 Dec 2024 16:18:19 +0100
Message-Id: <20241213151821.65748-30-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::634;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x634.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103600339116600

From: Alexander Graf <graf@amazon.com>

Apple has its own virtio-blk PCI device ID where it deviates from the
official virtio-pci spec slightly: It puts a new "apple type"
field at a static offset in config space and introduces a new barrier
command.

This patch first creates a mechanism for virtio-blk downstream classes to
handle unknown commands. It then creates such a downstream class and a new
vmapple-virtio-blk-pci class which support the additional apple type config
identifier as well as the barrier command.

The 'aux' or 'root' device type are selected using the 'variant' property.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Use recommended object type declaration pattern.
 * Correctly log unimplemented code paths.
 * Most header code moved to .c, type name #defines moved to vmapple.h

v5:

 * Corrected handling of potentially unaligned writes to virtio config area.
 * Simplified passing through device variant type to subobject.

v9:

 * Correctly specify class_size for VMAppleVirtIOBlkClass

v10:

 * Folded v9 patch 16/16 into this one, changing the device type design to
   provide a single device type with a variant property instead of 2 differ=
ent
   subtypes for aux and root volumes.
 * Tidied up error reporting for the variant property.

 hw/block/virtio-blk.c               |  19 ++-
 hw/core/qdev-properties-system.c    |   8 ++
 hw/vmapple/Kconfig                  |   3 +
 hw/vmapple/meson.build              |   1 +
 hw/vmapple/virtio-blk.c             | 205 ++++++++++++++++++++++++++++
 include/hw/pci/pci_ids.h            |   1 +
 include/hw/qdev-properties-system.h |   5 +
 include/hw/virtio/virtio-blk.h      |  12 +-
 include/hw/vmapple/vmapple.h        |   2 +
 qapi/virtio.json                    |  14 ++
 10 files changed, 265 insertions(+), 5 deletions(-)
 create mode 100644 hw/vmapple/virtio-blk.c

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 9166d7974d4..9e8337bb639 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -50,12 +50,12 @@ static void virtio_blk_init_request(VirtIOBlock *s, Vir=
tQueue *vq,
     req->mr_next =3D NULL;
 }
=20
-static void virtio_blk_free_request(VirtIOBlockReq *req)
+void virtio_blk_free_request(VirtIOBlockReq *req)
 {
     g_free(req);
 }
=20
-static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char sta=
tus)
+void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
 {
     VirtIOBlock *s =3D req->dev;
     VirtIODevice *vdev =3D VIRTIO_DEVICE(s);
@@ -966,8 +966,18 @@ static int virtio_blk_handle_request(VirtIOBlockReq *r=
eq, MultiReqBuffer *mrb)
         break;
     }
     default:
-        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
-        virtio_blk_free_request(req);
+    {
+        /*
+         * Give subclasses a chance to handle unknown requests. This way t=
he
+         * class lookup is not in the hot path.
+         */
+        VirtIOBlkClass *vbk =3D VIRTIO_BLK_GET_CLASS(s);
+        if (!vbk->handle_unknown_request ||
+            !vbk->handle_unknown_request(req, mrb, type)) {
+            virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+            virtio_blk_free_request(req);
+        }
+    }
     }
     return 0;
 }
@@ -2044,6 +2054,7 @@ static const TypeInfo virtio_blk_info =3D {
     .instance_size =3D sizeof(VirtIOBlock),
     .instance_init =3D virtio_blk_instance_init,
     .class_init =3D virtio_blk_class_init,
+    .class_size =3D sizeof(VirtIOBlkClass),
 };
=20
 static void virtio_register_types(void)
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-sys=
tem.c
index 22ea1ed3583..32abfc20b31 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -1283,3 +1283,11 @@ const PropertyInfo qdev_prop_iothread_vq_mapping_lis=
t =3D {
     .set =3D set_iothread_vq_mapping_list,
     .release =3D release_iothread_vq_mapping_list,
 };
+
+const PropertyInfo qdev_prop_vmapple_virtio_blk_variant =3D {
+    .name  =3D "VMAppleVirtioBlkVariant",
+    .enum_table  =3D &VMAppleVirtioBlkVariant_lookup,
+    .get   =3D qdev_propinfo_get_enum,
+    .set   =3D qdev_propinfo_set_enum,
+    .set_default_value =3D qdev_propinfo_set_default_value_enum,
+};
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index 8bbeb9a9237..bcd1be63e3c 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -7,3 +7,6 @@ config VMAPPLE_BDIF
 config VMAPPLE_CFG
     bool
=20
+config VMAPPLE_VIRTIO_BLK
+    bool
+
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index 64b78693a31..bf17cf906c9 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -1,3 +1,4 @@
 system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('aes.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_CFG',  if_true: files('cfg.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_VIRTIO_BLK',  if_true: files('virtio-b=
lk.c'))
diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c
new file mode 100644
index 00000000000..9aeb2931922
--- /dev/null
+++ b/hw/vmapple/virtio-blk.c
@@ -0,0 +1,205 @@
+/*
+ * VMApple specific VirtIO Block implementation
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * VMApple uses almost standard VirtIO Block, but with a few key differenc=
es:
+ *
+ *  - Different PCI device/vendor ID
+ *  - An additional "type" identifier to differentiate AUX and Root volumes
+ *  - An additional BARRIER command
+ */
+
+#include "qemu/osdep.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/virtio/virtio-blk.h"
+#include "hw/virtio/virtio-pci.h"
+#include "qemu/bswap.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+
+#define TYPE_VMAPPLE_VIRTIO_BLK  "vmapple-virtio-blk"
+OBJECT_DECLARE_TYPE(VMAppleVirtIOBlk, VMAppleVirtIOBlkClass, VMAPPLE_VIRTI=
O_BLK)
+
+typedef struct VMAppleVirtIOBlkClass {
+    VirtIOBlkClass parent;
+
+    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
+} VMAppleVirtIOBlkClass;
+
+typedef struct VMAppleVirtIOBlk {
+    VirtIOBlock parent_obj;
+
+    uint32_t apple_type;
+} VMAppleVirtIOBlk;
+
+/*
+ * vmapple-virtio-blk-pci: This extends VirtioPCIProxy.
+ */
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleVirtIOBlkPCI, VMAPPLE_VIRTIO_BLK_PCI)
+
+#define VIRTIO_BLK_T_APPLE_BARRIER     0x10000
+
+static bool vmapple_virtio_blk_handle_unknown_request(VirtIOBlockReq *req,
+                                                      MultiReqBuffer *mrb,
+                                                      uint32_t type)
+{
+    switch (type) {
+    case VIRTIO_BLK_T_APPLE_BARRIER:
+        qemu_log_mask(LOG_UNIMP, "%s: Barrier requests are currently no-op=
s\n",
+                      __func__);
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+        virtio_blk_free_request(req);
+        return true;
+    default:
+        return false;
+    }
+}
+
+/*
+ * VMApple virtio-blk uses the same config format as normal virtio, with o=
ne
+ * exception: It adds an "apple type" specififer at the same location that
+ * the spec reserves for max_secure_erase_sectors. Let's hook into the
+ * get_config code path here, run it as usual and then patch in the apple =
type.
+ */
+static void vmapple_virtio_blk_get_config(VirtIODevice *vdev, uint8_t *con=
fig)
+{
+    VMAppleVirtIOBlk *dev =3D VMAPPLE_VIRTIO_BLK(vdev);
+    VMAppleVirtIOBlkClass *vvbk =3D VMAPPLE_VIRTIO_BLK_GET_CLASS(dev);
+    struct virtio_blk_config *blkcfg =3D (struct virtio_blk_config *)confi=
g;
+
+    vvbk->get_config(vdev, config);
+
+    g_assert(dev->parent_obj.config_size >=3D endof(struct virtio_blk_conf=
ig, zoned));
+
+    /* Apple abuses the field for max_secure_erase_sectors as type id */
+    stl_he_p(&blkcfg->max_secure_erase_sectors, dev->apple_type);
+}
+
+static void vmapple_virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+    VirtIOBlkClass *vbk =3D VIRTIO_BLK_CLASS(klass);
+    VirtioDeviceClass *vdc =3D VIRTIO_DEVICE_CLASS(klass);
+    VMAppleVirtIOBlkClass *vvbk =3D VMAPPLE_VIRTIO_BLK_CLASS(klass);
+
+    vbk->handle_unknown_request =3D vmapple_virtio_blk_handle_unknown_requ=
est;
+    vvbk->get_config =3D vdc->get_config;
+    vdc->get_config =3D vmapple_virtio_blk_get_config;
+}
+
+static const TypeInfo vmapple_virtio_blk_info =3D {
+    .name          =3D TYPE_VMAPPLE_VIRTIO_BLK,
+    .parent        =3D TYPE_VIRTIO_BLK,
+    .instance_size =3D sizeof(VMAppleVirtIOBlk),
+    .class_size    =3D sizeof(VMAppleVirtIOBlkClass),
+    .class_init    =3D vmapple_virtio_blk_class_init,
+};
+
+/* PCI Devices */
+
+struct VMAppleVirtIOBlkPCI {
+    VirtIOPCIProxy parent_obj;
+    VMAppleVirtIOBlk vdev;
+    VMAppleVirtioBlkVariant variant;
+};
+
+
+static Property vmapple_virtio_blk_pci_properties[] =3D {
+    DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+                       DEV_NVECTORS_UNSPECIFIED),
+    DEFINE_PROP_VMAPPLE_VIRTIO_BLK_VARIANT("variant", VMAppleVirtIOBlkPCI,=
 variant,
+                                           VM_APPLE_VIRTIO_BLK_VARIANT_UNS=
PECIFIED),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmapple_virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error=
 **errp)
+{
+    ERRP_GUARD();
+    VMAppleVirtIOBlkPCI *dev =3D VMAPPLE_VIRTIO_BLK_PCI(vpci_dev);
+    DeviceState *vdev =3D DEVICE(&dev->vdev);
+    VirtIOBlkConf *conf =3D &dev->vdev.parent_obj.conf;
+
+    if (dev->variant =3D=3D VM_APPLE_VIRTIO_BLK_VARIANT_UNSPECIFIED) {
+        error_setg(errp, "vmapple virtio block device variant unspecified"=
);
+        error_append_hint(errp,
+                          "Variant property must be set to 'aux' or 'root'=
.\n"
+                          "Use a regular virtio-blk-pci device instead whe=
n "
+                          "neither is applicaple.\n");
+        return;
+    }
+
+    if (conf->num_queues =3D=3D VIRTIO_BLK_AUTO_NUM_QUEUES) {
+        conf->num_queues =3D virtio_pci_optimal_num_queues(0);
+    }
+
+    if (vpci_dev->nvectors =3D=3D DEV_NVECTORS_UNSPECIFIED) {
+        vpci_dev->nvectors =3D conf->num_queues + 1;
+    }
+
+    /*
+     * We don't support zones, but we need the additional config space siz=
e.
+     * Let's just expose the feature so the rest of the virtio-blk logic
+     * allocates enough space for us. The guest will ignore zones anyway.
+     */
+    virtio_add_feature(&dev->vdev.parent_obj.host_features, VIRTIO_BLK_F_Z=
ONED);
+    /* Propagate the apple type down to the virtio-blk device */
+    dev->vdev.apple_type =3D dev->variant;
+    /* and spawn the virtio-blk device */
+    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
+
+    /*
+     * The virtio-pci machinery adjusts its vendor/device ID based on whet=
her
+     * we support modern or legacy virtio. Let's patch it back to the Apple
+     * identifiers here.
+     */
+    pci_config_set_vendor_id(vpci_dev->pci_dev.config, PCI_VENDOR_ID_APPLE=
);
+    pci_config_set_device_id(vpci_dev->pci_dev.config,
+                             PCI_DEVICE_ID_APPLE_VIRTIO_BLK);
+}
+
+static void vmapple_virtio_blk_pci_class_init(ObjectClass *klass, void *da=
ta)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+    VirtioPCIClass *k =3D VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k =3D PCI_DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    device_class_set_props(dc, vmapple_virtio_blk_pci_properties);
+    k->realize =3D vmapple_virtio_blk_pci_realize;
+    pcidev_k->vendor_id =3D PCI_VENDOR_ID_APPLE;
+    pcidev_k->device_id =3D PCI_DEVICE_ID_APPLE_VIRTIO_BLK;
+    pcidev_k->revision =3D VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id =3D PCI_CLASS_STORAGE_SCSI;
+}
+
+static void vmapple_virtio_blk_pci_instance_init(Object *obj)
+{
+    VMAppleVirtIOBlkPCI *dev =3D VMAPPLE_VIRTIO_BLK_PCI(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VMAPPLE_VIRTIO_BLK);
+}
+
+static const VirtioPCIDeviceTypeInfo vmapple_virtio_blk_pci_info =3D {
+    .generic_name  =3D TYPE_VMAPPLE_VIRTIO_BLK_PCI,
+    .instance_size =3D sizeof(VMAppleVirtIOBlkPCI),
+    .instance_init =3D vmapple_virtio_blk_pci_instance_init,
+    .class_init    =3D vmapple_virtio_blk_pci_class_init,
+};
+
+static void vmapple_virtio_blk_register_types(void)
+{
+    type_register_static(&vmapple_virtio_blk_info);
+    virtio_pci_types_register(&vmapple_virtio_blk_pci_info);
+}
+
+type_init(vmapple_virtio_blk_register_types)
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index f1a53fea8d6..33e2898be95 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -191,6 +191,7 @@
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
 #define PCI_DEVICE_ID_APPLE_U3_AGP       0x004b
 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC   0x0021
+#define PCI_DEVICE_ID_APPLE_VIRTIO_BLK   0x1a00
=20
 #define PCI_VENDOR_ID_SUN                0x108e
 #define PCI_DEVICE_ID_SUN_EBUS           0x1000
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properti=
es-system.h
index 7ec37f6316c..3631e309690 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -30,6 +30,7 @@ extern const PropertyInfo qdev_prop_pcie_link_speed;
 extern const PropertyInfo qdev_prop_pcie_link_width;
 extern const PropertyInfo qdev_prop_cpus390entitlement;
 extern const PropertyInfo qdev_prop_iothread_vq_mapping_list;
+extern const PropertyInfo qdev_prop_vmapple_virtio_blk_variant;
=20
 #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
     DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
@@ -97,4 +98,8 @@ extern const PropertyInfo qdev_prop_iothread_vq_mapping_l=
ist;
     DEFINE_PROP(_name, _state, _field, qdev_prop_iothread_vq_mapping_list,=
 \
                 IOThreadVirtQueueMappingList *)
=20
+#define DEFINE_PROP_VMAPPLE_VIRTIO_BLK_VARIANT(_n, _s, _f, _d) \
+    DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_vmapple_virtio_blk_varian=
t, \
+                       VMAppleVirtioBlkVariant)
+
 #endif
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 5c14110c4b1..28d5046ea6c 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -24,7 +24,7 @@
 #include "qapi/qapi-types-virtio.h"
=20
 #define TYPE_VIRTIO_BLK "virtio-blk-device"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlock, VIRTIO_BLK)
+OBJECT_DECLARE_TYPE(VirtIOBlock, VirtIOBlkClass, VIRTIO_BLK)
=20
 /* This is the last element of the write scatter-gather list */
 struct virtio_blk_inhdr
@@ -100,6 +100,16 @@ typedef struct MultiReqBuffer {
     bool is_write;
 } MultiReqBuffer;
=20
+typedef struct VirtIOBlkClass {
+    /*< private >*/
+    VirtioDeviceClass parent;
+    /*< public >*/
+    bool (*handle_unknown_request)(VirtIOBlockReq *req, MultiReqBuffer *mr=
b,
+                                   uint32_t type);
+} VirtIOBlkClass;
+
 void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq);
+void virtio_blk_free_request(VirtIOBlockReq *req);
+void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status);
=20
 #endif
diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
index 3bba59f5ec7..9c1ad1bd8c3 100644
--- a/include/hw/vmapple/vmapple.h
+++ b/include/hw/vmapple/vmapple.h
@@ -18,4 +18,6 @@
=20
 #define TYPE_VMAPPLE_CFG "vmapple-cfg"
=20
+#define TYPE_VMAPPLE_VIRTIO_BLK_PCI "vmapple-virtio-blk-pci"
+
 #endif /* HW_VMAPPLE_VMAPPLE_H */
diff --git a/qapi/virtio.json b/qapi/virtio.json
index 2529c2d8b20..d351d2166ef 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -992,3 +992,17 @@
 ##
 { 'enum': 'GranuleMode',
   'data': [ '4k', '8k', '16k', '64k', 'host' ] }
+
+##
+# @VMAppleVirtioBlkVariant:
+#
+# @unspecified: The default, not a valid setting.
+#
+# @root: Block device holding the root volume
+#
+# @aux: Block device holding auxiliary data required for boot
+#
+# Since: 9.2
+##
+{ 'enum': 'VMAppleVirtioBlkVariant',
+  'data': [ 'unspecified', 'root', 'aux' ] }
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103482; cv=none;
	d=zohomail.com; s=zohoarc;
	b=ju/DvoU9qLrOHOYFiSDG1CXGOKHTJnWBLu4CextFoJpKPeHR2djzCGQVmn/fs2On6Vqpkue1mBjPqQ3vpg6/zc5OGBIIZw58P9r2J8d4XmBMs9z0F5W7DGEGGN9ODFmbbaAFaJuotMBxDSCWAYDiG7MYmJtRKcMCSbzpGxAtdFM=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103482;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=mJRB2wtK4bqp5QasoGeSFB3JeRDBMHdwYrZnWTkgUnQ=;
	b=dP+atsCUnNzPyfDufNmJHsltYMN3K0X/O5l/krVI+gP6zgjMc1e0b7c2PTRovv/APiT9ysuRkVDtmkMmNUqYV436EDHgys7agSNstdqFgeXrtTVEGj7XA/QKOxZlozRh17aznCViwtl/EklOdUDQCHsN4pLQb/mZOHh5fq8LjX0=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103482644265.0263328250252;
 Fri, 13 Dec 2024 07:24:42 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7Sp-0006hV-FX; Fri, 13 Dec 2024 10:20:24 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rr-0004cS-DZ
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:25 -0500
Received: from mail-ej1-x635.google.com ([2a00:1450:4864:20::635])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rg-0005Cq-2W
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:23 -0500
Received: by mail-ej1-x635.google.com with SMTP id
 a640c23a62f3a-aa6a618981eso297773466b.3
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:03 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.00
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:01 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103142;
 x=1734707942;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=mJRB2wtK4bqp5QasoGeSFB3JeRDBMHdwYrZnWTkgUnQ=;
 b=srrkIpkvvOwjuylrD8IaTBMQw3y0+iLaAU+Z4IjHC9nHPZCGBYJpPn3jmL4vbC4UZv
 cej1al6549/uS+pAWORiclrPkBmxEn8cT+sXRGAccO0CNFlLDsdqp/PDyiWE9/MQJnF1
 3GbicJweNwltC0kT1Ge2rVu9VbwlletpKuEteKEtosFbWLuMotVcr/kPVdKpfCUd4heD
 OgDEid6MqZRNoF/kZ35rcXqZCo79fvDMn1YEHnBnXQ/BOe6hFsd740PVOL5O0h8UyDRh
 FQS34UmItHxWGFo8AW5nz6Xcji8QcL5oV2mFpTqsxckAT+Xom51dMEUPAhuhlVVkcXMW
 U/Vw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103142; x=1734707942;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=mJRB2wtK4bqp5QasoGeSFB3JeRDBMHdwYrZnWTkgUnQ=;
 b=Y5VdOYJxyS9K5R/xcrdqVh1bJq33QLmWz/I15Oz2sRkKxcoa7i5bqlvG5y8Sc2ZOSH
 EfsSRG1aTmv+eYKenfSLIDc2f50p9I794PS0xxZc77hQjgWiOLeyebiK5dxsTsKlMnE3
 aA1jdFF/Bj3Gud7sbQlzjwlMyS+1QF/krvQ+U4AUxZuYjpQJMbkhO4WMDnqEExRn92Eo
 QVGtEv/ATnEPgDKJtHYVRW6ZDWne2zc5DKlsJ46Hg0rLKs/iUkZEhFlJf+MkTgSuzH2P
 DWW5qEm14f3z8IsdOFg7hiAMrIfkO9O0ARFD8zQc4aJnvsK8IC9sHu0AZnbtRHCt8zh9
 M0eA==
X-Gm-Message-State: AOJu0YymlxnhVnMkNzGfWrHWTrmMNMWw6X7woZmKRpEdPFb/P52xOpFY
 EHKmixGod26Hr5psVn33/5Wz3LgBzNHvFRsRrRp94wVgNyuCMWRXrLNJeT3i9/YhHIevVKAfExk
 6Ag==
X-Gm-Gg: ASbGncsLkdz9eFULj5rt84qBTyPsuA4UC7ti+1fNra0xYhjO3d1sezBTmpGBbUZ0leJ
 eqnfM/pxriK32LZy2ZBwRp6ZuWrndMZSf0J1oV14+0fjemJc/eHZ187YpK8WAjhzbaAFPQAoutC
 5F7L7Pj5YPaxEYogoVS/U2p0yzJgcJBZgUpdU60yqGnO1EskCyuQRM/lsgyAhfPpreP/GXr7+qG
 29YL9hgleVyAekhMhu7H7jEcrm9FCTdhW8Uk8NMGQkfNxkbe3koMamnXHkYAyXjnDMDHPR/6rq4
 30jaa/hSin6XMUgr1hZeAO17CSLZcv/f
X-Google-Smtp-Source: 
 AGHT+IEr+DWxu4jsKoydg8YBKks0/RMn5rINRatDZIQbdqKvkMWlVvBLhw1Kw2m0NCj78VsDY5jkZQ==
X-Received: by 2002:a17:907:3faa:b0:aa6:75d3:7d2d with SMTP id
 a640c23a62f3a-aab77e7c615mr299403666b.40.1734103141975;
 Fri, 13 Dec 2024 07:19:01 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 13/15] hw/vmapple/virtio-blk: Add support for apple
 virtio-blk
Date: Fri, 13 Dec 2024 16:18:03 +0100
Message-Id: <20241213151821.65748-14-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::635;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x635.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103483638116600

From: Alexander Graf <graf@amazon.com>

Apple has its own virtio-blk PCI device ID where it deviates from the
official virtio-pci spec slightly: It puts a new "apple type"
field at a static offset in config space and introduces a new barrier
command.

This patch first creates a mechanism for virtio-blk downstream classes to
handle unknown commands. It then creates such a downstream class and a new
vmapple-virtio-blk-pci class which support the additional apple type config
identifier as well as the barrier command.

The 'aux' or 'root' device type are selected using the 'variant' property.

Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v4:

 * Use recommended object type declaration pattern.
 * Correctly log unimplemented code paths.
 * Most header code moved to .c, type name #defines moved to vmapple.h

v5:

 * Corrected handling of potentially unaligned writes to virtio config area.
 * Simplified passing through device variant type to subobject.

v9:

 * Correctly specify class_size for VMAppleVirtIOBlkClass

v10:

 * Folded v9 patch 16/16 into this one, changing the device type design to
   provide a single device type with a variant property instead of 2 differ=
ent
   subtypes for aux and root volumes.
 * Tidied up error reporting for the variant property.

 hw/block/virtio-blk.c               |  19 ++-
 hw/core/qdev-properties-system.c    |   8 ++
 hw/vmapple/Kconfig                  |   3 +
 hw/vmapple/meson.build              |   1 +
 hw/vmapple/virtio-blk.c             | 205 ++++++++++++++++++++++++++++
 include/hw/pci/pci_ids.h            |   1 +
 include/hw/qdev-properties-system.h |   5 +
 include/hw/virtio/virtio-blk.h      |  12 +-
 include/hw/vmapple/vmapple.h        |   2 +
 qapi/virtio.json                    |  14 ++
 10 files changed, 265 insertions(+), 5 deletions(-)
 create mode 100644 hw/vmapple/virtio-blk.c

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 9166d7974d4..9e8337bb639 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -50,12 +50,12 @@ static void virtio_blk_init_request(VirtIOBlock *s, Vir=
tQueue *vq,
     req->mr_next =3D NULL;
 }
=20
-static void virtio_blk_free_request(VirtIOBlockReq *req)
+void virtio_blk_free_request(VirtIOBlockReq *req)
 {
     g_free(req);
 }
=20
-static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char sta=
tus)
+void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
 {
     VirtIOBlock *s =3D req->dev;
     VirtIODevice *vdev =3D VIRTIO_DEVICE(s);
@@ -966,8 +966,18 @@ static int virtio_blk_handle_request(VirtIOBlockReq *r=
eq, MultiReqBuffer *mrb)
         break;
     }
     default:
-        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
-        virtio_blk_free_request(req);
+    {
+        /*
+         * Give subclasses a chance to handle unknown requests. This way t=
he
+         * class lookup is not in the hot path.
+         */
+        VirtIOBlkClass *vbk =3D VIRTIO_BLK_GET_CLASS(s);
+        if (!vbk->handle_unknown_request ||
+            !vbk->handle_unknown_request(req, mrb, type)) {
+            virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+            virtio_blk_free_request(req);
+        }
+    }
     }
     return 0;
 }
@@ -2044,6 +2054,7 @@ static const TypeInfo virtio_blk_info =3D {
     .instance_size =3D sizeof(VirtIOBlock),
     .instance_init =3D virtio_blk_instance_init,
     .class_init =3D virtio_blk_class_init,
+    .class_size =3D sizeof(VirtIOBlkClass),
 };
=20
 static void virtio_register_types(void)
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-sys=
tem.c
index 22ea1ed3583..32abfc20b31 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -1283,3 +1283,11 @@ const PropertyInfo qdev_prop_iothread_vq_mapping_lis=
t =3D {
     .set =3D set_iothread_vq_mapping_list,
     .release =3D release_iothread_vq_mapping_list,
 };
+
+const PropertyInfo qdev_prop_vmapple_virtio_blk_variant =3D {
+    .name  =3D "VMAppleVirtioBlkVariant",
+    .enum_table  =3D &VMAppleVirtioBlkVariant_lookup,
+    .get   =3D qdev_propinfo_get_enum,
+    .set   =3D qdev_propinfo_set_enum,
+    .set_default_value =3D qdev_propinfo_set_default_value_enum,
+};
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index 8bbeb9a9237..bcd1be63e3c 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -7,3 +7,6 @@ config VMAPPLE_BDIF
 config VMAPPLE_CFG
     bool
=20
+config VMAPPLE_VIRTIO_BLK
+    bool
+
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index 64b78693a31..bf17cf906c9 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -1,3 +1,4 @@
 system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('aes.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_CFG',  if_true: files('cfg.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_VIRTIO_BLK',  if_true: files('virtio-b=
lk.c'))
diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c
new file mode 100644
index 00000000000..9aeb2931922
--- /dev/null
+++ b/hw/vmapple/virtio-blk.c
@@ -0,0 +1,205 @@
+/*
+ * VMApple specific VirtIO Block implementation
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * VMApple uses almost standard VirtIO Block, but with a few key differenc=
es:
+ *
+ *  - Different PCI device/vendor ID
+ *  - An additional "type" identifier to differentiate AUX and Root volumes
+ *  - An additional BARRIER command
+ */
+
+#include "qemu/osdep.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/virtio/virtio-blk.h"
+#include "hw/virtio/virtio-pci.h"
+#include "qemu/bswap.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+
+#define TYPE_VMAPPLE_VIRTIO_BLK  "vmapple-virtio-blk"
+OBJECT_DECLARE_TYPE(VMAppleVirtIOBlk, VMAppleVirtIOBlkClass, VMAPPLE_VIRTI=
O_BLK)
+
+typedef struct VMAppleVirtIOBlkClass {
+    VirtIOBlkClass parent;
+
+    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
+} VMAppleVirtIOBlkClass;
+
+typedef struct VMAppleVirtIOBlk {
+    VirtIOBlock parent_obj;
+
+    uint32_t apple_type;
+} VMAppleVirtIOBlk;
+
+/*
+ * vmapple-virtio-blk-pci: This extends VirtioPCIProxy.
+ */
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleVirtIOBlkPCI, VMAPPLE_VIRTIO_BLK_PCI)
+
+#define VIRTIO_BLK_T_APPLE_BARRIER     0x10000
+
+static bool vmapple_virtio_blk_handle_unknown_request(VirtIOBlockReq *req,
+                                                      MultiReqBuffer *mrb,
+                                                      uint32_t type)
+{
+    switch (type) {
+    case VIRTIO_BLK_T_APPLE_BARRIER:
+        qemu_log_mask(LOG_UNIMP, "%s: Barrier requests are currently no-op=
s\n",
+                      __func__);
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+        virtio_blk_free_request(req);
+        return true;
+    default:
+        return false;
+    }
+}
+
+/*
+ * VMApple virtio-blk uses the same config format as normal virtio, with o=
ne
+ * exception: It adds an "apple type" specififer at the same location that
+ * the spec reserves for max_secure_erase_sectors. Let's hook into the
+ * get_config code path here, run it as usual and then patch in the apple =
type.
+ */
+static void vmapple_virtio_blk_get_config(VirtIODevice *vdev, uint8_t *con=
fig)
+{
+    VMAppleVirtIOBlk *dev =3D VMAPPLE_VIRTIO_BLK(vdev);
+    VMAppleVirtIOBlkClass *vvbk =3D VMAPPLE_VIRTIO_BLK_GET_CLASS(dev);
+    struct virtio_blk_config *blkcfg =3D (struct virtio_blk_config *)confi=
g;
+
+    vvbk->get_config(vdev, config);
+
+    g_assert(dev->parent_obj.config_size >=3D endof(struct virtio_blk_conf=
ig, zoned));
+
+    /* Apple abuses the field for max_secure_erase_sectors as type id */
+    stl_he_p(&blkcfg->max_secure_erase_sectors, dev->apple_type);
+}
+
+static void vmapple_virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+    VirtIOBlkClass *vbk =3D VIRTIO_BLK_CLASS(klass);
+    VirtioDeviceClass *vdc =3D VIRTIO_DEVICE_CLASS(klass);
+    VMAppleVirtIOBlkClass *vvbk =3D VMAPPLE_VIRTIO_BLK_CLASS(klass);
+
+    vbk->handle_unknown_request =3D vmapple_virtio_blk_handle_unknown_requ=
est;
+    vvbk->get_config =3D vdc->get_config;
+    vdc->get_config =3D vmapple_virtio_blk_get_config;
+}
+
+static const TypeInfo vmapple_virtio_blk_info =3D {
+    .name          =3D TYPE_VMAPPLE_VIRTIO_BLK,
+    .parent        =3D TYPE_VIRTIO_BLK,
+    .instance_size =3D sizeof(VMAppleVirtIOBlk),
+    .class_size    =3D sizeof(VMAppleVirtIOBlkClass),
+    .class_init    =3D vmapple_virtio_blk_class_init,
+};
+
+/* PCI Devices */
+
+struct VMAppleVirtIOBlkPCI {
+    VirtIOPCIProxy parent_obj;
+    VMAppleVirtIOBlk vdev;
+    VMAppleVirtioBlkVariant variant;
+};
+
+
+static Property vmapple_virtio_blk_pci_properties[] =3D {
+    DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+                       DEV_NVECTORS_UNSPECIFIED),
+    DEFINE_PROP_VMAPPLE_VIRTIO_BLK_VARIANT("variant", VMAppleVirtIOBlkPCI,=
 variant,
+                                           VM_APPLE_VIRTIO_BLK_VARIANT_UNS=
PECIFIED),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmapple_virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error=
 **errp)
+{
+    ERRP_GUARD();
+    VMAppleVirtIOBlkPCI *dev =3D VMAPPLE_VIRTIO_BLK_PCI(vpci_dev);
+    DeviceState *vdev =3D DEVICE(&dev->vdev);
+    VirtIOBlkConf *conf =3D &dev->vdev.parent_obj.conf;
+
+    if (dev->variant =3D=3D VM_APPLE_VIRTIO_BLK_VARIANT_UNSPECIFIED) {
+        error_setg(errp, "vmapple virtio block device variant unspecified"=
);
+        error_append_hint(errp,
+                          "Variant property must be set to 'aux' or 'root'=
.\n"
+                          "Use a regular virtio-blk-pci device instead whe=
n "
+                          "neither is applicaple.\n");
+        return;
+    }
+
+    if (conf->num_queues =3D=3D VIRTIO_BLK_AUTO_NUM_QUEUES) {
+        conf->num_queues =3D virtio_pci_optimal_num_queues(0);
+    }
+
+    if (vpci_dev->nvectors =3D=3D DEV_NVECTORS_UNSPECIFIED) {
+        vpci_dev->nvectors =3D conf->num_queues + 1;
+    }
+
+    /*
+     * We don't support zones, but we need the additional config space siz=
e.
+     * Let's just expose the feature so the rest of the virtio-blk logic
+     * allocates enough space for us. The guest will ignore zones anyway.
+     */
+    virtio_add_feature(&dev->vdev.parent_obj.host_features, VIRTIO_BLK_F_Z=
ONED);
+    /* Propagate the apple type down to the virtio-blk device */
+    dev->vdev.apple_type =3D dev->variant;
+    /* and spawn the virtio-blk device */
+    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
+
+    /*
+     * The virtio-pci machinery adjusts its vendor/device ID based on whet=
her
+     * we support modern or legacy virtio. Let's patch it back to the Apple
+     * identifiers here.
+     */
+    pci_config_set_vendor_id(vpci_dev->pci_dev.config, PCI_VENDOR_ID_APPLE=
);
+    pci_config_set_device_id(vpci_dev->pci_dev.config,
+                             PCI_DEVICE_ID_APPLE_VIRTIO_BLK);
+}
+
+static void vmapple_virtio_blk_pci_class_init(ObjectClass *klass, void *da=
ta)
+{
+    DeviceClass *dc =3D DEVICE_CLASS(klass);
+    VirtioPCIClass *k =3D VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k =3D PCI_DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    device_class_set_props(dc, vmapple_virtio_blk_pci_properties);
+    k->realize =3D vmapple_virtio_blk_pci_realize;
+    pcidev_k->vendor_id =3D PCI_VENDOR_ID_APPLE;
+    pcidev_k->device_id =3D PCI_DEVICE_ID_APPLE_VIRTIO_BLK;
+    pcidev_k->revision =3D VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id =3D PCI_CLASS_STORAGE_SCSI;
+}
+
+static void vmapple_virtio_blk_pci_instance_init(Object *obj)
+{
+    VMAppleVirtIOBlkPCI *dev =3D VMAPPLE_VIRTIO_BLK_PCI(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VMAPPLE_VIRTIO_BLK);
+}
+
+static const VirtioPCIDeviceTypeInfo vmapple_virtio_blk_pci_info =3D {
+    .generic_name  =3D TYPE_VMAPPLE_VIRTIO_BLK_PCI,
+    .instance_size =3D sizeof(VMAppleVirtIOBlkPCI),
+    .instance_init =3D vmapple_virtio_blk_pci_instance_init,
+    .class_init    =3D vmapple_virtio_blk_pci_class_init,
+};
+
+static void vmapple_virtio_blk_register_types(void)
+{
+    type_register_static(&vmapple_virtio_blk_info);
+    virtio_pci_types_register(&vmapple_virtio_blk_pci_info);
+}
+
+type_init(vmapple_virtio_blk_register_types)
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index f1a53fea8d6..33e2898be95 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -191,6 +191,7 @@
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
 #define PCI_DEVICE_ID_APPLE_U3_AGP       0x004b
 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC   0x0021
+#define PCI_DEVICE_ID_APPLE_VIRTIO_BLK   0x1a00
=20
 #define PCI_VENDOR_ID_SUN                0x108e
 #define PCI_DEVICE_ID_SUN_EBUS           0x1000
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properti=
es-system.h
index 7ec37f6316c..3631e309690 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -30,6 +30,7 @@ extern const PropertyInfo qdev_prop_pcie_link_speed;
 extern const PropertyInfo qdev_prop_pcie_link_width;
 extern const PropertyInfo qdev_prop_cpus390entitlement;
 extern const PropertyInfo qdev_prop_iothread_vq_mapping_list;
+extern const PropertyInfo qdev_prop_vmapple_virtio_blk_variant;
=20
 #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
     DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
@@ -97,4 +98,8 @@ extern const PropertyInfo qdev_prop_iothread_vq_mapping_l=
ist;
     DEFINE_PROP(_name, _state, _field, qdev_prop_iothread_vq_mapping_list,=
 \
                 IOThreadVirtQueueMappingList *)
=20
+#define DEFINE_PROP_VMAPPLE_VIRTIO_BLK_VARIANT(_n, _s, _f, _d) \
+    DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_vmapple_virtio_blk_varian=
t, \
+                       VMAppleVirtioBlkVariant)
+
 #endif
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 5c14110c4b1..28d5046ea6c 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -24,7 +24,7 @@
 #include "qapi/qapi-types-virtio.h"
=20
 #define TYPE_VIRTIO_BLK "virtio-blk-device"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlock, VIRTIO_BLK)
+OBJECT_DECLARE_TYPE(VirtIOBlock, VirtIOBlkClass, VIRTIO_BLK)
=20
 /* This is the last element of the write scatter-gather list */
 struct virtio_blk_inhdr
@@ -100,6 +100,16 @@ typedef struct MultiReqBuffer {
     bool is_write;
 } MultiReqBuffer;
=20
+typedef struct VirtIOBlkClass {
+    /*< private >*/
+    VirtioDeviceClass parent;
+    /*< public >*/
+    bool (*handle_unknown_request)(VirtIOBlockReq *req, MultiReqBuffer *mr=
b,
+                                   uint32_t type);
+} VirtIOBlkClass;
+
 void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq);
+void virtio_blk_free_request(VirtIOBlockReq *req);
+void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status);
=20
 #endif
diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
index 3bba59f5ec7..9c1ad1bd8c3 100644
--- a/include/hw/vmapple/vmapple.h
+++ b/include/hw/vmapple/vmapple.h
@@ -18,4 +18,6 @@
=20
 #define TYPE_VMAPPLE_CFG "vmapple-cfg"
=20
+#define TYPE_VMAPPLE_VIRTIO_BLK_PCI "vmapple-virtio-blk-pci"
+
 #endif /* HW_VMAPPLE_VMAPPLE_H */
diff --git a/qapi/virtio.json b/qapi/virtio.json
index 2529c2d8b20..d351d2166ef 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -992,3 +992,17 @@
 ##
 { 'enum': 'GranuleMode',
   'data': [ '4k', '8k', '16k', '64k', 'host' ] }
+
+##
+# @VMAppleVirtioBlkVariant:
+#
+# @unspecified: The default, not a valid setting.
+#
+# @root: Block device holding the root volume
+#
+# @aux: Block device holding auxiliary data required for boot
+#
+# Since: 9.2
+##
+{ 'enum': 'VMAppleVirtioBlkVariant',
+  'data': [ 'unspecified', 'root', 'aux' ] }
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103682; cv=none;
	d=zohomail.com; s=zohoarc;
	b=V+FgnIFrpQva5EeDP9UvaVPFhXoKOxCyjsgPKf/qCYW1FPhm0xLOcNhztl2EI2br2EdLghObSmeaRpvcjHzDqmnfEFCNpxlFOJIRlxipn9H80UKcgcPEX+vbw5+jGyNG+gDXrk4B82kgbspu2YRgjPdgJFDflq0jNVilN/9QCnE=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103682;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=wSBpg2hYj8CiNrxPOnsHHRCwOt6RUqezuji7AZqApGE=;
	b=FyWlwIVTnchFxCpM7pBfrTZsDdr7hvLTlpkQXCvaYh8orN+IMENwzCzGuhePtww9slapqT7ew4iHL6ikpa9cxXi8LxtX7Dzm1XWSJ32yK37g+G33IV4F2eCfdbBj8DCrreeGXxlleMCL+hAT618iR9DIJeNRAf+dTLbExIz2EXU=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 173410368261272.522604972061;
 Fri, 13 Dec 2024 07:28:02 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7TH-0007mQ-CU; Fri, 13 Dec 2024 10:20:51 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7SE-0004yH-0q
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:46 -0500
Received: from mail-ej1-x62d.google.com ([2a00:1450:4864:20::62d])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S3-0005RF-8C
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:45 -0500
Received: by mail-ej1-x62d.google.com with SMTP id
 a640c23a62f3a-aa6a3c42400so318726266b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:34 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.32
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:33 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103174;
 x=1734707974;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=wSBpg2hYj8CiNrxPOnsHHRCwOt6RUqezuji7AZqApGE=;
 b=ppGMd1pNcd+4In8fw5V90RZS1+9CXZ50L0ZMiDiF9gMvywyPk2+EJ2gQT/lM1q2tdd
 PBn+U2YYhSBTFQXVhoZjfBw7k8c8CyrgpbX9mVfmQaOVmhTu9EV92T2NbhAjGHnM5bpX
 Lrha0Az02PpFh1nsGA05LQeGA5ik41WX2IvHa5ZUilWhZrYz4azaui/FMq9zFCe+ba2S
 71YTCqm6pWrXua4P3rlcMyPJ08W3dt4jLK0WwHGsBIjbur76E0Q0KxjZyXpoG7iy3dmT
 LVnQe0mKNIA9GT0kCop3TvqwKLNLPvsHPe8CVCpUpAIN9o7Le2PtAlmD/h55c2RmPXkG
 xEJA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103174; x=1734707974;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=wSBpg2hYj8CiNrxPOnsHHRCwOt6RUqezuji7AZqApGE=;
 b=drj0IJK+YgosAFhoUVeXuja/ZKyDynJqH68qPPxBmyhvKUQ1FjML/xvXLh3ajBY3wJ
 LZgK4UOGUhymcbO9b/q9QzcmxURzpft/rFRs2pUojFw2bEglF8MkZS+T18lrXqzVU7nG
 GDpL4qg1g/sY4W4eoWkgzVvgBq7YzQXvg8ltbFgpsx7T1p7qOn1XlSE9+IBgFY94mDAL
 bLnLg6S9smRlnQt5/QZglwhsCsi/Ei0jhah28Qej/z3vx4kY/bqjUIBFG6VjXXu1w0N7
 xxffIUBcJainZOHBkdBVyFMuIFE7L8xG1aPzshrcibMZs9esToWtTXS1Dh09J5v9uOno
 9UBQ==
X-Gm-Message-State: AOJu0YyMg1LRCwqV4wZ4UjPLHG8Rvsd/NHBsqiKIVTIbOuWJYUJMZN8n
 W3B+UdGFnZW0yfIFCDslmX6D5BKbotOYnwdiM/GneNlN5cGT+5QoBTuIghae4v9QjBe/zUYhKuj
 hHw==
X-Gm-Gg: ASbGncs7QYTio4kY92gpfHSFN3/8anjfeuAzauO5K1hTyiSoAVHxtSbEU5UNGTq8UQk
 SqumRERZk/0v2HZq7Xiz+Ofy78rJfUIbLXe0F3Q+omfz6F6TqLXuLwW404IWRWjWyFBBSzmaDyx
 kZZ9W+N0lAZlUw/pa2Gb5UMVXs2DX318Yel1dbMjKqCqD92ymu3raA5tEroczAv2mjvx//Ng93a
 CUK1pwrUqe5c8F6KI9kx9OHe+/DQ3ZYoqtTu7AwtUtm95lEx+6PoORpN7AJiAyGaUm+SruFCosr
 KruLzPA9o4FbYXhuPvLoAs9yU2SE5OBb
X-Google-Smtp-Source: 
 AGHT+IH3vPN8OrY/FjyTEENdPORXBL2scMFbSqkuqSFCNID3xOwjVcWxaenO+1nw38CLmHESwk7LWA==
X-Received: by 2002:a17:907:3f20:b0:aa6:ad4c:7d55 with SMTP id
 a640c23a62f3a-aa6c415fa8fmr841195766b.14.1734103173633;
 Fri, 13 Dec 2024 07:19:33 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu
Subject: [PATCH v14 14/15] hw/block/virtio-blk: Replaces request free function
 with g_free
Date: Fri, 13 Dec 2024 16:18:20 +0100
Message-Id: <20241213151821.65748-31-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62d;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62d.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103684493116600
Content-Type: text/plain; charset="utf-8"

The virtio_blk_free_request() function has been a 1-liner forwarding
to g_free() for a while now. We may as well call g_free on the request
pointer directly.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/block/virtio-blk.c          | 43 +++++++++++++++-------------------
 hw/vmapple/virtio-blk.c        |  2 +-
 include/hw/virtio/virtio-blk.h |  1 -
 3 files changed, 20 insertions(+), 26 deletions(-)

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 9e8337bb639..40d2c9bc591 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -50,11 +50,6 @@ static void virtio_blk_init_request(VirtIOBlock *s, Virt=
Queue *vq,
     req->mr_next =3D NULL;
 }
=20
-void virtio_blk_free_request(VirtIOBlockReq *req)
-{
-    g_free(req);
-}
-
 void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
 {
     VirtIOBlock *s =3D req->dev;
@@ -93,7 +88,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req=
, int error,
         if (acct_failed) {
             block_acct_failed(blk_get_stats(s->blk), &req->acct);
         }
-        virtio_blk_free_request(req);
+        g_free(req);
     }
=20
     blk_error_action(s->blk, action, is_read, error);
@@ -136,7 +131,7 @@ static void virtio_blk_rw_complete(void *opaque, int re=
t)
=20
         virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
         block_acct_done(blk_get_stats(s->blk), &req->acct);
-        virtio_blk_free_request(req);
+        g_free(req);
     }
 }
=20
@@ -151,7 +146,7 @@ static void virtio_blk_flush_complete(void *opaque, int=
 ret)
=20
     virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
     block_acct_done(blk_get_stats(s->blk), &req->acct);
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret)
@@ -169,7 +164,7 @@ static void virtio_blk_discard_write_zeroes_complete(vo=
id *opaque, int ret)
     if (is_write_zeroes) {
         block_acct_done(blk_get_stats(s->blk), &req->acct);
     }
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s, VirtQueue *v=
q)
@@ -214,7 +209,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
=20
 fail:
     virtio_blk_req_complete(req, status);
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static inline void submit_requests(VirtIOBlock *s, MultiReqBuffer *mrb,
@@ -612,7 +607,7 @@ static void virtio_blk_zone_report_complete(void *opaqu=
e, int ret)
=20
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
     g_free(data->zone_report_data.zones);
     g_free(data);
 }
@@ -661,7 +656,7 @@ static void virtio_blk_handle_zone_report(VirtIOBlockRe=
q *req,
     return;
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static void virtio_blk_zone_mgmt_complete(void *opaque, int ret)
@@ -677,7 +672,7 @@ static void virtio_blk_zone_mgmt_complete(void *opaque,=
 int ret)
     }
=20
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op)
@@ -719,7 +714,7 @@ static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *=
req, BlockZoneOp op)
     return 0;
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
     return err_status;
 }
=20
@@ -750,7 +745,7 @@ static void virtio_blk_zone_append_complete(void *opaqu=
e, int ret)
=20
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
     g_free(data);
 }
=20
@@ -788,7 +783,7 @@ static int virtio_blk_handle_zone_append(VirtIOBlockReq=
 *req,
=20
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
     return err_status;
 }
=20
@@ -855,7 +850,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
             virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
             block_acct_invalid(blk_get_stats(s->blk),
                                is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_RE=
AD);
-            virtio_blk_free_request(req);
+            g_free(req);
             return 0;
         }
=20
@@ -911,7 +906,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
                               VIRTIO_BLK_ID_BYTES));
         iov_from_buf(in_iov, in_num, 0, serial, size);
         virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-        virtio_blk_free_request(req);
+        g_free(req);
         break;
     }
     case VIRTIO_BLK_T_ZONE_APPEND & ~VIRTIO_BLK_T_OUT:
@@ -943,7 +938,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
         if (unlikely(!(type & VIRTIO_BLK_T_OUT) ||
                      out_len > sizeof(dwz_hdr))) {
             virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
-            virtio_blk_free_request(req);
+            g_free(req);
             return 0;
         }
=20
@@ -960,7 +955,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
                                                             is_write_zeroe=
s);
         if (err_status !=3D VIRTIO_BLK_S_OK) {
             virtio_blk_req_complete(req, err_status);
-            virtio_blk_free_request(req);
+            g_free(req);
         }
=20
         break;
@@ -975,7 +970,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
         if (!vbk->handle_unknown_request ||
             !vbk->handle_unknown_request(req, mrb, type)) {
             virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
-            virtio_blk_free_request(req);
+            g_free(req);
         }
     }
     }
@@ -998,7 +993,7 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
         while ((req =3D virtio_blk_get_request(s, vq))) {
             if (virtio_blk_handle_request(req, &mrb)) {
                 virtqueue_detach_element(req->vq, &req->elem, 0);
-                virtio_blk_free_request(req);
+                g_free(req);
                 break;
             }
         }
@@ -1048,7 +1043,7 @@ static void virtio_blk_dma_restart_bh(void *opaque)
             while (req) {
                 next =3D req->next;
                 virtqueue_detach_element(req->vq, &req->elem, 0);
-                virtio_blk_free_request(req);
+                g_free(req);
                 req =3D next;
             }
             break;
@@ -1131,7 +1126,7 @@ static void virtio_blk_reset(VirtIODevice *vdev)
             /* No other threads can access req->vq here */
             virtqueue_detach_element(req->vq, &req->elem, 0);
=20
-            virtio_blk_free_request(req);
+            g_free(req);
         }
     }
=20
diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c
index 9aeb2931922..52d857166bd 100644
--- a/hw/vmapple/virtio-blk.c
+++ b/hw/vmapple/virtio-blk.c
@@ -55,7 +55,7 @@ static bool vmapple_virtio_blk_handle_unknown_request(Vir=
tIOBlockReq *req,
         qemu_log_mask(LOG_UNIMP, "%s: Barrier requests are currently no-op=
s\n",
                       __func__);
         virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-        virtio_blk_free_request(req);
+        g_free(req);
         return true;
     default:
         return false;
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 28d5046ea6c..dcb2c89aed5 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -109,7 +109,6 @@ typedef struct VirtIOBlkClass {
 } VirtIOBlkClass;
=20
 void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq);
-void virtio_blk_free_request(VirtIOBlockReq *req);
 void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status);
=20
 #endif
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103660; cv=none;
	d=zohomail.com; s=zohoarc;
	b=dk+kbcibd09dbiwsnu2Sig0qbXcR54vaEPdSqlzIn6NU3qcJJl0KlEwD0S63ibnDnSiHU0oI+Ujgl/CtiyBvEagy/smxP/1yv4pJ76pGt3F3kH7hG/Dm8XukV9krGj9HMeMY44+MyXSyvo53IMEezS174h26QabBHoVayVac+pg=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103660;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=wSBpg2hYj8CiNrxPOnsHHRCwOt6RUqezuji7AZqApGE=;
	b=PL5s7HuGYDOXO5G6foHIct7hr/MHvxDJ4uiLB3cGqrucy1kTs/EzELy9lCWianIBBhf/D52qKX5DlS32RIJNKSIP49Dh0OaY8acQILnPHVMtYm9b/XlScFwvO+U3tLGbQTxOzHaC5KZmi5BKcBefWf8/HLfz9g/uncqpEtAwb8s=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103660424795.7889046472676;
 Fri, 13 Dec 2024 07:27:40 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SM-00058s-MG; Fri, 13 Dec 2024 10:19:54 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rg-0004T9-B1
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:13 -0500
Received: from mail-ej1-x62d.google.com ([2a00:1450:4864:20::62d])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Ra-0005DF-Tw
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:11 -0500
Received: by mail-ej1-x62d.google.com with SMTP id
 a640c23a62f3a-aa67ac42819so308655466b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:05 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.02
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:03 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103144;
 x=1734707944;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=wSBpg2hYj8CiNrxPOnsHHRCwOt6RUqezuji7AZqApGE=;
 b=jcEcem4QGlTFLPrhGuAilUGq2sKXMa97vQStws2mFMmdsTihfpcuQv57+1yMuGkXCa
 iL4jmUhcWDFVbetcbh+zDA3yDSROaqKfbQ5HEig+IZV3f1sVSDvMicic+sVwMgz++2Ne
 gq5G7SNRpcpZ7psZlnZBGhuDRZck5XbSsf2nhXponbWwK7Fhq+uw2hVdujD/2Fam037v
 mWdbUsWCfuojFrnlCeOAeDaSn7W5+BoPfNEFbt0ZhhaCuS0negQwoYQXs0z6CKI9tNk+
 nJUWlt+k8DdkDXGEU9a0jPXFs0ipPxV9Nvr+/QYgKOL1QOXU5oinJ8ekx42MhlIKcCfc
 GpNw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103144; x=1734707944;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=wSBpg2hYj8CiNrxPOnsHHRCwOt6RUqezuji7AZqApGE=;
 b=CpEpbywdF8isMrk2arWfJ1p4GsQm+KKqDnjpgbWP3rGQRy4qgpKkOVz522AasEEQrO
 OWgIM7oGqshCHx6mIbYuiQsV2ZrRb5vdXF5ya2Ni6uyVQm0ciO9lVW2+Ru1HLhzCw1yS
 BTSlJ1advFdvDrhytHCo8os0Tj8RMr6fN9s4y13pXMel1jHbX8sbGEgcZ9qzW/iGtxvd
 QLAhclarhjP2S/ECcr24bayXyKemB+XrW5/5YkzrgXPlDorbOb9dYqwKuqQ0pb+JTzqD
 vaeeAZbx+Jzs4A0DcZWhwLXofRJRYr0Wfc+wJX9W0SLmMy1anZBJkaSyEKMjcxnUNTIV
 nayQ==
X-Gm-Message-State: AOJu0YwWeJjHvHiU2/WnFcMWRqHUR7+Ss8zupvH78BshyGbJ/zZZrw6X
 W83lCbKB649UxukKpVEDXEhIMcsKL0N/stQApOsN3oydaBtY2SjhxRKBQ+iy30oUwnJV9PzaGL4
 o2g==
X-Gm-Gg: ASbGncueje1CeoxOFAlfH7uNKIgb8GewIPC91nOsbmgPTf//rUdoqYIcd/HkJm4tKqm
 eKGwHjUSqL/AGXcwfuIwz1ooBBwrGlR/DwJYRH2JVGvRP2e1m4NnPURRdJRXVMmakp/Gt37a92E
 8bZaBI8GifbBtKL5zRcuwRvMl9HJhrnKL/XNjkRxgniM0i8GqkIr2rxns9xIZj33Zi+sPqWOfSk
 okQi2UAycZtrpg8eljTu818+BsEmjGnNORg7eLbxaNMxcPJ08eZqM4gRjRz0Hke8QcTPgFVqvna
 qq/mJiR7Cme/uZa1Xzur/wxHPx/8+RV2
X-Google-Smtp-Source: 
 AGHT+IH1ljfSW25bSKNCm9MeVySd9An+H7BG1PQmDqu0BtbDpdYLoSyvBrp429Xm6C+Y4r+JAujMZg==
X-Received: by 2002:a17:907:7813:b0:aab:740f:e467 with SMTP id
 a640c23a62f3a-aab778c1711mr271477666b.8.1734103143886;
 Fri, 13 Dec 2024 07:19:03 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu
Subject: [PATCH v13 14/15] hw/block/virtio-blk: Replaces request free function
 with g_free
Date: Fri, 13 Dec 2024 16:18:04 +0100
Message-Id: <20241213151821.65748-15-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62d;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62d.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103662489116600
Content-Type: text/plain; charset="utf-8"

The virtio_blk_free_request() function has been a 1-liner forwarding
to g_free() for a while now. We may as well call g_free on the request
pointer directly.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/block/virtio-blk.c          | 43 +++++++++++++++-------------------
 hw/vmapple/virtio-blk.c        |  2 +-
 include/hw/virtio/virtio-blk.h |  1 -
 3 files changed, 20 insertions(+), 26 deletions(-)

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 9e8337bb639..40d2c9bc591 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -50,11 +50,6 @@ static void virtio_blk_init_request(VirtIOBlock *s, Virt=
Queue *vq,
     req->mr_next =3D NULL;
 }
=20
-void virtio_blk_free_request(VirtIOBlockReq *req)
-{
-    g_free(req);
-}
-
 void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
 {
     VirtIOBlock *s =3D req->dev;
@@ -93,7 +88,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req=
, int error,
         if (acct_failed) {
             block_acct_failed(blk_get_stats(s->blk), &req->acct);
         }
-        virtio_blk_free_request(req);
+        g_free(req);
     }
=20
     blk_error_action(s->blk, action, is_read, error);
@@ -136,7 +131,7 @@ static void virtio_blk_rw_complete(void *opaque, int re=
t)
=20
         virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
         block_acct_done(blk_get_stats(s->blk), &req->acct);
-        virtio_blk_free_request(req);
+        g_free(req);
     }
 }
=20
@@ -151,7 +146,7 @@ static void virtio_blk_flush_complete(void *opaque, int=
 ret)
=20
     virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
     block_acct_done(blk_get_stats(s->blk), &req->acct);
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret)
@@ -169,7 +164,7 @@ static void virtio_blk_discard_write_zeroes_complete(vo=
id *opaque, int ret)
     if (is_write_zeroes) {
         block_acct_done(blk_get_stats(s->blk), &req->acct);
     }
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s, VirtQueue *v=
q)
@@ -214,7 +209,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
=20
 fail:
     virtio_blk_req_complete(req, status);
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static inline void submit_requests(VirtIOBlock *s, MultiReqBuffer *mrb,
@@ -612,7 +607,7 @@ static void virtio_blk_zone_report_complete(void *opaqu=
e, int ret)
=20
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
     g_free(data->zone_report_data.zones);
     g_free(data);
 }
@@ -661,7 +656,7 @@ static void virtio_blk_handle_zone_report(VirtIOBlockRe=
q *req,
     return;
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static void virtio_blk_zone_mgmt_complete(void *opaque, int ret)
@@ -677,7 +672,7 @@ static void virtio_blk_zone_mgmt_complete(void *opaque,=
 int ret)
     }
=20
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
 }
=20
 static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op)
@@ -719,7 +714,7 @@ static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *=
req, BlockZoneOp op)
     return 0;
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
     return err_status;
 }
=20
@@ -750,7 +745,7 @@ static void virtio_blk_zone_append_complete(void *opaqu=
e, int ret)
=20
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
     g_free(data);
 }
=20
@@ -788,7 +783,7 @@ static int virtio_blk_handle_zone_append(VirtIOBlockReq=
 *req,
=20
 out:
     virtio_blk_req_complete(req, err_status);
-    virtio_blk_free_request(req);
+    g_free(req);
     return err_status;
 }
=20
@@ -855,7 +850,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
             virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
             block_acct_invalid(blk_get_stats(s->blk),
                                is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_RE=
AD);
-            virtio_blk_free_request(req);
+            g_free(req);
             return 0;
         }
=20
@@ -911,7 +906,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
                               VIRTIO_BLK_ID_BYTES));
         iov_from_buf(in_iov, in_num, 0, serial, size);
         virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-        virtio_blk_free_request(req);
+        g_free(req);
         break;
     }
     case VIRTIO_BLK_T_ZONE_APPEND & ~VIRTIO_BLK_T_OUT:
@@ -943,7 +938,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
         if (unlikely(!(type & VIRTIO_BLK_T_OUT) ||
                      out_len > sizeof(dwz_hdr))) {
             virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
-            virtio_blk_free_request(req);
+            g_free(req);
             return 0;
         }
=20
@@ -960,7 +955,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
                                                             is_write_zeroe=
s);
         if (err_status !=3D VIRTIO_BLK_S_OK) {
             virtio_blk_req_complete(req, err_status);
-            virtio_blk_free_request(req);
+            g_free(req);
         }
=20
         break;
@@ -975,7 +970,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re=
q, MultiReqBuffer *mrb)
         if (!vbk->handle_unknown_request ||
             !vbk->handle_unknown_request(req, mrb, type)) {
             virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
-            virtio_blk_free_request(req);
+            g_free(req);
         }
     }
     }
@@ -998,7 +993,7 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
         while ((req =3D virtio_blk_get_request(s, vq))) {
             if (virtio_blk_handle_request(req, &mrb)) {
                 virtqueue_detach_element(req->vq, &req->elem, 0);
-                virtio_blk_free_request(req);
+                g_free(req);
                 break;
             }
         }
@@ -1048,7 +1043,7 @@ static void virtio_blk_dma_restart_bh(void *opaque)
             while (req) {
                 next =3D req->next;
                 virtqueue_detach_element(req->vq, &req->elem, 0);
-                virtio_blk_free_request(req);
+                g_free(req);
                 req =3D next;
             }
             break;
@@ -1131,7 +1126,7 @@ static void virtio_blk_reset(VirtIODevice *vdev)
             /* No other threads can access req->vq here */
             virtqueue_detach_element(req->vq, &req->elem, 0);
=20
-            virtio_blk_free_request(req);
+            g_free(req);
         }
     }
=20
diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c
index 9aeb2931922..52d857166bd 100644
--- a/hw/vmapple/virtio-blk.c
+++ b/hw/vmapple/virtio-blk.c
@@ -55,7 +55,7 @@ static bool vmapple_virtio_blk_handle_unknown_request(Vir=
tIOBlockReq *req,
         qemu_log_mask(LOG_UNIMP, "%s: Barrier requests are currently no-op=
s\n",
                       __func__);
         virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-        virtio_blk_free_request(req);
+        g_free(req);
         return true;
     default:
         return false;
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 28d5046ea6c..dcb2c89aed5 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -109,7 +109,6 @@ typedef struct VirtIOBlkClass {
 } VirtIOBlkClass;
=20
 void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq);
-void virtio_blk_free_request(VirtIOBlockReq *req);
 void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status);
=20
 #endif
--=20
2.39.5 (Apple Git-154)
From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103474; cv=none;
	d=zohomail.com; s=zohoarc;
	b=OVa36GYFa8lkw9U3M09qiyyKQAFqkjlm5/SfJiB8FwLPnn7ixwqUCl7rpL2zs1wmVAvy1LIdKKiTOqhBrB2YE6BKzjTcZgRDigjRHRKh5d+JgBYMhCKsBCqqQlEoUoTYFp9tmNeXAHeGJ1Nt7ufn0qOK7ewRqFkRtpM2BplsqRI=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103474;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=6XXnAjka+/vJApRVmgup9wxlnm3yW4bIWtTdCh+SjD8=;
	b=BIqyTPpeMCTOA2ShQW67/yVMdY1wg8RJcqT4Oxc4Cneh3kkLmFAEwQhGzxecwcXjwVRdxBcBxk5kE7V+LSzM7UT7tiblH/rl/N4QNzyDuPiVY18GYAOhGPB8F96T3BWU0t+Rn2FCI3dh7MdU07g3WiFosvuLFev9hrNIVb/PSq4=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103474236227.96753031599144;
 Fri, 13 Dec 2024 07:24:34 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7SS-0005P8-H2; Fri, 13 Dec 2024 10:20:00 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Rl-0004VM-6R
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:18 -0500
Received: from mail-ej1-x62d.google.com ([2a00:1450:4864:20::62d])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7Re-0005ES-Ei
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:15 -0500
Received: by mail-ej1-x62d.google.com with SMTP id
 a640c23a62f3a-a9f1c590ecdso251898066b.1
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:07 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.04
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:05 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103146;
 x=1734707946;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=6XXnAjka+/vJApRVmgup9wxlnm3yW4bIWtTdCh+SjD8=;
 b=fHmRXCevLQlYQh036ui0RIwmkHbtcyqzZ9g08qLhuJOOJFp0m1Np41ItUvkyZHDoU4
 tHvJF+MsWsZmWuzcqDx1Cwe7hc9sYDS88NBFu37uvQenQuXVrKcjlGcqazw+rrFnDnn4
 6CI43fIWPpVzpflQv+QrKLlPO2s0G6u0tBg4uhUwgAtD0FliapLuRHywkpueY2xKtCFt
 YYrnuYxIMbOzMFDugGvKXP4ezCi3Y14vE+tN+J0oVszaFvPh+t4WFa814T3xQHjxQ3s3
 mOHOgL61RpvNGHjWz8m8zy+9MMdBpEWIR9JN2C/rRPgJ3GA8WvJhb1Iv0RpysgofGKYD
 1ROw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103146; x=1734707946;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=6XXnAjka+/vJApRVmgup9wxlnm3yW4bIWtTdCh+SjD8=;
 b=h7UQ/4KS/sWNn9RADPnFWb26dM9gsTehDS4TebaBQqqtWgQzac8fPdV/e3NUck3jVJ
 d/vI9bBKD0gqLpqnCfGGmBvP6YScFq4aV9vBMKd7MbAITxxS0xyatkl4d2IcsGHaf/rB
 3X9i0g8p76BnjAevIAoIgbRFKsYsSegUYcFSmmhNwyKiqTxj+OSXpXdwPZx0BgOGJJWz
 6EBjAtoV7p6ggn04rkQ+Wlhc9FO+i85K2rUTyVItU8EPpkhPzvUwd7L6MNEiDwl1ArEz
 y5knF40HwquDSS3+UeRdAAIQZD3OTnSeDZ3yDvrWOBiq3CCPcHYC9RETF4lp1pThJ1Pw
 mp2g==
X-Gm-Message-State: AOJu0YxoefOmPLzmq67bK64awK2w/1bFkd/EJKr4VDY9Cfir9Z9RsUyg
 a8kyoj6JdiaOfOp3ww71jHks4yzb6PNl9VCamEHdG5G0G4NuA5mV1E7N6OviPhBIryay28yN98O
 /zg==
X-Gm-Gg: ASbGncuv6lBVB0YIyP4/jimaMuSLMoS3G9mrbgLy7mfuIG8uuI0inkEnBBsXgM59XOz
 Eah1xteHElxeENp94hv3/dJUM+vpmHa7qPlm2Mb+Za1wz5yIAPobdnkPiYh8C6TSmvuoJVLWEqC
 xaMzpuLvHPbfRRGE7dpCIFKo3My8jQyIx78oTzUg3qx4irxlt/Wg24MsECLwqZUkMwpPYt74m2f
 eCci0iWVwRAsGUZM28kCdTM9b9JSHrKsbzUn8/0hCYETqrwRJ74SgoqVSL/jYJ3/jZ4kNOR6keb
 H0Grgj4UdjCAic8yS3aB+/XRTxDPfAk4
X-Google-Smtp-Source: 
 AGHT+IHeZhX2I9NF3vd4DuY6B/jzAXuA4IwMmG5TE0B2xzBiE+igYEKXnbEmsdi046b6LOOvcq0Lag==
X-Received: by 2002:a17:907:2d1f:b0:aa6:82e8:e89b with SMTP id
 a640c23a62f3a-aab779af938mr291860066b.28.1734103145891;
 Fri, 13 Dec 2024 07:19:05 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v13 15/15] hw/vmapple/vmapple: Add vmapple machine type
Date: Fri, 13 Dec 2024 16:18:05 +0100
Message-Id: <20241213151821.65748-16-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::62d;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x62d.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103475685116600

From: Alexander Graf <graf@amazon.com>

Apple defines a new "vmapple" machine type as part of its proprietary
macOS Virtualization.Framework vmm. This machine type is similar to the
virt one, but with subtle differences in base devices, a few special
vmapple device additions and a vastly different boot chain.

This patch reimplements this machine type in QEMU. To use it, you
have to have a readily installed version of macOS for VMApple,
run on macOS with -accel hvf, pass the Virtualization.Framework
boot rom (AVPBooter) in via -bios, pass the aux and root volume as pflash
and pass aux and root volume as virtio drives. In addition, you also
need to find the machine UUID and pass that as -M vmapple,uuid=3D parameter:

$ qemu-system-aarch64 -accel hvf -M vmapple,uuid=3D0x1234 -m 4G \
    -bios /System/Library/Frameworks/Virtualization.framework/Versions/A/Re=
sources/AVPBooter.vmapple2.bin
    -drive file=3Daux,if=3Dpflash,format=3Draw \
    -drive file=3Droot,if=3Dpflash,format=3Draw \
    -drive file=3Daux,if=3Dnone,id=3Daux,format=3Draw \
    -device vmapple-virtio-blk-pci,variant=3Daux,drive=3Daux \
    -drive file=3Droot,if=3Dnone,id=3Droot,format=3Draw \
    -device vmapple-virtio-blk-pci,variant=3Droot,drive=3Droot

With all these in place, you should be able to see macOS booting
successfully.

Known issues:
 - Keyboard and mouse/tablet input is laggy. The reason is a quirk/bug
   in macOS's XHCI driver when using pin-based interrupts instead of
   MSI-X. A workaround is in the works.
 - Currently only macOS 12 guests are supported. The boot process for
   13+ will need further investigation and adjustment.

Signed-off-by: Alexander Graf <graf@amazon.com>
Co-authored-by: Phil Dennis-Jordan <phil@philjordan.eu>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v3:
 * Rebased on latest upstream, updated affinity and NIC creation
   API usage
 * Included Apple-variant virtio-blk in build dependency
 * Updated API usage for setting 'redist-region-count' array-typed property=
 on GIC.
 * Switched from virtio HID devices (for which macOS 12 does not contain
   drivers) to an XHCI USB controller and USB HID devices.

v4:
 * Fixups for v4 changes to the other patches in the set.
 * Corrected the assert macro to use
 * Removed superfluous endian conversions corresponding to cfg's.
 * Init error handling improvement.
 * No need to select CPU type on TCG, as only HVF is supported.
 * Machine type version bumped to 9.2
 * #include order improved

v5:
 * Fixed memory reservation for ecam alias region.
 * Better error handling setting properties on devices.
 * Simplified the machine ECID/UUID extraction script and actually created a
   file for it rather than quoting its code in documentation.

v7:
 * Tiny error handling fix, un-inlined function.

v8:
 * Use object_property_add_uint64_ptr rather than defining custom UUID
   property get/set functions.

v9:
 * Documentation improvements
 * Fixed variable name and struct field used during pvpanic device creation.

v10:
 * Documentation fixup for changed virtio-blk device type.
 * Small improvements to shell commands in documentation.
 * Improved propagation of errors during cfg device instantiation.

v11:
 * Quoted more strings in the documentation's shell script code.

v13:
 * Bumped the machine type version from 9.2 to 10.0.

 MAINTAINERS                 |   1 +
 contrib/vmapple/uuid.sh     |   9 +
 docs/system/arm/vmapple.rst |  63 ++++
 docs/system/target-arm.rst  |   1 +
 hw/vmapple/Kconfig          |  20 ++
 hw/vmapple/meson.build      |   1 +
 hw/vmapple/vmapple.c        | 646 ++++++++++++++++++++++++++++++++++++
 7 files changed, 741 insertions(+)
 create mode 100755 contrib/vmapple/uuid.sh
 create mode 100644 docs/system/arm/vmapple.rst
 create mode 100644 hw/vmapple/vmapple.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b6019220662..489b0df3659 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2771,6 +2771,7 @@ R: Phil Dennis-Jordan <phil@philjordan.eu>
 S: Maintained
 F: hw/vmapple/*
 F: include/hw/vmapple/*
+F: docs/system/arm/vmapple.rst
=20
 Subsystems
 ----------
diff --git a/contrib/vmapple/uuid.sh b/contrib/vmapple/uuid.sh
new file mode 100755
index 00000000000..956e8c3afed
--- /dev/null
+++ b/contrib/vmapple/uuid.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Used for converting a guest provisioned using Virtualization.framework
+# for use with the QEMU 'vmapple' aarch64 machine type.
+#
+# Extracts the Machine UUID from Virtualization.framework VM JSON file.
+# (as produced by 'macosvm', passed as command line argument)
+
+plutil -extract machineId raw "$1" | base64 -d | plutil -extract ECID raw -
+
diff --git a/docs/system/arm/vmapple.rst b/docs/system/arm/vmapple.rst
new file mode 100644
index 00000000000..5090a8997c3
--- /dev/null
+++ b/docs/system/arm/vmapple.rst
@@ -0,0 +1,63 @@
+VMApple machine emulation
+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
+
+VMApple is the device model that the macOS built-in hypervisor called "Vir=
tualization.framework"
+exposes to Apple Silicon macOS guests. The "vmapple" machine model in QEMU=
 implements the same
+device model, but does not use any code from Virtualization.Framework.
+
+Prerequisites
+-------------
+
+To run the vmapple machine model, you need to
+
+ * Run on Apple Silicon
+ * Run on macOS 12.0 or above
+ * Have an already installed copy of a Virtualization.Framework macOS 12 v=
irtual
+   machine. Note that newer versions than 12.x are currently NOT supported=
 on
+   the guest side. I will assume that you installed it using the
+   `macosvm <https://github.com/s-u/macosvm>` CLI.
+
+First, we need to extract the UUID from the virtual machine that you insta=
lled. You can do this
+by running the shell script in contrib/vmapple/uuid.sh on the macosvm.json=
 file.
+
+.. code-block:: bash
+  :caption: uuid.sh script to extract the UUID from a macosvm.json file
+
+  $ contrib/vmapple/uuid.sh "path/to/macosvm.json"
+
+Now we also need to trim the aux partition. It contains metadata that we c=
an just discard:
+
+.. code-block:: bash
+  :caption: Command to trim the aux file
+
+  $ dd if=3D"aux.img" of=3D"aux.img.trimmed" bs=3D$(( 0x4000 )) skip=3D1
+
+How to run
+----------
+
+Then, we can launch QEMU with the Virtualization.Framework pre-boot enviro=
nment and the readily
+installed target disk images. I recommend to port forward the VM's ssh and=
 vnc ports to the host
+to get better interactive access into the target system:
+
+.. code-block:: bash
+  :caption: Example execution command line
+
+  $ UUID=3D"$(contrib/vmapple/uuid.sh 'macosvm.json')"
+  $ AVPBOOTER=3D"/System/Library/Frameworks/Virtualization.framework/Resou=
rces/AVPBooter.vmapple2.bin"
+  $ AUX=3D"aux.img.trimmed"
+  $ DISK=3D"disk.img"
+  $ qemu-system-aarch64 \
+       -serial mon:stdio \
+       -m 4G \
+       -accel hvf \
+       -M vmapple,uuid=3D"$UUID" \
+       -bios "$AVPBOOTER" \
+       -drive file=3D"$AUX",if=3Dpflash,format=3Draw \
+       -drive file=3D"$DISK",if=3Dpflash,format=3Draw \
+       -drive file=3D"$AUX",if=3Dnone,id=3Daux,format=3Draw \
+       -drive file=3D"$DISK",if=3Dnone,id=3Droot,format=3Draw \
+       -device vmapple-virtio-blk-pci,variant=3Daux,drive=3Daux \
+       -device vmapple-virtio-blk-pci,variant=3Droot,drive=3Droot \
+       -netdev user,id=3Dnet0,ipv6=3Doff,hostfwd=3Dtcp::2222-:22,hostfwd=
=3Dtcp::5901-:5900 \
+       -device virtio-net-pci,netdev=3Dnet0
+
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
index 9aaa9c414c9..3426f79100b 100644
--- a/docs/system/target-arm.rst
+++ b/docs/system/target-arm.rst
@@ -102,6 +102,7 @@ Board-specific documentation
    arm/stellaris
    arm/stm32
    arm/virt
+   arm/vmapple
    arm/xenpvh
    arm/xlnx-versal-virt
    arm/xlnx-zynq
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index bcd1be63e3c..6a4c4a7fa2e 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -10,3 +10,23 @@ config VMAPPLE_CFG
 config VMAPPLE_VIRTIO_BLK
     bool
=20
+config VMAPPLE
+    bool
+    depends on ARM
+    depends on HVF
+    default y if ARM
+    imply PCI_DEVICES
+    select ARM_GIC
+    select PLATFORM_BUS
+    select PCI_EXPRESS
+    select PCI_EXPRESS_GENERIC_BRIDGE
+    select PL011 # UART
+    select PL031 # RTC
+    select PL061 # GPIO
+    select GPIO_PWR
+    select PVPANIC_MMIO
+    select VMAPPLE_AES
+    select VMAPPLE_BDIF
+    select VMAPPLE_CFG
+    select MAC_PVG_MMIO
+    select VMAPPLE_VIRTIO_BLK
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index bf17cf906c9..e572f7d5602 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -2,3 +2,4 @@ system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('=
aes.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_CFG',  if_true: files('cfg.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_VIRTIO_BLK',  if_true: files('virtio-b=
lk.c'))
+specific_ss.add(when: 'CONFIG_VMAPPLE',     if_true: files('vmapple.c'))
diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c
new file mode 100644
index 00000000000..deefbd5def8
--- /dev/null
+++ b/hw/vmapple/vmapple.c
@@ -0,0 +1,646 @@
+/*
+ * VMApple machine emulation
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * VMApple is the device model that the macOS built-in hypervisor called
+ * "Virtualization.framework" exposes to Apple Silicon macOS guests. The
+ * machine model in this file implements the same device model in QEMU, but
+ * does not use any code from Virtualization.Framework.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/datadir.h"
+#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
+#include "qemu/help-texts.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/option.h"
+#include "qemu/units.h"
+#include "monitor/qdev.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "hw/loader.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "hw/usb.h"
+#include "hw/arm/boot.h"
+#include "hw/arm/primecell.h"
+#include "hw/char/pl011.h"
+#include "hw/intc/arm_gic.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "hw/misc/pvpanic.h"
+#include "hw/pci-host/gpex.h"
+#include "hw/usb/xhci.h"
+#include "hw/virtio/virtio-pci.h"
+#include "hw/vmapple/vmapple.h"
+#include "net/net.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/visitor.h"
+#include "qapi/qapi-visit-common.h"
+#include "standard-headers/linux/input.h"
+#include "sysemu/hvf.h"
+#include "sysemu/kvm.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "sysemu/sysemu.h"
+#include "target/arm/internals.h"
+#include "target/arm/kvm_arm.h"
+
+struct VMAppleMachineClass {
+    MachineClass parent;
+};
+
+struct VMAppleMachineState {
+    MachineState parent;
+
+    Notifier machine_done;
+    struct arm_boot_info bootinfo;
+    MemMapEntry *memmap;
+    const int *irqmap;
+    DeviceState *gic;
+    DeviceState *cfg;
+    DeviceState *pvpanic;
+    Notifier powerdown_notifier;
+    PCIBus *bus;
+    MemoryRegion fw_mr;
+    MemoryRegion ecam_alias;
+    uint64_t uuid;
+};
+
+#define DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, latest) \
+    static void vmapple##major##_##minor##_class_init(ObjectClass *oc, \
+                                                    void *data) \
+    { \
+        MachineClass *mc =3D MACHINE_CLASS(oc); \
+        vmapple_machine_##major##_##minor##_options(mc); \
+        mc->desc =3D "QEMU " # major "." # minor " Apple Virtual Machine";=
 \
+        if (latest) { \
+            mc->alias =3D "vmapple"; \
+        } \
+    } \
+    static const TypeInfo machvmapple##major##_##minor##_info =3D { \
+        .name =3D MACHINE_TYPE_NAME("vmapple-" # major "." # minor), \
+        .parent =3D TYPE_VMAPPLE_MACHINE, \
+        .class_init =3D vmapple##major##_##minor##_class_init, \
+    }; \
+    static void machvmapple_machine_##major##_##minor##_init(void) \
+    { \
+        type_register_static(&machvmapple##major##_##minor##_info); \
+    } \
+    type_init(machvmapple_machine_##major##_##minor##_init);
+
+#define DEFINE_VMAPPLE_MACHINE_AS_LATEST(major, minor) \
+    DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, true)
+#define DEFINE_VMAPPLE_MACHINE(major, minor) \
+    DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, false)
+
+#define TYPE_VMAPPLE_MACHINE   MACHINE_TYPE_NAME("vmapple")
+OBJECT_DECLARE_TYPE(VMAppleMachineState, VMAppleMachineClass, VMAPPLE_MACH=
INE)
+
+/* Number of external interrupt lines to configure the GIC with */
+#define NUM_IRQS 256
+
+enum {
+    VMAPPLE_FIRMWARE,
+    VMAPPLE_CONFIG,
+    VMAPPLE_MEM,
+    VMAPPLE_GIC_DIST,
+    VMAPPLE_GIC_REDIST,
+    VMAPPLE_UART,
+    VMAPPLE_RTC,
+    VMAPPLE_PCIE,
+    VMAPPLE_PCIE_MMIO,
+    VMAPPLE_PCIE_ECAM,
+    VMAPPLE_GPIO,
+    VMAPPLE_PVPANIC,
+    VMAPPLE_APV_GFX,
+    VMAPPLE_APV_IOSFC,
+    VMAPPLE_AES_1,
+    VMAPPLE_AES_2,
+    VMAPPLE_BDOOR,
+    VMAPPLE_MEMMAP_LAST,
+};
+
+static MemMapEntry memmap[] =3D {
+    [VMAPPLE_FIRMWARE] =3D           { 0x00100000, 0x00100000 },
+    [VMAPPLE_CONFIG] =3D             { 0x00400000, 0x00010000 },
+
+    [VMAPPLE_GIC_DIST] =3D           { 0x10000000, 0x00010000 },
+    [VMAPPLE_GIC_REDIST] =3D         { 0x10010000, 0x00400000 },
+
+    [VMAPPLE_UART] =3D               { 0x20010000, 0x00010000 },
+    [VMAPPLE_RTC] =3D                { 0x20050000, 0x00001000 },
+    [VMAPPLE_GPIO] =3D               { 0x20060000, 0x00001000 },
+    [VMAPPLE_PVPANIC] =3D            { 0x20070000, 0x00000002 },
+    [VMAPPLE_BDOOR] =3D              { 0x30000000, 0x00200000 },
+    [VMAPPLE_APV_GFX] =3D            { 0x30200000, 0x00010000 },
+    [VMAPPLE_APV_IOSFC] =3D          { 0x30210000, 0x00010000 },
+    [VMAPPLE_AES_1] =3D              { 0x30220000, 0x00004000 },
+    [VMAPPLE_AES_2] =3D              { 0x30230000, 0x00004000 },
+    [VMAPPLE_PCIE_ECAM] =3D          { 0x40000000, 0x10000000 },
+    [VMAPPLE_PCIE_MMIO] =3D          { 0x50000000, 0x1fff0000 },
+
+    /* Actual RAM size depends on configuration */
+    [VMAPPLE_MEM] =3D                { 0x70000000ULL, GiB},
+};
+
+static const int irqmap[] =3D {
+    [VMAPPLE_UART] =3D 1,
+    [VMAPPLE_RTC] =3D 2,
+    [VMAPPLE_GPIO] =3D 0x5,
+    [VMAPPLE_APV_IOSFC] =3D 0x10,
+    [VMAPPLE_APV_GFX] =3D 0x11,
+    [VMAPPLE_AES_1] =3D 0x12,
+    [VMAPPLE_PCIE] =3D 0x20,
+};
+
+#define GPEX_NUM_IRQS 16
+
+static void create_bdif(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    DeviceState *bdif;
+    SysBusDevice *bdif_sb;
+    DriveInfo *di_aux =3D drive_get(IF_PFLASH, 0, 0);
+    DriveInfo *di_root =3D drive_get(IF_PFLASH, 0, 1);
+
+    if (!di_aux) {
+        error_report("No AUX device. Please specify one as pflash drive.");
+        exit(1);
+    }
+
+    if (!di_root) {
+        /* Fall back to the first IF_VIRTIO device as root device */
+        di_root =3D drive_get(IF_VIRTIO, 0, 0);
+    }
+
+    if (!di_root) {
+        error_report("No root device. Please specify one as virtio drive."=
);
+        exit(1);
+    }
+
+    /* PV backdoor device */
+    bdif =3D qdev_new(TYPE_VMAPPLE_BDIF);
+    bdif_sb =3D SYS_BUS_DEVICE(bdif);
+    sysbus_mmio_map(bdif_sb, 0, vms->memmap[VMAPPLE_BDOOR].base);
+
+    qdev_prop_set_drive(DEVICE(bdif), "aux", blk_by_legacy_dinfo(di_aux));
+    qdev_prop_set_drive(DEVICE(bdif), "root", blk_by_legacy_dinfo(di_root)=
);
+
+    sysbus_realize_and_unref(bdif_sb, &error_fatal);
+}
+
+static void create_pvpanic(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    SysBusDevice *pvpanic;
+
+    vms->pvpanic =3D qdev_new(TYPE_PVPANIC_MMIO_DEVICE);
+    pvpanic =3D SYS_BUS_DEVICE(vms->pvpanic);
+    sysbus_mmio_map(pvpanic, 0, vms->memmap[VMAPPLE_PVPANIC].base);
+
+    sysbus_realize_and_unref(pvpanic, &error_fatal);
+}
+
+static bool create_cfg(VMAppleMachineState *vms, MemoryRegion *mem,
+                       Error **errp)
+{
+    ERRP_GUARD();
+    SysBusDevice *cfg;
+    MachineState *machine =3D MACHINE(vms);
+    uint32_t rnd =3D 1;
+
+    vms->cfg =3D qdev_new(TYPE_VMAPPLE_CFG);
+    cfg =3D SYS_BUS_DEVICE(vms->cfg);
+    sysbus_mmio_map(cfg, 0, vms->memmap[VMAPPLE_CONFIG].base);
+
+    qemu_guest_getrandom_nofail(&rnd, sizeof(rnd));
+
+    qdev_prop_set_uint32(vms->cfg, "nr-cpus", machine->smp.cpus);
+    qdev_prop_set_uint64(vms->cfg, "ecid", vms->uuid);
+    qdev_prop_set_uint64(vms->cfg, "ram-size", machine->ram_size);
+    qdev_prop_set_uint32(vms->cfg, "rnd", rnd);
+
+    if (!sysbus_realize_and_unref(cfg, errp)) {
+        error_prepend(errp, "Error creating vmapple cfg device: ");
+        return false;
+    }
+
+    return true;
+}
+
+static void create_gfx(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    int irq_gfx =3D vms->irqmap[VMAPPLE_APV_GFX];
+    int irq_iosfc =3D vms->irqmap[VMAPPLE_APV_IOSFC];
+    SysBusDevice *gfx;
+
+    gfx =3D SYS_BUS_DEVICE(qdev_new("apple-gfx-mmio"));
+    sysbus_mmio_map(gfx, 0, vms->memmap[VMAPPLE_APV_GFX].base);
+    sysbus_mmio_map(gfx, 1, vms->memmap[VMAPPLE_APV_IOSFC].base);
+    sysbus_connect_irq(gfx, 0, qdev_get_gpio_in(vms->gic, irq_gfx));
+    sysbus_connect_irq(gfx, 1, qdev_get_gpio_in(vms->gic, irq_iosfc));
+    sysbus_realize_and_unref(gfx, &error_fatal);
+}
+
+static void create_aes(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    int irq =3D vms->irqmap[VMAPPLE_AES_1];
+    SysBusDevice *aes;
+
+    aes =3D SYS_BUS_DEVICE(qdev_new(TYPE_APPLE_AES));
+    sysbus_mmio_map(aes, 0, vms->memmap[VMAPPLE_AES_1].base);
+    sysbus_mmio_map(aes, 1, vms->memmap[VMAPPLE_AES_2].base);
+    sysbus_connect_irq(aes, 0, qdev_get_gpio_in(vms->gic, irq));
+    sysbus_realize_and_unref(aes, &error_fatal);
+}
+
+static int arm_gic_ppi_index(int cpu_nr, int ppi_index)
+{
+    return NUM_IRQS + cpu_nr * GIC_INTERNAL + ppi_index;
+}
+
+static void create_gic(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    MachineState *ms =3D MACHINE(vms);
+    /* We create a standalone GIC */
+    SysBusDevice *gicbusdev;
+    QList *redist_region_count;
+    int i;
+    unsigned int smp_cpus =3D ms->smp.cpus;
+
+    vms->gic =3D qdev_new(gicv3_class_name());
+    qdev_prop_set_uint32(vms->gic, "revision", 3);
+    qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
+    /*
+     * Note that the num-irq property counts both internal and external
+     * interrupts; there are always 32 of the former (mandated by GIC spec=
).
+     */
+    qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32);
+
+    uint32_t redist0_capacity =3D
+                vms->memmap[VMAPPLE_GIC_REDIST].size / GICV3_REDIST_SIZE;
+    uint32_t redist0_count =3D MIN(smp_cpus, redist0_capacity);
+
+    redist_region_count =3D qlist_new();
+    qlist_append_int(redist_region_count, redist0_count);
+    qdev_prop_set_array(vms->gic, "redist-region-count", redist_region_cou=
nt);
+
+    gicbusdev =3D SYS_BUS_DEVICE(vms->gic);
+    sysbus_realize_and_unref(gicbusdev, &error_fatal);
+    sysbus_mmio_map(gicbusdev, 0, vms->memmap[VMAPPLE_GIC_DIST].base);
+    sysbus_mmio_map(gicbusdev, 1, vms->memmap[VMAPPLE_GIC_REDIST].base);
+
+    /*
+     * Wire the outputs from each CPU's generic timer and the GICv3
+     * maintenance interrupt signal to the appropriate GIC PPI inputs,
+     * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inpu=
ts.
+     */
+    for (i =3D 0; i < smp_cpus; i++) {
+        DeviceState *cpudev =3D DEVICE(qemu_get_cpu(i));
+
+        /* Map the virt timer to PPI 27 */
+        qdev_connect_gpio_out(cpudev, GTIMER_VIRT,
+                              qdev_get_gpio_in(vms->gic,
+                                               arm_gic_ppi_index(i, 27)));
+
+        /* Map the GIC IRQ and FIQ lines to CPU */
+        sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_=
IRQ));
+        sysbus_connect_irq(gicbusdev, i + smp_cpus,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+    }
+}
+
+static void create_uart(const VMAppleMachineState *vms, int uart,
+                        MemoryRegion *mem, Chardev *chr)
+{
+    hwaddr base =3D vms->memmap[uart].base;
+    int irq =3D vms->irqmap[uart];
+    DeviceState *dev =3D qdev_new(TYPE_PL011);
+    SysBusDevice *s =3D SYS_BUS_DEVICE(dev);
+
+    qdev_prop_set_chr(dev, "chardev", chr);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    memory_region_add_subregion(mem, base,
+                                sysbus_mmio_get_region(s, 0));
+    sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
+}
+
+static void create_rtc(const VMAppleMachineState *vms)
+{
+    hwaddr base =3D vms->memmap[VMAPPLE_RTC].base;
+    int irq =3D vms->irqmap[VMAPPLE_RTC];
+
+    sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq));
+}
+
+static DeviceState *gpio_key_dev;
+static void vmapple_powerdown_req(Notifier *n, void *opaque)
+{
+    /* use gpio Pin 3 for power button event */
+    qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
+}
+
+static void create_gpio_devices(const VMAppleMachineState *vms, int gpio,
+                                MemoryRegion *mem)
+{
+    DeviceState *pl061_dev;
+    hwaddr base =3D vms->memmap[gpio].base;
+    int irq =3D vms->irqmap[gpio];
+    SysBusDevice *s;
+
+    pl061_dev =3D qdev_new("pl061");
+    /* Pull lines down to 0 if not driven by the PL061 */
+    qdev_prop_set_uint32(pl061_dev, "pullups", 0);
+    qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff);
+    s =3D SYS_BUS_DEVICE(pl061_dev);
+    sysbus_realize_and_unref(s, &error_fatal);
+    memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
+    sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
+    gpio_key_dev =3D sysbus_create_simple("gpio-key", -1,
+                                        qdev_get_gpio_in(pl061_dev, 3));
+}
+
+static void vmapple_firmware_init(VMAppleMachineState *vms,
+                                  MemoryRegion *sysmem)
+{
+    hwaddr size =3D vms->memmap[VMAPPLE_FIRMWARE].size;
+    hwaddr base =3D vms->memmap[VMAPPLE_FIRMWARE].base;
+    const char *bios_name;
+    int image_size;
+    char *fname;
+
+    bios_name =3D MACHINE(vms)->firmware;
+    if (!bios_name) {
+        error_report("No firmware specified");
+        exit(1);
+    }
+
+    fname =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (!fname) {
+        error_report("Could not find ROM image '%s'", bios_name);
+        exit(1);
+    }
+
+    memory_region_init_ram(&vms->fw_mr, NULL, "firmware", size, &error_fat=
al);
+    image_size =3D load_image_mr(fname, &vms->fw_mr);
+
+    g_free(fname);
+    if (image_size < 0) {
+        error_report("Could not load ROM image '%s'", bios_name);
+        exit(1);
+    }
+
+    memory_region_add_subregion(get_system_memory(), base, &vms->fw_mr);
+}
+
+static void create_pcie(VMAppleMachineState *vms)
+{
+    hwaddr base_mmio =3D vms->memmap[VMAPPLE_PCIE_MMIO].base;
+    hwaddr size_mmio =3D vms->memmap[VMAPPLE_PCIE_MMIO].size;
+    hwaddr base_ecam =3D vms->memmap[VMAPPLE_PCIE_ECAM].base;
+    hwaddr size_ecam =3D vms->memmap[VMAPPLE_PCIE_ECAM].size;
+    int irq =3D vms->irqmap[VMAPPLE_PCIE];
+    MemoryRegion *mmio_alias;
+    MemoryRegion *mmio_reg;
+    MemoryRegion *ecam_reg;
+    DeviceState *dev;
+    int i;
+    PCIHostState *pci;
+    DeviceState *usb_controller;
+    USBBus *usb_bus;
+
+    dev =3D qdev_new(TYPE_GPEX_HOST);
+    qdev_prop_set_uint32(dev, "num-irqs", GPEX_NUM_IRQS);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+    /* Map only the first size_ecam bytes of ECAM space */
+    ecam_reg =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+    memory_region_init_alias(&vms->ecam_alias, OBJECT(dev), "pcie-ecam",
+                             ecam_reg, 0, size_ecam);
+    memory_region_add_subregion(get_system_memory(), base_ecam,
+                                &vms->ecam_alias);
+
+    /*
+     * Map the MMIO window from [0x50000000-0x7fff0000] in PCI space into
+     * system address space at [0x50000000-0x7fff0000].
+     */
+    mmio_alias =3D g_new0(MemoryRegion, 1);
+    mmio_reg =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+                             mmio_reg, base_mmio, size_mmio);
+    memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias=
);
+
+    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
+                           qdev_get_gpio_in(vms->gic, irq + i));
+        gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
+    }
+
+    pci =3D PCI_HOST_BRIDGE(dev);
+    vms->bus =3D pci->bus;
+    g_assert(vms->bus);
+
+    while ((dev =3D qemu_create_nic_device("virtio-net-pci", true, NULL)))=
 {
+        qdev_realize_and_unref(dev, BUS(vms->bus), &error_fatal);
+    }
+
+    usb_controller =3D qdev_new(TYPE_QEMU_XHCI);
+    qdev_realize_and_unref(usb_controller, BUS(pci->bus), &error_fatal);
+
+    usb_bus =3D USB_BUS(object_resolve_type_unambiguous(TYPE_USB_BUS,
+                                                      &error_fatal));
+    usb_create_simple(usb_bus, "usb-kbd");
+    usb_create_simple(usb_bus, "usb-tablet");
+}
+
+static void vmapple_reset(void *opaque)
+{
+    VMAppleMachineState *vms =3D opaque;
+    hwaddr base =3D vms->memmap[VMAPPLE_FIRMWARE].base;
+
+    cpu_set_pc(first_cpu, base);
+}
+
+static void mach_vmapple_init(MachineState *machine)
+{
+    VMAppleMachineState *vms =3D VMAPPLE_MACHINE(machine);
+    MachineClass *mc =3D MACHINE_GET_CLASS(machine);
+    const CPUArchIdList *possible_cpus;
+    MemoryRegion *sysmem =3D get_system_memory();
+    int n;
+    unsigned int smp_cpus =3D machine->smp.cpus;
+    unsigned int max_cpus =3D machine->smp.max_cpus;
+
+    vms->memmap =3D memmap;
+    machine->usb =3D true;
+
+    possible_cpus =3D mc->possible_cpu_arch_ids(machine);
+    assert(possible_cpus->len =3D=3D max_cpus);
+    for (n =3D 0; n < possible_cpus->len; n++) {
+        Object *cpu;
+        CPUState *cs;
+
+        if (n >=3D smp_cpus) {
+            break;
+        }
+
+        cpu =3D object_new(possible_cpus->cpus[n].type);
+        object_property_set_int(cpu, "mp-affinity",
+                                possible_cpus->cpus[n].arch_id, &error_fat=
al);
+
+        cs =3D CPU(cpu);
+        cs->cpu_index =3D n;
+
+        numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpu),
+                          &error_fatal);
+
+        if (object_property_find(cpu, "has_el3")) {
+            object_property_set_bool(cpu, "has_el3", false, &error_fatal);
+        }
+        if (object_property_find(cpu, "has_el2")) {
+            object_property_set_bool(cpu, "has_el2", false, &error_fatal);
+        }
+        object_property_set_int(cpu, "psci-conduit", QEMU_PSCI_CONDUIT_HVC,
+                                &error_fatal);
+
+        /* Secondary CPUs start in PSCI powered-down state */
+        if (n > 0) {
+            object_property_set_bool(cpu, "start-powered-off", true,
+                                     &error_fatal);
+        }
+
+        object_property_set_link(cpu, "memory", OBJECT(sysmem), &error_abo=
rt);
+        qdev_realize(DEVICE(cpu), NULL, &error_fatal);
+        object_unref(cpu);
+    }
+
+    memory_region_add_subregion(sysmem, vms->memmap[VMAPPLE_MEM].base,
+                                machine->ram);
+
+    create_gic(vms, sysmem);
+    create_bdif(vms, sysmem);
+    create_pvpanic(vms, sysmem);
+    create_aes(vms, sysmem);
+    create_gfx(vms, sysmem);
+    create_uart(vms, VMAPPLE_UART, sysmem, serial_hd(0));
+    create_rtc(vms);
+    create_pcie(vms);
+
+    create_gpio_devices(vms, VMAPPLE_GPIO, sysmem);
+
+    vmapple_firmware_init(vms, sysmem);
+    create_cfg(vms, sysmem, &error_fatal);
+
+    /* connect powerdown request */
+    vms->powerdown_notifier.notify =3D vmapple_powerdown_req;
+    qemu_register_powerdown_notifier(&vms->powerdown_notifier);
+
+    vms->bootinfo.ram_size =3D machine->ram_size;
+    vms->bootinfo.board_id =3D -1;
+    vms->bootinfo.loader_start =3D vms->memmap[VMAPPLE_MEM].base;
+    vms->bootinfo.skip_dtb_autoload =3D true;
+    vms->bootinfo.firmware_loaded =3D true;
+    arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
+
+    qemu_register_reset(vmapple_reset, vms);
+}
+
+static CpuInstanceProperties
+vmapple_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
+{
+    MachineClass *mc =3D MACHINE_GET_CLASS(ms);
+    const CPUArchIdList *possible_cpus =3D mc->possible_cpu_arch_ids(ms);
+
+    assert(cpu_index < possible_cpus->len);
+    return possible_cpus->cpus[cpu_index].props;
+}
+
+
+static int64_t vmapple_get_default_cpu_node_id(const MachineState *ms, int=
 idx)
+{
+    return idx % ms->numa_state->num_nodes;
+}
+
+static const CPUArchIdList *vmapple_possible_cpu_arch_ids(MachineState *ms)
+{
+    int n;
+    unsigned int max_cpus =3D ms->smp.max_cpus;
+
+    if (ms->possible_cpus) {
+        assert(ms->possible_cpus->len =3D=3D max_cpus);
+        return ms->possible_cpus;
+    }
+
+    ms->possible_cpus =3D g_malloc0(sizeof(CPUArchIdList) +
+                                  sizeof(CPUArchId) * max_cpus);
+    ms->possible_cpus->len =3D max_cpus;
+    for (n =3D 0; n < ms->possible_cpus->len; n++) {
+        ms->possible_cpus->cpus[n].type =3D ms->cpu_type;
+        ms->possible_cpus->cpus[n].arch_id =3D
+            arm_build_mp_affinity(n, GICV3_TARGETLIST_BITS);
+        ms->possible_cpus->cpus[n].props.has_thread_id =3D true;
+        ms->possible_cpus->cpus[n].props.thread_id =3D n;
+    }
+    return ms->possible_cpus;
+}
+
+static void vmapple_machine_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc =3D MACHINE_CLASS(oc);
+
+    mc->init =3D mach_vmapple_init;
+    mc->max_cpus =3D 32;
+    mc->block_default_type =3D IF_VIRTIO;
+    mc->no_cdrom =3D 1;
+    mc->pci_allow_0_address =3D true;
+    mc->minimum_page_bits =3D 12;
+    mc->possible_cpu_arch_ids =3D vmapple_possible_cpu_arch_ids;
+    mc->cpu_index_to_instance_props =3D vmapple_cpu_index_to_props;
+    mc->default_cpu_type =3D ARM_CPU_TYPE_NAME("host");
+    mc->get_default_cpu_node_id =3D vmapple_get_default_cpu_node_id;
+    mc->default_ram_id =3D "mach-vmapple.ram";
+
+    object_register_sugar_prop(TYPE_VIRTIO_PCI, "disable-legacy",
+                               "on", true);
+}
+
+static void vmapple_instance_init(Object *obj)
+{
+    VMAppleMachineState *vms =3D VMAPPLE_MACHINE(obj);
+
+    vms->irqmap =3D irqmap;
+
+    object_property_add_uint64_ptr(obj, "uuid", &vms->uuid,
+                                   OBJ_PROP_FLAG_READWRITE);
+    object_property_set_description(obj, "uuid", "Machine UUID (SDOM)");
+}
+
+static const TypeInfo vmapple_machine_info =3D {
+    .name          =3D TYPE_VMAPPLE_MACHINE,
+    .parent        =3D TYPE_MACHINE,
+    .abstract      =3D true,
+    .instance_size =3D sizeof(VMAppleMachineState),
+    .class_size    =3D sizeof(VMAppleMachineClass),
+    .class_init    =3D vmapple_machine_class_init,
+    .instance_init =3D vmapple_instance_init,
+};
+
+static void machvmapple_machine_init(void)
+{
+    type_register_static(&vmapple_machine_info);
+}
+type_init(machvmapple_machine_init);
+
+static void vmapple_machine_10_0_options(MachineClass *mc)
+{
+}
+DEFINE_VMAPPLE_MACHINE_AS_LATEST(10, 0)
+
--=20
2.39.5 (Apple Git-154)


From nobody Sun May 11 23:29:00 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734103662; cv=none;
	d=zohomail.com; s=zohoarc;
	b=klUjXoE9v4BOJ6zUSIo3E7EP4WXdMDUNMPGJNAGuQmLi/afcXZAS9112zmlCVyswpamqv7+jpi/LKAZNWQkHR5I1SLBB2YTpA3lcqaD8VireNPlu52v8K2o6g4xquUZJu4/Kovp904se5VL18qTl3iOE63/TXxJPQ97dOKYJAh4=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734103662;
 h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=Z2pNk9QC4qGLH9SRfY3PX18dpiOTIYqJToscnWHedMY=;
	b=NyK67fFJWK8F5DJkjUy/VprDwLHMOcb0W8gvNtcMX2Wj+Grw3RZWxLthZ7mzujkexJV9Md2+sPK4ITQQ9FindjvtIw4uUtYpqqM4TuXWzpolP2ogeysichyUWSdURQj9SJ6lS4sQ87YzCy4tdObBZuwLFhqt8Ue+J4mkfBAFEwI=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734103662101460.27424287160693;
 Fri, 13 Dec 2024 07:27:42 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tM7UR-0001ZA-IU; Fri, 13 Dec 2024 10:22:03 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7SJ-00055D-RW
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:51 -0500
Received: from mail-ej1-x630.google.com ([2a00:1450:4864:20::630])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tM7S7-0005SW-5u
 for qemu-devel@nongnu.org; Fri, 13 Dec 2024 10:19:51 -0500
Received: by mail-ej1-x630.google.com with SMTP id
 a640c23a62f3a-aa69077b93fso275675366b.0
 for <qemu-devel@nongnu.org>; Fri, 13 Dec 2024 07:19:36 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 a640c23a62f3a-aab8dd35b19sm29284166b.33.2024.12.13.07.19.33
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Fri, 13 Dec 2024 07:19:35 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734103176;
 x=1734707976;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=Z2pNk9QC4qGLH9SRfY3PX18dpiOTIYqJToscnWHedMY=;
 b=X/8FV3k4f6eywf0DpXo7MHQNYwwWkQviyNPEQIlJm7OEMXObpPeoWxV+pOnPIwYUPP
 lnP0hX53qsVx0d5VT04GQoZhnZOrxdDM8CL/PaDuDgg2BPpU1/YAo/ye/WcpSC/fgHrO
 9w20aHrk21fjozk074F/tpoObk+yH8d06gavsxHF8nSjxlecNcTXBfnYX1ld2AbiEi6Y
 6YlJw3MY4sY7lIt90EbBk2NLs0wKx5Wp/7eQjtIw9T8L9vaP8a2GAtQv5miFKOfH/f7E
 E09KWEVdlcQHKxHF0GQIt8jOq/fq7g/GsqznGiHGKwChUctIZNmWJrtTaPXTTagrOzN+
 Mo1w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734103176; x=1734707976;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=Z2pNk9QC4qGLH9SRfY3PX18dpiOTIYqJToscnWHedMY=;
 b=gNbEXg+GT9OMtODBg9voDvBDjBrrFULaz9/76Ms3Rzg0hliMzJVuOKtrnhEKiyZtPb
 PLwLG81Bm06qDownM2pYlxW8D8sZTE94waxhdQ6+ZAy5qQ1s5wqANsPml78iU0uzcXCr
 0HuHmTuIV1JTtAFyT1k9anjhY/emoeKY8Xe0obbuWfWh85QBs8ImfdpZm98uBWqrWYKD
 /cM9n/SDKQiMWIVbTHILjgUhOoMNG0jLLPeH7UlYxRWqgvKkRr4pTF5u7rOXCZCOXQoO
 vRlDftSs5Z8rhhjgaxiJEzIPuNEU5pAybbmCmBWZ5vGMZaveJoxICVS1GhNPBcdk+J1y
 lbkw==
X-Gm-Message-State: AOJu0YwcI9TNyzPH3GHrfD9rgIOi0cQKtrKthOp1xJEnGwr5ukZUm00g
 xhR81HMLfPyZZdqSlLP94OM6JYtNm4hIgUFS28ozYOpcR5qUweut/PcmAtdd9DteoAhom30h/aW
 unA==
X-Gm-Gg: ASbGncvQ3bZaeXxcz2rPhfqEN4T0R9dp0OGGsnYojiFPaSLdfctT6rM3Y6fEyqnxF7H
 4Rz1Df0678yCeTqCz3mk2yWT2nklWd7Yxf2kX6tXw1HuTx5whFlDN02nDwKu/Zvmq8feSEm2dt1
 dXUMoMGMlOkZyKIhzepNBu4bIoQu1BtzMwpkCK9uRkzCrzDsTlvxhBNfGI0RgNnPaWr6N19TaJ0
 0rpvqzz8lZZVqqOPwq4JupfQSES+LVllKBQoyvAdxfdayUn+qa5hSr5gmuGuizKRicxS5cWscK2
 Wkd/ctfSMSoLWOIlvHRl1X8+NfDY3Oxp
X-Google-Smtp-Source: 
 AGHT+IHnBpPPCK8FTh1sukJVAQfk9HqFwKSA28msdlJmsnlSXhL9YwzMnoHKomJK9i4d0CugT8bNCA==
X-Received: by 2002:a17:907:980f:b0:aa6:8fa5:f3e3 with SMTP id
 a640c23a62f3a-aab778be6c9mr253695166b.8.1734103175448;
 Fri, 13 Dec 2024 07:19:35 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v14 15/15] hw/vmapple/vmapple: Add vmapple machine type
Date: Fri, 13 Dec 2024 16:18:21 +0100
Message-Id: <20241213151821.65748-32-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241213151821.65748-1-phil@philjordan.eu>
References: <20241213151821.65748-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::630;
 envelope-from=phil@philjordan.eu; helo=mail-ej1-x630.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734103664537116600

From: Alexander Graf <graf@amazon.com>

Apple defines a new "vmapple" machine type as part of its proprietary
macOS Virtualization.Framework vmm. This machine type is similar to the
virt one, but with subtle differences in base devices, a few special
vmapple device additions and a vastly different boot chain.

This patch reimplements this machine type in QEMU. To use it, you
have to have a readily installed version of macOS for VMApple,
run on macOS with -accel hvf, pass the Virtualization.Framework
boot rom (AVPBooter) in via -bios, pass the aux and root volume as pflash
and pass aux and root volume as virtio drives. In addition, you also
need to find the machine UUID and pass that as -M vmapple,uuid=3D parameter:

$ qemu-system-aarch64 -accel hvf -M vmapple,uuid=3D0x1234 -m 4G \
    -bios /System/Library/Frameworks/Virtualization.framework/Versions/A/Re=
sources/AVPBooter.vmapple2.bin
    -drive file=3Daux,if=3Dpflash,format=3Draw \
    -drive file=3Droot,if=3Dpflash,format=3Draw \
    -drive file=3Daux,if=3Dnone,id=3Daux,format=3Draw \
    -device vmapple-virtio-blk-pci,variant=3Daux,drive=3Daux \
    -drive file=3Droot,if=3Dnone,id=3Droot,format=3Draw \
    -device vmapple-virtio-blk-pci,variant=3Droot,drive=3Droot

With all these in place, you should be able to see macOS booting
successfully.

Known issues:
 - Keyboard and mouse/tablet input is laggy. The reason for this is
   that macOS's XHCI driver seems to expect interrupter mapping to
   be disabled when MSI/MSI-X is unavailable. I have found a
   workaround but discovered a bunch of other XHCI spec non-compliance
   in the process, so I'm fixing all of those in a separate patch
   set.
 - Currently only macOS 12 guests are supported. The boot process for
   13+ will need further investigation and adjustment.

Signed-off-by: Alexander Graf <graf@amazon.com>
Co-authored-by: Phil Dennis-Jordan <phil@philjordan.eu>
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---

v3:
 * Rebased on latest upstream, updated affinity and NIC creation
   API usage
 * Included Apple-variant virtio-blk in build dependency
 * Updated API usage for setting 'redist-region-count' array-typed property=
 on GIC.
 * Switched from virtio HID devices (for which macOS 12 does not contain
   drivers) to an XHCI USB controller and USB HID devices.

v4:
 * Fixups for v4 changes to the other patches in the set.
 * Corrected the assert macro to use
 * Removed superfluous endian conversions corresponding to cfg's.
 * Init error handling improvement.
 * No need to select CPU type on TCG, as only HVF is supported.
 * Machine type version bumped to 9.2
 * #include order improved

v5:
 * Fixed memory reservation for ecam alias region.
 * Better error handling setting properties on devices.
 * Simplified the machine ECID/UUID extraction script and actually created a
   file for it rather than quoting its code in documentation.

v7:
 * Tiny error handling fix, un-inlined function.

v8:
 * Use object_property_add_uint64_ptr rather than defining custom UUID
   property get/set functions.

v9:
 * Documentation improvements
 * Fixed variable name and struct field used during pvpanic device creation.

v10:
 * Documentation fixup for changed virtio-blk device type.
 * Small improvements to shell commands in documentation.
 * Improved propagation of errors during cfg device instantiation.

v11:
 * Quoted more strings in the documentation's shell script code.

v13:
 * Bumped the machine type version from 9.2 to 10.0.

 MAINTAINERS                 |   1 +
 contrib/vmapple/uuid.sh     |   9 +
 docs/system/arm/vmapple.rst |  63 ++++
 docs/system/target-arm.rst  |   1 +
 hw/vmapple/Kconfig          |  20 ++
 hw/vmapple/meson.build      |   1 +
 hw/vmapple/vmapple.c        | 648 ++++++++++++++++++++++++++++++++++++
 7 files changed, 743 insertions(+)
 create mode 100755 contrib/vmapple/uuid.sh
 create mode 100644 docs/system/arm/vmapple.rst
 create mode 100644 hw/vmapple/vmapple.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 692872d7d1c..94e43c9a52f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2771,6 +2771,7 @@ M: Phil Dennis-Jordan <phil@philjordan.eu>
 S: Maintained
 F: hw/vmapple/*
 F: include/hw/vmapple/*
+F: docs/system/arm/vmapple.rst
=20
 Subsystems
 ----------
diff --git a/contrib/vmapple/uuid.sh b/contrib/vmapple/uuid.sh
new file mode 100755
index 00000000000..956e8c3afed
--- /dev/null
+++ b/contrib/vmapple/uuid.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Used for converting a guest provisioned using Virtualization.framework
+# for use with the QEMU 'vmapple' aarch64 machine type.
+#
+# Extracts the Machine UUID from Virtualization.framework VM JSON file.
+# (as produced by 'macosvm', passed as command line argument)
+
+plutil -extract machineId raw "$1" | base64 -d | plutil -extract ECID raw -
+
diff --git a/docs/system/arm/vmapple.rst b/docs/system/arm/vmapple.rst
new file mode 100644
index 00000000000..5090a8997c3
--- /dev/null
+++ b/docs/system/arm/vmapple.rst
@@ -0,0 +1,63 @@
+VMApple machine emulation
+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
+
+VMApple is the device model that the macOS built-in hypervisor called "Vir=
tualization.framework"
+exposes to Apple Silicon macOS guests. The "vmapple" machine model in QEMU=
 implements the same
+device model, but does not use any code from Virtualization.Framework.
+
+Prerequisites
+-------------
+
+To run the vmapple machine model, you need to
+
+ * Run on Apple Silicon
+ * Run on macOS 12.0 or above
+ * Have an already installed copy of a Virtualization.Framework macOS 12 v=
irtual
+   machine. Note that newer versions than 12.x are currently NOT supported=
 on
+   the guest side. I will assume that you installed it using the
+   `macosvm <https://github.com/s-u/macosvm>` CLI.
+
+First, we need to extract the UUID from the virtual machine that you insta=
lled. You can do this
+by running the shell script in contrib/vmapple/uuid.sh on the macosvm.json=
 file.
+
+.. code-block:: bash
+  :caption: uuid.sh script to extract the UUID from a macosvm.json file
+
+  $ contrib/vmapple/uuid.sh "path/to/macosvm.json"
+
+Now we also need to trim the aux partition. It contains metadata that we c=
an just discard:
+
+.. code-block:: bash
+  :caption: Command to trim the aux file
+
+  $ dd if=3D"aux.img" of=3D"aux.img.trimmed" bs=3D$(( 0x4000 )) skip=3D1
+
+How to run
+----------
+
+Then, we can launch QEMU with the Virtualization.Framework pre-boot enviro=
nment and the readily
+installed target disk images. I recommend to port forward the VM's ssh and=
 vnc ports to the host
+to get better interactive access into the target system:
+
+.. code-block:: bash
+  :caption: Example execution command line
+
+  $ UUID=3D"$(contrib/vmapple/uuid.sh 'macosvm.json')"
+  $ AVPBOOTER=3D"/System/Library/Frameworks/Virtualization.framework/Resou=
rces/AVPBooter.vmapple2.bin"
+  $ AUX=3D"aux.img.trimmed"
+  $ DISK=3D"disk.img"
+  $ qemu-system-aarch64 \
+       -serial mon:stdio \
+       -m 4G \
+       -accel hvf \
+       -M vmapple,uuid=3D"$UUID" \
+       -bios "$AVPBOOTER" \
+       -drive file=3D"$AUX",if=3Dpflash,format=3Draw \
+       -drive file=3D"$DISK",if=3Dpflash,format=3Draw \
+       -drive file=3D"$AUX",if=3Dnone,id=3Daux,format=3Draw \
+       -drive file=3D"$DISK",if=3Dnone,id=3Droot,format=3Draw \
+       -device vmapple-virtio-blk-pci,variant=3Daux,drive=3Daux \
+       -device vmapple-virtio-blk-pci,variant=3Droot,drive=3Droot \
+       -netdev user,id=3Dnet0,ipv6=3Doff,hostfwd=3Dtcp::2222-:22,hostfwd=
=3Dtcp::5901-:5900 \
+       -device virtio-net-pci,netdev=3Dnet0
+
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
index 9aaa9c414c9..3426f79100b 100644
--- a/docs/system/target-arm.rst
+++ b/docs/system/target-arm.rst
@@ -102,6 +102,7 @@ Board-specific documentation
    arm/stellaris
    arm/stm32
    arm/virt
+   arm/vmapple
    arm/xenpvh
    arm/xlnx-versal-virt
    arm/xlnx-zynq
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
index bcd1be63e3c..6a4c4a7fa2e 100644
--- a/hw/vmapple/Kconfig
+++ b/hw/vmapple/Kconfig
@@ -10,3 +10,23 @@ config VMAPPLE_CFG
 config VMAPPLE_VIRTIO_BLK
     bool
=20
+config VMAPPLE
+    bool
+    depends on ARM
+    depends on HVF
+    default y if ARM
+    imply PCI_DEVICES
+    select ARM_GIC
+    select PLATFORM_BUS
+    select PCI_EXPRESS
+    select PCI_EXPRESS_GENERIC_BRIDGE
+    select PL011 # UART
+    select PL031 # RTC
+    select PL061 # GPIO
+    select GPIO_PWR
+    select PVPANIC_MMIO
+    select VMAPPLE_AES
+    select VMAPPLE_BDIF
+    select VMAPPLE_CFG
+    select MAC_PVG_MMIO
+    select VMAPPLE_VIRTIO_BLK
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
index bf17cf906c9..e572f7d5602 100644
--- a/hw/vmapple/meson.build
+++ b/hw/vmapple/meson.build
@@ -2,3 +2,4 @@ system_ss.add(when: 'CONFIG_VMAPPLE_AES',  if_true: files('=
aes.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_CFG',  if_true: files('cfg.c'))
 system_ss.add(when: 'CONFIG_VMAPPLE_VIRTIO_BLK',  if_true: files('virtio-b=
lk.c'))
+specific_ss.add(when: 'CONFIG_VMAPPLE',     if_true: files('vmapple.c'))
diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c
new file mode 100644
index 00000000000..66336942c8d
--- /dev/null
+++ b/hw/vmapple/vmapple.c
@@ -0,0 +1,648 @@
+/*
+ * VMApple machine emulation
+ *
+ * Copyright =C2=A9 2023 Amazon.com, Inc. or its affiliates. All Rights Re=
served.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late=
r.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * VMApple is the device model that the macOS built-in hypervisor called
+ * "Virtualization.framework" exposes to Apple Silicon macOS guests. The
+ * machine model in this file implements the same device model in QEMU, but
+ * does not use any code from Virtualization.Framework.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/datadir.h"
+#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
+#include "qemu/help-texts.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/option.h"
+#include "qemu/units.h"
+#include "monitor/qdev.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "hw/loader.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "hw/usb.h"
+#include "hw/arm/boot.h"
+#include "hw/arm/primecell.h"
+#include "hw/char/pl011.h"
+#include "hw/intc/arm_gic.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "hw/misc/pvpanic.h"
+#include "hw/pci-host/gpex.h"
+#include "hw/usb/xhci.h"
+#include "hw/virtio/virtio-pci.h"
+#include "hw/vmapple/vmapple.h"
+#include "net/net.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/visitor.h"
+#include "qapi/qapi-visit-common.h"
+#include "standard-headers/linux/input.h"
+#include "sysemu/hvf.h"
+#include "sysemu/kvm.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "sysemu/sysemu.h"
+#include "target/arm/internals.h"
+#include "target/arm/kvm_arm.h"
+
+struct VMAppleMachineClass {
+    MachineClass parent;
+};
+
+struct VMAppleMachineState {
+    MachineState parent;
+
+    Notifier machine_done;
+    struct arm_boot_info bootinfo;
+    MemMapEntry *memmap;
+    const int *irqmap;
+    DeviceState *gic;
+    DeviceState *cfg;
+    DeviceState *pvpanic;
+    Notifier powerdown_notifier;
+    PCIBus *bus;
+    MemoryRegion fw_mr;
+    MemoryRegion ecam_alias;
+    uint64_t uuid;
+};
+
+#define DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, latest) \
+    static void vmapple##major##_##minor##_class_init(ObjectClass *oc, \
+                                                    void *data) \
+    { \
+        MachineClass *mc =3D MACHINE_CLASS(oc); \
+        vmapple_machine_##major##_##minor##_options(mc); \
+        mc->desc =3D "QEMU " # major "." # minor " Apple Virtual Machine";=
 \
+        if (latest) { \
+            mc->alias =3D "vmapple"; \
+        } \
+    } \
+    static const TypeInfo machvmapple##major##_##minor##_info =3D { \
+        .name =3D MACHINE_TYPE_NAME("vmapple-" # major "." # minor), \
+        .parent =3D TYPE_VMAPPLE_MACHINE, \
+        .class_init =3D vmapple##major##_##minor##_class_init, \
+    }; \
+    static void machvmapple_machine_##major##_##minor##_init(void) \
+    { \
+        type_register_static(&machvmapple##major##_##minor##_info); \
+    } \
+    type_init(machvmapple_machine_##major##_##minor##_init);
+
+#define DEFINE_VMAPPLE_MACHINE_AS_LATEST(major, minor) \
+    DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, true)
+#define DEFINE_VMAPPLE_MACHINE(major, minor) \
+    DEFINE_VMAPPLE_MACHINE_LATEST(major, minor, false)
+
+#define TYPE_VMAPPLE_MACHINE   MACHINE_TYPE_NAME("vmapple")
+OBJECT_DECLARE_TYPE(VMAppleMachineState, VMAppleMachineClass, VMAPPLE_MACH=
INE)
+
+/* Number of external interrupt lines to configure the GIC with */
+#define NUM_IRQS 256
+
+enum {
+    VMAPPLE_FIRMWARE,
+    VMAPPLE_CONFIG,
+    VMAPPLE_MEM,
+    VMAPPLE_GIC_DIST,
+    VMAPPLE_GIC_REDIST,
+    VMAPPLE_UART,
+    VMAPPLE_RTC,
+    VMAPPLE_PCIE,
+    VMAPPLE_PCIE_MMIO,
+    VMAPPLE_PCIE_ECAM,
+    VMAPPLE_GPIO,
+    VMAPPLE_PVPANIC,
+    VMAPPLE_APV_GFX,
+    VMAPPLE_APV_IOSFC,
+    VMAPPLE_AES_1,
+    VMAPPLE_AES_2,
+    VMAPPLE_BDOOR,
+    VMAPPLE_MEMMAP_LAST,
+};
+
+static MemMapEntry memmap[] =3D {
+    [VMAPPLE_FIRMWARE] =3D           { 0x00100000, 0x00100000 },
+    [VMAPPLE_CONFIG] =3D             { 0x00400000, 0x00010000 },
+
+    [VMAPPLE_GIC_DIST] =3D           { 0x10000000, 0x00010000 },
+    [VMAPPLE_GIC_REDIST] =3D         { 0x10010000, 0x00400000 },
+
+    [VMAPPLE_UART] =3D               { 0x20010000, 0x00010000 },
+    [VMAPPLE_RTC] =3D                { 0x20050000, 0x00001000 },
+    [VMAPPLE_GPIO] =3D               { 0x20060000, 0x00001000 },
+    [VMAPPLE_PVPANIC] =3D            { 0x20070000, 0x00000002 },
+    [VMAPPLE_BDOOR] =3D              { 0x30000000, 0x00200000 },
+    [VMAPPLE_APV_GFX] =3D            { 0x30200000, 0x00010000 },
+    [VMAPPLE_APV_IOSFC] =3D          { 0x30210000, 0x00010000 },
+    [VMAPPLE_AES_1] =3D              { 0x30220000, 0x00004000 },
+    [VMAPPLE_AES_2] =3D              { 0x30230000, 0x00004000 },
+    [VMAPPLE_PCIE_ECAM] =3D          { 0x40000000, 0x10000000 },
+    [VMAPPLE_PCIE_MMIO] =3D          { 0x50000000, 0x1fff0000 },
+
+    /* Actual RAM size depends on configuration */
+    [VMAPPLE_MEM] =3D                { 0x70000000ULL, GiB},
+};
+
+static const int irqmap[] =3D {
+    [VMAPPLE_UART] =3D 1,
+    [VMAPPLE_RTC] =3D 2,
+    [VMAPPLE_GPIO] =3D 0x5,
+    [VMAPPLE_APV_IOSFC] =3D 0x10,
+    [VMAPPLE_APV_GFX] =3D 0x11,
+    [VMAPPLE_AES_1] =3D 0x12,
+    [VMAPPLE_PCIE] =3D 0x20,
+};
+
+#define GPEX_NUM_IRQS 16
+
+static void create_bdif(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    DeviceState *bdif;
+    SysBusDevice *bdif_sb;
+    DriveInfo *di_aux =3D drive_get(IF_PFLASH, 0, 0);
+    DriveInfo *di_root =3D drive_get(IF_PFLASH, 0, 1);
+
+    if (!di_aux) {
+        error_report("No AUX device. Please specify one as pflash drive.");
+        exit(1);
+    }
+
+    if (!di_root) {
+        /* Fall back to the first IF_VIRTIO device as root device */
+        di_root =3D drive_get(IF_VIRTIO, 0, 0);
+    }
+
+    if (!di_root) {
+        error_report("No root device. Please specify one as virtio drive."=
);
+        exit(1);
+    }
+
+    /* PV backdoor device */
+    bdif =3D qdev_new(TYPE_VMAPPLE_BDIF);
+    bdif_sb =3D SYS_BUS_DEVICE(bdif);
+    sysbus_mmio_map(bdif_sb, 0, vms->memmap[VMAPPLE_BDOOR].base);
+
+    qdev_prop_set_drive(DEVICE(bdif), "aux", blk_by_legacy_dinfo(di_aux));
+    qdev_prop_set_drive(DEVICE(bdif), "root", blk_by_legacy_dinfo(di_root)=
);
+
+    sysbus_realize_and_unref(bdif_sb, &error_fatal);
+}
+
+static void create_pvpanic(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    SysBusDevice *pvpanic;
+
+    vms->pvpanic =3D qdev_new(TYPE_PVPANIC_MMIO_DEVICE);
+    pvpanic =3D SYS_BUS_DEVICE(vms->pvpanic);
+    sysbus_mmio_map(pvpanic, 0, vms->memmap[VMAPPLE_PVPANIC].base);
+
+    sysbus_realize_and_unref(pvpanic, &error_fatal);
+}
+
+static bool create_cfg(VMAppleMachineState *vms, MemoryRegion *mem,
+                       Error **errp)
+{
+    ERRP_GUARD();
+    SysBusDevice *cfg;
+    MachineState *machine =3D MACHINE(vms);
+    uint32_t rnd =3D 1;
+
+    vms->cfg =3D qdev_new(TYPE_VMAPPLE_CFG);
+    cfg =3D SYS_BUS_DEVICE(vms->cfg);
+    sysbus_mmio_map(cfg, 0, vms->memmap[VMAPPLE_CONFIG].base);
+
+    qemu_guest_getrandom_nofail(&rnd, sizeof(rnd));
+
+    qdev_prop_set_uint32(vms->cfg, "nr-cpus", machine->smp.cpus);
+    qdev_prop_set_uint64(vms->cfg, "ecid", vms->uuid);
+    qdev_prop_set_uint64(vms->cfg, "ram-size", machine->ram_size);
+    qdev_prop_set_uint32(vms->cfg, "rnd", rnd);
+
+    if (!sysbus_realize_and_unref(cfg, errp)) {
+        error_prepend(errp, "Error creating vmapple cfg device: ");
+        return false;
+    }
+
+    return true;
+}
+
+static void create_gfx(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    int irq_gfx =3D vms->irqmap[VMAPPLE_APV_GFX];
+    int irq_iosfc =3D vms->irqmap[VMAPPLE_APV_IOSFC];
+    SysBusDevice *gfx;
+
+    gfx =3D SYS_BUS_DEVICE(qdev_new("apple-gfx-mmio"));
+    sysbus_mmio_map(gfx, 0, vms->memmap[VMAPPLE_APV_GFX].base);
+    sysbus_mmio_map(gfx, 1, vms->memmap[VMAPPLE_APV_IOSFC].base);
+    sysbus_connect_irq(gfx, 0, qdev_get_gpio_in(vms->gic, irq_gfx));
+    sysbus_connect_irq(gfx, 1, qdev_get_gpio_in(vms->gic, irq_iosfc));
+    sysbus_realize_and_unref(gfx, &error_fatal);
+}
+
+static void create_aes(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    int irq =3D vms->irqmap[VMAPPLE_AES_1];
+    SysBusDevice *aes;
+
+    aes =3D SYS_BUS_DEVICE(qdev_new(TYPE_APPLE_AES));
+    sysbus_mmio_map(aes, 0, vms->memmap[VMAPPLE_AES_1].base);
+    sysbus_mmio_map(aes, 1, vms->memmap[VMAPPLE_AES_2].base);
+    sysbus_connect_irq(aes, 0, qdev_get_gpio_in(vms->gic, irq));
+    sysbus_realize_and_unref(aes, &error_fatal);
+}
+
+static int arm_gic_ppi_index(int cpu_nr, int ppi_index)
+{
+    return NUM_IRQS + cpu_nr * GIC_INTERNAL + ppi_index;
+}
+
+static void create_gic(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+    MachineState *ms =3D MACHINE(vms);
+    /* We create a standalone GIC */
+    SysBusDevice *gicbusdev;
+    QList *redist_region_count;
+    int i;
+    unsigned int smp_cpus =3D ms->smp.cpus;
+
+    vms->gic =3D qdev_new(gicv3_class_name());
+    qdev_prop_set_uint32(vms->gic, "revision", 3);
+    qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
+    /*
+     * Note that the num-irq property counts both internal and external
+     * interrupts; there are always 32 of the former (mandated by GIC spec=
).
+     */
+    qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32);
+
+    uint32_t redist0_capacity =3D
+                vms->memmap[VMAPPLE_GIC_REDIST].size / GICV3_REDIST_SIZE;
+    uint32_t redist0_count =3D MIN(smp_cpus, redist0_capacity);
+
+    redist_region_count =3D qlist_new();
+    qlist_append_int(redist_region_count, redist0_count);
+    qdev_prop_set_array(vms->gic, "redist-region-count", redist_region_cou=
nt);
+
+    gicbusdev =3D SYS_BUS_DEVICE(vms->gic);
+    sysbus_realize_and_unref(gicbusdev, &error_fatal);
+    sysbus_mmio_map(gicbusdev, 0, vms->memmap[VMAPPLE_GIC_DIST].base);
+    sysbus_mmio_map(gicbusdev, 1, vms->memmap[VMAPPLE_GIC_REDIST].base);
+
+    /*
+     * Wire the outputs from each CPU's generic timer and the GICv3
+     * maintenance interrupt signal to the appropriate GIC PPI inputs,
+     * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inpu=
ts.
+     */
+    for (i =3D 0; i < smp_cpus; i++) {
+        DeviceState *cpudev =3D DEVICE(qemu_get_cpu(i));
+
+        /* Map the virt timer to PPI 27 */
+        qdev_connect_gpio_out(cpudev, GTIMER_VIRT,
+                              qdev_get_gpio_in(vms->gic,
+                                               arm_gic_ppi_index(i, 27)));
+
+        /* Map the GIC IRQ and FIQ lines to CPU */
+        sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_=
IRQ));
+        sysbus_connect_irq(gicbusdev, i + smp_cpus,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+    }
+}
+
+static void create_uart(const VMAppleMachineState *vms, int uart,
+                        MemoryRegion *mem, Chardev *chr)
+{
+    hwaddr base =3D vms->memmap[uart].base;
+    int irq =3D vms->irqmap[uart];
+    DeviceState *dev =3D qdev_new(TYPE_PL011);
+    SysBusDevice *s =3D SYS_BUS_DEVICE(dev);
+
+    qdev_prop_set_chr(dev, "chardev", chr);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    memory_region_add_subregion(mem, base,
+                                sysbus_mmio_get_region(s, 0));
+    sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
+}
+
+static void create_rtc(const VMAppleMachineState *vms)
+{
+    hwaddr base =3D vms->memmap[VMAPPLE_RTC].base;
+    int irq =3D vms->irqmap[VMAPPLE_RTC];
+
+    sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq));
+}
+
+static DeviceState *gpio_key_dev;
+static void vmapple_powerdown_req(Notifier *n, void *opaque)
+{
+    /* use gpio Pin 3 for power button event */
+    qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
+}
+
+static void create_gpio_devices(const VMAppleMachineState *vms, int gpio,
+                                MemoryRegion *mem)
+{
+    DeviceState *pl061_dev;
+    hwaddr base =3D vms->memmap[gpio].base;
+    int irq =3D vms->irqmap[gpio];
+    SysBusDevice *s;
+
+    pl061_dev =3D qdev_new("pl061");
+    /* Pull lines down to 0 if not driven by the PL061 */
+    qdev_prop_set_uint32(pl061_dev, "pullups", 0);
+    qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff);
+    s =3D SYS_BUS_DEVICE(pl061_dev);
+    sysbus_realize_and_unref(s, &error_fatal);
+    memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
+    sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
+    gpio_key_dev =3D sysbus_create_simple("gpio-key", -1,
+                                        qdev_get_gpio_in(pl061_dev, 3));
+}
+
+static void vmapple_firmware_init(VMAppleMachineState *vms,
+                                  MemoryRegion *sysmem)
+{
+    hwaddr size =3D vms->memmap[VMAPPLE_FIRMWARE].size;
+    hwaddr base =3D vms->memmap[VMAPPLE_FIRMWARE].base;
+    const char *bios_name;
+    int image_size;
+    char *fname;
+
+    bios_name =3D MACHINE(vms)->firmware;
+    if (!bios_name) {
+        error_report("No firmware specified");
+        exit(1);
+    }
+
+    fname =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (!fname) {
+        error_report("Could not find ROM image '%s'", bios_name);
+        exit(1);
+    }
+
+    memory_region_init_ram(&vms->fw_mr, NULL, "firmware", size, &error_fat=
al);
+    image_size =3D load_image_mr(fname, &vms->fw_mr);
+
+    g_free(fname);
+    if (image_size < 0) {
+        error_report("Could not load ROM image '%s'", bios_name);
+        exit(1);
+    }
+
+    memory_region_add_subregion(get_system_memory(), base, &vms->fw_mr);
+}
+
+static void create_pcie(VMAppleMachineState *vms)
+{
+    hwaddr base_mmio =3D vms->memmap[VMAPPLE_PCIE_MMIO].base;
+    hwaddr size_mmio =3D vms->memmap[VMAPPLE_PCIE_MMIO].size;
+    hwaddr base_ecam =3D vms->memmap[VMAPPLE_PCIE_ECAM].base;
+    hwaddr size_ecam =3D vms->memmap[VMAPPLE_PCIE_ECAM].size;
+    int irq =3D vms->irqmap[VMAPPLE_PCIE];
+    MemoryRegion *mmio_alias;
+    MemoryRegion *mmio_reg;
+    MemoryRegion *ecam_reg;
+    DeviceState *dev;
+    int i;
+    PCIHostState *pci;
+    DeviceState *usb_controller;
+    USBBus *usb_bus;
+
+    dev =3D qdev_new(TYPE_GPEX_HOST);
+    qdev_prop_set_uint32(dev, "num-irqs", GPEX_NUM_IRQS);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+    /* Map only the first size_ecam bytes of ECAM space */
+    ecam_reg =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+    memory_region_init_alias(&vms->ecam_alias, OBJECT(dev), "pcie-ecam",
+                             ecam_reg, 0, size_ecam);
+    memory_region_add_subregion(get_system_memory(), base_ecam,
+                                &vms->ecam_alias);
+
+    /*
+     * Map the MMIO window from [0x50000000-0x7fff0000] in PCI space into
+     * system address space at [0x50000000-0x7fff0000].
+     */
+    mmio_alias =3D g_new0(MemoryRegion, 1);
+    mmio_reg =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+                             mmio_reg, base_mmio, size_mmio);
+    memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias=
);
+
+    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
+                           qdev_get_gpio_in(vms->gic, irq + i));
+        gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
+    }
+
+    pci =3D PCI_HOST_BRIDGE(dev);
+    vms->bus =3D pci->bus;
+    g_assert(vms->bus);
+
+    while ((dev =3D qemu_create_nic_device("virtio-net-pci", true, NULL)))=
 {
+        qdev_realize_and_unref(dev, BUS(vms->bus), &error_fatal);
+    }
+
+    if (defaults_enabled()) {
+        usb_controller =3D qdev_new(TYPE_QEMU_XHCI);
+        qdev_realize_and_unref(usb_controller, BUS(pci->bus), &error_fatal=
);
+
+        usb_bus =3D USB_BUS(object_resolve_type_unambiguous(TYPE_USB_BUS,
+                                                          &error_fatal));
+        usb_create_simple(usb_bus, "usb-kbd");
+        usb_create_simple(usb_bus, "usb-tablet");
+    }
+}
+
+static void vmapple_reset(void *opaque)
+{
+    VMAppleMachineState *vms =3D opaque;
+    hwaddr base =3D vms->memmap[VMAPPLE_FIRMWARE].base;
+
+    cpu_set_pc(first_cpu, base);
+}
+
+static void mach_vmapple_init(MachineState *machine)
+{
+    VMAppleMachineState *vms =3D VMAPPLE_MACHINE(machine);
+    MachineClass *mc =3D MACHINE_GET_CLASS(machine);
+    const CPUArchIdList *possible_cpus;
+    MemoryRegion *sysmem =3D get_system_memory();
+    int n;
+    unsigned int smp_cpus =3D machine->smp.cpus;
+    unsigned int max_cpus =3D machine->smp.max_cpus;
+
+    vms->memmap =3D memmap;
+    machine->usb =3D true;
+
+    possible_cpus =3D mc->possible_cpu_arch_ids(machine);
+    assert(possible_cpus->len =3D=3D max_cpus);
+    for (n =3D 0; n < possible_cpus->len; n++) {
+        Object *cpu;
+        CPUState *cs;
+
+        if (n >=3D smp_cpus) {
+            break;
+        }
+
+        cpu =3D object_new(possible_cpus->cpus[n].type);
+        object_property_set_int(cpu, "mp-affinity",
+                                possible_cpus->cpus[n].arch_id, &error_fat=
al);
+
+        cs =3D CPU(cpu);
+        cs->cpu_index =3D n;
+
+        numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpu),
+                          &error_fatal);
+
+        if (object_property_find(cpu, "has_el3")) {
+            object_property_set_bool(cpu, "has_el3", false, &error_fatal);
+        }
+        if (object_property_find(cpu, "has_el2")) {
+            object_property_set_bool(cpu, "has_el2", false, &error_fatal);
+        }
+        object_property_set_int(cpu, "psci-conduit", QEMU_PSCI_CONDUIT_HVC,
+                                &error_fatal);
+
+        /* Secondary CPUs start in PSCI powered-down state */
+        if (n > 0) {
+            object_property_set_bool(cpu, "start-powered-off", true,
+                                     &error_fatal);
+        }
+
+        object_property_set_link(cpu, "memory", OBJECT(sysmem), &error_abo=
rt);
+        qdev_realize(DEVICE(cpu), NULL, &error_fatal);
+        object_unref(cpu);
+    }
+
+    memory_region_add_subregion(sysmem, vms->memmap[VMAPPLE_MEM].base,
+                                machine->ram);
+
+    create_gic(vms, sysmem);
+    create_bdif(vms, sysmem);
+    create_pvpanic(vms, sysmem);
+    create_aes(vms, sysmem);
+    create_gfx(vms, sysmem);
+    create_uart(vms, VMAPPLE_UART, sysmem, serial_hd(0));
+    create_rtc(vms);
+    create_pcie(vms);
+
+    create_gpio_devices(vms, VMAPPLE_GPIO, sysmem);
+
+    vmapple_firmware_init(vms, sysmem);
+    create_cfg(vms, sysmem, &error_fatal);
+
+    /* connect powerdown request */
+    vms->powerdown_notifier.notify =3D vmapple_powerdown_req;
+    qemu_register_powerdown_notifier(&vms->powerdown_notifier);
+
+    vms->bootinfo.ram_size =3D machine->ram_size;
+    vms->bootinfo.board_id =3D -1;
+    vms->bootinfo.loader_start =3D vms->memmap[VMAPPLE_MEM].base;
+    vms->bootinfo.skip_dtb_autoload =3D true;
+    vms->bootinfo.firmware_loaded =3D true;
+    arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
+
+    qemu_register_reset(vmapple_reset, vms);
+}
+
+static CpuInstanceProperties
+vmapple_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
+{
+    MachineClass *mc =3D MACHINE_GET_CLASS(ms);
+    const CPUArchIdList *possible_cpus =3D mc->possible_cpu_arch_ids(ms);
+
+    assert(cpu_index < possible_cpus->len);
+    return possible_cpus->cpus[cpu_index].props;
+}
+
+
+static int64_t vmapple_get_default_cpu_node_id(const MachineState *ms, int=
 idx)
+{
+    return idx % ms->numa_state->num_nodes;
+}
+
+static const CPUArchIdList *vmapple_possible_cpu_arch_ids(MachineState *ms)
+{
+    int n;
+    unsigned int max_cpus =3D ms->smp.max_cpus;
+
+    if (ms->possible_cpus) {
+        assert(ms->possible_cpus->len =3D=3D max_cpus);
+        return ms->possible_cpus;
+    }
+
+    ms->possible_cpus =3D g_malloc0(sizeof(CPUArchIdList) +
+                                  sizeof(CPUArchId) * max_cpus);
+    ms->possible_cpus->len =3D max_cpus;
+    for (n =3D 0; n < ms->possible_cpus->len; n++) {
+        ms->possible_cpus->cpus[n].type =3D ms->cpu_type;
+        ms->possible_cpus->cpus[n].arch_id =3D
+            arm_build_mp_affinity(n, GICV3_TARGETLIST_BITS);
+        ms->possible_cpus->cpus[n].props.has_thread_id =3D true;
+        ms->possible_cpus->cpus[n].props.thread_id =3D n;
+    }
+    return ms->possible_cpus;
+}
+
+static void vmapple_machine_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc =3D MACHINE_CLASS(oc);
+
+    mc->init =3D mach_vmapple_init;
+    mc->max_cpus =3D 32;
+    mc->block_default_type =3D IF_VIRTIO;
+    mc->no_cdrom =3D 1;
+    mc->pci_allow_0_address =3D true;
+    mc->minimum_page_bits =3D 12;
+    mc->possible_cpu_arch_ids =3D vmapple_possible_cpu_arch_ids;
+    mc->cpu_index_to_instance_props =3D vmapple_cpu_index_to_props;
+    mc->default_cpu_type =3D ARM_CPU_TYPE_NAME("host");
+    mc->get_default_cpu_node_id =3D vmapple_get_default_cpu_node_id;
+    mc->default_ram_id =3D "mach-vmapple.ram";
+
+    object_register_sugar_prop(TYPE_VIRTIO_PCI, "disable-legacy",
+                               "on", true);
+}
+
+static void vmapple_instance_init(Object *obj)
+{
+    VMAppleMachineState *vms =3D VMAPPLE_MACHINE(obj);
+
+    vms->irqmap =3D irqmap;
+
+    object_property_add_uint64_ptr(obj, "uuid", &vms->uuid,
+                                   OBJ_PROP_FLAG_READWRITE);
+    object_property_set_description(obj, "uuid", "Machine UUID (SDOM)");
+}
+
+static const TypeInfo vmapple_machine_info =3D {
+    .name          =3D TYPE_VMAPPLE_MACHINE,
+    .parent        =3D TYPE_MACHINE,
+    .abstract      =3D true,
+    .instance_size =3D sizeof(VMAppleMachineState),
+    .class_size    =3D sizeof(VMAppleMachineClass),
+    .class_init    =3D vmapple_machine_class_init,
+    .instance_init =3D vmapple_instance_init,
+};
+
+static void machvmapple_machine_init(void)
+{
+    type_register_static(&vmapple_machine_info);
+}
+type_init(machvmapple_machine_init);
+
+static void vmapple_machine_10_0_options(MachineClass *mc)
+{
+}
+DEFINE_VMAPPLE_MACHINE_AS_LATEST(10, 0)
+
--=20
2.39.5 (Apple Git-154)