From patchwork Sun Dec 8 20:22:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898646 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 138FEE77181 for ; Sun, 8 Dec 2024 20:24:28 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNnq-00028n-11; Sun, 08 Dec 2024 15:22: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 ) id 1tKNnm-000277-5S for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:50 -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 ) id 1tKNni-000815-Au for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:49 -0500 Received: by mail-ej1-x634.google.com with SMTP id a640c23a62f3a-a9ec267b879so713970866b.2 for ; Sun, 08 Dec 2024 12:22:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689365; x=1734294165; 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=aGHeV2fkKmAouKlC9HBuDSY0rCiJ9SndThF/nrthEDR6CXw1TH2AMCL7MHI4v5dtvU 99GRqvCz3zoR/xZCkNBZCRXiIO7zqr2zDB/nVzslSVeQ3wi4VuFtC2YoZMDHnlxiEfXA qUwrfcP5dbX2oU0D8YwJbnEUh+SGkfqIyyMDxQGUiPgj+G+tK+dVGRTPw93CEITpPfDP O90Gzkq5Ptr4YVAIEKkdutofMjWQ/mJNwnqvjXouErCNp/vm1es/01yS8bxr7Bg1cJ17 X/yPG4LnqCT9fWKh56+YIh3eaW156tLoDfQFNVOVgMH0qA4f7ZkKklaOS1cmTCkzs2Le veoQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689365; x=1734294165; 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=AgOTU3anBUrxc35t0tJVhFOkJ3sk1keTU96Tnv27l1Dw7x7AVgb92RgESHG+b7lMuA IQ0cE7DiLkfQkHokcmd9QVxZ+8hUxbI4VWVD4sE+FLCyWKJvxn2Oe6BfD7/f9FJsgfWh i0/fzrHiG9EdakG40MnLHvlbR7ltP0q+RRjoH9HRdig5Vqq1iNmm7WAlrB/fWt10oUO/ cyq2aan7iL9lGzlvsDIkGZVzDCss3vWxQGwJRgwzOwZnyaAHU3ax3SVvBIbxm7IXfdWP iyYpR6WFW2f+ooiMm2er7EEbqhk0j138/BO0BFZeYbtCN0lKTxRIghP+dsKfQmKlXFx2 kaiA== X-Gm-Message-State: AOJu0YwImFRQMVSTqsIT3euR9nsq1WmyfB8aTccxpR69P1tZfsLo/zHO TdXwtIdZZSSLSG0KXWDsmxnJ0Ha8LxzhIJ98kFJOBzIVvVtaAAMkrqq+tv/P2SG1z+W/1IYFVaj Y/mV2 X-Gm-Gg: ASbGncusWtcHZIY25+tTnRFv+9qjytk1tbrWtxjfjAoghM2F/w+H8Lsud6F6i/Yvb4E vyzy1HBxQkHbGTZ3eCC46nraatNVvhDviuLuPm/9b4IXukzpBdmuzYTj22x2KXprYkOCDHdR4dH Wi1p+04RtORIdBDdW5RlxHINh2ioat5TGeKOf9dPUdeXdq+ip87Ix3NToPn6lV0caU9GE6tIdoB uUaDgh6zwoPnK0EMlm3iYCe8k5gsjDwvjMea2nMRoGD8vv3Fr3J0fOSm621Uelk7N8MqZTbINGs qGQWCctWEY2jG0k3rqBwPgmTYA== X-Google-Smtp-Source: AGHT+IHfBvudKcNJmGYLw0WIVL9Wxb7IKH7DVa2Mqu+fhNvwgBzGaxxnSXgdARt41yze1ng3wqkfNA== X-Received: by 2002:a17:907:9556:b0:aa6:6ece:8eb1 with SMTP id a640c23a62f3a-aa66ece9010mr493428266b.54.1733689364722; Sun, 08 Dec 2024 12:22:44 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.43 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:22:44 -0800 (PST) From: Phil Dennis-Jordan 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: Sun, 8 Dec 2024 21:22:24 +0100 Message-Id: <20241208202238.68873-2-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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 Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 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 -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); #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 @@ #include "qemu/osdep.h" #include "qemu-main.h" +#include "qemu/main-loop.h" #include "sysemu/sysemu.h" #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 + * must be #included here even with no SDL code called from this file. + */ #include #endif -int qemu_default_main(void) +#ifdef CONFIG_DARWIN +#include +#endif + +static void *qemu_default_main(void *opaque) { int status; + bql_lock(); status = qemu_main_loop(); qemu_cleanup(status); + bql_unlock(); - return status; + exit(status); } -int (*qemu_main)(void) = 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) = os_darwin_cfrunloop_main; +#endif 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; +@class QemuCocoaPasteboardTypeOwner; + static void cocoa_update(DisplayChangeListener *dcl, int x, int y, int w, int h); @@ -107,6 +109,7 @@ static void cocoa_switch(DisplayChangeListener *dcl, static NSInteger cbchangecount = -1; static QemuClipboardInfo *cbinfo; static QemuEvent cbevent; +static QemuCocoaPasteboardTypeOwner *cbowner; // 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"); - if (cocoaView) - [cocoaView release]; + [cocoaView release]; + [cbowner release]; + cbowner = nil; + [super dealloc]; } @@ -1943,8 +1948,6 @@ - (void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSPasteboardType)t @end -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(QemuClipboardInfo *info, } } -/* - * 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 = 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, DisplayOptions *opts) COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n"); - qemu_main = cocoa_main; - // Pull this console process up to being a fully-fledged graphical // app with a menubar and Dock icon ProcessSerialNumber psn = { 0, kCurrentProcess }; @@ -2190,6 +2156,12 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts) qemu_clipboard_peer_register(&cbpeer); [pool release]; + + /* + * The Cocoa UI will run the NSApplication runloop on the main thread + * rather than the default Core Foundation one. + */ + qemu_main = cocoa_main; } static QemuDisplay qemu_display_cocoa = { 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" #include "ui/console.h" #include "ui/gtk.h" @@ -2485,6 +2486,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *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 = NULL; } 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" static int sdl2_num_outputs; static struct sdl2_console *sdl2_console; @@ -965,6 +966,9 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) } atexit(sdl_cleanup); + + /* SDL's event polling (in dpy_refresh) must happen on the main thread. */ + qemu_main = NULL; } static QemuDisplay qemu_display_sdl2 = { From patchwork Sun Dec 8 20:22:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898655 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F1560E77173 for ; Sun, 8 Dec 2024 20:25:41 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNns-0002BJ-QX; Sun, 08 Dec 2024 15:22: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 ) id 1tKNnq-00029L-9T for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:54 -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 ) id 1tKNnm-00081o-3O for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:54 -0500 Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-a9a977d6cc7so536001766b.3 for ; Sun, 08 Dec 2024 12:22:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689368; x=1734294168; 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=3P0OhWusWA1UJowvMNR/Eh3nQuue8s/YqKMMTGNFbW5V9nDoVJsYz0NHjWv82zdBSe uZCKjAAa6EuNKngQFN7ZzI93G/mSGj3O/SxCDgX3jPxsQuBHln7g+AkGpEiOnW2ZjZ1W KCKpXrzPVUS4dBwbAgStzE7U/jFfWWYb14W1ll7N7VihKw2iCnp0z6t4GXOSAcbV+QZt AMfjruIExE/MufETIhSKEePqCueeoTAOmBaBwapfMftc1d5XdQId8B5gkiZkKqERgP8J 4WAEyxbyjTMhYXZLKwBoQxB+rgQrX9a5+rw9c3bqJzBJpOCbl5zakfnQdMlhVwbp3jh+ X8rA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689368; x=1734294168; 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=hLnKUGms3LMpLNFrQHLVJWTwSqL2v8UtnE8Ncjx39SQnQWijAf9M8sMxCQnx2gb/5D zrE4cBZOCFHJ6jE6oS8WwsPb5P0TG8onT5RxZZDm4vWRyS8SjF8WLsFKqzoJGD2F5W3l lVbL6xyJfsFnDVhW2uh0lYnnloToS9FZ2AmqFoyjpDKhhFhA3+4yyOCbe9LbMJ+EiJX0 Hrxt9YrMaoJ1Lhkx6kJlbLOdpOHLPLe2hfe/jeoNC5r5iVuRzb5Zu2f+G7z291xrihQo gXMMYL/yBn5zSnRISuLmvingIFX5Fn1K55mls9lATWq7yTgDBNT1/uTSSKX4DhcZ2Pvn Ei1w== X-Gm-Message-State: AOJu0Ywpol1nCmJf1xdeQCVoV4F62rK7gkkPK9/L2Tegai+alhZgy3XP Cdnlbtw+iU/BPY44nfToo+TCQ21r/twLz2953KWTMpTjZ/ga393ZVSFxY01mlQnAZsNDUGS8Otu 0stEI X-Gm-Gg: ASbGncvaXJPfRg/aHNyQuRmYjMeW691LdHWQ8xHBJoA5QlzyY1PGiC5xy+sQaBPS7ZL gmANJnKc5GhcXHsPz5AkxJER5yynkNSs71Gg6YYs/60qXTr5HUtDbnWNuovJtpPAKbus07Y9LKh cVZ+KdmkeKMde6nx082uMGne8Lbim32Oj7q+W4JMiIHgEY44ePgQeIMEnY8remmDyE/+Op1E2QI rrThh5bwkE6AUj7Pk/eqgdl8xvFBXqsbWSQ7aOVQMNl8AD8pCBppTpwEmHrZqr2JlhYH/eDpSDh QHS03nHJHVhCSCr6wh3smGFThQ== X-Google-Smtp-Source: AGHT+IHdxCeMtuyapDfyG4A6n3sjNu/Pn+5OPYC29BOfXatDzkosIvabt2pZgkpC10CemyPflZ8KLg== X-Received: by 2002:a05:6402:915:b0:5d0:d818:559d with SMTP id 4fb4d7f45d1cf-5d3be6801a6mr29799061a12.11.1733689368276; Sun, 08 Dec 2024 12:22:48 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.44 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:22:46 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 02/15] hw/display/apple-gfx: Introduce ParavirtualizedGraphics.Framework support Date: Sun, 8 Dec 2024 21:22:25 +0100 Message-Id: <20241208202238.68873-3-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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 Co-authored-by: Alexander Graf 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 strategies have been used (libdispatch, blocking and non-blocking BHs, RCU, etc.) depending on the specific requirements at each framework entry and exit point. Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 Resettable 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 from 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 calls 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 using 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 functionality. * 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 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) variant + * + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * 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 provides + * 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-based + * system device for macOS on arm64 VMs. + */ + +#include "qemu/osdep.h" +#import +#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 add + * 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 unmapMemory; +@property (readwrite, nonatomic, copy, nullable) IOSFCRaiseInterrupt raiseInterrupt; +@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 = opaque; + job->value = [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 = { + .state = opaque, + .offset = offset, + .completed = false, + }; + dispatch_queue_t queue = + 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 = 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 = { + .state = opaque, + .offset = offset, + .value = val, + .completed = false, + }; + dispatch_queue_t queue = + 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 = { + .read = iosfc_read, + .write = iosfc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +static void raise_irq_bh(void *opaque) +{ + qemu_irq *irq = opaque; + + qemu_irq_pulse(*irq); +} + +static void *apple_gfx_mmio_map_surface_memory(uint64_t guest_physical_address, + uint64_t length, bool read_only) +{ + void *mem; + MemoryRegion *region = NULL; + + RCU_READ_LOCK_GUARD(); + mem = apple_gfx_host_ptr_for_gpa_range(guest_physical_address, + length, read_only, ®ion); + if (mem) { + memory_region_ref(region); + } + return mem; +} + +static bool apple_gfx_mmio_unmap_surface_memory(void *ptr) +{ + MemoryRegion *region; + ram_addr_t offset = 0; + + RCU_READ_LOCK_GUARD(); + region = memory_region_from_host(ptr, &offset); + if (!region) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: memory at %p to be unmapped not " + "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 = + [PGIOSurfaceHostDeviceDescriptor new]; + PGIOSurfaceHostDevice *iosfc_host_dev; + + iosfc_desc.mapMemory = + ^bool(uint64_t phys, uint64_t len, bool ro, void **va, void *e, void *f) { + *va = apple_gfx_mmio_map_surface_memory(phys, len, ro); + + trace_apple_gfx_iosfc_map_memory(phys, len, ro, va, e, f, *va); + + return *va != NULL; + }; + + iosfc_desc.unmapMemory = + ^bool(void *va, void *b, void *c, void *d, void *e, void *f) { + return apple_gfx_mmio_unmap_surface_memory(va); + }; + + iosfc_desc.raiseInterrupt = ^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 = + [[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 = APPLE_GFX_MMIO(dev); + PGDeviceDescriptor *desc = [PGDeviceDescriptor new]; + + desc.raiseInterrupt = ^(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 = true; + s->pgiosfc = apple_gfx_prepare_iosurface_host_device(s); + + if (!apple_gfx_common_realize(&s->common, dev, desc, errp)) { + [s->pgiosfc release]; + s->pgiosfc = nil; + } + + [desc release]; + desc = nil; + } +} + +static void apple_gfx_mmio_init(Object *obj) +{ + AppleGFXMMIOState *s = 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 = APPLE_GFX_MMIO(obj); + [s->common.pgdev reset]; +} + + +static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.hold = apple_gfx_mmio_reset; + dc->hotpluggable = false; + dc->realize = apple_gfx_mmio_realize; +} + +static TypeInfo apple_gfx_mmio_types[] = { + { + .name = TYPE_APPLE_GFX_MMIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AppleGFXMMIOState), + .class_init = apple_gfx_mmio_class_init, + .instance_init = 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 +#import +#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 pgdev; + id pgdisp; + QemuConsole *con; + id mtl; + id mtl_queue; + + /* List `tasks` is protected by task_mutex */ + QemuMutex task_mutex; + PGTaskList tasks; + + /* Mutable state (BQL protected) */ + QEMUCursor *cursor; + DisplaySurface *surface; + id 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 © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * 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 provides + * 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 +#include +#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[] = { + { .x = 1440, .y = 1080 }, + { .x = 1280, .y = 1024 }, +}; + +static Error *apple_gfx_mig_blocker; +static uint32_t next_pgdisplay_serial_num = 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 + * which is opaque from the framework's point of view. It is used in callbacks + * 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 their + * 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 managing + * 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 are + * 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 = mach_vm_allocate(mach_task_self(), &task_mem, len, VM_FLAGS_ANYWHERE); + if (r != KERN_SUCCESS) { + return NULL; + } + + task = g_new0(PGTask_t, 1); + task->s = s; + task->address = task_mem; + task->len = len; + task->mapped_regions = 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 = task->mapped_regions; + MemoryRegion *region; + size_t i; + + for (i = 0; i < regions->len; ++i) { + region = 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 = 0; + hwaddr ram_region_length = length; + + ram_region = 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 = memory_region_get_ram_ptr(ram_region); + if (!host_ptr) { + return NULL; + } + host_ptr += ram_region_offset; + *mapping_in_region = 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 = true; + MemoryRegion *region; + + RCU_READ_LOCK_GUARD(); + QEMU_LOCK_GUARD(&s->task_mutex); + + trace_apple_gfx_map_memory(task, range_count, virtual_offset, read_only); + for (int i = 0; i < range_count; i++) { + PGPhysicalMemoryRange_t *range = &ranges[i]; + + target = task->address + virtual_offset; + virtual_offset += range->physicalLength; + + trace_apple_gfx_map_memory_range(i, range->physicalAddress, + range->physicalLength); + + region = NULL; + source_ptr = apple_gfx_host_ptr_for_gpa_range(range->physicalAddress, + range->physicalLength, + read_only, ®ion); + if (!source_ptr) { + success = 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 = 0; + max_protection = 0; + /* Map guest RAM at range->physicalAddress into PG task memory range */ + r = 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 == 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 = task->address + virtual_offset; + r = mach_vm_allocate(mach_task_self(), &range_address, length, + VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE); + g_assert(r == 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 = s->using_managed_texture_storage; + uint32_t width = surface_width(s->surface); + uint32_t height = surface_height(s->surface); + MTLRegion region = MTLRegionMake2D(0, 0, width, height); + id command_buffer = [s->mtl_queue commandBuffer]; + id texture = s->texture; + + assert(bql_locked()); + [texture retain]; + [command_buffer retain]; + + s->rendering_frame_width = width; + s->rendering_frame_height = height; + + dispatch_async(get_background_queue(), ^{ + /* + * This is not safe to call from the BQL/BH due to PVG-internal locks + * causing deadlocks. + */ + bool r = [s->pgdisp encodeCurrentFrameToCommandBuffer:command_buffer + texture:texture + region:region]; + if (!r) { + [texture release]; + [command_buffer release]; + qemu_log_mask(LOG_GUEST_ERROR, + "%s: encodeCurrentFrameToCommandBuffer:texture:region: " + "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 synced. */ + id blit = [command_buffer blitCommandEncoder]; + [blit synchronizeResource:texture]; + [blit endEncoding]; + } + [texture release]; + [command_buffer addCompletedHandler: + ^(id cb) + { + aio_bh_schedule_oneshot(qemu_get_aio_context(), + apple_gfx_render_frame_completed_bh, s); + }]; + [command_buffer commit]; + [command_buffer release]; + }); +} + +static void copy_mtl_texture_to_surface_mem(id 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 = texture.width, height = texture.height; + MTLRegion region = 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 = opaque; + + @autoreleasepool { + --s->pending_frames; + assert(s->pending_frames >= 0); + + /* Only update display if mode hasn't changed since we started rendering. */ + if (s->rendering_frame_width == surface_width(s->surface) && + s->rendering_frame_height == surface_height(s->surface)) { + copy_mtl_texture_to_surface_mem(s->texture, surface_data(s->surface)); + if (s->gfx_update_requested) { + s->gfx_update_requested = false; + dpy_gfx_update_full(s->con); + graphic_hw_update_done(s->con); + s->new_frame_ready = false; + } else { + s->new_frame_ready = true; + } + } + if (s->pending_frames > 0) { + apple_gfx_render_new_frame(s); + } + } +} + +static void apple_gfx_fb_update_display(void *opaque) +{ + AppleGFXState *s = opaque; + + assert(bql_locked()); + if (s->new_frame_ready) { + dpy_gfx_update_full(s->con); + s->new_frame_ready = false; + graphic_hw_update_done(s->con); + } else if (s->pending_frames > 0) { + s->gfx_update_requested = true; + } else { + graphic_hw_update_done(s->con); + } +} + +static const GraphicHwOps apple_gfx_fb_ops = { + .gfx_update = apple_gfx_fb_update_display, + .gfx_update_async = 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 == surface_width(s->surface) && + height == surface_height(s->surface)) { + return; + } + + [s->texture release]; + + s->surface = qemu_create_displaysurface(width, height); + + @autoreleasepool { + textureDescriptor = + [MTLTextureDescriptor + texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm + width:width + height:height + mipmapped:NO]; + textureDescriptor.usage = s->pgdisp.minimumTextureUsage; + s->texture = [s->mtl newTextureWithDescriptor:textureDescriptor]; + s->using_managed_texture_storage = + (s->texture.storageMode == 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 = opaque; + update_cursor(s); +} + +typedef struct AppleGFXSetCursorGlyphJob { + AppleGFXState *s; + NSBitmapImageRep *glyph; + PGDisplayCoord_t hotspot; +} AppleGFXSetCursorGlyphJob; + +static void set_cursor_glyph(void *opaque) +{ + AppleGFXSetCursorGlyphJob *job = opaque; + AppleGFXState *s = job->s; + NSBitmapImageRep *glyph = job->glyph; + uint32_t bpp = glyph.bitsPerPixel; + size_t width = glyph.pixelsWide; + size_t height = glyph.pixelsHigh; + size_t padding_bytes_per_row = glyph.bytesPerRow - width * 4; + const uint8_t* px_data = glyph.bitmapData; + + trace_apple_gfx_cursor_set(bpp, width, height); + + if (s->cursor) { + cursor_unref(s->cursor); + s->cursor = NULL; + } + + if (bpp == 32) { /* Shouldn't be anything else, but just to be safe...*/ + s->cursor = cursor_alloc(width, height); + s->cursor->hot_x = job->hotspot.x; + s->cursor->hot_y = job->hotspot.y; + + uint32_t *dest_px = s->cursor->data; + + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + /* + * NSBitmapImageRep's red & blue channels are swapped + * compared to QEMUCursor's. + */ + *dest_px = + (px_data[0] << 16u) | + (px_data[1] << 8u) | + (px_data[2] << 0u) | + (px_data[3] << 24u); + ++dest_px; + px_data += 4; + } + px_data += 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 = opaque; + MemTxResult r; + + r = dma_memory_read(&address_space_memory, job->physical_address, + job->dst, job->length, MEMTXATTRS_UNSPECIFIED); + job->success = r == MEMTX_OK; + + qemu_sem_post(&job->sem); +} + +static bool apple_gfx_read_memory(AppleGFXState *s, hwaddr physical_address, + uint64_t length, void *dst) +{ + AppleGFXReadMemoryJob job = { + .physical_address = physical_address, .length = length, .dst = 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 = opaque; + job->value = [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 = { + .state = opaque, + .offset = offset, + .completed = false, + }; + dispatch_queue_t queue = 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 = 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 turn + * may call back out on one or more of the callback blocks. For this reason, + * 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 = { + .state = opaque, + .offset = offset, + .value = val, + .completed = false, + }; + dispatch_queue_t queue = 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 = { + .read = apple_gfx_read, + .write = apple_gfx_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static size_t apple_gfx_get_default_mmio_range_size(void) +{ + size_t mmio_range_size; + @autoreleasepool { + PGDeviceDescriptor *desc = [PGDeviceDescriptor new]; + mmio_range_size = 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 = 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 *desc) +{ + desc.createTask = ^(uint64_t vmSize, void * _Nullable * _Nonnull baseAddress) { + PGTask_t *task = apple_gfx_new_task(s, vmSize); + *baseAddress = (void *)task->address; + trace_apple_gfx_create_task(vmSize, *baseAddress); + return task; + }; + + desc.destroyTask = ^(PGTask_t * _Nonnull task) { + trace_apple_gfx_destroy_task(task, task->mapped_regions->len); + + apple_gfx_destroy_task(s, task); + }; + + desc.mapMemory = ^bool(PGTask_t * _Nonnull task, uint32_t range_count, + 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 = ^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 = ^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 = opaque; + + /* Drop frames if guest gets too far ahead. */ + if (s->pending_frames >= 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(AppleGFXState *s) +{ + PGDisplayDescriptor *disp_desc = [PGDisplayDescriptor new]; + + disp_desc.name = @"QEMU display"; + disp_desc.sizeInMillimeters = NSMakeSize(400., 300.); /* A 20" display */ + disp_desc.queue = dispatch_get_main_queue(); + disp_desc.newFrameEventHandler = ^(void) { + trace_apple_gfx_new_frame(); + aio_bh_schedule_oneshot(qemu_get_aio_context(), new_frame_handler_bh, s); + }; + disp_desc.modeChangeHandler = ^(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 = ^(NSBitmapImageRep *glyph, + PGDisplayCoord_t hotspot) { + AppleGFXSetCursorGlyphJob *job = g_malloc0(sizeof(*job)); + job->s = s; + job->glyph = glyph; + job->hotspot = hotspot; + [glyph retain]; + aio_bh_schedule_oneshot(qemu_get_aio_context(), + set_cursor_glyph, job); + }; + disp_desc.cursorShowHandler = ^(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 = ^(void) { + trace_apple_gfx_cursor_move(); + aio_bh_schedule_oneshot(qemu_get_aio_context(), + update_cursor_bh, s); + }; + + return disp_desc; +} + +static NSArray* apple_gfx_prepare_display_mode_array(void) +{ + PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)]; + NSArray* mode_array; + int i; + + for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) { + modes[i] = + [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i] refreshRateInHz:60.]; + } + + mode_array = [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_gfx_modes)]; + + for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) { + [modes[i] release]; + modes[i] = nil; + } + + return mode_array; +} + +static id copy_suitable_metal_device(void) +{ + id dev = nil; + NSArray> *devs = MTLCopyAllDevices(); + + /* Prefer a unified memory GPU. Failing that, pick a non-removable GPU. */ + for (size_t i = 0; i < devs.count; ++i) { + if (devs[i].hasUnifiedMemory) { + dev = devs[i]; + break; + } + if (!devs[i].removable) { + dev = devs[i]; + } + } + + if (dev != nil) { + [dev retain]; + } else { + dev = 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 == 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 = copy_suitable_metal_device(); + s->mtl_queue = [s->mtl newCommandQueue]; + + desc.device = s->mtl; + + apple_gfx_register_task_mapping_handlers(s, desc); + + s->cursor_show = true; + + s->pgdev = PGNewDeviceWithDescriptor(desc); + + disp_desc = apple_gfx_prepare_display_descriptor(s); + /* + * Although the framework does, this integration currently does not support + * 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 macOS + * guest will ignore these displays if they share the same serial number, + * so ensure each instance gets a unique one. + */ + s->pgdisp = [s->pgdev newDisplayWithDescriptor:disp_desc + port:0 + serialNum:next_pgdisplay_serial_num++]; + [disp_desc release]; + s->pgdisp.modeList = apple_gfx_prepare_display_mode_array(); + + s->con = 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('artist.c')) system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('ati.c', 'ati_2d.c', 'ati_dbg.c'), pixman]) +if host_os == 'darwin' + system_ss.add(when: 'CONFIG_MAC_PVG', if_true: [files('apple-gfx.m'), pvg, metal]) + if cpu == 'aarch64' + system_ss.add(when: 'CONFIG_MAC_PVG_MMIO', if_true: [files('apple-gfx-mmio.m'), pvg, metal]) + endif +endif if config_all_devices.has_key('CONFIG_VIRTIO_GPU') virtio_gpu_ss = 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=0x%"PRIx64" res=0x%"PRIx64 +apple_gfx_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64 +apple_gfx_create_task(uint32_t vm_size, void *va) "vm_size=0x%x base_addr=%p" +apple_gfx_destroy_task(void *task, unsigned int num_mapped_regions) "task=%p, task->mapped_regions->len=%u" +apple_gfx_map_memory(void *task, uint32_t range_count, uint64_t virtual_offset, uint32_t read_only) "task=%p range_count=0x%x virtual_offset=0x%"PRIx64" read_only=%d" +apple_gfx_map_memory_range(uint32_t i, uint64_t phys_addr, uint64_t phys_len) "[%d] phys_addr=0x%"PRIx64" phys_len=0x%"PRIx64 +apple_gfx_remap(uint64_t retval, void *source_ptr, uint64_t target) "retval=%"PRId64" source=%p target=0x%"PRIx64 +apple_gfx_unmap_memory(void *task, uint64_t virtual_offset, uint64_t length) "task=%p virtual_offset=0x%"PRIx64" length=0x%"PRIx64 +apple_gfx_read_memory(uint64_t phys_address, uint64_t length, void *dst) "phys_addr=0x%"PRIx64" length=0x%"PRIx64" dest=%p" +apple_gfx_raise_irq(uint32_t vector) "vector=0x%x" +apple_gfx_new_frame(void) "" +apple_gfx_mode_change(uint64_t x, uint64_t y) "x=%"PRId64" y=%"PRId64 +apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint64_t height) "bpp=%d width=%"PRId64" height=0x%"PRId64 +apple_gfx_cursor_show(uint32_t show) "show=%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=0x%"PRIx64" res=0x%"PRIx64 +apple_gfx_mmio_iosfc_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"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=0x%"PRIx64" len=0x%"PRIx64" ro=%d va=%p e=%p f=%p -> *va=%p" +apple_gfx_iosfc_map_memory_new_region(size_t i, void *region, uint64_t start, uint64_t end) "index=%zu, region=%p, 0x%"PRIx64"-0x%"PRIx64 +apple_gfx_iosfc_unmap_memory(void *a, void *b, void *c, void *d, void *e, void *f) "a=%p b=%p c=%p d=%p e=%p f=%p" +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=0x%x" + diff --git a/meson.build b/meson.build index 147097c652e..1303664e167 100644 --- a/meson.build +++ b/meson.build @@ -794,6 +794,8 @@ socket = [] version_res = [] coref = [] iokit = [] +pvg = not_found +metal = [] emulator_link_args = [] midl = not_found widl = not_found @@ -815,6 +817,8 @@ elif host_os == 'darwin' coref = dependency('appleframeworks', modules: 'CoreFoundation') iokit = dependency('appleframeworks', modules: 'IOKit', required: false) host_dsosuf = '.dylib' + pvg = dependency('appleframeworks', modules: 'ParavirtualizedGraphics') + metal = dependency('appleframeworks', modules: 'Metal') elif host_os == 'sunos' socket = [cc.find_library('socket'), cc.find_library('nsl'), From patchwork Sun Dec 8 20:22:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898648 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E1197E77180 for ; Sun, 8 Dec 2024 20:24:37 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNnw-0002EW-0G; Sun, 08 Dec 2024 15:23: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 ) id 1tKNnr-0002B0-MB for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:55 -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 ) id 1tKNnn-00082U-Lx for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:55 -0500 Received: by mail-ed1-x535.google.com with SMTP id 4fb4d7f45d1cf-5d3d14336f0so3275189a12.3 for ; Sun, 08 Dec 2024 12:22:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689370; x=1734294170; 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=BnEuKn53agxFNyZzS2csnm1bHK0iNNaCfaiJg0t2ljBxkIdfcXGDlNa3zJPtsJgvzX AsuQLKSHqi9Ss7r8pBrUXiZUIwwS4QUbXfQj63yqjt9iTB6X2YIeFbhE5jNwdlo+ma8W BFlIMCihDIH81hFFOlqhz+6yUl3Wmuilp0pD2O3GGzcJc5DauUp6S1v2SdzEJkqwifo/ cEPZOLomzA7N44r2wQtoXnLLeIVnPMBgI/qb6A8bW7dAPaIxzCKQHDgExytFiYmj7gLF a8ysgXvAYh2YL6rXaKSq43O5Y5ZQnXiyGv3LGYvlhYDoe3HL6wmscfqtQWHD0KSnbvpy IGNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689370; x=1734294170; 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=wARDoQ6LvINRuOSe2CYGBSv2XQylHqbdYTN5ePZjjNDlaPopFpOnpekkcox3tEdwrD V8h7u325f2Eo32wHwkVXYv2t8D5trvEiHr6tQDVsqvPfwF/GTpO+MErVSSyCEgJofZKx FuqN9kgRhoWDc44ISN3/LfI5rWKnQkG6gxcbMDhLf2SJA8alk27DA7nzeqo4vqHhW5CE LWp6UI/e8L9NR8sxPI8TK+3gWyb9X2jFG/036EBnbXnGuEDdMMCXaMyiaSr7syS4z9vJ 9o6fJZTYXe5y9+cr2lVb7Rx4DhvdVwJS5orSQsg7IQFfJOAFTe14Pu7gd2ikOUiLbhk2 Oz/g== X-Gm-Message-State: AOJu0Ywu3kiIEvmiZe1x3hV7d/OmK1ytLry+n5dzhBMStpHC6UcdKoPX SJgCLplSa6j68GS5XNe80PSp+IahZdv4aZqIaEazQMzLjfa4Wm3rtGHouYh2BIH0uGZ7IaVKn94 ltYej X-Gm-Gg: ASbGncs4xX72Av1k5gr0iMtWOzgpCbm6oyvbIJADGopUL5f7qoXFc3YYtpAHQEfcfvZ dHROhj6z4RNlcKTuIwvUEvPaoEjuOSZ6rX94SAYsfrTts/eBUC481A9HW2OQ5+ZH6jVDg3i+LX5 8r6ffgsHJyE3K1kb9BNfRKgeE3u5mTshhtR7WIqq0E1uwtQIFdO2tNUyluyPLpHOqxNhT93IS8P 2tFBU5UykIHo6ukYnUM5IDSN1ZfRYsudebbd4iaLTQwpFROs47n7mbqV9pImo7STRM1u9ZjSanZ f0su43D7Q7bh8TDs3wRn0+eKaA== X-Google-Smtp-Source: AGHT+IE8L9zC5CZpG3y1dy2uvP7mAwqMgMA/EWeEljpbnNCuSRp0dO5WTgzv01URXD3tMrzH48uj9g== X-Received: by 2002:a17:906:3292:b0:aa6:4494:e354 with SMTP id a640c23a62f3a-aa64494e742mr814074766b.42.1733689370038; Sun, 08 Dec 2024 12:22:50 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.48 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:22:49 -0800 (PST) From: Phil Dennis-Jordan 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: Sun, 8 Dec 2024 21:22:26 +0100 Message-Id: <20241208202238.68873-4-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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 Reviewed-by: Akihiko Odaki --- 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 +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 © 2023-2024 Phil Dennis-Jordan + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * ParavirtualizedGraphics.framework is a set of libraries that macOS provides + * 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 device + * 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 + +OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXPCIState, APPLE_GFX_PCI) + +struct AppleGFXPCIState { + PCIDevice parent_obj; + + AppleGFXState common; +}; + +static const char* apple_gfx_pci_option_rom_path = NULL; + +static void apple_gfx_init_option_rom_path(void) +{ + NSURL *option_rom_url = PGCopyOptionROMURL(); + const char *option_rom_path = option_rom_url.fileSystemRepresentation; + apple_gfx_pci_option_rom_path = g_strdup(option_rom_path); + [option_rom_url release]; +} + +static void apple_gfx_pci_init(Object *obj) +{ + AppleGFXPCIState *s = 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 = PCI_DEVICE_CLASS(object_get_class(obj)); + apple_gfx_init_option_rom_path(); + pci->romfile = 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 = 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 = g_malloc0(sizeof(*job)); + job->device = dev; + job->vector = 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 = APPLE_GFX_PCI(dev); + int ret; + + pci_register_bar(dev, PG_PCI_BAR_MMIO, + PCI_BASE_ADDRESS_SPACE_MEMORY, &s->common.iomem_gfx); + + ret = msi_init(dev, 0x0 /* config offset; 0 = find space */, + PG_PCI_MAX_MSI_VECTORS, true /* msi64bit */, + false /* msi_per_vector_mask */, errp); + if (ret != 0) { + return; + } + + @autoreleasepool { + PGDeviceDescriptor *desc = [PGDeviceDescriptor new]; + desc.raiseInterrupt = ^(uint32_t vector) { + apple_gfx_pci_interrupt(dev, vector); + }; + + apple_gfx_common_realize(&s->common, DEVICE(dev), desc, errp); + [desc release]; + desc = nil; + } +} + +static void apple_gfx_pci_reset(Object *obj, ResetType type) +{ + AppleGFXPCIState *s = APPLE_GFX_PCI(obj); + [s->common.pgdev reset]; +} + +static void apple_gfx_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pci = PCI_DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.hold = apple_gfx_pci_reset; + dc->desc = "macOS Paravirtualized Graphics PCI Display Controller"; + dc->hotpluggable = false; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + + pci->vendor_id = PG_PCI_VENDOR_ID; + pci->device_id = PG_PCI_DEVICE_ID; + pci->class_id = PCI_CLASS_DISPLAY_OTHER; + pci->realize = apple_gfx_pci_realize; + + /* TODO: Property for setting mode list */ +} + +static TypeInfo apple_gfx_pci_types[] = { + { + .name = TYPE_APPLE_GFX_PCI, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(AppleGFXPCIState), + .class_init = apple_gfx_pci_class_init, + .instance_init = apple_gfx_pci_init, + .interfaces = (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('ati.c', 'ati_2d.c', 'ati_ if host_os == '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 == 'aarch64' system_ss.add(when: 'CONFIG_MAC_PVG_MMIO', if_true: [files('apple-gfx-mmio.m'), pvg, metal]) endif From patchwork Sun Dec 8 20:22:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898647 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 70B06E77173 for ; Sun, 8 Dec 2024 20:24:32 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNnw-0002Es-Lp; Sun, 08 Dec 2024 15:23: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 ) id 1tKNnt-0002Bv-AT for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:57 -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 ) id 1tKNnp-000830-Jo for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:57 -0500 Received: by mail-ej1-x62f.google.com with SMTP id a640c23a62f3a-aa679ad4265so100104066b.0 for ; Sun, 08 Dec 2024 12:22:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689372; x=1734294172; 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=WsrJgEGM0LElA/tP3Ocv4z3QWHlJIH3hxNBE6OthS2Om48a6XxeRWrtzTNQV8C0sG9 1+LrnhAXgTRGoaD7HKXi4GMRVFHJj4kro3ue0vxMzfld9syc9cwQ4a4Xk8Mh6tUoWWwF o3Jb+X4minxIZJGvllOHjCDeTgLdeyq2h/FmbPkLtcA5AsaX5TQbb4wNzFe/ppwq1wMj 2v2Fy9Nb7CfUHpl5Dr41Z2q14a7VptP92ATj5Bvdm8HbgmzZ2YWAgUzC86FEQpwtQ7nJ wLN3uJJe+tGVgAuNpJKdFWmglWDQbRnKCqbZF+Gk+C8gQpf+10CSLWJaoFjHUHPNmfTk RX5Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689372; x=1734294172; 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=MT6VGX+mYmqbIHvjGRcHHB+bUKplzUI5KweEgNdqfuKFQOtbeHLnrJscbve7YQRQqC 8xw6fykPdGCh341+MDS20SybadfZaodMqQULhv39YtCLG5YQBPupPxPiBwhAeLutDWxZ dKzgxH21ggvXJrk4CS4FHbyW5AJuelHc+hjIEAOPOK6PRL+Inlg/jvn2yhaY9BlK7bOK ab/mjgdqHLzhXw5jgTKuBBzm7JBpxJwdoAMOmJCoRRqJ65DPuuMe6BG4fe7Y2gcHtV3F KiduJ99jx9g4O+MNlovFQ7Al9ZEcUMn6juAnhkAXd1f2vpaC2ldOuyHoVE5374rZMHaZ m4AA== X-Gm-Message-State: AOJu0YzReYvi4lrtyPqPld6elt2rjS3DRCJI+z1xxidQwnOMjN6Tzfbe HkUfTp5AHMaKMqJMHPH1gh4cpW4RP/vpAnPoD4Q5VOmHGOemX8i/ZkHfZiaCrYgBlsD2/s2M6LW 1/T0v X-Gm-Gg: ASbGncuK++vpVz8aPPPwCvW/3FYhBU8aq1cJqeilSjBm4Owju92DxUM1jsComfsQzXn Tgln76yNh0q/IolYtBwNjYkocU6hHdu03BvTFrhGzimZIiZlYvOQijBfUHnnD9kiLBQs7V8AY8q mfj/Q9zAu+S1seMfhxYbpe7KBtgJTIgVI3IewmmL7DqL0VAZwwJhGCmL6/Yg4bG8y5FNhwdKZvQ pKsV/EzoyWRiFVryG8ZWkE1/AxALZ8JDe1poQGio68EjnaiC2rP8VpR2DJCgRszMMvw97pxktK1 X4VXS57ZeVAKn/Ic0RoyeUKTPg== X-Google-Smtp-Source: AGHT+IG4DVdly819Id8Q6GQ664lI4I7r6Ab7atvHvRubEL7ySs4fdvWb35IRrS7fO/Lg/0ESvu1mRQ== X-Received: by 2002:a17:906:18b1:b0:aa5:438b:513e with SMTP id a640c23a62f3a-aa637626aaamr1003870566b.30.1733689371895; Sun, 08 Dec 2024 12:22:51 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.50 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:22:51 -0800 (PST) From: Phil Dennis-Jordan 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: Sun, 8 Dec 2024 21:22:27 +0100 Message-Id: <20241208202238.68873-5-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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", "3840x2160@60"]}' Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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, ResetType type) [s->common.pgdev reset]; } +static Property apple_gfx_mmio_properties[] = { + DEFINE_PROP_ARRAY("display-modes", AppleGFXMMIOState, + common.num_display_modes, common.display_modes, + qdev_prop_display_mode, AppleGFXDisplayMode), + DEFINE_PROP_END_OF_LIST(), +}; static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data) { @@ -267,6 +273,8 @@ static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data) rc->phases.hold = apple_gfx_mmio_reset; dc->hotpluggable = false; dc->realize = apple_gfx_mmio_realize; + + device_class_set_props(dc, apple_gfx_mmio_properties); } static TypeInfo apple_gfx_mmio_types[] = { 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]; } +static Property apple_gfx_pci_properties[] = { + 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 = DEVICE_CLASS(klass); @@ -130,7 +137,7 @@ static void apple_gfx_pci_class_init(ObjectClass *klass, void *data) pci->class_id = PCI_CLASS_DISPLAY_OTHER; pci->realize = apple_gfx_pci_realize; - /* TODO: Property for setting mode list */ + device_class_set_props(dc, apple_gfx_pci_properties); } static TypeInfo apple_gfx_pci_types[] = { 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 #include "qemu/typedefs.h" #include "exec/memory.h" +#include "hw/qdev-properties.h" #include "ui/surface.h" @class PGDeviceDescriptor; @@ -27,6 +28,12 @@ typedef QTAILQ_HEAD(, PGTask_s) PGTaskList; +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 mtl; id mtl_queue; + AppleGFXDisplayMode *display_modes; + uint32_t num_display_modes; /* 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_physical, uint64_t length, bool read_only, MemoryRegion **mapping_in_region); +extern const PropertyInfo qdev_prop_display_mode; + #endif 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" -static const PGDisplayCoord_t apple_gfx_modes[] = { - { .x = 1440, .y = 1080 }, - { .x = 1280, .y = 1024 }, +static const AppleGFXDisplayMode apple_gfx_default_modes[] = { + { 1920, 1080, 60 }, + { 1440, 1080, 60 }, + { 1280, 1024, 60 }, }; static Error *apple_gfx_mig_blocker; @@ -690,22 +691,24 @@ static void new_frame_handler_bh(void *opaque) return disp_desc; } -static NSArray* apple_gfx_prepare_display_mode_array(void) +static NSArray *apple_gfx_create_display_mode_array( + const AppleGFXDisplayMode display_modes[], uint32_t display_mode_count) { - PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)]; - NSArray* mode_array; - int i; - - for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) { - modes[i] = - [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i] refreshRateInHz:60.]; - } - - mode_array = [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_gfx_modes)]; - - for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) { - [modes[i] release]; - modes[i] = nil; + uint32_t i; + PGDisplayMode *mode_obj; + NSMutableArray *mode_array = + [[NSMutableArray alloc] initWithCapacity:display_mode_count]; + + for (i = 0; i < display_mode_count; i++) { + const AppleGFXDisplayMode *mode = &display_modes[i]; + trace_apple_gfx_display_mode(i, mode->width_px, mode->height_px); + PGDisplayCoord_t mode_size = { mode->width_px, mode->height_px }; + + mode_obj = + [[PGDisplayMode alloc] initWithSizeInPixels:mode_size + refreshRateInHz:mode->refresh_rate_hz]; + [mode_array addObject:mode_obj]; + [mode_obj release]; } return mode_array; @@ -741,6 +744,9 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev, PGDeviceDescriptor *desc, Error **errp) { PGDisplayDescriptor *disp_desc; + const AppleGFXDisplayMode *display_modes = apple_gfx_default_modes; + uint32_t num_display_modes = ARRAY_SIZE(apple_gfx_default_modes); + NSArray *mode_array; if (apple_gfx_mig_blocker == NULL) { error_setg(&apple_gfx_mig_blocker, @@ -776,8 +782,99 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev, port:0 serialNum:next_pgdisplay_serial_num++]; [disp_desc release]; - s->pgdisp.modeList = apple_gfx_prepare_display_mode_array(); + + if (s->display_modes != NULL && s->num_display_modes > 0) { + trace_apple_gfx_common_realize_modes_property(s->num_display_modes); + display_modes = s->display_modes; + num_display_modes = s->num_display_modes; + } + s->pgdisp.modeList = mode_array = + apple_gfx_create_display_mode_array(display_modes, num_display_modes); + [mode_array release]; s->con = 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 = opaque; + AppleGFXDisplayMode *mode = object_field_prop_ptr(obj, prop); + /* 3 uint16s (max 5 digits) + 2 separator characters + nul. */ + char buffer[5 * 3 + 2 + 1]; + char *pos = buffer; + + int rc = 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 = opaque; + AppleGFXDisplayMode *mode = object_field_prop_ptr(obj, prop); + const char *endptr; + g_autofree char *str = NULL; + int ret; + int val; + + if (!visit_type_str(v, name, &str, errp)) { + return; + } + + endptr = str; + + ret = qemu_strtoi(endptr, &endptr, 10, &val); + if (ret || val > UINT16_MAX || val <= 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 = val; + if (*endptr != 'x') { + goto separator_error; + } + + ret = qemu_strtoi(endptr + 1, &endptr, 10, &val); + if (ret || val > UINT16_MAX || val <= 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 = val; + if (*endptr != '@') { + goto separator_error; + } + + ret = qemu_strtoi(endptr + 1, &endptr, 10, &val); + if (ret || val > UINT16_MAX || val <= 0) { + error_setg(errp, "refresh rate in '%s'" + " must be a positive decimal integer (Hertz)", name); + return; + } + mode->refresh_rate_hz = val; + return; + +separator_error: + error_setg(errp, "Each display mode takes the format " + "'x@'"); +} + +const PropertyInfo qdev_prop_display_mode = { + .name = "display_mode", + .description = + "Display mode in pixels and Hertz, as x@ " + "Example: 3840x2160@60", + .get = apple_gfx_get_display_mode, + .set = 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, uint64_t height) "bpp=%d widt apple_gfx_cursor_show(uint32_t show) "show=%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 modes supplied by 'display-modes' device property" +apple_gfx_display_mode(uint32_t mode_idx, uint16_t width_px, uint16_t height_px) "mode %2"PRIu32": %4"PRIu16"x%4"PRIu16 # apple-gfx-mmio.m apple_gfx_mmio_iosfc_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64 From patchwork Sun Dec 8 20:22:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898656 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9D3AAE77180 for ; Sun, 8 Dec 2024 20:25:49 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNny-0002GC-2u; Sun, 08 Dec 2024 15:23: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 ) id 1tKNnt-0002CH-Kl for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:57 -0500 Received: from mail-ej1-x636.google.com ([2a00:1450:4864:20::636]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tKNnq-00083W-UQ for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:57 -0500 Received: by mail-ej1-x636.google.com with SMTP id a640c23a62f3a-aa68d0b9e7bso17777866b.3 for ; Sun, 08 Dec 2024 12:22:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689373; x=1734294173; 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=YTij3bXu5nZDt0Vwg+IprqKvFSAcOqEgivoe2gV/mPY=; b=lY+n3Xcs+nMAJ3OAlZjGRZypP0LMzfAL3XxC816KXfdjxfx73NGXNIvFzOn0elU9vy c7dFj+7enrFjBnqqreiSvVykCdJE3bWTTlmJwhefAAnGZTaITAjgcckgfRaOE/B5n2+v WWjQ4JGR6MaN6Zku/DRyL8sVaaB6ziQwqGK7mhA29Lamx3/fg6AhVRZTvVGt7IPtq4Di 3fApHW03Wk7KUvf9ZFIsoEqGjkSRhvr3PNrZUM2B7q5WkdlkOr82R4hue6iMP0gR6xIC rszEiLx3EdahhXSH34qpNOe4FiPOWDdAecoSz8AMXoHMyXcRxt1DQAuT/cdir9IdXbcb uI/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689373; x=1734294173; 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=YTij3bXu5nZDt0Vwg+IprqKvFSAcOqEgivoe2gV/mPY=; b=BSWeRd9/PKYvyayUkyNuEz1n08T7OYfUOrspTOf+OXjxbcp6OJ68rDysvZv0uQLc/F T5O8CmrPnAn8nO3282RTBse2mzUelGEbdfWtggTJT/JrlrM0twmIfLHdOvJWMqABp2iy r5QXSU7KOMiN05gPVcZ+CWUNEECnOTxChBQH6PqtnaoOrpOVls7NRK32sdlJ2mZanKyH 3WI4SC15a2VCxlcc9kK+o6LGzu3WunflkYcKe26j+Z9s7kA+v3+g6dD+FoBw7ZkvYDZ4 1TCvZAVXvAQ5hl/BpnSIeSfiyvl927ZXntpSGw3PZP7nT2goNsiZ2GXLiQgcKU0UYKUh /Ddg== X-Gm-Message-State: AOJu0Yykr3FBS3PI/Kg+PECWM90rPApGGPuJ1C1K0TmbxfazVK8VDIxo gsCO4ZUFrbhJbcTLIxFAETnTOscD3eE2hR7BVkLwbE2OIB7LEU6B04DxCjsq7IzpVZiRUlqMquj jE8s8 X-Gm-Gg: ASbGncvDI+y6fwMeknYD2i8m6WTjbn/SMUQug00bRM5ME+t2kCTOPxF3vr838ukqpOf JWiCSGdADccjxzlCbE2Di5cph0VN2THStkJuzAxvUdKhZQGMdoVXysXRhTpACU5JMJvS1fntob1 2z4Lkfw8ga4xNBC6FCCAEICHIPcgPePOKlhaoVl6ODKNwZjZKmdsEawlSzpx8vBpCaTUR8yh8u+ 4X5mFzyFTvmH0X6WBv5Zy+UAcOe9EGDNwRs5g8McTGZ26L/Jnu6MqlGjPGhxptNPW0aGBTmAqVq 3fSv50HoHezI2Q6By2gnNEnEdg== X-Google-Smtp-Source: AGHT+IHTNe9idJqzd5HPM7VUB/kQeBJ5NKo2nGLhxf8vM+deXNb3VTppZHJOuK9REciS9XJJK53R3Q== X-Received: by 2002:a17:906:328e:b0:aa6:5eae:7ed6 with SMTP id a640c23a62f3a-aa65eae884amr542745266b.13.1733689373609; Sun, 08 Dec 2024 12:22:53 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.52 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:22:53 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 05/15] MAINTAINERS: Add myself as maintainer for apple-gfx, reviewer for HVF Date: Sun, 8 Dec 2024 21:22:28 +0100 Message-Id: <20241208202238.68873-6-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 Received-SPF: neutral client-ip=2a00:1450:4864:20::636; envelope-from=phil@philjordan.eu; helo=mail-ej1-x636.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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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. I anticipate that the resulting workload should be covered by the funding I'm receiving for improving Qemu in combination with macOS. As of right now this runs out at the end of 2024; I expect the workload on apple-gfx should be relatively minor and manageable in my spare time beyond that. I may have to remove myself from more general HVF duties once the contract runs out if it's more than I can manage. Signed-off-by: Phil Dennis-Jordan Reviewed-by: Roman Bolshakov --- 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 M: Roman Bolshakov +R: Phil Dennis-Jordan 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 M: Roman Bolshakov +R: Phil Dennis-Jordan 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 +macOS PV Graphics (apple-gfx) +M: Phil Dennis-Jordan +S: Maintained +F: hw/display/apple-gfx* + PIIX4 South Bridge (i82371AB) M: Hervé Poussineau M: Philippe Mathieu-Daudé From patchwork Sun Dec 8 20:22:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898650 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2962BE77173 for ; Sun, 8 Dec 2024 20:25:05 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNnz-0002J5-SR; Sun, 08 Dec 2024 15:23: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 ) id 1tKNnv-0002Dm-EF for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:59 -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 ) id 1tKNns-00084M-Mh for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:22:59 -0500 Received: by mail-ej1-x62d.google.com with SMTP id a640c23a62f3a-aa650ccbe0eso229533566b.2 for ; Sun, 08 Dec 2024 12:22:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689375; x=1734294175; 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=2BhaxJPT8+nsUjQ4T4wil5DeNV7H7UZCjXKcZrKKfGW2fu2wEOAdjBvIKdsTKJggLv qQNn7UUvLmvTEcEfMqU0JDY1a7rQ68W8Pj2X0RN2u0Aruzs44gaWnfYe3OAeSXf13Wau Pa/V0Vk8FfzV7I7Igy6GAm5oeJgWWxDEewaDZYnQVKyuiOGcJK+Gztrw7Xb70Wv5YWOy nA6YlSVbUrzxUUvwe1bgyIv6BPx0FuNKGUh3inBDM8pcGu+YdEZn62BLS5qzVPjcjfOv d2Za6CgzqCnxELV9WQLaz3UccHPCMennHypjChoA3nsq90Z/SxqMQcMc6SQSRo2nFZJ2 RMgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689375; x=1734294175; 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=fy39g58qccDsu58Wq5yjqyQhQsc0k3DkFCYsqVI0pK2sUXOgVqRlM5GZtihePGRQx2 FiRuKdJO7e9//FOQy4ZaiMRZ9eBUkBT6J4+ZU985QEvKhnJKmaeOwAsrSbcl358Uhj3h CvelSfM/cnJvz2KJTEoURPGVAIY4OKWME6fTaHOW+a1mjPjPEJB3wcJ8GKotkc6nuOz6 6KmRPsrWADRqSkyOr4sDZUwDUuTRNEWX//amVmTAycvF0dYHW3citCSPg71juPJADy/O zp71v5RSt9LDpMamRILRcTlDF1B7tN2cEj8p+jT94J+Vp4/YdCiC4Ag2JD00byc8LqlX jpog== X-Gm-Message-State: AOJu0YzUkWflWrmsvX00wAW9j0g9FaDXjCE2elBtsuAQWI2ae0RbxEO9 dT6hR6sX6U51lfNqj+osoYouMeiR2IwtfNpEuIUCIWhOXlOfiipNOsj2I15T2KxmNqQV+WYyd+N BPZDc X-Gm-Gg: ASbGnctFQMLf8Ule5LyNHEi046rR/8cZOQMw4+e8vjr3cOEm50mESAW8E4aPgW6Gwa/ +bI1LtQNexE1pSxa7q18xxzlurmFlpGLHhwbRy0NenF4xECco233q6x7XHhwNUscMf6UB32BKeJ F6Cryhe08u2CgQdMCKOc5WPbR4imvcUBCmB6Q/z+ZHOl3XZtaq5kaSEy6ZqMRlPqFvrWBKMlQn9 SM8i67JSgpgdxMUBzbyr5UsvS90gwpgWeNl5n9/D2YcvqIA3FweZ+GMImOK/0hS2zAGUESMdKnp 1AT1MFeG39/SVulrJ4jd0AaD1w== X-Google-Smtp-Source: AGHT+IGls4MEqFq6xqQpby551YBXNsiQcO6j24u3lPjSmIZmO9Durr/VgxkrvQV85hBAjPCd7Gq7qg== X-Received: by 2002:a17:907:7848:b0:aa6:7adc:718a with SMTP id a640c23a62f3a-aa67adc72d5mr258852266b.8.1733689375322; Sun, 08 Dec 2024 12:22:55 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.53 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:22:55 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 06/15] hw: Add vmapple subdir Date: Sun, 8 Dec 2024 21:22:29 +0100 Message-Id: <20241208202238.68873-7-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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 Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 +VMapple +M: Alexander Graf +R: Phil Dennis-Jordan +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 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', From patchwork Sun Dec 8 20:22:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898654 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 84887E7717F for ; Sun, 8 Dec 2024 20:25:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNo0-0002JA-45; Sun, 08 Dec 2024 15:23:04 -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 ) id 1tKNnw-0002Ej-DH for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:00 -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 ) id 1tKNnu-00085D-Lz for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:00 -0500 Received: by mail-ej1-x62c.google.com with SMTP id a640c23a62f3a-aa549f2fa32so715062066b.0 for ; Sun, 08 Dec 2024 12:22:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689377; x=1734294177; 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=X0YDEYbLJCzuICGOj9xUB0EsUHxB1sUssdUrvVgFZ4mS9eE94fLlh7I/EGT1uxppL8 HUFyqlUg+eji40DxJggZx7Chqm9IvUtB2LOqd1k65wqgPP+W7P5ScSca/8RxVv/3GA7o 1vnFZp2qbm8F1vkxCXvyC4L5fE+GS9n7NOlh5AFOCAmfX+BSLCCZIjFG/hZ52p7wmmmf uEwgR60yichsINVrPgTwZIa0JeR2NmV7d0BC54OY8R9zSvK1M9CHTQ94G5+qj9q5Y1Pl Wuslknhfqpw8vkJDXxeHS83GoRK+B/BbA20XK4Vro5v3JGdwKwkvs0Vb2hXHWm9blXzz dMDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689377; x=1734294177; 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=I8Mlgo/oR9dGnuNOAnfehtHPPsRVDq0DNtYGDBuWzFOGPx90JvNtyftJ7LbHwjOLc4 A7qpyjqSidgot+Mwjg5gStp/CeS3J51IQiZU1pcQoSiFbFx4BqnTzQg6KnYSKoKnv3gd 7dZ2sx1OOkDKX9O5BiB/n/MW1XyEREBuFFBZoKiM3BAvtAeqUcLp/qZAtqfAJ0yn3emz uYcArCwRef17DZ976jPuEg5CMXrRjD3p8J2oLb9VG7oBslVH2ja5rRqrjrRzCP6GS5Pa M9zSrvbnaRn8Rehkumi6A6rlduvw+4GrhydJJw3fiSNQWRw+csgjsm4302Q9OLegpDlY qf2Q== X-Gm-Message-State: AOJu0YwsckJSEYK2GzWpS72GVx3kMpNmI0mBB1WdGy775uhaY9CEtWxc Op2akT9myrPY7yQ50vdC74l8OX3nc3JGNjMXS8a8DBpQJZA3JR8Rbqv8OcQ785hATTfzzS+F1cw aDSpz X-Gm-Gg: ASbGncuOJ7O7hCdTI5ckRQu76wp4Ea+PpoOnHWn95nZdd+rnnnYFheasFJVObFkvJRr 3GUg7tMdGFfhZJ909o3zL0H4RqRyVQUKmAxtHpzgelylXnPFBKoIzlblwXpxUbcbLMBt8Y3s+Lr JzhYf2691y4PqDxg5legVcnjSJxf5AZNE7J0N31oraOyCf+aD0GKArmbak63uPXJOb+XNCMTYX9 gRTd13RP441Llf/qZC0r7TC8fVaGQwOSdvvvohve1Q4TgGoMQzq6HAlg/BE4aepDvT7eA0s+Av+ 3SGqJr38D1ZcAetcLww9mSbkIw== X-Google-Smtp-Source: AGHT+IGMND6ICvKzQkqGjOuR28YHlzlJhSwB8Zg4/WDlotrJEKJRUtmDpRmBM1Uxrq6Taxgx+h4SjA== X-Received: by 2002:a17:907:938a:b0:aa6:851d:af4d with SMTP id a640c23a62f3a-aa6851db0ddmr159912366b.21.1733689377118; Sun, 08 Dec 2024 12:22:57 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.55 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:22:56 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 07/15] hw/misc/pvpanic: Add MMIO interface Date: Sun, 8 Dec 2024 21:22:30 +0100 Message-Id: <20241208202238.68873-8-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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 Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 +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')) 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 © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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 = 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[] = { + 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 = DEVICE_CLASS(klass); + + device_class_set_props(dc, pvpanic_mmio_properties); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo pvpanic_mmio_info = { + .name = TYPE_PVPANIC_MMIO_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PVPanicMMIOState), + .instance_init = pvpanic_mmio_initfn, + .class_init = 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 @@ #define TYPE_PVPANIC_ISA_DEVICE "pvpanic" #define TYPE_PVPANIC_PCI_DEVICE "pvpanic-pci" +#define TYPE_PVPANIC_MMIO_DEVICE "pvpanic-mmio" #define PVPANIC_IOPORT_PROP "ioport" From patchwork Sun Dec 8 20:22:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898652 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 85865E77180 for ; Sun, 8 Dec 2024 20:25:25 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNo1-0002JL-5c; Sun, 08 Dec 2024 15:23: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 ) id 1tKNny-0002HE-B6 for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:02 -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 ) id 1tKNnw-000869-Mf for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:02 -0500 Received: by mail-ej1-x633.google.com with SMTP id a640c23a62f3a-aa62f1d2b21so523818166b.1 for ; Sun, 08 Dec 2024 12:23:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689379; x=1734294179; 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=guKZBafbZn0TLuVeqf76YbNFwhpgNI5HUWpsKsBZcYR9RDegtqz/ModZZ5cihS5cvH 23ogYT3Lf7Sz4zgFjyMS83ut1rliJi6Rd/t3yZ3N0ophHihgNBNCp60vDHjXnTW7qMpI +4f0CvnQeTaxXcKR1P3EB/VH/tocmleDZFH7owwKPpxBjS4FS3StJtFKDn/oDBorNdMX AvKw45oTSu6QJMElW9+/tDwNuS9jW09Y8TaDSvv/cxv3E+/twZaw888BCbLCZJM3Uq5D S2dzaFoFgIiWdf19WycPAgJ7tTwNKcTuV03KjgdZM7lm9efGbjrdAgo+Q1uH5OAaFH8R vUig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689379; x=1734294179; 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=K50R+s4zJVL9/noCi/a7dIC4e8sSY0PCy2wgmxrW+OFaxlW6gsB1+YM+oqit2/f0DA 7V7/X663HmUDM88UG9XD3CVjt1DbwCU4zKLQ6YYwhsxvNNsz/ip8yd4dVNLJN7b1hBFW RyvN7bngzr0Zyyb6bBZyPxBzE25GIcS7sugw/COesHSgDRBNyJ0nLLO6OypTs6iVwKKl LKbok8XW6L7sZY7r/I/dDPsEOSPxLeYGT+Cca103U/wgSW0D8XCD6g8yzZ1eS+9gT4i1 72Y6h1RnOu3E+oDByH7v5CXLMTOQUjKbyfbDg8JfL26qv2wmodZoeBhpYihj78uiyXq6 nPtg== X-Gm-Message-State: AOJu0YxUC9PU83hDEHdXRwAlaifjGIn4FLUdXzC8XDI3YvNqLeI4m7CE nxICz7KjqTcU2Is8QAA+an0T7MhMJTGpORr+GAtHb7y5Md8xnU5rAILjXGCsT1OYJPoDA/mR1pY tKEzO X-Gm-Gg: ASbGnctjG2vy6Wvwwe5Vad3yJM/OarFAU+ZfNwXpOLIAAvRuQPdwj+rui2QtaAglOIK D07yZC7UAVIMY67FPyeowK4D3WvhlEwTaZFasRkZMogFqJOAsjMxWwcjyREp++HpMbbaCUQYFBo 95RU57o+ST5+ju8Q4Qbabt+SMJmlYADEdq+autvEaSk5L0PzKKWWKetqB8/uCEkDAkOzEgEciC7 rZ5xBmQg5nEGNRv7XCoWOWSwlE9PzMwyBd4GDLDu96o/YnoAyz11mRnx5TOCTRATuskU/INAmYB 6qLp/BZdkm+biWJzpTBdPPl2GA== X-Google-Smtp-Source: AGHT+IEd/RneVGd0XG6VOIQbVbyIrqEsn8EM4SEAG0TsrTKHyaZmxpROh4o73/aZS8BWnmCbPjE2Ug== X-Received: by 2002:a17:906:3cb2:b0:aa6:538e:a311 with SMTP id a640c23a62f3a-aa6538ea57dmr605554866b.18.1733689379002; Sun, 08 Dec 2024 12:22:59 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.57 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:22:58 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 08/15] hvf: arm: Ignore writes to CNTP_CTL_EL0 Date: Sun, 8 Dec 2024 21:22:31 +0100 Message-Id: <20241208202238.68873-9-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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 Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/log.h" #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 = 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; From patchwork Sun Dec 8 20:22:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898658 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 04DB9E77173 for ; Sun, 8 Dec 2024 20:26:36 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNo3-0002Lo-0U; Sun, 08 Dec 2024 15:23:07 -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 ) id 1tKNo0-0002JJ-RY for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:04 -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 ) id 1tKNny-000874-Cl for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:04 -0500 Received: by mail-ed1-x534.google.com with SMTP id 4fb4d7f45d1cf-5d3e829ff44so1819638a12.0 for ; Sun, 08 Dec 2024 12:23:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689381; x=1734294181; 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=xVec6KsIiPJvrATMXpKfpKqM5tlkskrUHRHrwVn2Sm1ohdjC3Nniqr9xJVBsl38S23 EKMv0sBiSJnVPD417VWS6qRLpAzqU21vJ4rI4cH3Hn9k9sWPBZ9Qy4+SVcNUwOXAPnC6 sGl4eC8oRucFmpIuuKpEyoAVj7rfp9hgKSvjGdUsaz6FVoG125FSYHWcjjIwEemnbUf8 JwBU0+FUHDELG9yl64S4YUgm+hYdgL8b1Ru/TlUzkPZ6CuEa3wiGvHVI3WyQlKFKP7Yr lRBcOTmusq/1kqmv/UE1Wmi7PDjC5GVp0Hmxagc/U4ZBreKDA3Mk9XjqkL7Kl6/LKnZa KdLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689381; x=1734294181; 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=LGITIhsT7RAy7tN/wyssC6H6Gm9vKCkb81sdnvAJA4RIaArCqJykUJ8tfj/9ubNfsH BcfuBuNW521rGRzFPwvItU+6JuWt6Qx7sFSQEMMDexOoxutOZB+XRGTjjR/cJYt9hbCK LKPnwoRxmem1E/TuDH/3PPEjg4FXm36Xs8o5g32xFu9DFgnk5J3ElB3JQWZ+UmwHtTXj 7rhdgN878fwTGpcHdy/lDOpa3y8a1hCGQD6jATtV+nWbUszYBbSw+5/MPs7UhaF1WqDX FQ2xRPTYklJH5Q5DIhrD0ZBRiDD/1IbHsw4ES8GpIGAB8bAAC83wOqYdmfZjEB0eTNzo Jevg== X-Gm-Message-State: AOJu0YxvnbqKEfF9U0V5OijCXqFTwbOr5So+0DApii0vpcxx6s8fHnCp vIsJJf1k5q2bwxBmVvVId4+xh9eVm38wXusSKMC3b+5A5rrBMVjyzuQ+smWN8uTerPk+EcEwLuB obXjV X-Gm-Gg: ASbGncte7YCBJgyNK5fWUApELa26B/OlFuE48DUQVP5QUm5YWMa6AvCuyrANamRNDiO aOSnxwSh49R+ai8R+U8Kcs9Y5J0MsQWRAN6yVncY7WmFjzB6/FGhjlUwULWMaIWq4GRDY2X8ADJ 2++Ia8IVpRa9WBk3gEz/9WbL+bb2olWA7RPKwxDhHVxIQNasgh/NN6gdnK5Ci3PZuSj6IdQh6gv c8kWt1vV4d04GRnwxT497nR5gzmBx483qWq5Kl50XiC/Q/TWGUtqEihX6aB+AUHENr3PmCPUsd6 wtUSlA4J0KMqD7wKiGVfXGyZSg== X-Google-Smtp-Source: AGHT+IFCkhzOxwiy38XSUQ+5O8/c8s4BeQNAoyeDhg7l+fNE4kpYGFGYN54KBmr/LWvSbgkNGDpSRQ== X-Received: by 2002:a17:906:1da9:b0:aa6:50ee:d44c with SMTP id a640c23a62f3a-aa650eed58cmr603108966b.15.1733689380825; Sun, 08 Dec 2024 12:23:00 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.22.59 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:23:00 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 09/15] gpex: Allow more than 4 legacy IRQs Date: Sun, 8 Dec 2024 21:22:32 +0100 Message-Id: <20241208202238.68873-10-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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 Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 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); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 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); } - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 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 LoongArchVirtMachineState *lvms, { int pin, dev; uint32_t irq_map_stride = 0; - uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {}; + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 10] = {}; uint32_t *irq_map = full_irq_map; const MachineState *ms = MACHINE(lvms); @@ -454,11 +454,11 @@ static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms, * to wrap to any number of devices. */ - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { + for (dev = 0; dev < PCI_NUM_PINS; dev++) { int devfn = dev * 0x8; - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { - int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); + for (pin = 0; pin < PCI_NUM_PINS; pin++) { + int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); int i = 0; /* Fill PCI address cells */ @@ -482,7 +482,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms, 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); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 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(MachineState *machine, virt_memmap[VIRT_PCIE_PIO].base, s->pio_alias); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { irq = 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 *nodename, int irq_base, { int pin, dev; uint32_t irq_map_stride = 0; - uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] = {}; uint32_t *irq_map = full_irq_map; /* @@ -330,11 +330,11 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, * possible slot) seeing the interrupt-map-mask will allow the table * to wrap to any number of devices. */ - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { + for (dev = 0; dev < PCI_NUM_PINS; dev++) { int devfn = dev << 3; - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { - int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); + for (pin = 0; pin < PCI_NUM_PINS; pin++) { + int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); int i = 0; /* Fill PCI address cells */ @@ -357,7 +357,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, } 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)); qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", @@ -409,7 +409,7 @@ static void openrisc_virt_pcie_init(OR1KVirtState *state, memory_region_add_subregion(get_system_memory(), pio_base, alias); /* Connect IRQ lines. */ - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { pcie_irq = get_per_cpu_irq(cpus, num_cpus, irq_base + i); 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 */ +struct GPEXIrq { + qemu_irq irq; + int irq_num; +}; + static void gpex_set_irq(void *opaque, int irq_num, int level) { GPEXHost *s = opaque; - qemu_set_irq(s->irq[irq_num], level); + qemu_set_irq(s->irq[irq_num].irq, level); } int gpex_set_irq_num(GPEXHost *s, int index, int gsi) { - if (index >= GPEX_NUM_IRQS) { + if (index >= s->num_irqs) { return -EINVAL; } - s->irq_num[index] = gsi; + s->irq[index].irq_num = gsi; return 0; } @@ -62,7 +68,7 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin) { PCIINTxRoute route; GPEXHost *s = opaque; - int gsi = s->irq_num[pin]; + int gsi = s->irq[pin].irq_num; route.irq = gsi; if (gsi < 0) { @@ -74,6 +80,13 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin) return route; } +static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) +{ + PCIBus *bus = 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 = PCI_HOST_BRIDGE(dev); @@ -82,6 +95,8 @@ static void gpex_host_realize(DeviceState *dev, Error **errp) PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); int i; + s->irq = g_malloc0_n(s->num_irqs, sizeof(*s->irq)); + pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX); sysbus_init_mmio(sbd, &pex->mmio); @@ -128,19 +143,27 @@ static void gpex_host_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->io_ioport); } - for (i = 0; i < GPEX_NUM_IRQS; i++) { - sysbus_init_irq(sbd, &s->irq[i]); - s->irq_num[i] = -1; + for (i = 0; i < s->num_irqs; i++) { + sysbus_init_irq(sbd, &s->irq[i].irq); + s->irq[i].irq_num = -1; } pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq, - pci_swizzle_map_irq_fn, s, &s->io_mmio, - &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); 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); } +static void gpex_host_unrealize(DeviceState *dev) +{ + GPEXHost *s = 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[] = { 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(), }; @@ -176,6 +200,7 @@ static void gpex_host_class_init(ObjectClass *klass, void *data) hc->root_bus_path = gpex_host_root_bus_path; dc->realize = gpex_host_realize; + dc->unrealize = gpex_host_unrealize; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "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 = 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] = {}; uint32_t *irq_map = full_irq_map; @@ -180,11 +180,11 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, * possible slot) seeing the interrupt-map-mask will allow the table * to wrap to any number of devices. */ - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { + for (dev = 0; dev < PCI_NUM_PINS; dev++) { int devfn = dev * 0x8; - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { - int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); + for (pin = 0; pin < PCI_NUM_PINS; pin++) { + int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); int i = 0; /* Fill PCI address cells */ @@ -210,7 +210,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, } 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)); qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", @@ -1182,7 +1182,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i); 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); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { qemu_irq irq = qemu_allocate_irq(xpc->set_pci_intx_irq, s, i); 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 = xtensa_get_extints(env); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { void *q = extints[irq_base + i]; 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) -#define GPEX_NUM_IRQS 4 - struct GPEXRootState { /*< private >*/ PCIDevice parent_obj; @@ -49,6 +47,7 @@ struct GPEXConfig { PCIBus *bus; }; +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; bool allow_unmapped_accesses; From patchwork Sun Dec 8 20:22:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898653 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EB125E77173 for ; Sun, 8 Dec 2024 20:25:31 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNo7-0002Pg-GR; Sun, 08 Dec 2024 15:23:11 -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 ) id 1tKNo5-0002N9-2m for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:09 -0500 Received: from mail-ed1-x529.google.com ([2a00:1450:4864:20::529]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tKNo0-00087f-QQ for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:08 -0500 Received: by mail-ed1-x529.google.com with SMTP id 4fb4d7f45d1cf-5d3e6274015so1658870a12.0 for ; Sun, 08 Dec 2024 12:23:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689383; x=1734294183; 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=Bzjxvoq6BPQJwazUIn9HKtsQokxhigBx99ZPO4UBcvhJHRSELl5yF+0STADw9uzXIh 5Qnj7F5FLWTsntD0Y652SRhm33yLRBZmScHpqjx4Q2BXQsjc058QI9Y5tG+u0aqgQaG1 Vg8T85cCkAhWn8ci3quUD95lBuTKOufvG/cMT3+ZnFAeA8JEs8dt0qxaEg6kqXcCWk8N km1YqOOMtw+C8mkGkf3S21cvIPjcGsaDaQa9ZB0E/gyTnFB89MpwCLDfJcZxqP4s09Ka hVho9QSnfIeSGwwg/txfVxML0OCLqTUKaT6GKfQrG3fEkF4zlfzSNvzdSI1s3UPkRGGK VArQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689383; x=1734294183; 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=OKgZ8jPzNx2BtWfphA3E9qJvaZ+aV1DZiQSiHUYjMY8qKExvSooNX9i2tJsOEpwSct aR1PVM3I2g1Z1HKXUY/6rXy44ITsAwRcynNYEERNPK6IpL4p/HOKhY2xhf9+LBH0oyNi DRcplkFmJW35+t5rSjkZ4xnTRmcuJ9f4jRBrDZF4FKkpv+Q2zRj+BvAWHh5NY4BPzYT9 CIdBc/gL+SncZyGowz7vekfZLWKZrhDShGdtbWBL9bq4VSnK0Y3KmsmISP33tzvaHIty p6a4JbBhU1Sy1TH3VMqbAwlwqKm98StXRR/Vtz/ckFycToaWxdyQjBBUEX+IdlZt1pZs 0fCQ== X-Gm-Message-State: AOJu0YyTp3eF/LwfFcce65YS8lrHOnkFZCDN5Pk19zmf46vt1dnAw+N/ TUlIJBZk7H664k+kMtskaiR6zM8fAo5z8PoIPJ320sHRxiYWectpw35ZmXe2vaTHmNVqux//Gbc B2mzo X-Gm-Gg: ASbGncs3o3SF377wv/K2jCaDRRHGslW84iSMETQAT+XjheyTvPfoCSWU8NvxIaNij9A H+4nP5KWIrDnJM857c85welNcaLAo+hJFW/Yx4y/wwD+kPKA4ii+BWu43Q8TEZcojL1Ko/o017h 3SwemzjLv8et2yzmIBATDKp9O2qDb3/fdnnbcOfyicCazAaAK5uABUajaGWsiXRWHu4/N1biAYn ILcc81NIVWEcXKk4NH3eoFG8qcPX7nQV41F2MDzexE5h1rF25FgzOd2cJvllsbVM6pqatagDF7n /1ru1RSxBy1wF2+BinZ3ZuQW+g== X-Google-Smtp-Source: AGHT+IE6qBoi3s/Cw0SzRtjaVdgB7QHia1Y9m6HnDZ3BiRCXm5ymOVr6MD61Us4rpPHENR1YLqT6YA== X-Received: by 2002:a17:906:4ca:b0:aa6:1e9a:e46a with SMTP id a640c23a62f3a-aa63a2c6679mr1040345966b.57.1733689382764; Sun, 08 Dec 2024 12:23:02 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.23.01 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:23:02 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 10/15] hw/vmapple/aes: Introduce aes engine Date: Sun, 8 Dec 2024 21:22:33 +0100 Message-Id: <20241208202238.68873-11-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 Received-SPF: neutral client-ip=2a00:1450:4864:20::529; envelope-from=phil@philjordan.eu; helo=mail-ed1-x529.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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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 Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 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 © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * 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_KEY_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] = { + [0] = 16, + [1] = 24, + [2] = 32, + [3] = 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] = { + [1] = { + .key_len = 32, + .key = { 0x1 }, + }, + [2] = { + .key_len = 32, + .key = { 0x2 }, + }, + [3] = { + .key_len = 32, + .key = { 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 = opaque; + uint64_t res = 0; + + switch (offset) { + case REG_STATUS: + res = s->status; + break; + case REG_IRQ_STATUS: + res = s->irq_status; + break; + case REG_IRQ_ENABLE: + res = s->irq_enable; + break; + case REG_WATERMARK: + res = s->watermark; + break; + case REG_Q_STATUS: + res = s->q_status; + break; + case REG_FLAG_INFO: + res = 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 == MAX_FIFO_SIZE) { + /* Exceeded the FIFO. Bail out */ + return; + } + + s->fifo[s->fifo_idx++] = val; +} + +static bool has_payload(AESState *s, uint32_t elems) +{ + return s->fifo_idx >= elems + 1; +} + +static bool cmd_key(AESState *s) +{ + uint32_t cmd = s->fifo[0]; + uint32_t key_select = (cmd & CMD_KEY_SELECT_MASK) >> CMD_KEY_SELECT_SHIFT; + uint32_t ctxt = (cmd & CMD_KEY_CONTEXT_MASK) >> CMD_KEY_CONTEXT_SHIFT; + uint32_t key_len; + + switch ((cmd & CMD_KEY_BLOCK_MODE_MASK) >> CMD_KEY_BLOCK_MODE_SHIFT) { + case 0: + s->block_mode = QCRYPTO_CIPHER_MODE_ECB; + break; + case 1: + s->block_mode = QCRYPTO_CIPHER_MODE_CBC; + break; + default: + return false; + } + + s->is_encrypt = cmd & CMD_KEY_ENCRYPT_MASK; + key_len = key_lens[(cmd & CMD_KEY_KEY_LEN_MASK) >> CMD_KEY_KEY_LEN_SHIFT]; + + if (key_select) { + trace_aes_cmd_key_select_builtin(ctxt, key_select, + s->is_encrypt ? "en" : "de", + QCryptoCipherMode_str(s->block_mode)); + s->key[ctxt] = 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 = key_len; + } + + return true; +} + +static bool cmd_iv(AESState *s) +{ + uint32_t cmd = s->fifo[0]; + uint32_t ctxt = (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 = 0x1000; + char hex[MAX_LEN * 2 + 1] = ""; + + 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 = s->fifo[0]; + uint32_t ctxt_iv = 0; + uint32_t ctxt_key = (cmd & CMD_DATA_KEY_CTX_MASK) >> CMD_DATA_KEY_CTX_SHIFT; + uint32_t len = cmd & CMD_DATA_LEN_MASK; + uint64_t src_addr = s->fifo[2]; + uint64_t dst_addr = s->fifo[3]; + QCryptoCipherAlgo alg; + g_autoptr(QCryptoCipher) cipher = NULL; + g_autoptr(GByteArray) src = NULL; + g_autoptr(GByteArray) dst = NULL; + MemTxResult r; + + src_addr |= ((uint64_t)s->fifo[1] << 16) & 0xffff00000000ULL; + dst_addr |= ((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 >= ARRAY_SIZE(s->key) || + ctxt_iv >= ARRAY_SIZE(s->iv)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key or iv\n", __func__); + return false; + } + + src = g_byte_array_sized_new(len); + g_byte_array_set_size(src, len); + dst = g_byte_array_sized_new(len); + g_byte_array_set_size(dst, len); + + r = dma_memory_read(s->as, src_addr, src->data, len, MEMTXATTRS_UNSPECIFIED); + if (r != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA read of %"PRIu32" bytes " + "from 0x%"PRIx64" failed. (r=%d)\n", + __func__, len, src_addr, r); + return false; + } + + dump_data("cmd_data(): src_data=", src->data, len); + + switch (s->key[ctxt_key].key_len) { + case 128 / 8: + alg = QCRYPTO_CIPHER_ALGO_AES_128; + break; + case 192 / 8: + alg = QCRYPTO_CIPHER_ALGO_AES_192; + break; + case 256 / 8: + alg = QCRYPTO_CIPHER_ALGO_AES_256; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key length\n", __func__); + return false; + } + cipher = 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 != QCRYPTO_CIPHER_MODE_ECB) { + if (qcrypto_cipher_setiv(cipher, (void *)s->iv[ctxt_iv].iv, + sizeof(s->iv[ctxt_iv].iv), NULL) != 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to set IV\n", __func__); + return false; + } + } + if (s->is_encrypt) { + if (qcrypto_cipher_encrypt(cipher, src->data, dst->data, len, NULL) != 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Encryption failed\n", __func__); + return false; + } + } else { + if (qcrypto_cipher_decrypt(cipher, src->data, dst->data, len, NULL) != 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Decryption failed\n", __func__); + return false; + } + } + + dump_data("cmd_data(): dst_data=", dst->data, len); + r = dma_memory_write(s->as, dst_addr, dst->data, len, MEMTXATTRS_UNSPECIFIED); + if (r != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA write of %"PRIu32" bytes " + "to 0x%"PRIx64" failed. (r=%d)\n", + __func__, len, src_addr, r); + return false; + } + + return true; +} + +static bool cmd_store_iv(AESState *s) +{ + uint32_t cmd = s->fifo[0]; + uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT; + uint64_t addr = 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 >= ARRAY_SIZE(s->iv)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid context. ctxt = %u, allowed: 0..%zu\n", + __func__, ctxt, ARRAY_SIZE(s->iv) - 1); + return false; + } + + addr |= ((uint64_t)cmd << 32) & 0xff00000000ULL; + dma_result = 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 == MEMTX_OK; +} + +static bool cmd_flag(AESState *s) +{ + uint32_t cmd = s->fifo[0]; + uint32_t raise_irq = cmd & CMD_FLAG_RAISE_IRQ_MASK; + + /* We always process data when it's coming in, so fire an IRQ immediately */ + if (raise_irq) { + s->irq_status |= REG_IRQ_STATUS_FLAG; + } + + s->flag_info = 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 = s->fifo[0] >> CMD_SHIFT; + bool success = false; + + if (!s->fifo_idx) { + return; + } + + switch (cmd) { + case CMD_KEY: + success = cmd_key(s); + break; + case CMD_IV: + success = cmd_iv(s); + break; + case CMD_DATA: + success = cmd_data(s); + break; + case CMD_STORE_IV: + success = cmd_store_iv(s); + break; + case CMD_FLAG: + success = cmd_flag(s); + break; + default: + s->irq_status |= REG_IRQ_STATUS_INVALID_CMD; + break; + } + + if (success) { + s->fifo_idx = 0; + } + + trace_aes_fifo_process(cmd, success); +} + +static void aes1_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ + AESState *s = opaque; + + trace_aes_write(offset, val); + + switch (offset) { + case REG_IRQ_STATUS: + s->irq_status &= ~val; + break; + case REG_IRQ_ENABLE: + s->irq_enable = 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 %"PRIx64"\n", + __func__, offset, val); + return; + } + + aes_update_irq(s); +} + +static const MemoryRegionOps aes1_ops = { + .read = aes1_read, + .write = aes1_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static uint64_t aes2_read(void *opaque, hwaddr offset, unsigned size) +{ + uint64_t res = 0; + + switch (offset) { + case 0: + res = 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 %"PRIx64"\n", + __func__, offset, val); + return; + } +} + +static const MemoryRegionOps aes2_ops = { + .read = aes2_read, + .write = aes2_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void aes_reset(Object *obj, ResetType type) +{ + AESState *s = APPLE_AES(obj); + + s->status = 0x3f80; + s->q_status = 2; + s->irq_status = 0; + s->irq_enable = 0; + s->watermark = 0; +} + +static void aes_init(Object *obj) +{ + AESState *s = APPLE_AES(obj); + + memory_region_init_io(&s->iomem1, obj, &aes1_ops, s, TYPE_APPLE_AES, 0x4000); + memory_region_init_io(&s->iomem2, obj, &aes2_ops, s, TYPE_APPLE_AES, 0x4000); + 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 = &address_space_memory; +} + +static void aes_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.hold = aes_reset; +} + +static const TypeInfo aes_info = { + .name = TYPE_APPLE_AES, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AESState), + .class_init = aes_class_init, + .instance_init = 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. +# aes.c +aes_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64 +aes_cmd_key_select_builtin(uint32_t ctx, uint32_t key_id, const char *direction, const char *cipher) "[%d] Selecting builtin key %d to %scrypt with %s" +aes_cmd_key_select_new(uint32_t ctx, uint32_t key_len, const char *direction, const char *cipher) "[%d] Selecting new key size=%d to %scrypt with %s" +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=%d iv=%d] src=0x%"PRIx64" dst=0x%"PRIx64" len=0x%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=0x%"PRIx64"x -> 0x%08x 0x%08x 0x%08x 0x%08x" +aes_cmd_flag(uint32_t raise, uint32_t flag_info) "raise=%d flag_info=0x%x" +aes_fifo_process(uint32_t cmd, bool success) "cmd=%d success=%d" +aes_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64 +aes_2_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64 +aes_2_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"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 © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * 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 *buf, size_t len, void qemu_hexdump(FILE *fp, const char *prefix, const void *bufptr, size_t size); +/** + * 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 them to + * @buffer. Finally, a nul terminating character is written; @buffer therefore + * 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 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qemu/host-utils.h" static inline char hexdump_nibble(unsigned x) { @@ -97,3 +98,20 @@ void qemu_hexdump(FILE *fp, const char *prefix, } } + +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 = umul64_overflow(data_size, 2, &required_buffer_size); + overflow |= uadd64_overflow(required_buffer_size, 1, &required_buffer_size); + assert(!overflow && buffer_size >= required_buffer_size); + + for (i = 0; i < data_size; i++) { + uint8_t val = data[i]; + *(buffer++) = hexdump_nibble(val >> 4); + *(buffer++) = hexdump_nibble(val & 0xf); + } + *buffer = '\0'; +} From patchwork Sun Dec 8 20:22:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898651 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7254CE7717F for ; Sun, 8 Dec 2024 20:25:05 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNo7-0002Pz-Lg; Sun, 08 Dec 2024 15:23:11 -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 ) id 1tKNo6-0002OL-J2 for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:10 -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 ) id 1tKNo2-00088E-8q for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:10 -0500 Received: by mail-ed1-x535.google.com with SMTP id 4fb4d7f45d1cf-5d0ac27b412so4569708a12.1 for ; Sun, 08 Dec 2024 12:23:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689385; x=1734294185; 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=qZP6DAr9H+dSQFTHodzJEG+rrj9DZ3ubfMP+xHSht9Yvn6w1Cy+dGU3FeXReMGFOTH B5X/LY/iC5f7qfEYxC4hHoDfbRRiDXuu7xCwxQmVDbv5skgVeTkRcrgctY1RXgxoCS6I avUtyytZB71TSBcuUrU2psa50sPaW9t1VEOcQQUjetPfAiT1XmgerhTcyZj2AbNVbIig uJD7AROM4O0GbeDflFdz5eJiLZHAZJ/vIC7mlJM80Yot3YEYO/G/9GanPogASYrXah81 ou5jt7jDR3zkc8MFVEPoP+g88ftniw/hl0ijLnpbQ6ZGQjzDCUMgCLtyGHh2RoZhC0bx gkcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689385; x=1734294185; 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=qK8T0uViNaYswKQB4dWm8tPAbz+i/vnY4NBmMLUlZXq6fLrk62Z1/efr7JJw/ovTL8 afL8y4PGC8l6gOeajsK+zK+uJC0s+gN6Kaq3UFvUOS9u5Nr9ESZnQtXejWz38vAAi2jV 5VHVM9pBqtk8EGoA1yYc59SMJ/5O6PWMsRGK406HTthA0dsaJu/5ckYdjlOaPUpcWLNi 0inZvJDgToDlhCAo+kkoRzysL0dEnfm57NMkYKzR8WC5ZvXy34WY1lFmbZzlTR5XBDpb Q642HRnf16S693NS+BHjv+6uCw1qbQBS5oAgo6dZ5waTBIC2j7/FfOj+Ph2NuK+wKLkI Ig4g== X-Gm-Message-State: AOJu0YyumOQTVK4T4RCKCBg1FWoMOaVEFuxUBDim5M58SFQhBrfkoDoV e1flySfdaPtEARMRMUkyr3JtnFGtdzrfpleTIxFtcqdSDmSiQpn2/ksbNnbcLvIl6Q8+X1yXaJL rGmB+ X-Gm-Gg: ASbGnctSji4fDlwdZeox0b2zYzeIeJCcp9tbV/fzTKtiP9uZW0dXalq2RZrFm3OOH/Z vB3ZrAGSBmTK0afzIfNcMZaP26fS6yclQfFtohos+FnfAfqvyU1PHbzsGFMJvYYEtWKqy2ZYg8Z Eb1+cXAkrZCKhHcsyFs/nynanvy1pjHtZsEcjvv92HIqfpNbVHPGDal0+dAoAYMmOQuZ34+6clh w8N7IA2aPy9Q+QtBbxIGx70D0PfKzXquYAuVtAybGrMCKqaD6nXG80EsdtlSdEZprbBltNH3anI 7alBBaQDnukRwfJYZshDmT431A== X-Google-Smtp-Source: AGHT+IHtPb+Kkf5wAHdstmjS0HzyqJC0AjtNO2jhXDyJNKq5w45SzUWPPxPUYnE7Fl2vmufR8i+hqg== X-Received: by 2002:a17:907:9385:b0:a9a:3705:9ad9 with SMTP id a640c23a62f3a-aa63a2550c2mr857698966b.50.1733689384563; Sun, 08 Dec 2024 12:23:04 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.23.02 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:23:04 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 11/15] hw/vmapple/bdif: Introduce vmapple backdoor interface Date: Sun, 8 Dec 2024 21:22:34 +0100 Message-Id: <20241208202238.68873-12-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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 Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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. 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 +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 © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * 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 = -1; + uint64_t devid = offset & REG_DEVID_MASK; + + switch (offset & ~REG_DEVID_MASK) { + case REG_STATUS: + ret = REG_STATUS_ACTIVE; + break; + case REG_CFG: + ret = REG_CFG_ACTIVE; + break; + case REG_UNK1: + ret = 0x420; + break; + case REG_BUSY: + ret = REG_BUSY_READY; + break; + case REG_UNK2: + ret = 0x1; + break; + case REG_UNK3: + ret = 0x0; + break; + case REG_NEXT_DEVICE: + switch (devid) { + case DEVID_ROOT: + ret = 0x8000000; + break; + case DEVID_AUX: + ret = 0x10000; + break; + } + break; + } + + trace_bdif_read(offset, size, ret); + return ret; +} + +static void le2cpu_sector(VblkSector *sector) +{ + sector->sector = le32_to_cpu(sector->sector); +} + +static void le2cpu_reqcmd(VblkReqCmd *cmd) +{ + cmd->addr = le64_to_cpu(cmd->addr); + cmd->len = le32_to_cpu(cmd->len); + cmd->flags = 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 = 0; + g_autofree char *buf = NULL; + uint8_t ret = VBLK_RET_FAILED; + int r; + MemTxResult dma_result; + + dma_result = dma_memory_read(&address_space_memory, gp_addr, + &req, sizeof(req), MEMTXATTRS_UNSPECIFIED); + if (dma_result != MEMTX_OK) { + goto out; + } + + le2cpu_req(&req); + + if (req.sector.len != sizeof(sector)) { + goto out; + } + + /* Read the vblk command */ + dma_result = dma_memory_read(&address_space_memory, req.sector.addr, + §or, sizeof(sector), + MEMTXATTRS_UNSPECIFIED); + if (dma_result != MEMTX_OK) { + goto out; + } + le2cpu_sector(§or); + + off = sector.sector * 512ULL + static_off; + + /* Sanity check that we're not allocating bogus sizes */ + if (req.data.len > 128 * MiB) { + goto out; + } + + buf = g_malloc0(req.data.len); + switch (req.data.flags) { + case VBLK_DATA_FLAGS_READ: + r = blk_pread(blk, off, req.data.len, buf, 0); + trace_bdif_vblk_read(devid == DEVID_AUX ? "aux" : "root", + req.data.addr, off, req.data.len, r); + if (r < 0) { + goto out; + } + dma_result = dma_memory_write(&address_space_memory, req.data.addr, buf, + req.data.len, MEMTXATTRS_UNSPECIFIED); + if (dma_result == MEMTX_OK) { + ret = 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 = opaque; + uint64_t devid = (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 = { + .read = bdif_read, + .write = bdif_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static void bdif_init(Object *obj) +{ + VMAppleBdifState *s = 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[] = { + 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 = DEVICE_CLASS(klass); + + dc->desc = "VMApple Backdoor Interface"; + device_class_set_props(dc, bdif_properties); +} + +static const TypeInfo bdif_info = { + .name = TYPE_VMAPPLE_BDIF, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VMAppleBdifState), + .instance_init = bdif_init, + .class_init = 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=0x%"PRIx64" res=0x%"PRIx64 aes_2_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64 aes_dump_data(const char *desc, const char *hex) "%s%s" +# bdif.c +bdif_read(uint64_t offset, uint32_t size, uint64_t value) "offset=0x%"PRIx64" size=0x%x value=0x%"PRIx64 +bdif_write(uint64_t offset, uint32_t size, uint64_t value) "offset=0x%"PRIx64" size=0x%x value=0x%"PRIx64 +bdif_vblk_read(const char *dev, uint64_t addr, uint64_t offset, uint32_t len, int r) "dev=%s addr=0x%"PRIx64" off=0x%"PRIx64" size=0x%x r=%d" + 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 @@ #define TYPE_APPLE_AES "apple-aes" +#define TYPE_VMAPPLE_BDIF "vmapple-bdif" + #endif /* HW_VMAPPLE_VMAPPLE_H */ From patchwork Sun Dec 8 20:22:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898645 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 92FC6E7717F for ; Sun, 8 Dec 2024 20:24:26 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNo9-0002RQ-3J; Sun, 08 Dec 2024 15:23:13 -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 ) id 1tKNo6-0002Of-NQ for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:10 -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 ) id 1tKNo3-00088o-R4 for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:10 -0500 Received: by mail-ej1-x633.google.com with SMTP id a640c23a62f3a-aa670ffe302so127564166b.2 for ; Sun, 08 Dec 2024 12:23:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689386; x=1734294186; 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=GKwZl3sYzjVDyHEB2hVJ7bueQq1gML0+axfdJn79618UMdbu/oB6tK/SY01p05S5re QNsZY5hV1qD9eftXO/UhPH+MqrKZdLRIG4FQifuw0jDTikirAK1CNj7gGsqvWx2V8tLZ iuCBRjn3j3yi9LmZ4l5jjYJJ5lfEJP/n4WYua0AFUjOOs5uyX7w7yGykbwCyIrxBoz8z cJEfFwwEacM3tvyaLZ8/WL7JqaoeByBjK/lpqQTPAkJddO28L1g4+lkLOSNuJTuerAHS yQDRztVacC0AcR3A+dnsljd1xwInVSHLQmfU+BDNVn9sPcGYIBEAHadBQg5e7IBGEAcT MyxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689386; x=1734294186; 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=kBkUNhN1LLKpCEHhiE0Fr63GrrsGTVuEpAe2dBktrsj+a0FojMPS8Fx23wr7agtaK6 rXDyzM04Z7KWn7jREYIC89FTp04REKUnJc86Hn7XuSItanocmT18XTmSTfNcips5xE6z Hcc3vEmB0b1EPaKW1qGu5bURGZqv6jmnsM/GZStxrmSRWNCvO5Yl0bokedQsSp7nLeIm A9trKQwarYUXEArL69s9ZKdWtOhUfvpsPaC/jVi2YZ5XCZwKNvwMTQbNHeYgGkuKOdyI HADKat/2lUHPOenw1YMLs/rMKGw8w6cCgSKyt54F3jzcerO9rkdIawkAKnMhbW2/OIUk zo5Q== X-Gm-Message-State: AOJu0YyDiPUh4YgSTDth92z7hdWZfy8qvwyWKmduWNKFghmgAiwpy1SO CAHuG7hqpyGGAbcVqvEX7tT9JJAbeR+GJovQ2c83+a+lKW536MkTiaCsXBfGophDnDXQRVqBbZB VrNvG X-Gm-Gg: ASbGncuofk6Cejh4YF3FfFPOJgFLGnuy+GfsEAlkgWWKZnmZvmzDykPPU1gC09RrCvG XUPw9m7k4V59FDNDl2fe5PajuEp4eYm6YT04gPlIfHrr7yLDj4GoPGdll5cgwipudr1324S8Pd0 Bnbb3WMPJUV+qUximAsv7FrXdWlb4XhdceL46O08kYhOSvZvhoEBFDq4ejbV1b418/Ev/gJn2gV MmB17OrVo9gynI/AD1rx36ZYA2AGkT8d6Ue1gvktrkKzV814a4zHcPPsn5rS5staFgKIo3BehVM Kq4fFyQXGy4U4iXeJWClscSRzQ== X-Google-Smtp-Source: AGHT+IFxCoLavVxtvE3tFOP8r7ECj0HwTnk2ABFLQBoLpGeS17CgB9gRIXyCGma1geumeq9w6avmBA== X-Received: by 2002:a17:906:9d2:b0:aa6:841a:dff0 with SMTP id a640c23a62f3a-aa6841b1083mr194574266b.32.1733689386351; Sun, 08 Dec 2024 12:23:06 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.23.04 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:23:06 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 12/15] hw/vmapple/cfg: Introduce vmapple cfg region Date: Sun, 8 Dec 2024 21:22:35 +0100 Message-Id: <20241208202238.68873-13-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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 Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 +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 © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * 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 = VMAPPLE_CFG(obj); + VMAppleCfg *cfg; + + cfg = memory_region_get_ram_ptr(&s->mem); + memset(cfg, 0, VMAPPLE_CFG_SIZE); + *cfg = 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 = 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 = VMAPPLE_CFG(dev); + uint32_t i; + + if (!s->serial) { + s->serial = g_strdup("1234"); + } + if (!s->model) { + s->model = g_strdup("VM0001"); + } + if (!s->soc_name) { + s->soc_name = 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 = 2; + s->cfg.unk1 = 1; + s->cfg.unk2 = 1; + s->cfg.unk3 = 0x20; + s->cfg.unk4 = 0; + s->cfg.unk5 = 1; + s->cfg.unk6 = 1; + s->cfg.unk7 = 0; + s->cfg.unk10 = 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 = 0; i < s->cfg.nr_cpus; i++) { + s->cfg.cpu_ids[i] = i; + } +} + +static void vmapple_cfg_init(Object *obj) +{ + VMAppleCfgState *s = VMAPPLE_CFG(obj); + + memory_region_init_ram(&s->mem, obj, "VMApple Config", VMAPPLE_CFG_SIZE, + &error_fatal); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mem); +} + +static Property vmapple_cfg_properties[] = { + 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_installer1, 0), + DEFINE_PROP_UINT32("run_installer2", VMAppleCfgState, cfg.run_installer2, 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 = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + dc->realize = vmapple_cfg_realize; + dc->desc = "VMApple Configuration Region"; + device_class_set_props(dc, vmapple_cfg_properties); + rc->phases.hold = vmapple_cfg_reset; +} + +static const TypeInfo vmapple_cfg_info = { + .name = TYPE_VMAPPLE_CFG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VMAppleCfgState), + .instance_init = vmapple_cfg_init, + .class_init = 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 @@ #define TYPE_VMAPPLE_BDIF "vmapple-bdif" +#define TYPE_VMAPPLE_CFG "vmapple-cfg" + #endif /* HW_VMAPPLE_VMAPPLE_H */ From patchwork Sun Dec 8 20:22:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898657 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B3498E7717F for ; Sun, 8 Dec 2024 20:26:06 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNoD-0002Vl-6K; Sun, 08 Dec 2024 15:23:17 -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 ) id 1tKNo8-0002Qy-PW for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:12 -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 ) id 1tKNo5-00089H-NG for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:12 -0500 Received: by mail-ej1-x632.google.com with SMTP id a640c23a62f3a-aa543c4db92so754008066b.0 for ; Sun, 08 Dec 2024 12:23:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689388; x=1734294188; 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=IQxJY3VrsVvYqM82vkQI1hVKl4n4VdL62yhsTv5qMDXZEq1i1n5736GColTaI5zXQi cHLHupg+Vb1fNqrg13coGFbyO9UwpcWIlnn/Cvibbbm4wS/rVRjlY9tQ4x5/kCw5Uc4E ImYWjY82d624c8ErR6aT1bMiEGUKcMkn+NFnRDiNbbsoh2i6wqMsxHaCytRqdnsP8mbz ndwvh1I4A3ONaQe1OBUOoJRMcDIDagJt+U8TK0Dswo4x0eeIaL5dAtQ4u+UrndkyD6Ts VCIqsAzp9v/OLOVxvqKDURTZoAZoR+qbGmpY6hbYb7fn5Cr9LST8x5vGHjLIpfSK0wv8 tyKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689388; x=1734294188; 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=Qgus2bD2IQ73sHa8hrcUQIvveCA1SGARD+EqtqJta9Db9uJUkBB8Xr1xrBOVojCnNR QOB/XV5sUaJwBGBVWlqsuz/5ZcZqXzNa9URVa/cJG2Aj8n8us0EST3o2KrgZU2Kuw3xO /cC4DHsbgoAXSrmYSwXZeverplVvBhSqQUDxr1ULSUgKfvbsDD7Si4kk/GeDbon0n+Ik W0Y4lkrBvQ3lgNH5FoWsGbrjP8xjEdBi+GoiTXrD0J0DTBjQCgq/LwcImilt5Tu6l4rl qW4upjCSgxps642TDo912TACsa1MPZ3DyyqfuIwE6pwoaFHWhgDMScGaULEHGgLxTtV+ XZug== X-Gm-Message-State: AOJu0YxBcwOKtClNcIR2ZepPivgX1/BGfaKg2G2gNeyjopHiCYRklVuh 0hZGWAIRuopyBs9wCi4S20bg8pUf6JzGpcgKtCLK8niegKJhDqDIcxRoagsHK4u8G90YCc646d0 1PNMF X-Gm-Gg: ASbGncuM6qq75S1zlNT7jUlFTM0EePhrKPg63UCURFGNpVxH2CpbvyybXNGrMpVU6Co IWZO/XHQdZXYxwMPg+41QoJ6OSXYInfYt95N8ZWh7CPxM7j/khnHqO561Evcqm8to2oEYbObRxB up1o/cUMRdOR2l5dUpUx3dmwI/yW71zzZXacYyq6K34b7tqOMYJC8ejxFdHmf3ZQcAaEzEU5hKi QYTEfOZwqGiybo6BXnO3tY544ZqbNIHgLH5lYK9YSZg9GTs3Ao1/6efCyosq85BH3vITNyNZid3 a/Ljbs3FCXSEaraaB/rsV1X2Dg== X-Google-Smtp-Source: AGHT+IH/+LDlAwgazXc2G0FnUFqtZzlEKhDVVw6SNWB6xNKQ62RmGZ2Sj9UZR+xF4rz4E4R7YCVjfw== X-Received: by 2002:a17:906:32c3:b0:aa6:7d82:540a with SMTP id a640c23a62f3a-aa67d8258dbmr196186266b.61.1733689388149; Sun, 08 Dec 2024 12:23:08 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.23.06 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:23:07 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 13/15] hw/vmapple/virtio-blk: Add support for apple virtio-blk Date: Sun, 8 Dec 2024 21:22:36 +0100 Message-Id: <20241208202238.68873-14-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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 Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 different 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, VirtQueue *vq, req->mr_next = NULL; } -static void virtio_blk_free_request(VirtIOBlockReq *req) +void virtio_blk_free_request(VirtIOBlockReq *req) { g_free(req); } -static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) +void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) { VirtIOBlock *s = req->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); @@ -966,8 +966,18 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, 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 the + * class lookup is not in the hot path. + */ + VirtIOBlkClass *vbk = 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 = { .instance_size = sizeof(VirtIOBlock), .instance_init = virtio_blk_instance_init, .class_init = virtio_blk_class_init, + .class_size = sizeof(VirtIOBlkClass), }; static void virtio_register_types(void) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.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_list = { .set = set_iothread_vq_mapping_list, .release = release_iothread_vq_mapping_list, }; + +const PropertyInfo qdev_prop_vmapple_virtio_blk_variant = { + .name = "VMAppleVirtioBlkVariant", + .enum_table = &VMAppleVirtioBlkVariant_lookup, + .get = qdev_propinfo_get_enum, + .set = qdev_propinfo_set_enum, + .set_default_value = 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 +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-blk.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 © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * 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 differences: + * + * - 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_VIRTIO_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-ops\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 one + * 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 *config) +{ + VMAppleVirtIOBlk *dev = VMAPPLE_VIRTIO_BLK(vdev); + VMAppleVirtIOBlkClass *vvbk = VMAPPLE_VIRTIO_BLK_GET_CLASS(dev); + struct virtio_blk_config *blkcfg = (struct virtio_blk_config *)config; + + vvbk->get_config(vdev, config); + + g_assert(dev->parent_obj.config_size >= endof(struct virtio_blk_config, 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 = VIRTIO_BLK_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VMAppleVirtIOBlkClass *vvbk = VMAPPLE_VIRTIO_BLK_CLASS(klass); + + vbk->handle_unknown_request = vmapple_virtio_blk_handle_unknown_request; + vvbk->get_config = vdc->get_config; + vdc->get_config = vmapple_virtio_blk_get_config; +} + +static const TypeInfo vmapple_virtio_blk_info = { + .name = TYPE_VMAPPLE_VIRTIO_BLK, + .parent = TYPE_VIRTIO_BLK, + .instance_size = sizeof(VMAppleVirtIOBlk), + .class_size = sizeof(VMAppleVirtIOBlkClass), + .class_init = vmapple_virtio_blk_class_init, +}; + +/* PCI Devices */ + +struct VMAppleVirtIOBlkPCI { + VirtIOPCIProxy parent_obj; + VMAppleVirtIOBlk vdev; + VMAppleVirtioBlkVariant variant; +}; + + +static Property vmapple_virtio_blk_pci_properties[] = { + 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_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vmapple_virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + ERRP_GUARD(); + VMAppleVirtIOBlkPCI *dev = VMAPPLE_VIRTIO_BLK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOBlkConf *conf = &dev->vdev.parent_obj.conf; + + if (dev->variant == 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 when " + "neither is applicaple.\n"); + return; + } + + if (conf->num_queues == VIRTIO_BLK_AUTO_NUM_QUEUES) { + conf->num_queues = virtio_pci_optimal_num_queues(0); + } + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = conf->num_queues + 1; + } + + /* + * We don't support zones, but we need the additional config space size. + * 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_ZONED); + /* Propagate the apple type down to the virtio-blk device */ + dev->vdev.apple_type = 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 whether + * 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 *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + device_class_set_props(dc, vmapple_virtio_blk_pci_properties); + k->realize = vmapple_virtio_blk_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_APPLE; + pcidev_k->device_id = PCI_DEVICE_ID_APPLE_VIRTIO_BLK; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void vmapple_virtio_blk_pci_instance_init(Object *obj) +{ + VMAppleVirtIOBlkPCI *dev = 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 = { + .generic_name = TYPE_VMAPPLE_VIRTIO_BLK_PCI, + .instance_size = sizeof(VMAppleVirtIOBlkPCI), + .instance_init = vmapple_virtio_blk_pci_instance_init, + .class_init = 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 #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-properties-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; #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_list; DEFINE_PROP(_name, _state, _field, qdev_prop_iothread_vq_mapping_list, \ IOThreadVirtQueueMappingList *) +#define DEFINE_PROP_VMAPPLE_VIRTIO_BLK_VARIANT(_n, _s, _f, _d) \ + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_vmapple_virtio_blk_variant, \ + 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" #define TYPE_VIRTIO_BLK "virtio-blk-device" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlock, VIRTIO_BLK) +OBJECT_DECLARE_TYPE(VirtIOBlock, VirtIOBlkClass, VIRTIO_BLK) /* 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; +typedef struct VirtIOBlkClass { + /*< private >*/ + VirtioDeviceClass parent; + /*< public >*/ + bool (*handle_unknown_request)(VirtIOBlockReq *req, MultiReqBuffer *mrb, + 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); #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 @@ #define TYPE_VMAPPLE_CFG "vmapple-cfg" +#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' ] } From patchwork Sun Dec 8 20:22:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898644 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 46FD9E77173 for ; Sun, 8 Dec 2024 20:23:57 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNoB-0002Tr-RB; Sun, 08 Dec 2024 15:23:15 -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 ) id 1tKNoA-0002S2-6g for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:14 -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 ) id 1tKNo7-0008Ag-Vu for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:13 -0500 Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-aa543c4db92so754011966b.0 for ; Sun, 08 Dec 2024 12:23:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689390; x=1734294190; 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=iXaHAeQOzUjwy4NBKuJD/f06/LhUmgHmEJCuYTZoHO1fP0P/8qnQZC0+azTee1fx1N RJyHA0NYwilaQMp+0VEF5qITzs9PKiHnQiKQ5l06tKWzmNYO2Ugw8B9uijZXtjiDCJer 3xY/Kq8VeQ7EoPSHzRzS2+JUZIEyG+ih075N6lCBmUDqs0cx+Y643HF30jOYszYcRG9R pseMJtKZ+UyK4ZkBDvYwnRFaTHr0A+eNSbL5Kpi3kgfsY/aHsysAfqhAGscPDUQIaQH7 qH847BMBPMA8DDv/4QPlmXGWtnaOZKK+UWz8xsCez504Nk43/l8o16zpafXgN69b6N49 alGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689390; x=1734294190; 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=A5lkZQy6OUd+rPeM/kP2yt6KSEKP9k6DuE1863dkLvesrFqBwA2fEGY/ypXk/8roG4 V30z9Yyk3kfbMosuA3If4KF4kdmZvLZ3VnhOHy4IN+L3f2GpSMpUfFGYMInUP/fbjDD/ M6U1/QX8AGGqB2Ccc69nnIH6DQ6eqiQ9yQcsU4za0qUg5SPcw5lma5CZuU59eSZqPB9c NRV2HevmSY3Ww9VFDrpmqX3kFskhfhG7DumeCU75F+/NQvdJ+I1AOJCZAY4vkMgwEbMU +bbiEYIA4I/TNmqj40tmuokU5eTGLfY/G9vPT8sTUv8wlfpGZ3EAucbu83mzfnlw459V C+Ow== X-Gm-Message-State: AOJu0Yw/1VwH68XOgb1xhBaw+YsygI0HHMblJn44d+yEyGzF8G272Jlb QrrUSbValsKP43qf7U0MKwpjbO2sxyfd04OfV9+QG6h6B4y3yJIC6Fi5M7zpwph+eMgZXxr5XSn qTXef X-Gm-Gg: ASbGncupKpAbuWUFPSTOZkD87QaeGD8Kwtk1JE96nA6E08WV3WJatbGIJDBTccov5S+ /lgRhKZ0lLcvDhgwpNKZLXMhHrAWkPF1MkLKiAus4Q1WVhBJXpoeOwlQV8uPdBVsNaoyGAPzMuT /KzS+Up+IyT6UrJnA7tcXZ7lM4hg4LiUEawWpS99uUcsvt5doTFfkiFpV0MDs0jx76fEkXpgHxH Hvl63z1yTp9UmhxrQeNQfdlkLr1fq16Tr9fizpXB59VS2TFk6R58elso8CpAw8gUxhQnsbtAiKv pbwG6gABlIB6bYbl/pi8U4B5JA== X-Google-Smtp-Source: AGHT+IGgrtdSDT9B0eBqHTNO5jqJqaoAQQ1vzAOhYUNP2kHITLwkgMG8QlxodL763QgKvePBy/2XzQ== X-Received: by 2002:a17:906:3094:b0:aa6:18b6:310e with SMTP id a640c23a62f3a-aa63a2417f2mr1009887966b.38.1733689390594; Sun, 08 Dec 2024 12:23:10 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.23.08 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:23:09 -0800 (PST) From: Phil Dennis-Jordan 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: Sun, 8 Dec 2024 21:22:37 +0100 Message-Id: <20241208202238.68873-15-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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 Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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, VirtQueue *vq, req->mr_next = NULL; } -void virtio_blk_free_request(VirtIOBlockReq *req) -{ - g_free(req); -} - void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) { VirtIOBlock *s = 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); } blk_error_action(s->blk, action, is_read, error); @@ -136,7 +131,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret) 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); } } @@ -151,7 +146,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret) 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); } static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret) @@ -169,7 +164,7 @@ static void virtio_blk_discard_write_zeroes_complete(void *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); } static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s, VirtQueue *vq) @@ -214,7 +209,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) fail: virtio_blk_req_complete(req, status); - virtio_blk_free_request(req); + g_free(req); } static inline void submit_requests(VirtIOBlock *s, MultiReqBuffer *mrb, @@ -612,7 +607,7 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret) 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(VirtIOBlockReq *req, return; out: virtio_blk_req_complete(req, err_status); - virtio_blk_free_request(req); + g_free(req); } 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) } virtio_blk_req_complete(req, err_status); - virtio_blk_free_request(req); + g_free(req); } 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; } @@ -750,7 +745,7 @@ static void virtio_blk_zone_append_complete(void *opaque, int ret) out: virtio_blk_req_complete(req, err_status); - virtio_blk_free_request(req); + g_free(req); g_free(data); } @@ -788,7 +783,7 @@ static int virtio_blk_handle_zone_append(VirtIOBlockReq *req, out: virtio_blk_req_complete(req, err_status); - virtio_blk_free_request(req); + g_free(req); return err_status; } @@ -855,7 +850,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, 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_READ); - virtio_blk_free_request(req); + g_free(req); return 0; } @@ -911,7 +906,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, 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 *req, 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; } @@ -960,7 +955,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) is_write_zeroes); if (err_status != VIRTIO_BLK_S_OK) { virtio_blk_req_complete(req, err_status); - virtio_blk_free_request(req); + g_free(req); } break; @@ -975,7 +970,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, 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 = 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 = req->next; virtqueue_detach_element(req->vq, &req->elem, 0); - virtio_blk_free_request(req); + g_free(req); req = 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); - virtio_blk_free_request(req); + g_free(req); } } 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(VirtIOBlockReq *req, qemu_log_mask(LOG_UNIMP, "%s: Barrier requests are currently no-ops\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; 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); #endif From patchwork Sun Dec 8 20:22:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 13898649 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 76763E77173 for ; Sun, 8 Dec 2024 20:24:52 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tKNoH-0002Yd-ND; Sun, 08 Dec 2024 15:23:21 -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 ) id 1tKNoE-0002WH-D5 for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:18 -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 ) id 1tKNoA-0008BV-7f for qemu-devel@nongnu.org; Sun, 08 Dec 2024 15:23:18 -0500 Received: by mail-ej1-x629.google.com with SMTP id a640c23a62f3a-aa629402b53so482056066b.3 for ; Sun, 08 Dec 2024 12:23:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1733689393; x=1734294193; 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=UCMMr/KxKy7v4Wh5TImA4mOVFfIm3Q+aIs7+saR/0NBYmfz5fzCYV6V8bp4hfzp7ni jpkpUtynK9mgjmM4LK38oQZPANI1EcrWlOwxBmmC/74JKpf04AVAx7qUaejRocEusMCx ZFslDQ9wOnbX/2+6axU+rHApht4grfhCIKBU4yx4D/q+JKtespdrA0SeVCYgsEYnFxlM 4Jig1HdYI2zVPH5iTIDxytHP62z1MyffgUgsAgXp60jvBMGCGdb3H2JYEq/4GQsI8afB OwGbR6hY3RPI7XWBlwV/j9DfJEcEqXy9S3K6Qb2QcMjo8pU2/X/cvEYQ+fPIL3oLYnZm IyaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733689393; x=1734294193; 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=DbN5Fad1vm0ueA96AWc2f5ha2k7IC3fF9O6qRCbXH3180dOcAlLh3HDRfnTp7eCOlU h74R6QmPB5cteWvB+iT8hs6090GroZA0HPvs01i5FoRkOsMqHEFxckpfHWcQKjyi0UDU 6MpGL7FDfxQX5ctMK8Ynw2/aqM5BqL+gmHfhk9LuVpwsSTk6fHnFM1/6yU9mSARoFJZu ZBfj5WKmhUH8khBUT1UJn4qs/N8fvPKldLaogLNOo2uAczCTrI8VBPkaoxqMWZWgp7Gn 2BK0bjjFgPGXLMmUg+RHA7F/VcanGgNF+5M7adjsZzcFBvGFTWvKSi6ntDNnkkRcl5/j WAHg== X-Gm-Message-State: AOJu0YysTpYKZB6avYu+1WaULtaTSHRNUKQfH/4ohJ5I5o0ZFfV/HiDf PsLzOVcziKFcDBcgy6lrTuP3DZRgjG7tGe/HCGMpJxgt0mR+QAlIz7CFcLLT2Zuc3vGgwidIB4t Dzoow X-Gm-Gg: ASbGncsctbQkZtSdR6NpoqEbeWGv7IKqojdCNBVEYrLyCdidY4lXNLaYPlS0UlJaS4e m3GXTDomVct7og5NTMIZl3UjI8uk1L2h9OwvHlLGMN7F7NdR8FWJkuehOivpNsBpM8X6XB00gqR yixm8cUJWMmnq5B5MqaClzkkE/AX1t82tPlZDI5yPeCc+oJnhFUXuEtSKU/ZEHWT5iYb6rSqLY1 CoechzdoiJdCyEBVmMo+GH29gzLhCjxn4wogNZhNpu4OskoLwg491yzVxgjwSZZOx726JOfa8U5 G7bZPgXJVBoYUevZCbIgKCVTiA== X-Google-Smtp-Source: AGHT+IFRq9hC8EC7YoPVC9hjG7KIe3SYOvmQMVhtcAw7Y5mqXkryHrNU7M1IHNRfVECwUKd8JLXSTQ== X-Received: by 2002:a17:907:90d5:b0:aa6:82ea:69d6 with SMTP id a640c23a62f3a-aa682ea6a9cmr253912666b.18.1733689392518; Sun, 08 Dec 2024 12:23:12 -0800 (PST) Received: from localhost.localdomain (h082218084190.host.wavenet.at. [82.218.84.190]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa625e4eee4sm585759266b.26.2024.12.08.12.23.10 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sun, 08 Dec 2024 12:23:12 -0800 (PST) From: Phil Dennis-Jordan 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 Subject: [PATCH v13 15/15] hw/vmapple/vmapple: Add vmapple machine type Date: Sun, 8 Dec 2024 21:22:38 +0100 Message-Id: <20241208202238.68873-16-phil@philjordan.eu> X-Mailer: git-send-email 2.39.5 (Apple Git-154) In-Reply-To: <20241208202238.68873-1-phil@philjordan.eu> References: <20241208202238.68873-1-phil@philjordan.eu> MIME-Version: 1.0 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Alexander Graf 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= parameter: $ qemu-system-aarch64 -accel hvf -M vmapple,uuid=0x1234 -m 4G \ -bios /System/Library/Frameworks/Virtualization.framework/Versions/A/Resources/AVPBooter.vmapple2.bin -drive file=aux,if=pflash,format=raw \ -drive file=root,if=pflash,format=raw \ -drive file=aux,if=none,id=aux,format=raw \ -device vmapple-virtio-blk-pci,variant=aux,drive=aux \ -drive file=root,if=none,id=root,format=raw \ -device vmapple-virtio-blk-pci,variant=root,drive=root 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 Co-authored-by: Phil Dennis-Jordan Signed-off-by: Phil Dennis-Jordan Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki --- 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 S: Maintained F: hw/vmapple/* F: include/hw/vmapple/* +F: docs/system/arm/vmapple.rst 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 +======================================================================================== + +VMApple is the device model that the macOS built-in hypervisor called "Virtualization.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 virtual + 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 ` CLI. + +First, we need to extract the UUID from the virtual machine that you installed. 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 can just discard: + +.. code-block:: bash + :caption: Command to trim the aux file + + $ dd if="aux.img" of="aux.img.trimmed" bs=$(( 0x4000 )) skip=1 + +How to run +---------- + +Then, we can launch QEMU with the Virtualization.Framework pre-boot environment 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="$(contrib/vmapple/uuid.sh 'macosvm.json')" + $ AVPBOOTER="/System/Library/Frameworks/Virtualization.framework/Resources/AVPBooter.vmapple2.bin" + $ AUX="aux.img.trimmed" + $ DISK="disk.img" + $ qemu-system-aarch64 \ + -serial mon:stdio \ + -m 4G \ + -accel hvf \ + -M vmapple,uuid="$UUID" \ + -bios "$AVPBOOTER" \ + -drive file="$AUX",if=pflash,format=raw \ + -drive file="$DISK",if=pflash,format=raw \ + -drive file="$AUX",if=none,id=aux,format=raw \ + -drive file="$DISK",if=none,id=root,format=raw \ + -device vmapple-virtio-blk-pci,variant=aux,drive=aux \ + -device vmapple-virtio-blk-pci,variant=root,drive=root \ + -netdev user,id=net0,ipv6=off,hostfwd=tcp::2222-:22,hostfwd=tcp::5901-:5900 \ + -device virtio-net-pci,netdev=net0 + 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 +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-blk.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 © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * 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 = MACHINE_CLASS(oc); \ + vmapple_machine_##major##_##minor##_options(mc); \ + mc->desc = "QEMU " # major "." # minor " Apple Virtual Machine"; \ + if (latest) { \ + mc->alias = "vmapple"; \ + } \ + } \ + static const TypeInfo machvmapple##major##_##minor##_info = { \ + .name = MACHINE_TYPE_NAME("vmapple-" # major "." # minor), \ + .parent = TYPE_VMAPPLE_MACHINE, \ + .class_init = 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_MACHINE) + +/* 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[] = { + [VMAPPLE_FIRMWARE] = { 0x00100000, 0x00100000 }, + [VMAPPLE_CONFIG] = { 0x00400000, 0x00010000 }, + + [VMAPPLE_GIC_DIST] = { 0x10000000, 0x00010000 }, + [VMAPPLE_GIC_REDIST] = { 0x10010000, 0x00400000 }, + + [VMAPPLE_UART] = { 0x20010000, 0x00010000 }, + [VMAPPLE_RTC] = { 0x20050000, 0x00001000 }, + [VMAPPLE_GPIO] = { 0x20060000, 0x00001000 }, + [VMAPPLE_PVPANIC] = { 0x20070000, 0x00000002 }, + [VMAPPLE_BDOOR] = { 0x30000000, 0x00200000 }, + [VMAPPLE_APV_GFX] = { 0x30200000, 0x00010000 }, + [VMAPPLE_APV_IOSFC] = { 0x30210000, 0x00010000 }, + [VMAPPLE_AES_1] = { 0x30220000, 0x00004000 }, + [VMAPPLE_AES_2] = { 0x30230000, 0x00004000 }, + [VMAPPLE_PCIE_ECAM] = { 0x40000000, 0x10000000 }, + [VMAPPLE_PCIE_MMIO] = { 0x50000000, 0x1fff0000 }, + + /* Actual RAM size depends on configuration */ + [VMAPPLE_MEM] = { 0x70000000ULL, GiB}, +}; + +static const int irqmap[] = { + [VMAPPLE_UART] = 1, + [VMAPPLE_RTC] = 2, + [VMAPPLE_GPIO] = 0x5, + [VMAPPLE_APV_IOSFC] = 0x10, + [VMAPPLE_APV_GFX] = 0x11, + [VMAPPLE_AES_1] = 0x12, + [VMAPPLE_PCIE] = 0x20, +}; + +#define GPEX_NUM_IRQS 16 + +static void create_bdif(VMAppleMachineState *vms, MemoryRegion *mem) +{ + DeviceState *bdif; + SysBusDevice *bdif_sb; + DriveInfo *di_aux = drive_get(IF_PFLASH, 0, 0); + DriveInfo *di_root = 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 = 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 = qdev_new(TYPE_VMAPPLE_BDIF); + bdif_sb = 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 = qdev_new(TYPE_PVPANIC_MMIO_DEVICE); + pvpanic = 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 = MACHINE(vms); + uint32_t rnd = 1; + + vms->cfg = qdev_new(TYPE_VMAPPLE_CFG); + cfg = 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 = vms->irqmap[VMAPPLE_APV_GFX]; + int irq_iosfc = vms->irqmap[VMAPPLE_APV_IOSFC]; + SysBusDevice *gfx; + + gfx = 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 = vms->irqmap[VMAPPLE_AES_1]; + SysBusDevice *aes; + + aes = 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 = MACHINE(vms); + /* We create a standalone GIC */ + SysBusDevice *gicbusdev; + QList *redist_region_count; + int i; + unsigned int smp_cpus = ms->smp.cpus; + + vms->gic = 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 = + vms->memmap[VMAPPLE_GIC_REDIST].size / GICV3_REDIST_SIZE; + uint32_t redist0_count = MIN(smp_cpus, redist0_capacity); + + redist_region_count = qlist_new(); + qlist_append_int(redist_region_count, redist0_count); + qdev_prop_set_array(vms->gic, "redist-region-count", redist_region_count); + + gicbusdev = 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 inputs. + */ + for (i = 0; i < smp_cpus; i++) { + DeviceState *cpudev = 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 = vms->memmap[uart].base; + int irq = vms->irqmap[uart]; + DeviceState *dev = qdev_new(TYPE_PL011); + SysBusDevice *s = 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 = vms->memmap[VMAPPLE_RTC].base; + int irq = 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 = vms->memmap[gpio].base; + int irq = vms->irqmap[gpio]; + SysBusDevice *s; + + pl061_dev = 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 = 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 = sysbus_create_simple("gpio-key", -1, + qdev_get_gpio_in(pl061_dev, 3)); +} + +static void vmapple_firmware_init(VMAppleMachineState *vms, + MemoryRegion *sysmem) +{ + hwaddr size = vms->memmap[VMAPPLE_FIRMWARE].size; + hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base; + const char *bios_name; + int image_size; + char *fname; + + bios_name = MACHINE(vms)->firmware; + if (!bios_name) { + error_report("No firmware specified"); + exit(1); + } + + fname = 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_fatal); + image_size = 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 = vms->memmap[VMAPPLE_PCIE_MMIO].base; + hwaddr size_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].size; + hwaddr base_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].base; + hwaddr size_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].size; + int irq = 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 = 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 = 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 = g_new0(MemoryRegion, 1); + mmio_reg = 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 = 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 = PCI_HOST_BRIDGE(dev); + vms->bus = pci->bus; + g_assert(vms->bus); + + while ((dev = qemu_create_nic_device("virtio-net-pci", true, NULL))) { + qdev_realize_and_unref(dev, BUS(vms->bus), &error_fatal); + } + + usb_controller = qdev_new(TYPE_QEMU_XHCI); + qdev_realize_and_unref(usb_controller, BUS(pci->bus), &error_fatal); + + usb_bus = 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 = opaque; + hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base; + + cpu_set_pc(first_cpu, base); +} + +static void mach_vmapple_init(MachineState *machine) +{ + VMAppleMachineState *vms = VMAPPLE_MACHINE(machine); + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *possible_cpus; + MemoryRegion *sysmem = get_system_memory(); + int n; + unsigned int smp_cpus = machine->smp.cpus; + unsigned int max_cpus = machine->smp.max_cpus; + + vms->memmap = memmap; + machine->usb = true; + + possible_cpus = mc->possible_cpu_arch_ids(machine); + assert(possible_cpus->len == max_cpus); + for (n = 0; n < possible_cpus->len; n++) { + Object *cpu; + CPUState *cs; + + if (n >= smp_cpus) { + break; + } + + cpu = object_new(possible_cpus->cpus[n].type); + object_property_set_int(cpu, "mp-affinity", + possible_cpus->cpus[n].arch_id, &error_fatal); + + cs = CPU(cpu); + cs->cpu_index = 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_abort); + 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 = vmapple_powerdown_req; + qemu_register_powerdown_notifier(&vms->powerdown_notifier); + + vms->bootinfo.ram_size = machine->ram_size; + vms->bootinfo.board_id = -1; + vms->bootinfo.loader_start = vms->memmap[VMAPPLE_MEM].base; + vms->bootinfo.skip_dtb_autoload = true; + vms->bootinfo.firmware_loaded = 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 = MACHINE_GET_CLASS(ms); + const CPUArchIdList *possible_cpus = 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 = ms->smp.max_cpus; + + if (ms->possible_cpus) { + assert(ms->possible_cpus->len == max_cpus); + return ms->possible_cpus; + } + + ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + + sizeof(CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; + for (n = 0; n < ms->possible_cpus->len; n++) { + ms->possible_cpus->cpus[n].type = ms->cpu_type; + ms->possible_cpus->cpus[n].arch_id = + arm_build_mp_affinity(n, GICV3_TARGETLIST_BITS); + ms->possible_cpus->cpus[n].props.has_thread_id = true; + ms->possible_cpus->cpus[n].props.thread_id = n; + } + return ms->possible_cpus; +} + +static void vmapple_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = mach_vmapple_init; + mc->max_cpus = 32; + mc->block_default_type = IF_VIRTIO; + mc->no_cdrom = 1; + mc->pci_allow_0_address = true; + mc->minimum_page_bits = 12; + mc->possible_cpu_arch_ids = vmapple_possible_cpu_arch_ids; + mc->cpu_index_to_instance_props = vmapple_cpu_index_to_props; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("host"); + mc->get_default_cpu_node_id = vmapple_get_default_cpu_node_id; + mc->default_ram_id = "mach-vmapple.ram"; + + object_register_sugar_prop(TYPE_VIRTIO_PCI, "disable-legacy", + "on", true); +} + +static void vmapple_instance_init(Object *obj) +{ + VMAppleMachineState *vms = VMAPPLE_MACHINE(obj); + + vms->irqmap = 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 = { + .name = TYPE_VMAPPLE_MACHINE, + .parent = TYPE_MACHINE, + .abstract = true, + .instance_size = sizeof(VMAppleMachineState), + .class_size = sizeof(VMAppleMachineClass), + .class_init = vmapple_machine_class_init, + .instance_init = 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) +