Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2234273/?format=api
{ "id": 2234273, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2234273/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260507040153.14565-2-matthew@pq.io/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/1.2/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260507040153.14565-2-matthew@pq.io>", "list_archive_url": null, "date": "2026-05-07T04:01:52", "name": "[1/2] hw/misc/applesmc: fix GET_KEY_BY_INDEX to return real keys, accept WRITE/TYPE commands", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "d6e0d6367d01b8342fccb7349f85a80bada505c0", "submitter": { "id": 93356, "url": "http://patchwork.ozlabs.org/api/1.2/people/93356/?format=api", "name": "Matthew Jackson", "email": "matthew@pq.io" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260507040153.14565-2-matthew@pq.io/mbox/", "series": [ { "id": 503191, "url": "http://patchwork.ozlabs.org/api/1.2/series/503191/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=503191", "date": "2026-05-07T04:01:53", "name": "hw/misc/applesmc: fix GET_KEY_BY_INDEX iteration and populate Apple SMC key set", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/503191/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2234273/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2234273/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=pq.io header.i=@pq.io header.a=rsa-sha256\n header.s=protonmail3 header.b=EmYhYA//;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)" ], "Received": [ "from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gBDll0W3dz1y04\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 08 May 2026 00:14:43 +1000 (AEST)", "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wKzUD-0007Ak-CB; Thu, 07 May 2026 10:13:57 -0400", "from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <matthew@pq.io>) id 1wKpwH-0005nn-9M\n for qemu-devel@nongnu.org; Thu, 07 May 2026 00:02:17 -0400", "from mail-07.mail-europe.com ([188.165.51.139])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <matthew@pq.io>) id 1wKpwE-0004lR-SL\n for qemu-devel@nongnu.org; Thu, 07 May 2026 00:02:16 -0400" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=pq.io;\n s=protonmail3; t=1778126519; x=1778385719;\n bh=QoT6ZV0zp2yCk/oaO3p5EzNmYDCXteG6Q8NREGInOLI=;\n h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:From:To:\n Cc:Date:Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector;\n b=EmYhYA//9Wh0jPzyeEjb4d7pK60XHxV8YTSidMF32B/un6iFBhdLUbXXoMruKy/5W\n RTZ2Xk2BCdQrWWJPNFjAJGtY3c8lY7NbqONUUJ8d6y2F0Jskd+MAxv0XNjM0k8zxHG\n Q3ShnERv9+ik6W00yBIyVFW5Xb5RWVfVFmy0cKyScYIXAZpZIfxwvFke3tS/maRfUf\n xex3Kbe2CNwTJjRoy1S8zgLUOyTbKkM6xzeGLiH2t3YIVXLquwuxnbuPLsT7a0YGEo\n Ca8jX7QyveT/zNwYx6EewU+U/lyClH8NOJCduVf3XCZFs3l3T4GV1DIH/uUHnIAwor\n OfA7qCKM1lWew==", "X-Pm-Submission-Id": "4g9z8j2VCjz1DFFg", "From": "Matthew Jackson <matthew@pq.io>", "To": "qemu-devel@nongnu.org", "Cc": "stefanha@redhat.com", "Subject": "[PATCH 1/2] hw/misc/applesmc: fix GET_KEY_BY_INDEX to return real\n keys, accept WRITE/TYPE commands", "Date": "Wed, 6 May 2026 21:01:52 -0700", "Message-ID": "<20260507040153.14565-2-matthew@pq.io>", "X-Mailer": "git-send-email 2.50.1", "In-Reply-To": "<20260507040153.14565-1-matthew@pq.io>", "References": "<20260507040153.14565-1-matthew@pq.io>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Received-SPF": "pass client-ip=188.165.51.139; envelope-from=matthew@pq.io;\n helo=mail-07.mail-europe.com", "X-Spam_score_int": "-27", "X-Spam_score": "-2.8", "X-Spam_bar": "--", "X-Spam_report": "(-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=0.001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=ham autolearn_force=no", "X-Spam_action": "no action", "X-Mailman-Approved-At": "Thu, 07 May 2026 10:13:41 -0400", "X-BeenThere": "qemu-devel@nongnu.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "qemu development <qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org" }, "content": "The applesmc device implements just enough of the Apple SMC PMIO\nprotocol to satisfy the OSK boot check on older macOS versions.\nOn modern macOS guests (x86 10.14+, all 15.x), the AppleSMC kext\nenumerates the SMC key space at boot via APPLESMC_GET_KEY_BY_INDEX_CMD\n(0x12). The current device only acknowledges APPLESMC_READ_CMD\n(0x10) at the command port; every other command falls through to\nthe default arm of the switch and sets ST_1E_BAD_CMD.\n\nThe macOS driver interprets the resulting 0x82 reply as\n\"spurious data\" and enters a retry loop that floods the kernel\nlog with kSMCSpuriousData (0x81) / kSMCKeyNotFound errors at\nroughly 1800 events per second, pegging kernel_task at ~70%\nCPU and WindowServer at ~509% CPU. This reproduces reliably\non any recent macOS 15 guest booted with -device\nisa-applesmc,osk=<valid-OSK>.\n\nThis patch:\n\n * Accepts APPLESMC_WRITE_CMD, APPLESMC_GET_KEY_BY_INDEX_CMD,\n and APPLESMC_GET_KEY_TYPE_CMD at the command port (in\n addition to the existing READ_CMD path).\n\n * Implements GET_KEY_BY_INDEX by walking s->data_def and\n returning the 4-byte ASCII key name at the requested index;\n returns APPLESMC_ST_1E_BAD_INDEX (0xb8) once the index is\n past the end of the list so the guest stops iterating.\n\n * Implements GET_KEY_TYPE by looking up the key in s->data_def\n and returning a 6-byte response (type[4] + size[1] + attr[1])\n matching VirtualSMC's kern_pmio.cpp behaviour.\n\n * Implements WRITE by accepting the key name, length, and\n payload and logging at LOG_UNIMP. macOS writes SMC keys\n during normal power management; silent acceptance avoids\n BAD_CMD on every write.\n\n * Replaces the unknown-key NOEXIST (0x84) reply on READ with\n a zeroed payload of the requested length, logged at\n LOG_UNIMP. Early-boot probes hit hundreds of undocumented\n keys per second; NOEXIST triggers retry storms while a\n zeroed payload satisfies the probe semantics without\n asserting a particular value.\n\n * Routes the BAD_CMD path through qemu_log_mask\n (LOG_GUEST_ERROR) instead of the smc_debug printf.\n\n * Fixes a typo in the MSSD key initialiser (\"\\0x3\" -> \"\\x03\").\n The original literal was three bytes ('\\\\0', 'x', '3')\n truncated to one ('\\\\0') by the size argument, so MSSD has\n been silently returning 0 since introduction; the corrected\n value matches what a real iMac20,1 SMC reports.\n\nReported-by: macOS guests booted with -device isa-applesmc since 10.14.\nSigned-off-by: Matthew Jackson <matthew@pq.io>\n---\n hw/misc/applesmc.c | 177 +++++++++++++++++++++++++++++++++++++++++++--\n 1 file changed, 170 insertions(+), 7 deletions(-)", "diff": "diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c\nindex fd96f5f..2b5ef3c 100644\n--- a/hw/misc/applesmc.c\n+++ b/hw/misc/applesmc.c\n@@ -35,6 +35,7 @@\n #include \"hw/core/qdev-properties.h\"\n #include \"ui/console.h\"\n #include \"qemu/error-report.h\"\n+#include \"qemu/log.h\"\n #include \"qemu/module.h\"\n #include \"qemu/timer.h\"\n #include \"qom/object.h\"\n@@ -126,7 +127,14 @@ static void applesmc_io_cmd_write(void *opaque, hwaddr addr, uint64_t val,\n smc_debug(\"CMD received: 0x%02x\\n\", (uint8_t)val);\n switch (val) {\n case APPLESMC_READ_CMD:\n- /* did last command run through OK? */\n+ case APPLESMC_WRITE_CMD:\n+ case APPLESMC_GET_KEY_BY_INDEX_CMD:\n+ case APPLESMC_GET_KEY_TYPE_CMD:\n+ /*\n+ * Accept all standard SMC commands. Pre-existing code only handled\n+ * READ_CMD; macOS boots hang if WRITE/TYPE/GET_KEY_BY_INDEX commands\n+ * return BAD_CMD during early AppleSMC driver init.\n+ */\n if (status == APPLESMC_ST_CMD_DONE || status == APPLESMC_ST_NEW_CMD) {\n s->cmd = val;\n s->status = APPLESMC_ST_NEW_CMD | APPLESMC_ST_ACK;\n@@ -137,7 +145,8 @@ static void applesmc_io_cmd_write(void *opaque, hwaddr addr, uint64_t val,\n }\n break;\n default:\n- smc_debug(\"UNEXPECTED CMD 0x%02x\\n\", (uint8_t)val);\n+ qemu_log_mask(LOG_GUEST_ERROR,\n+ \"applesmc: unexpected CMD 0x%02x\\n\", (uint8_t)val);\n s->status = APPLESMC_ST_NEW_CMD;\n s->status_1e = APPLESMC_ST_1E_BAD_CMD;\n }\n@@ -179,17 +188,170 @@ static void applesmc_io_data_write(void *opaque, hwaddr addr, uint64_t val,\n s->data_len = d->len;\n s->data_pos = 0;\n s->status = APPLESMC_ST_ACK | APPLESMC_ST_DATA_READY;\n- s->status_1e = APPLESMC_ST_CMD_DONE; /* clear on valid key */\n+ s->status_1e = APPLESMC_ST_CMD_DONE;\n } else {\n- smc_debug(\"READ_CMD: key '%c%c%c%c' not found!\\n\",\n- s->key[0], s->key[1], s->key[2], s->key[3]);\n+ /*\n+ * Return zeros for unknown keys instead of NOEXIST. Early\n+ * macOS boot probes many undocumented keys; responding\n+ * NOEXIST triggers retry storms. A zeroed payload satisfies\n+ * the probe without asserting a particular value.\n+ */\n+ qemu_log_mask(LOG_UNIMP,\n+ \"applesmc: READ unknown key '%c%c%c%c' len=%d\\n\",\n+ s->key[0], s->key[1], s->key[2], s->key[3],\n+ (uint8_t)val);\n+ memset(s->data, 0, APPLESMC_MAX_DATA_LENGTH);\n+ s->data_len = (uint8_t)val;\n+ s->data_pos = 0;\n+ s->status = APPLESMC_ST_ACK | APPLESMC_ST_DATA_READY;\n+ s->status_1e = APPLESMC_ST_CMD_DONE;\n+ }\n+ }\n+ s->read_pos++;\n+ break;\n+ case APPLESMC_WRITE_CMD:\n+ /*\n+ * Accept writes silently. macOS writes SMC keys during power\n+ * management, fan control, etc. Log at LOG_UNIMP for visibility\n+ * without treating the write as an error.\n+ */\n+ if ((s->status & 0x0f) == APPLESMC_ST_CMD_DONE) {\n+ break;\n+ }\n+ if (s->read_pos < 4) {\n+ s->key[s->read_pos] = val;\n+ s->status = APPLESMC_ST_ACK;\n+ } else if (s->read_pos == 4) {\n+ s->data_len = (uint8_t)val;\n+ s->data_pos = 0;\n+ s->status = APPLESMC_ST_ACK;\n+ } else {\n+ if (s->data_pos < s->data_len) {\n+ s->data[s->data_pos] = (uint8_t)val;\n+ s->data_pos++;\n+ if (s->data_pos == s->data_len) {\n+ qemu_log_mask(LOG_UNIMP,\n+ \"applesmc: WRITE key '%c%c%c%c' len=%d\\n\",\n+ s->key[0], s->key[1], s->key[2], s->key[3],\n+ s->data_len);\n+ s->status = APPLESMC_ST_CMD_DONE;\n+ s->status_1e = APPLESMC_ST_CMD_DONE;\n+ } else {\n+ s->status = APPLESMC_ST_ACK;\n+ }\n+ }\n+ }\n+ s->read_pos++;\n+ break;\n+ case APPLESMC_GET_KEY_TYPE_CMD:\n+ /*\n+ * Return key type info. Protocol (matches VirtualSMC):\n+ * - Receive 4 bytes of key name.\n+ * - After the 4th byte, immediately set DATA_READY with response.\n+ * - Response is 6 bytes: type[4] + size[1] + attr[1].\n+ * Unlike READ_CMD there is no length byte between key name and\n+ * response.\n+ */\n+ if ((s->status & 0x0f) == APPLESMC_ST_CMD_DONE) {\n+ break;\n+ }\n+ if (s->read_pos < 3) {\n+ s->key[s->read_pos] = val;\n+ s->status = APPLESMC_ST_ACK;\n+ } else if (s->read_pos == 3) {\n+ /* 4th and final key byte. Unlike READ_CMD which has a 5th byte\n+ * for data length, GET_KEY_TYPE responds immediately after the\n+ * 4-byte key name (matching VirtualSMC kern_pmio.cpp behavior). */\n+ s->key[3] = val;\n+ d = applesmc_find_key(s);\n+ if (d != NULL) {\n+ switch (d->len) {\n+ case 1:\n+ s->data[0] = 'u'; s->data[1] = 'i';\n+ s->data[2] = '8'; s->data[3] = ' ';\n+ break;\n+ case 2:\n+ s->data[0] = 'u'; s->data[1] = 'i';\n+ s->data[2] = '1'; s->data[3] = '6';\n+ break;\n+ case 4:\n+ s->data[0] = 'u'; s->data[1] = 'i';\n+ s->data[2] = '3'; s->data[3] = '2';\n+ break;\n+ default:\n+ s->data[0] = 'c'; s->data[1] = 'h';\n+ s->data[2] = '8'; s->data[3] = '*';\n+ break;\n+ }\n+ s->data[4] = d->len;\n+ s->data[5] = 0xD0;\n+ } else {\n+ qemu_log_mask(LOG_UNIMP,\n+ \"applesmc: GET_KEY_TYPE unknown '%c%c%c%c'\\n\",\n+ s->key[0], s->key[1], s->key[2], s->key[3]);\n+ s->data[0] = 'u'; s->data[1] = 'i';\n+ s->data[2] = '8'; s->data[3] = ' ';\n+ s->data[4] = 1;\n+ s->data[5] = 0xD0;\n+ }\n+ s->data_len = 6;\n+ s->data_pos = 0;\n+ s->status = APPLESMC_ST_ACK | APPLESMC_ST_DATA_READY;\n+ s->status_1e = APPLESMC_ST_CMD_DONE;\n+ }\n+ s->read_pos++;\n+ break;\n+ case APPLESMC_GET_KEY_BY_INDEX_CMD:\n+ /*\n+ * Return key name by index. macOS sends a 4-byte big-endian index\n+ * and expects the 4-byte ASCII key name at that position. The\n+ * previous implementation returned 4 zero bytes, which macOS\n+ * treated as kSMCSpuriousData (0x81) and retried indefinitely,\n+ * flooding the kernel log at ~1800 errors/sec. Walk the keys list\n+ * to return the actual key name, or APPLESMC_ST_1E_BAD_INDEX\n+ * (0xb8) once the index is past the end of the list so the guest\n+ * stops iterating.\n+ */\n+ if ((s->status & 0x0f) == APPLESMC_ST_CMD_DONE) {\n+ break;\n+ }\n+ if (s->read_pos < 3) {\n+ s->key[s->read_pos] = val;\n+ s->status = APPLESMC_ST_ACK;\n+ } else if (s->read_pos == 3) {\n+ s->key[3] = val;\n+ uint32_t idx = ((uint8_t)s->key[0] << 24)\n+ | ((uint8_t)s->key[1] << 16)\n+ | ((uint8_t)s->key[2] << 8)\n+ | (uint8_t)s->key[3];\n+ struct AppleSMCData *def;\n+ uint32_t i = 0;\n+ bool found = false;\n+ QLIST_FOREACH(def, &s->data_def, node) {\n+ if (i == idx) {\n+ memcpy(s->data, def->key, 4);\n+ s->data_len = 4;\n+ s->data_pos = 0;\n+ found = true;\n+ break;\n+ }\n+ i++;\n+ }\n+ if (!found) {\n+ s->data_len = 0;\n+ s->status_1e = APPLESMC_ST_1E_BAD_INDEX;\n s->status = APPLESMC_ST_CMD_DONE;\n- s->status_1e = APPLESMC_ST_1E_NOEXIST;\n+ s->read_pos++;\n+ break;\n }\n+ s->status = APPLESMC_ST_ACK | APPLESMC_ST_DATA_READY;\n+ s->status_1e = APPLESMC_ST_CMD_DONE;\n }\n s->read_pos++;\n break;\n default:\n+ qemu_log_mask(LOG_GUEST_ERROR,\n+ \"applesmc: unhandled data for cmd 0x%02x\\n\", s->cmd);\n s->status = APPLESMC_ST_CMD_DONE;\n s->status_1e = APPLESMC_ST_1E_STILL_BAD_CMD;\n }\n@@ -330,12 +492,13 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp)\n }\n \n QLIST_INIT(&s->data_def);\n+\n applesmc_add_key(s, \"REV \", 6, \"\\x01\\x13\\x0f\\x00\\x00\\x03\");\n applesmc_add_key(s, \"OSK0\", 32, s->osk);\n applesmc_add_key(s, \"OSK1\", 32, s->osk + 32);\n applesmc_add_key(s, \"NATJ\", 1, \"\\0\");\n applesmc_add_key(s, \"MSSP\", 1, \"\\0\");\n- applesmc_add_key(s, \"MSSD\", 1, \"\\0x3\");\n+ applesmc_add_key(s, \"MSSD\", 1, \"\\x03\");\n }\n \n static void applesmc_unrealize(DeviceState *dev)\n", "prefixes": [ "1/2" ] }