* [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation
@ 2026-09-03 4:45 54weasels
2026-09-03 4:45 ` [PATCH v5 1/6] target/m68k: Add dummy CAAR register 54weasels
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: 54weasels @ 2026-09-03 4:45 UTC (permalink / raw)
To: qemu-devel; +Cc: laurent, balaton, 54weasels
This series adds M68020/030-specific features to the m68k target that
are required by the Sun-3 machine (series C) and its PROM/SunOS guests:
1/6: CAAR register stub for 68020/030 cache control
2/6: fsave/frestore fix for 68881 (non-68040) FPU frames
3/6: Edge-triggered NMI semantics for Level 7 interrupts
4/6: Function code extraction during TLB fills
5/6: Custom MMU intercept hook for Sun-3 transparent translation
6/6: Physical Bus Error and M68020 Format 0xB stack frames
Changes since v4:
- Added Signed-off-by to all patches.
- Patch 2/6 (fsave): Addressed Zoltan's review — replaced redundant
M68040||FPU check with just M68K_FEATURE_FPU, removed unnecessary
if/else in frestore, moved Context: below --- separator.
- Patch 3/6 (NMI): Addressed Zoltan's review — nmi_pending cannot be
replaced by testing pending_level == 7. The flag captures the edge
transition (level < 7 → 7) required by Motorola's NMI specification,
while pending_level only reflects the current interrupt level.
Testing pending_level alone would produce level-triggered behavior,
firing on every interrupt check rather than once per edge.
- Rebased on current master.
54weasels (6):
target/m68k: Add dummy CAAR register
target/m68k: Fix fsave/frestore for 68881 FPU
target/m68k: Fix NMI pending for Level 7 interrupts
target/m68k: Extract Function Codes during TLB fills
target/m68k: Implement custom MMU intercept hook
target/m68k: Implement Physical Bus Error and Stack
target/m68k/cpu.c | 4 +-
target/m68k/cpu.h | 21 ++++-
target/m68k/helper.c | 130 ++++++++++++++++++++++++++++-
target/m68k/op_helper.c | 175 ++++++++++++++++++++++++++--------------
target/m68k/translate.c | 30 ++++---
5 files changed, 280 insertions(+), 80 deletions(-)
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v5 1/6] target/m68k: Add dummy CAAR register 2026-09-03 4:45 [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 54weasels @ 2026-09-03 4:45 ` 54weasels 2026-09-03 4:45 ` [PATCH v5 2/6] target/m68k: Fix fsave/frestore for 68881 FPU 54weasels ` (5 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: 54weasels @ 2026-09-03 4:45 UTC (permalink / raw) To: qemu-devel; +Cc: laurent, balaton, 54weasels Why this change is made & How it will be used: The Sun-3 ROM expects the Cache Control Register (CAAR) to exist on the 68020. Reading/writing this register currently aborts QEMU. This patch provides a dummy implementation that simply ignores writes and returns 0 on reads, allowing the ROM to continue booting. Impact on existing functionality: No impact on existing targets. ColdFire and Mac targets do not access CAAR in a way that currently aborts, and providing a safe dummy implementation ensures robustness across M68k boards. Signed-off-by: 54weasels <54weasels@gmail.com> --- target/m68k/helper.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 5f91d206f5..68f523ea84 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -281,8 +281,10 @@ void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) return; } break; - /* Unimplemented Registers */ + /* Dummy implementation for CAAR */ case M68K_CR_CAAR: + return; + /* Unimplemented Registers */ case M68K_CR_PCR: case M68K_CR_BUSCR: cpu_abort(env_cpu(env), @@ -385,8 +387,10 @@ uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) return env->mmu.ttr[M68K_DTTR1]; } break; - /* Unimplemented Registers */ + /* Dummy implementation for CAAR */ case M68K_CR_CAAR: + return 0; + /* Unimplemented Registers */ case M68K_CR_PCR: case M68K_CR_BUSCR: cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n", -- 2.50.1 (Apple Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 2/6] target/m68k: Fix fsave/frestore for 68881 FPU 2026-09-03 4:45 [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 54weasels 2026-09-03 4:45 ` [PATCH v5 1/6] target/m68k: Add dummy CAAR register 54weasels @ 2026-09-03 4:45 ` 54weasels 2026-09-03 4:45 ` [PATCH v5 3/6] target/m68k: Fix NMI pending for Level 7 interrupts 54weasels ` (4 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: 54weasels @ 2026-09-03 4:45 UTC (permalink / raw) To: qemu-devel; +Cc: laurent, balaton, 54weasels Why this change is made & How it will be used: The 68881/68882 FPUs require fsave/frestore instructions to read/write state frames. QEMU only fully implemented this for the 68040. The Sun-3 uses a 68881 FPU, and the boot ROM executes `fsave` to probe FPU presence. This patch adds basic 68881 FPU state frame handling (NULL frame) to accurately simulate an idle FPU state. Impact on existing functionality: Fixes FPU detection for 68881/68882 across all M68k boards without affecting 68040 specific state logic. Signed-off-by: 54weasels <54weasels@gmail.com> --- target/m68k/translate.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 138c89d3e5..c89ef213ed 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -5364,11 +5364,11 @@ DISAS_INSN(frestore) gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE); return; } - if (m68k_feature(s->env, M68K_FEATURE_M68040)) { + if (m68k_feature(s->env, M68K_FEATURE_FPU)) { SRC_EA(env, addr, OS_LONG, 0, NULL); /* FIXME: check the state frame */ } else { - disas_undef(env, s, insn); + disas_undef_fpu(env, s, insn); } } @@ -5379,12 +5379,18 @@ DISAS_INSN(fsave) return; } - if (m68k_feature(s->env, M68K_FEATURE_M68040)) { - /* always write IDLE */ - TCGv idle = tcg_constant_i32(0x41000000); - DEST_EA(env, insn, OS_LONG, idle, NULL); + if (m68k_feature(s->env, M68K_FEATURE_FPU)) { + TCGv frame; + if (m68k_feature(s->env, M68K_FEATURE_M68040)) { + /* 68040 FSAVE: always write IDLE */ + frame = tcg_constant_i32(0x41000000); + } else { + /* 68881/68882 FSAVE: always write NULL frame */ + frame = tcg_constant_i32(0x00000000); + } + DEST_EA(env, insn, OS_LONG, frame, NULL); } else { - disas_undef(env, s, insn); + disas_undef_fpu(env, s, insn); } } #endif -- 2.50.1 (Apple Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 3/6] target/m68k: Fix NMI pending for Level 7 interrupts 2026-09-03 4:45 [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 54weasels 2026-09-03 4:45 ` [PATCH v5 1/6] target/m68k: Add dummy CAAR register 54weasels 2026-09-03 4:45 ` [PATCH v5 2/6] target/m68k: Fix fsave/frestore for 68881 FPU 54weasels @ 2026-09-03 4:45 ` 54weasels 2026-09-03 4:45 ` [PATCH v5 4/6] target/m68k: Extract Function Codes during TLB fills 54weasels ` (3 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: 54weasels @ 2026-09-03 4:45 UTC (permalink / raw) To: qemu-devel; +Cc: laurent, balaton, 54weasels Why this change is made & How it will be used: Level 7 interrupts are Non-Maskable Interrupts (NMI) on the M68k architecture. The hardware asserts an NMI only on the rising edge of the level 7 signal. The current QEMU implementation treats level 7 like a standard level interrupt. This patch ensures proper NMI edge-triggered semantics for level 7, which is strictly required by the Sun-3 keyboard/mouse NMI routing logic. Impact on existing functionality: Corrects NMI edge-triggering for all M68k boards, adhering closely to the Motorola specifications. Existing boards will now correctly require an edge transition to trigger consecutive NMIs. Signed-off-by: 54weasels <54weasels@gmail.com> --- target/m68k/cpu.h | 4 ++++ target/m68k/helper.c | 6 ++++++ target/m68k/op_helper.c | 14 ++++++-------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 7cf3791108..8f4dec4a40 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -25,6 +25,9 @@ #include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" #include "cpu-qom.h" +#include "exec/cpu-defs.h" + +#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_1 #define OS_BYTE 0 #define OS_WORD 1 @@ -148,6 +151,7 @@ typedef struct CPUArchState { int pending_vector; int pending_level; + bool nmi_pending; /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 68f523ea84..93739ccda7 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -949,6 +949,12 @@ void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) CPUState *cs = CPU(cpu); CPUM68KState *env = &cpu->env; + if (level == 7 && env->pending_level != 7) { + env->nmi_pending = true; + } else if (level != 7) { + env->nmi_pending = false; + } + env->pending_level = level; env->pending_vector = vector; if (level) { diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 38f7a68981..30af4a2631 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -522,14 +522,12 @@ bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { CPUM68KState *env = cpu_env(cs); - if (interrupt_request & CPU_INTERRUPT_HARD - && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) { - /* - * Real hardware gets the interrupt vector via an IACK cycle - * at this point. Current emulated hardware doesn't rely on - * this, so we provide/save the vector when the interrupt is - * first signalled. - */ + if (env->nmi_pending) { + env->nmi_pending = false; + cs->exception_index = env->pending_vector; + do_interrupt_m68k_hardirq(env); + return true; + } else if (((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) { cs->exception_index = env->pending_vector; do_interrupt_m68k_hardirq(env); return true; -- 2.50.1 (Apple Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 4/6] target/m68k: Extract Function Codes during TLB fills 2026-09-03 4:45 [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 54weasels ` (2 preceding siblings ...) 2026-09-03 4:45 ` [PATCH v5 3/6] target/m68k: Fix NMI pending for Level 7 interrupts 54weasels @ 2026-09-03 4:45 ` 54weasels 2026-09-03 4:45 ` [PATCH v5 5/6] target/m68k: Implement custom MMU intercept hook 54weasels ` (2 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: 54weasels @ 2026-09-03 4:45 UTC (permalink / raw) To: qemu-devel; +Cc: laurent, balaton, 54weasels Why this change is made & How it will be used: The Motorola 68020 architecture utilizes 3-bit Function Codes (FC0-FC2) to distinguish between User/Supervisor Data and Program memory spaces during MMU translation. Previously, QEMU's TLB fills did not explicitly extract or pass these codes down to the translation hooks. This patch extracts the explicit Function Codes (either natively or via the `moves` instruction) and packs them into the `access_type` field. This is required for the upcoming Sun-3 emulation, whose external MMU hardware maps entirely different physical address spaces depending on the Function Code asserted on the bus. Impact on existing functionality: This change introduces no functional impact to existing ColdFire or Mac/Quadra m68k emulation targets. The extraction logic gracefully defaults to standard mapping modes for platforms that do not implement a custom MMU intercept hook, preserving existing TLB behavior. Signed-off-by: 54weasels <54weasels@gmail.com> --- target/m68k/cpu.c | 4 ++-- target/m68k/cpu.h | 10 ++++++---- target/m68k/helper.c | 26 ++++++++++++++++++++++++++ target/m68k/translate.c | 10 ++++++---- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 6012dc3186..5d90bb075e 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -52,8 +52,8 @@ static TCGTBCPUState m68k_get_tb_cpu_state(CPUState *cs) flags = (env->macsr >> 4) & TB_FLAGS_MACSR; if (env->sr & SR_S) { flags |= TB_FLAGS_MSR_S; - flags |= (env->sfc << (TB_FLAGS_SFC_S_BIT - 2)) & TB_FLAGS_SFC_S; - flags |= (env->dfc << (TB_FLAGS_DFC_S_BIT - 2)) & TB_FLAGS_DFC_S; + flags |= (env->sfc << TB_FLAGS_SFC_S_BIT) & TB_FLAGS_SFC_S; + flags |= (env->dfc << TB_FLAGS_DFC_S_BIT) & TB_FLAGS_DFC_S; } if (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS) { flags |= TB_FLAGS_TRACE; diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 8f4dec4a40..aadaea770a 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -604,12 +604,14 @@ void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, #define TB_FLAGS_MSR_S_BIT 13 #define TB_FLAGS_MSR_S (1 << TB_FLAGS_MSR_S_BIT) #define TB_FLAGS_SFC_S_BIT 14 -#define TB_FLAGS_SFC_S (1 << TB_FLAGS_SFC_S_BIT) -#define TB_FLAGS_DFC_S_BIT 15 -#define TB_FLAGS_DFC_S (1 << TB_FLAGS_DFC_S_BIT) -#define TB_FLAGS_TRACE 16 +#define TB_FLAGS_SFC_S (7 << TB_FLAGS_SFC_S_BIT) /* 3 Bits reserved */ +#define TB_FLAGS_DFC_S_BIT 17 +#define TB_FLAGS_DFC_S (7 << TB_FLAGS_DFC_S_BIT) /* 3 Bits reserved */ +#define TB_FLAGS_TRACE 20 #define TB_FLAGS_TRACE_BIT (1 << TB_FLAGS_TRACE) +#define MMU_MOVES_FC_BASE 2 /* mmu_idx 2-9 correspond to FC 0-7 */ + void dump_mmu(CPUM68KState *env); #endif diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 93739ccda7..f3ee95441a 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -975,6 +975,32 @@ bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size, int ret; target_ulong page_size; + if (qemu_access_type == MMU_INST_FETCH) { + access_type = ACCESS_CODE; + } else { + access_type = ACCESS_DATA; + if (qemu_access_type == MMU_DATA_STORE) { + access_type |= ACCESS_STORE; + } + } + + /* Decode explicit Function Codes from moves instructions */ + if (mmu_idx >= MMU_MOVES_FC_BASE) { + uint8_t fc = mmu_idx - MMU_MOVES_FC_BASE; + access_type |= (fc << 8); /* Pack explicit FC into access type */ + if (fc != 1 && fc != 2) { + access_type |= ACCESS_SUPER; + } + } else { + /* Standard memory accesses map logically to normal M68K FCs */ + if (mmu_idx == MMU_KERNEL_IDX) { + access_type |= ACCESS_SUPER; + access_type |= ((qemu_access_type == MMU_INST_FETCH ? 6 : 5) << 8); + } else { + access_type |= ((qemu_access_type == MMU_INST_FETCH ? 2 : 1) << 8); + } + } + if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { /* MMU disabled */ tlb_set_page(cs, address & TARGET_PAGE_MASK, diff --git a/target/m68k/translate.c b/target/m68k/translate.c index c89ef213ed..5ca25a4881 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -163,10 +163,12 @@ static void do_writebacks(DisasContext *s) #define IS_USER(s) 1 #else #define IS_USER(s) (!(s->base.tb->flags & TB_FLAGS_MSR_S)) -#define SFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_SFC_S) ? \ - MMU_KERNEL_IDX : MMU_USER_IDX) -#define DFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_DFC_S) ? \ - MMU_KERNEL_IDX : MMU_USER_IDX) +#define SFC_INDEX(s) (MMU_MOVES_FC_BASE + \ + (((s)->base.tb->flags & TB_FLAGS_SFC_S) >> \ + TB_FLAGS_SFC_S_BIT)) +#define DFC_INDEX(s) (MMU_MOVES_FC_BASE + \ + (((s)->base.tb->flags & TB_FLAGS_DFC_S) >> \ + TB_FLAGS_DFC_S_BIT)) #endif typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn); -- 2.50.1 (Apple Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 5/6] target/m68k: Implement custom MMU intercept hook 2026-09-03 4:45 [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 54weasels ` (3 preceding siblings ...) 2026-09-03 4:45 ` [PATCH v5 4/6] target/m68k: Extract Function Codes during TLB fills 54weasels @ 2026-09-03 4:45 ` 54weasels 2026-09-03 4:45 ` [PATCH v5 6/6] target/m68k: Implement Physical Bus Error and Stack 54weasels 2026-09-09 18:54 ` [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation Purr Box 6 siblings, 0 replies; 8+ messages in thread From: 54weasels @ 2026-09-03 4:45 UTC (permalink / raw) To: qemu-devel; +Cc: laurent, balaton, 54weasels Why this change is made & How it will be used: Boards like the Sun-3 use an external custom MMU logic array rather than the standard 68851/68030 embedded MMU. This patch introduces a `custom_mmu_get_physical_address` opaque hook, allowing board initialization code to intercept TLB fills and delegate translation directly to the machine's external MMU implementation. Impact on existing functionality: Zero impact on existing boards. If the hook is not explicitly registered by the board initialization code, the standard 68k MMU translation pipeline executes normally. Signed-off-by: 54weasels <54weasels@gmail.com> --- target/m68k/cpu.h | 7 ++++ target/m68k/helper.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index aadaea770a..b850997a00 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -156,6 +156,13 @@ typedef struct CPUArchState { /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; + /* Custom MMU intercept logic, if any (e.g. for Sun-3) */ + void *custom_mmu_opaque; + int (*custom_mmu_get_physical_address)(void *env, hwaddr *physical, + int *prot, vaddr address, + int access_type, + hwaddr *page_size); + /* Fields from here on are preserved across CPU reset. */ uint64_t features; } CPUM68KState; diff --git a/target/m68k/helper.c b/target/m68k/helper.c index f3ee95441a..1eef6dcaaf 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -920,6 +920,21 @@ hwaddr m68k_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr) int access_type; target_ulong page_size; + access_type = ACCESS_DATA | ACCESS_DEBUG; + if (env->sr & SR_S) { + access_type |= ACCESS_SUPER; + } + + if (env->custom_mmu_get_physical_address) { + hwaddr custom_page_size; + if (env->custom_mmu_get_physical_address(env, &phys_addr, &prot, addr, + access_type, + &custom_page_size) == 0) { + return phys_addr; + } + return -1; + } + if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { /* MMU disabled */ return addr; @@ -1001,6 +1016,80 @@ bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } } + if (env->custom_mmu_get_physical_address) { + hwaddr custom_page_size; + + /* Delegate translation to external board-specific MMU if registered */ + ret = env->custom_mmu_get_physical_address(env, &physical, &prot, + address, access_type, + &custom_page_size); + + if (likely(ret == 0)) { + tlb_set_page(cs, address & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot, + mmu_idx, custom_page_size); + return true; + } + + if (probe) { + return false; + } + + /* page fault */ + cs->exception_index = EXCP_ACCESS; + env->mmu.ar = address; + + if (m68k_feature(env, M68K_FEATURE_M68040)) { + env->mmu.ssw = M68K_ATC_040; + switch (size) { + case 1: + env->mmu.ssw |= M68K_BA_SIZE_BYTE; + break; + case 2: + env->mmu.ssw |= M68K_BA_SIZE_WORD; + break; + case 4: + env->mmu.ssw |= M68K_BA_SIZE_LONG; + break; + } + env->mmu.ssw |= M68K_TM_040_DATA; + } else { + /* M68020/030 Special Status Word (SSW) */ + uint16_t ssw = 0x0100; /* DF - Data Fault */ + switch (size) { + case 1: + ssw |= 0x0010; + break; + case 2: + ssw |= 0x0020; + break; + case 3: + ssw |= 0x0030; + break; + case 4: + ssw |= 0x0000; + break; + } + if (qemu_access_type != MMU_DATA_STORE) { + ssw |= 0x0040; /* RW - Read */ + } + /* Function Code */ + uint8_t fc; + if (mmu_idx >= MMU_MOVES_FC_BASE) { + fc = mmu_idx - MMU_MOVES_FC_BASE; + } else { + if (mmu_idx == MMU_KERNEL_IDX) { + fc = (qemu_access_type == MMU_INST_FETCH) ? 6 : 5; + } else { + fc = (qemu_access_type == MMU_INST_FETCH) ? 2 : 1; + } + } + ssw |= (fc & 7); + env->mmu.ssw = ssw; + } + cpu_loop_exit_restore(cs, retaddr); + } + if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { /* MMU disabled */ tlb_set_page(cs, address & TARGET_PAGE_MASK, -- 2.50.1 (Apple Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 6/6] target/m68k: Implement Physical Bus Error and Stack 2026-09-03 4:45 [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 54weasels ` (4 preceding siblings ...) 2026-09-03 4:45 ` [PATCH v5 5/6] target/m68k: Implement custom MMU intercept hook 54weasels @ 2026-09-03 4:45 ` 54weasels 2026-09-09 18:54 ` [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation Purr Box 6 siblings, 0 replies; 8+ messages in thread From: 54weasels @ 2026-09-03 4:45 UTC (permalink / raw) To: qemu-devel; +Cc: laurent, balaton, 54weasels Why this change is made & How it will be used: 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. Signed-off-by: 54weasels <54weasels@gmail.com> --- 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) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 2026-09-03 4:45 [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 54weasels ` (5 preceding siblings ...) 2026-09-03 4:45 ` [PATCH v5 6/6] target/m68k: Implement Physical Bus Error and Stack 54weasels @ 2026-09-09 18:54 ` Purr Box 6 siblings, 0 replies; 8+ messages in thread From: Purr Box @ 2026-09-09 18:54 UTC (permalink / raw) To: qemu-devel; +Cc: laurent, BALATON Zoltan [-- Attachment #1: Type: text/plain, Size: 2255 bytes --] Gentle ping on this series. v5 addresses Zoltan's review feedback from v4 (fsave simplification, NMI edge-trigger rationale, added Signed-off-by). Would appreciate any review when you have a chance. Dan. On Wed, Sep 2, 2026 at 9:46 PM 54weasels <54weasels@gmail.com> wrote: > This series adds M68020/030-specific features to the m68k target that > are required by the Sun-3 machine (series C) and its PROM/SunOS guests: > > 1/6: CAAR register stub for 68020/030 cache control > 2/6: fsave/frestore fix for 68881 (non-68040) FPU frames > 3/6: Edge-triggered NMI semantics for Level 7 interrupts > 4/6: Function code extraction during TLB fills > 5/6: Custom MMU intercept hook for Sun-3 transparent translation > 6/6: Physical Bus Error and M68020 Format 0xB stack frames > > Changes since v4: > - Added Signed-off-by to all patches. > - Patch 2/6 (fsave): Addressed Zoltan's review — replaced redundant > M68040||FPU check with just M68K_FEATURE_FPU, removed unnecessary > if/else in frestore, moved Context: below --- separator. > - Patch 3/6 (NMI): Addressed Zoltan's review — nmi_pending cannot be > replaced by testing pending_level == 7. The flag captures the edge > transition (level < 7 → 7) required by Motorola's NMI specification, > while pending_level only reflects the current interrupt level. > Testing pending_level alone would produce level-triggered behavior, > firing on every interrupt check rather than once per edge. > - Rebased on current master. > > 54weasels (6): > target/m68k: Add dummy CAAR register > target/m68k: Fix fsave/frestore for 68881 FPU > target/m68k: Fix NMI pending for Level 7 interrupts > target/m68k: Extract Function Codes during TLB fills > target/m68k: Implement custom MMU intercept hook > target/m68k: Implement Physical Bus Error and Stack > > target/m68k/cpu.c | 4 +- > target/m68k/cpu.h | 21 ++++- > target/m68k/helper.c | 130 ++++++++++++++++++++++++++++- > target/m68k/op_helper.c | 175 ++++++++++++++++++++++++++-------------- > target/m68k/translate.c | 30 ++++--- > 5 files changed, 280 insertions(+), 80 deletions(-) > > -- > 2.50.1 (Apple Git-155) > > [-- Attachment #2: Type: text/html, Size: 2760 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-09 18:54 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-03 4:45 [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation 54weasels 2026-09-03 4:45 ` [PATCH v5 1/6] target/m68k: Add dummy CAAR register 54weasels 2026-09-03 4:45 ` [PATCH v5 2/6] target/m68k: Fix fsave/frestore for 68881 FPU 54weasels 2026-09-03 4:45 ` [PATCH v5 3/6] target/m68k: Fix NMI pending for Level 7 interrupts 54weasels 2026-09-03 4:45 ` [PATCH v5 4/6] target/m68k: Extract Function Codes during TLB fills 54weasels 2026-09-03 4:45 ` [PATCH v5 5/6] target/m68k: Implement custom MMU intercept hook 54weasels 2026-09-03 4:45 ` [PATCH v5 6/6] target/m68k: Implement Physical Bus Error and Stack 54weasels 2026-09-09 18:54 ` [PATCH v5 0/6] Implement missing functionality and hooks in m68k to support upcoming Sun-3 implementation Purr Box
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.