Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2231084/?format=api
{ "id": 2231084, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2231084/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260430104434.1482407-6-alex.bennee@linaro.org/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/1.1/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": "" }, "msgid": "<20260430104434.1482407-6-alex.bennee@linaro.org>", "date": "2026-04-30T10:44:32", "name": "[v4,5/7] target/arm: enable event stream on WFE instructions", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "6860362a05f49dd60ea83695b639679c089443f8", "submitter": { "id": 39532, "url": "http://patchwork.ozlabs.org/api/1.1/people/39532/?format=api", "name": "Alex Bennée", "email": "alex.bennee@linaro.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260430104434.1482407-6-alex.bennee@linaro.org/mbox/", "series": [ { "id": 502271, "url": "http://patchwork.ozlabs.org/api/1.1/series/502271/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=502271", "date": "2026-04-30T10:44:31", "name": "target/arm: fully model WFxT instructions for A-profile", "version": 4, "mbox": "http://patchwork.ozlabs.org/series/502271/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2231084/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2231084/checks/", "tags": {}, "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=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=NYTAp05L;\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 4g5rRj19zGz1yHZ\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 20:45:37 +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 1wIOt6-0008LF-Fy; Thu, 30 Apr 2026 06:44:56 -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 <alex.bennee@linaro.org>)\n id 1wIOsz-0008Gq-75\n for qemu-devel@nongnu.org; Thu, 30 Apr 2026 06:44:49 -0400", "from mail-wm1-x343.google.com ([2a00:1450:4864:20::343])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <alex.bennee@linaro.org>)\n id 1wIOsu-0005Kt-7U\n for qemu-devel@nongnu.org; Thu, 30 Apr 2026 06:44:48 -0400", "by mail-wm1-x343.google.com with SMTP id\n 5b1f17b1804b1-488a88aeec9so7582165e9.2\n for <qemu-devel@nongnu.org>; Thu, 30 Apr 2026 03:44:41 -0700 (PDT)", "from draig.lan ([185.124.0.195]) by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-48a7c2fb999sm57694655e9.6.2026.04.30.03.44.37\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Thu, 30 Apr 2026 03:44:38 -0700 (PDT)", "from draig.lan (localhost [IPv6:::1])\n by draig.lan (Postfix) with ESMTP id 494B35F941;\n Thu, 30 Apr 2026 11:44:35 +0100 (BST)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1777545880; x=1778150680; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=MsEsn1YZYtVVUa13L2AGk1G4k+OQISTqb0SX28KGc3A=;\n b=NYTAp05LPSdt9J8f0dKimOS0DBlBFpfgnUnzrS2JpXhzM0Xi/UzWQGHamfNTr5uCvB\n 85cuHxweWfrR0lWjsP1Xz//d6v8VS2dPeBXWqqSf/FzeqIyQWO2dpn45d4/eRmu9xVzd\n +aCRdAFil3fBy+Id7HxPE/QZs/RjrrTOKzradVEfdsMMh1TKKgBedqvvtd59kddnpiw0\n qOtpaE8X1Lh5ThnDa74b2yy6R1N33brRnIJ7jpNFxHgCHiFYXjANInDe2ThEu0g3WE71\n T9mdTL1ZnAt/1DVQ/vDlKwCVd6AmZupWQDx6eP0MCm7AzqQM+fGvul7zBD5SIF8ExQGz\n sXoQ==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777545880; x=1778150680;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=MsEsn1YZYtVVUa13L2AGk1G4k+OQISTqb0SX28KGc3A=;\n b=IExRrg91mxXyd7xoLv7ew5OsPlRs20U/lyLk7Vi+yfKacJBntDfY9Dx5nrMBq4gwPv\n JpFHUgVWkG/X5RsuViuQE6CCOXK0LVFqrdfM+8t5WMrms/rWMlecVoWytGf91l8Y/vAm\n tvVTcuyIXDPTMYG7UVXTs+qXTr+o91uy0o+IX5yEVGawt0rJNQC5bAeHIcqBJFW4VdVE\n TCAVpVEVXa0GDw4QbDd9c7uB+DcAKX1miiyF5sEUY1JlkDBx3iCuLYMkVKeN3XvuBikr\n BdIjgn0E4rcFVXWcZlgnVx4PgJR9oeOX35uiJsnwgIf++YxINQvS4IHWCUqQCKdp4l0n\n PO+g==", "X-Gm-Message-State": "AOJu0YxOZUZWoVUVVXpSvTd0lN3dsTafM3Qiiv3B59+m5bK+IqZL05Eo\n o/3Et2PZG7zQuOfhwc4ULt0eQAoEXMkyDsDWsuLvVetoeHBqOMxK+Yk9VjviqGzXoKc=", "X-Gm-Gg": "AeBDieu0eGpop4GryB2w0Ys3+xB0BpVlfSsH0u9ZKCN5VQzuvZMMbtDy8QwCTrrOD0g\n 5bXnOOXk7gnTY0UevHzRk1SVpVeieoN4BZ/N4mW1ASuRm/9SkcYP8sXOvd2B7cSni2+LeqWFHu2\n QrYi0CtbLgUA0zgo1cnqzS3bzpPwehdTsc1+4T+kq9b7cMuADA7oYg+mh3Y6cKCplGCdLoVpnE+\n e+ba5yoY05nLIuzJOfnQXDX55q2hlg4VNqSJ8ibXAm173Eahts2eqjk/FyokZ8MepBK5DWTp7H3\n HTGorXpDTVT56jJRzetje9sfF/IHGp72sExRXsh8JUUdFk/3+LxxfXDPITg6LZhCyNF8GsplxtR\n po2UawPu3x2Coy2TLi5PstrCC1kaX7K8NhLsdRKVsH72WoOW7OC8sZvgDe7NnjshVEIxBcu8rHX\n PXgLMC2oU9UAliHACVfEulZMWQ8OxuW521fA==", "X-Received": "by 2002:a05:600c:a00c:b0:48a:56d5:16f2 with SMTP id\n 5b1f17b1804b1-48a8415bbc1mr42026335e9.7.1777545880246;\n Thu, 30 Apr 2026 03:44:40 -0700 (PDT)", "From": "=?utf-8?q?Alex_Benn=C3=A9e?= <alex.bennee@linaro.org>", "To": "qemu-devel@nongnu.org", "Cc": "Mohamed Mediouni <mohamed@unpredictable.fr>, qemu-arm@nongnu.org,\n Pedro Barbuda <pbarbuda@microsoft.com>,\n Peter Maydell <peter.maydell@linaro.org>,\n Paolo Bonzini <pbonzini@redhat.com>, kvm@vger.kernel.org,\n Alexander Graf <agraf@csgraf.de>,\n =?utf-8?q?Alex_Benn=C3=A9e?= <alex.bennee@linaro.org>", "Subject": "[PATCH v4 5/7] target/arm: enable event stream on WFE instructions", "Date": "Thu, 30 Apr 2026 11:44:32 +0100", "Message-ID": "<20260430104434.1482407-6-alex.bennee@linaro.org>", "X-Mailer": "git-send-email 2.47.3", "In-Reply-To": "<20260430104434.1482407-1-alex.bennee@linaro.org>", "References": "<20260430104434.1482407-1-alex.bennee@linaro.org>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "Received-SPF": "pass client-ip=2a00:1450:4864:20::343;\n envelope-from=alex.bennee@linaro.org; helo=mail-wm1-x343.google.com", "X-Spam_score_int": "-20", "X-Spam_score": "-2.1", "X-Spam_bar": "--", "X-Spam_report": "(-2.1 / 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_NONE=-0.0001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=ham autolearn_force=no", "X-Spam_action": "no action", "X-BeenThere": "qemu-devel@nongnu.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "qemu 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": "Two generic timers (K and H) are capable of generating timer event\nstream events. Provide a helper to calculate when the nearest one will\nhappen.\n\nNow we can calculate when the next event stream event is we can re-use\nthe wfxt_timer and configure it to fire as we enter a WFE that is\ngoing to sleep. Reverse the M-profile logic so we can enter a sleep\nstate in both profiles.\n\nTo avoid issues with QEMU's incomplete ldst exclusive handling causing\npotential deadlocks in common WFE enabled locking patterns we take\nadvantage of the architectures flexibility and treat being in the\nexclusive region as a reason to exit.\n\nSigned-off-by: Alex Bennée <alex.bennee@linaro.org>\n\n---\nv2\n - merged target/arm: add gt_calc_next_event_stream\n - update to use halt_reason\n - made arm_wfxt_timer_cb atomically consume halt_reason\nv4\n - skip sleep if in the exclusive region\n - update commit message\n - remove the CF_PARALLEL guards so we work in smp\n---\n target/arm/cpu.c | 13 +++\n target/arm/tcg/op_helper.c | 143 ++++++++++++++++++++++++++++-----\n target/arm/tcg/translate-a64.c | 10 +--\n target/arm/tcg/translate.c | 16 +---\n 4 files changed, 140 insertions(+), 42 deletions(-)", "diff": "diff --git a/target/arm/cpu.c b/target/arm/cpu.c\nindex fb79981338c..a23b7e87495 100644\n--- a/target/arm/cpu.c\n+++ b/target/arm/cpu.c\n@@ -875,10 +875,23 @@ bool arm_cpu_exec_halt(CPUState *cs)\n }\n #endif\n \n+/*\n+ * Unlike almost everything else that messes with the halt_reason and\n+ * event_register details the timer callbacks are not in the vCPU\n+ * context.\n+ *\n+ * To prevent races we atomically consume a HALT_WFE and set the event\n+ * register. Either way we trigger the an exit event.\n+ */\n static void arm_wfxt_timer_cb(void *opaque)\n {\n ARMCPU *cpu = opaque;\n CPUState *cs = CPU(cpu);\n+ CPUARMState *env = &cpu->env;\n+\n+ if (qatomic_cmpxchg(&env->halt_reason, HALT_WFE, NOT_HALTED)) {\n+ qatomic_set(&env->event_register, true);\n+ }\n \n /*\n * We expect the CPU to be halted; this will cause arm_cpu_is_work()\ndiff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c\nindex 2b1fb1e059d..d0f45522b05 100644\n--- a/target/arm/tcg/op_helper.c\n+++ b/target/arm/tcg/op_helper.c\n@@ -483,6 +483,97 @@ void HELPER(sev)(CPUARMState *env)\n }\n }\n \n+#ifndef CONFIG_USER_ONLY\n+/*\n+ * Event Stream events don't do anything apart from wake up sleeping\n+ * cores. These helpers calculate the next event stream event time so\n+ * the WFE helper can decide when its next wake up tick will be.\n+ */\n+static int64_t gt_recalc_one_evt(CPUARMState *env, uint32_t control, uint64_t offset)\n+{\n+ ARMCPU *cpu = env_archcpu(env);\n+ bool evnten = FIELD_EX32(control, CNTxCTL, EVNTEN);\n+\n+ if (evnten) {\n+ int evnti = FIELD_EX32(control, CNTxCTL, EVNTI);\n+ bool evntis = FIELD_EX32(control, CNTxCTL, EVNTIS);\n+ bool evntdir = FIELD_EX32(control, CNTxCTL, EVNTDIR);\n+ /*\n+ * To figure out when the next event timer should fire we need\n+ * to calculate which bit of the counter we want to flip and\n+ * which transition counts.\n+ *\n+ * So we calculate 1 << bit - current lower bits and then add\n+ * 1 << bit if the bit needs to flip twice to meet evntdir\n+ */\n+ int bit = evntis ? evnti + 8 : evnti;\n+ uint64_t count = gt_get_countervalue(env) - offset;\n+ uint64_t target_bit = BIT_ULL(bit);\n+ uint64_t lower_bits = MAKE_64BIT_MASK(0, bit - 1);\n+ uint64_t next_tick = target_bit - (count & lower_bits);\n+ uint64_t abstick;\n+\n+ /* do we need to bit flip twice? */\n+ if (((count & target_bit) != 0) ^ evntdir) {\n+ next_tick += target_bit;\n+ }\n+\n+ /*\n+ * Note that the desired next expiry time might be beyond the\n+ * signed-64-bit range of a QEMUTimer -- in this case we just\n+ * set the timer for as far in the future as possible. When the\n+ * timer expires we will reset the timer for any remaining period.\n+ */\n+ if (uadd64_overflow(next_tick, offset, &abstick)) {\n+ abstick = UINT64_MAX;\n+ }\n+ if (abstick > INT64_MAX / gt_cntfrq_period_ns(cpu)) {\n+ return INT64_MAX;\n+ } else {\n+ return abstick;\n+ }\n+ }\n+\n+ return -1;\n+}\n+\n+/*\n+ * Calculate the next event stream time and return it. Returns -1 if\n+ * no event streams are enabled. It is up to the WFE helpers to decide\n+ * on the next time.\n+ */\n+static int64_t gt_calc_next_event_stream(CPUARMState *env)\n+{\n+ ARMCPU *cpu = env_archcpu(env);\n+ uint64_t hcr = arm_hcr_el2_eff(env);\n+ int64_t next_time = -1;\n+ uint64_t offset;\n+\n+ /* Unless we are missing EL2 this can generate events */\n+ if (arm_feature(env, ARM_FEATURE_EL2)) {\n+ offset = gt_direct_access_timer_offset(env, GTIMER_PHYS);\n+ next_time = gt_recalc_one_evt(env, env->cp15.cnthctl_el2, offset);\n+ }\n+\n+ /* Event stream events from virtual counter enabled? */\n+ if (!cpu_isar_feature(aa64_vh, cpu) ||\n+ !((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE))) {\n+ int64_t next_virt_time;\n+ offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);\n+ next_virt_time = gt_recalc_one_evt(env, env->cp15.c14_cntkctl, offset);\n+\n+ /* is this earlier than the next physical event? */\n+ if (next_virt_time > 0) {\n+ if (next_time < 0 || next_virt_time < next_time) {\n+ next_time = next_virt_time;\n+ }\n+ }\n+ }\n+\n+ return next_time;\n+}\n+#endif\n+\n void HELPER(wfe)(CPUARMState *env)\n {\n #ifdef CONFIG_USER_ONLY\n@@ -495,32 +586,44 @@ void HELPER(wfe)(CPUARMState *env)\n #else\n /*\n * WFE (Wait For Event) is a hint instruction.\n- * For Cortex-M (M-profile), we implement the strict architectural behavior:\n+ *\n * 1. Check the Event Register (set by SEV or SEVONPEND).\n * 2. If set, clear it and continue (consume the event).\n */\n- if (arm_feature(env, ARM_FEATURE_M)) {\n- CPUState *cs = env_cpu(env);\n+ CPUState *cs = env_cpu(env);\n+ ARMCPU *cpu = ARM_CPU(cs);\n \n- if (env->event_register) {\n- env->event_register = false;\n- return;\n- }\n+ if (env->event_register) {\n+ env->event_register = false;\n+ return;\n+ }\n \n- env->halt_reason = HALT_WFE;\n- cs->exception_index = EXCP_HLT;\n- cs->halted = 1;\n- cpu_loop_exit(cs);\n- } else {\n- /*\n- * For A-profile and others, we rely on the existing \"yield\" behavior.\n- * Don't actually halt the CPU, just yield back to top\n- * level loop. This is not going into a \"low power state\"\n- * (ie halting until some event occurs), so we never take\n- * a configurable trap to a different exception level\n- */\n- HELPER(yield)(env);\n+ /*\n+ * If the CPU has entered the exclusive region we could sleep\n+ * until the global monitor moves from Exclusive to Open Access.\n+ * However it would be expensive for QEMU to fully model the\n+ * global monitor and not doing so would potentially trigger\n+ * deadlocks in WFE enabled locking code. However as WFE is a hint\n+ * instruction the architecture allows for the PE to leave\n+ * low-power state for any reason. QEMU chooses to treat being in\n+ * an exclusive region as such and return directly.\n+ */\n+ if (env->exclusive_addr != -1) {\n+ return;\n+ }\n+\n+ /* For A-profile we also can be woken by the event stream */\n+ if (arm_feature(env, ARM_FEATURE_AARCH64) && cpu->wfxt_timer) {\n+ int64_t next_event = gt_calc_next_event_stream(env);\n+ if (next_event > 0) {\n+ timer_mod(cpu->wfxt_timer, next_event);\n+ }\n }\n+\n+ env->halt_reason = HALT_WFE;\n+ cs->exception_index = EXCP_HLT;\n+ cs->halted = 1;\n+ cpu_loop_exit(cs);\n #endif\n }\n \ndiff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c\nindex 07014717316..8b97136e78b 100644\n--- a/target/arm/tcg/translate-a64.c\n+++ b/target/arm/tcg/translate-a64.c\n@@ -2052,15 +2052,7 @@ static bool trans_SEVL(DisasContext *s, arg_SEV *a)\n \n static bool trans_WFE(DisasContext *s, arg_WFI *a)\n {\n- /*\n- * When running in MTTCG we don't generate jumps to the yield and\n- * WFE helpers as it won't affect the scheduling of other vCPUs.\n- * If we wanted to more completely model WFE/SEV so we don't busy\n- * spin unnecessarily we would need to do something more involved.\n- */\n- if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {\n- s->base.is_jmp = DISAS_WFE;\n- }\n+ s->base.is_jmp = DISAS_WFE;\n return true;\n }\n \ndiff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c\nindex 50d0184e84e..3ab49887ce6 100644\n--- a/target/arm/tcg/translate.c\n+++ b/target/arm/tcg/translate.c\n@@ -3262,19 +3262,9 @@ static bool trans_SEVL(DisasContext *s, arg_SEV *a)\n \n static bool trans_WFE(DisasContext *s, arg_WFE *a)\n {\n- /*\n- * When running single-threaded TCG code, use the helper to ensure that\n- * the next round-robin scheduled vCPU gets a crack.\n- *\n- * For Cortex-M, we implement the architectural WFE behavior (sleeping\n- * until an event occurs or the Event Register is set).\n- * For other profiles, we currently treat this as a NOP or yield,\n- * to preserve existing performance characteristics.\n- */\n- if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {\n- gen_update_pc(s, curr_insn_len(s));\n- s->base.is_jmp = DISAS_WFE;\n- }\n+ /* For WFE, halt the vCPU until an event. */\n+ gen_update_pc(s, curr_insn_len(s));\n+ s->base.is_jmp = DISAS_WFE;\n return true;\n }\n \n", "prefixes": [ "v4", "5/7" ] }