From: 54weasels <54weasels@gmail.com>
To: qemu-devel@nongnu.org
Cc: laurent@vivier.eu, 54weasels <54weasels@gmail.com>
Subject: [PATCH v4 6/6] target/m68k: Implement Physical Bus Error and Stack
Date: Mon, 17 Aug 2026 19:22:22 -0700 [thread overview]
Message-ID: <20260818022225.31801-7-54weasels@gmail.com> (raw)
In-Reply-To: <20260818022225.31801-1-54weasels@gmail.com>
High level description:
Physical memory timeouts (e.g., probing unpopulated memory locations) must generate a Bus Error exception, resulting in Format 0xA or 0xB stack frames on the 68020. The Sun-3 PROM probes memory sizes by intentionally causing bus errors and analyzing the Special Status Word (SSW) on the stack frame. This patch implements hardware-injected EXCP_ACCESS cycle generation and the corresponding 84-byte long stack frame teardown.
Impact on existing functionality:
Accurately populates the 68020 84-byte SSW stack frames. Older architectures (like 68000) safely ignore the hook and gracefully exit without generating the advanced frames.
Context: This patch was originally submitted as part of the monolithic Sun-3 Machine Emulation series (https://patchew.org/QEMU/20260503015756.99176-1-54weasels@gmail.com/) and has been split into atomic components.
---
target/m68k/helper.c | 1 +
target/m68k/op_helper.c | 161 +++++++++++++++++++++++++++-------------
2 files changed, 109 insertions(+), 53 deletions(-)
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 1eef6dcaaf..abfbcead69 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -29,6 +29,7 @@
#include "system/memory.h"
#include "gdbstub/helpers.h"
#include "fpu/softfloat.h"
+#include "qemu/log.h"
#include "qemu/qemu-print.h"
#define SIGNBIT (1u << 31)
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index 30af4a2631..1d4b244416 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -26,6 +26,7 @@
#include "qemu/plugin.h"
#if !defined(CONFIG_USER_ONLY)
+#include "system/runstate.h"
static void cf_rte(CPUM68KState *env)
{
@@ -74,6 +75,12 @@ throwaway:
case 7:
sp += 52;
break;
+ case 0xa: /* Short Bus Cycle Fault (Format 0xA) */
+ sp += 32 - 8; /* 32 bytes total - 8 bytes header = 24 bytes */
+ break;
+ case 0xb: /* Long Bus Cycle Fault (Format 0xB) */
+ sp += 92 - 8; /* 92 bytes total - 8 bytes header = 84 bytes */
+ break;
}
}
env->aregs[7] = sp;
@@ -343,56 +350,80 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
switch (cs->exception_index) {
case EXCP_ACCESS:
if (env->mmu.fault) {
- cpu_abort(cs, "DOUBLE MMU FAULT\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M68K: Double MMU Fault. Halting CPU and requesting reset.\n");
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ cs->halted = 1;
+ cs->exception_index = EXCP_HLT;
+ cpu_loop_exit(cs);
}
env->mmu.fault = true;
- /* push data 3 */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* push data 2 */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* push data 1 */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* write back 1 / push data 0 */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* write back 1 address */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* write back 2 data */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* write back 2 address */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* write back 3 data */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* write back 3 address */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
- /* fault address */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
- /* write back 1 status */
- sp -= 2;
- cpu_stw_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* write back 2 status */
- sp -= 2;
- cpu_stw_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* write back 3 status */
- sp -= 2;
- cpu_stw_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
- /* special status word */
- sp -= 2;
- cpu_stw_be_mmuidx_ra(env, sp, env->mmu.ssw, MMU_KERNEL_IDX, 0);
- /* effective address */
- sp -= 4;
- cpu_stl_be_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
-
- do_stack_frame(env, &sp, 7, oldsr, 0, env->pc);
+
+ if (m68k_feature(env, M68K_FEATURE_M68040)) {
+ /* push data 3 */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* push data 2 */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* push data 1 */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* write back 1 / push data 0 */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* write back 1 address */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* write back 2 data */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* write back 2 address */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* write back 3 data */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* write back 3 address */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
+ /* fault address */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
+ /* write back 1 status */
+ sp -= 2;
+ cpu_stw_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* write back 2 status */
+ sp -= 2;
+ cpu_stw_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* write back 3 status */
+ sp -= 2;
+ cpu_stw_be_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
+ /* special status word */
+ sp -= 2;
+ cpu_stw_be_mmuidx_ra(env, sp, env->mmu.ssw, MMU_KERNEL_IDX, 0);
+ /* effective address */
+ sp -= 4;
+ cpu_stl_be_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
+
+ do_stack_frame(env, &sp, 7, oldsr, 0, env->pc);
+ } else {
+ /* M68020 Long Bus Cycle Fault (Format 0xB) */
+ /*
+ * 84 bytes of internal state are pushed before the generic
+ * 8-byte header
+ */
+ sp -= 84;
+ for (int i = 0; i < 84; i += 4) {
+ cpu_stl_be_mmuidx_ra(env, sp + i, 0, MMU_KERNEL_IDX, 0);
+ }
+ /* Offset 0x02 from internal frame: SSW */
+ cpu_stw_be_mmuidx_ra(env, sp + 2, env->mmu.ssw, MMU_KERNEL_IDX, 0);
+ /* Offset 0x08 from internal frame: Fault Address */
+ cpu_stl_be_mmuidx_ra(env, sp + 8, env->mmu.ar, MMU_KERNEL_IDX, 0);
+
+ do_stack_frame(env, &sp, 0xb, oldsr, 0, env->pc);
+ }
env->mmu.fault = false;
if (qemu_loglevel_mask(CPU_LOG_INT)) {
qemu_log(" "
@@ -438,7 +469,9 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
env->aregs[7] = sp;
/* Jump to vector. */
+ env->mmu.fault = true;
env->pc = cpu_ldl_be_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0);
+ env->mmu.fault = false;
do_plugin_vcpu_interrupt_cb(cs, last_pc);
}
@@ -510,12 +543,34 @@ void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
if (access_type != MMU_DATA_STORE) {
env->mmu.ssw |= M68K_RW_040;
}
-
- env->mmu.ar = addr;
-
- cs->exception_index = EXCP_ACCESS;
- cpu_loop_exit(cs);
+ } else if (m68k_feature(env, M68K_FEATURE_M68020)) {
+ /*
+ * M68020 Long Bus Cycle Fault (Format 0xB).
+ * The Motorola 68020 hardware intrinsically generates a physical
+ * Bus Error exception whenever the system bus flags a transaction
+ * timeout or failure (e.g., attempting to read an unpopulated bus
+ * address). This natively injects the EXCP_ACCESS cycle to build
+ * the generic 84-byte exception stack frame.
+ */
+ env->mmu.ssw = 0;
+ if (access_type == MMU_INST_FETCH) {
+ env->mmu.ssw |= 0x1000;
+ } else if (access_type == MMU_DATA_STORE) {
+ env->mmu.ssw |= 0x0040;
+ } else {
+ env->mmu.ssw |= 0x0080;
+ }
+ } else {
+ /*
+ * Older architectures (e.g. 68000) do not currently support
+ * hardware-injected transaction failures in QEMU.
+ */
+ return;
}
+
+ env->mmu.ar = addr;
+ cs->exception_index = EXCP_ACCESS;
+ cpu_loop_exit(cs);
}
bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
--
2.50.1 (Apple Git-155)
prev parent reply other threads:[~2026-08-18 2:24 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-18 2:22 [PATCH v4 0/6] Implement missing functionality and hooks in mk68k to support upcoming sun3 impl 54weasels
2026-08-18 2:22 ` [PATCH v4 1/6] target/m68k: Add dummy CAAR register 54weasels
2026-08-18 2:22 ` [PATCH v4 2/6] target/m68k: Fix fsave/frestore for 68881 FPU 54weasels
2026-08-18 10:52 ` BALATON Zoltan
2026-08-20 4:37 ` Purr Box
2026-08-20 9:55 ` BALATON Zoltan
2026-08-18 2:22 ` [PATCH v4 3/6] target/m68k: Fix NMI pending for Level 7 interrupts 54weasels
2026-08-18 10:56 ` BALATON Zoltan
2026-08-20 7:37 ` Purr Box
2026-08-18 2:22 ` [PATCH v4 4/6] target/m68k: Extract Function Codes during TLB fills 54weasels
2026-08-18 2:22 ` [PATCH v4 5/6] target/m68k: Implement custom MMU intercept hook 54weasels
2026-08-18 2:22 ` 54weasels [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260818022225.31801-7-54weasels@gmail.com \
--to=54weasels@gmail.com \
--cc=laurent@vivier.eu \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.