Skip to content

Pr2349 rebased - #2375

Open
wtdcode wants to merge 22 commits into
devfrom
pr2349-rebased
Open

Pr2349 rebased#2375
wtdcode wants to merge 22 commits into
devfrom
pr2349-rebased

Conversation

@wtdcode

@wtdcode wtdcode commented Jul 28, 2026

Copy link
Copy Markdown
Member

#2349 Upgrade our QEMU fork to 7.1.22.

We will finally chase up to the upstream QEMU.

Nitr0-G and others added 21 commits July 28, 2026 09:04
Update the embedded QEMU-derived runtime and target code to the 7.2.22 baseline while preserving Unicorn's reduced integration model.

This brings in the QEMU 7.2 support code needed by the fork: softfloat/int128 and helper compatibility, TCG and translator glue, updated symbol-postfix headers, target feature masks, and generated binding constants.

CPU-visible coverage was expanded across the supported targets: AArch64 SVE/SME/MTE/PMU and M-profile MVE, RISC-V RVV/RVH/bitmanip/crypto/Zfh/Sstc/PMP paths, s390x MIE/VE/Vector-FP/string/crypto paths, PPC POWER10 groups, MIPS public modes and MSA registers, M68K FPU/MSP/ColdFire behavior, SPARC register access, and x86 AVX/AVX2/FMA/BMI/VAES/VPCLMUL validation.

The unit test suite was extended with focused regressions for the migrated behavior, and the local MSVC test tree has been validated with full parallel CTest.
Keep the aarch64 backend call emitter on the reduced tree's tcg_out_call pointer ABI so ubuntu-aarch64 builds compile again.

Use concise CTest failure output in Build UC2 so parallel CI logs expose the failing test case instead of losing it inside verbose interleaved output.
Align host TCG direct jump patching with the QEMU 7.2 tc_ptr/jmp_rx/jmp_rw ABI, add missing non-goto_ptr host backend definitions, and fix PPC host TCG opcode/table drift.

Move variable target page size state out of release-mode macros that depended on a local uc variable, using arch-postfixed target_page_bits_state instead.

Fix POSIX MIPS CPU alignment and preserve microMIPS entry state, and avoid Apple JIT state asserts when virtualized macOS runners cannot report SPRR permissions.
Keep variable target page size state per Unicorn engine instead of arch-global state, while preserving the improved finalization path.

Add a public control regression that runs two ARM engines with different page sizes in the same process.
Synchronize generated code writes with instruction fetches when patching TCG direct jumps and finalizing generated code. This keeps the reduced JIT path aligned with QEMU 7.2 host cache semantics on non-coherent host caches.
Align the reduced TCG generated-code pointers with the QEMU 7.2 RX/RW address model so host backends compute branch offsets, labels, prologue addresses, and jump patches against executable addresses while still writing through writable addresses.

Use runtime MIPS guest endianness for unaligned store helpers and declare the PPC host cache flush helper used by reduced per-target builds.
Keep split-WX conversion inline in the reduced single-mapping TCG runtime so per-arch archives do not define duplicate data symbols during GNU ld links.
Pin the Zig macOS workflow to macos-14 so Zig 0.14 does not run on an unsupported macOS 26 image.
Use pthread JIT write-protection transitions directly and avoid private SPRR state probes on Apple Silicon hosts.
Use helper typemasks when extending TCG call arguments so pointer operands are not treated as 32-bit values on aarch64 hosts. Restore s390x instruction-start metadata emission for early Unicorn exit TBs.
Avoid freeing BF16 VCVT temporaries after neon_store_reg consumes them.
Restore QEMU 7.2 ppc modulo lowering and long goto_tb reset handling.

Revalidate TLB entries after Unicorn memory callbacks that can flush or resize TLB state.
QEMU relies on signed arithmetic wrapping in a number of helpers. For
example the MVE DO_ABD macro computes (M) - (N) on extremal int32_t
operands, which overflows and is undefined behaviour.

clang exploits that UB and returns the negated result, which made
test_arm_m55_mve_vabd fail on the macOS runners while gcc happened to
emit the wrapping subtraction and passed. Upstream QEMU's configure
passes -fwrapv for the same reason, so do the same here.
@unknown-1-0

unknown-1-0 commented Jul 28, 2026

Copy link
Copy Markdown

Hi, @wtdcode and @Nitr0-G, thank you for the great work on this update.

I noticed that this PR fixes the same issue as #2370 (ran the tests from that PR, they pass). Should that PR be closed? And should the tests in it be added as a separate PR?

However, I also noticed that CONFIG_USER_ONLY defines are now used in the qemu/target/i386/ (specifically, in helper-tcg.h, fpu_helper.c and translate.c). Was it intentional to keep them (like in qemu/target/s390x and qemu/include/hw/ppc/ppc.h)? Or are they simply leftovers from QEMU that should be removed?

@wtdcode

wtdcode commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

Hi @unknown-1-0

Thanks for your interest and for discovering our "secret" works =). This branch is currently not ready for merging and is just for testing and interactive review. But I do expect this to be included in 2.2.0, the next release.

@@ -0,0 +1,62 @@
/*

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No symlinks.

RAMBlock *block;
ram_addr_t offset;

host = allocation_tag_probe_access(env, clean_ptr, access_type, size,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems different from https://github.com/qemu/qemu/blob/v7.2.22/target/arm/mte_helper.c#L121

Looks like you forget to port CPUTLBEntryFull? Is that intended? Or are you sure the semantic is equivalent?

tcg_ctx->cpu = NULL;

/* generate machine code */
tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nitr0-G How about this one?

@wtdcode

wtdcode commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

I used Claude to semi-manually review this PR and the above findings should be the most relevant. I will fix the others later.

@Nitr0-G

@wtdcode

wtdcode commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

@PhilippTakacs Let me know if this port breaks your workflows.

@PhilippTakacs

Copy link
Copy Markdown
Contributor

I have run some tests and get a NULL deref in qemu/hw/core/cpu.c:118:

static void cpu_legacy_unaligned_access(CPUState *cpu, vaddr addr,
                                        MMUAccessType access_type,
                                        int mmu_idx, uintptr_t retaddr)
{
    CPUClass *cc = CPU_GET_CLASS(cpu);

    cc->do_unaligned_access(cpu, addr, access_type, mmu_idx, retaddr);
}

The do_unaligned_access is NULL and some other function pointer in this struct also:

Process 13225 stopped
* thread #1, name = 'mogi_run_progra', stop reason = step in
    frame #0: 0x0000555555f9acb2 mogi_run_program_unicorn`cpu_legacy_unaligned_access(cpu=0x000055555747cf90, addr=140737488289272, access_type=MMU_DATA_STORE, mmu_idx=2, retaddr=140736274136276) at cpu.c:118:7
   115 	{
   116 	    CPUClass *cc = CPU_GET_CLASS(cpu);
   117 	
-> 118 	    cc->do_unaligned_access(cpu, addr, access_type, mmu_idx, retaddr);
   119 	}
   120 	
   121 	static const struct TCGCPUOps cpu_legacy_tcg_ops = {
(lldb) p cc
(CPUClass *) 0x0000555557489a50
(lldb) p cc->do_unaligned_access
(void (*)(CPUState *, vaddr, MMUAccessType, int, uintptr_t)) 0x0000000000000000
(lldb) p *cc
(CPUClass) {
  reset = 0x0000555556045e8f (mogi_run_program_unicorn`x86_cpu_reset at cpu.c:4569:1)
  has_work = 0x0000555556047160 (mogi_run_program_unicorn`x86_cpu_has_work at cpu.c:5115:1)
  do_interrupt = 0x000055555603b261 (mogi_run_program_unicorn`x86_cpu_do_interrupt_x86_64 at seg_helper.c:1205:1)
  do_unaligned_access = 0x0000000000000000
  get_arch_id = 0x0000555556046f3d (mogi_run_program_unicorn`x86_cpu_get_arch_id at cpu.c:5048:1)
  get_paging_enabled = 0x0000555556046f5f (mogi_run_program_unicorn`x86_cpu_get_paging_enabled at cpu.c:5055:1)
  get_memory_mapping = 0x00005555560779ab (mogi_run_program_unicorn`x86_cpu_get_memory_mapping_x86_64 at arch_memory_mapping.c:302:1)
  set_pc = 0x0000555556046f8c (mogi_run_program_unicorn`x86_cpu_set_pc at cpu.c:5062:1)
  synchronize_from_tb = 0x0000555556046fb6 (mogi_run_program_unicorn`x86_cpu_synchronize_from_tb at cpu.c:5069:1)
  tlb_fill = 0x0000555556096f14 (mogi_run_program_unicorn`unicorn_fill_tlb_x86_64 at unicorn_vtlb.c:62:1)
  tlb_fill_cpu = 0x00005555560419d4 (mogi_run_program_unicorn`x86_cpu_tlb_fill_x86_64 at excp_helper.c:678:1)
  get_phys_page_debug = 0x0000000000000000
  get_phys_page_attrs_debug = 0x0000555556032eb8 (mogi_run_program_unicorn`x86_cpu_get_phys_page_attrs_debug_x86_64 at helper.c:221:1)
  asidx_from_attrs = 0x0000555556042a6a (mogi_run_program_unicorn`x86_asidx_from_attrs at cpu.h:2009:1)
  debug_check_watchpoint = 0x0000000000000000
  debug_excp_handler = 0x0000555556042349 (mogi_run_program_unicorn`breakpoint_handler_x86_64 at bpt_helper.c:209:1)
  cpu_exec_enter = 0x0000555556033499 (mogi_run_program_unicorn`x86_cpu_exec_enter_x86_64 at helper.c:400:1)
  cpu_exec_exit = 0x000055555603352e (mogi_run_program_unicorn`x86_cpu_exec_exit_x86_64 at helper.c:411:1)
  cpu_exec_interrupt = 0x000055555603b391 (mogi_run_program_unicorn`x86_cpu_exec_interrupt_x86_64 at seg_helper.c:1228:1)
  tcg_ops = 0x0000555557275f40
  adjust_watchpoint_address = 0x0000000000000000
  tcg_initialize = 0x000055555601133b (mogi_run_program_unicorn`tcg_x86_init_x86_64 at translate.c:7111:1)
}
(lldb) bt
* thread #1, name = 'mogi_run_progra', stop reason = step in
  * frame #0: 0x0000555555f9acb2 mogi_run_program_unicorn`cpu_legacy_unaligned_access(cpu=0x000055555747cf90, addr=140737488289272, access_type=MMU_DATA_STORE, mmu_idx=2, retaddr=140736274136276) at cpu.c:118:7
    frame #1: 0x0000555555fb3ce2 mogi_run_program_unicorn`cpu_tcg_unaligned_access(cpu=0x000055555747cf90, addr=140737488289272, access_type=MMU_DATA_STORE, mmu_idx=2, retaddr=140736274136276) at tcg-cpu-ops.h:96:9
    frame #2: 0x0000555555fb8297 mogi_run_program_unicorn`store_helper(env=0x00005555574859e0, addr=140737488289272, val=0, oi=2098, retaddr=140736274136276, op=MO_64) at cputlb.c:2247:9
    frame #3: 0x0000555555fb9394 mogi_run_program_unicorn`helper_le_stq_mmu_x86_64(env=0x00005555574859e0, addr=140737488289272, val=0, oi=2098, retaddr=140736274136276) at cputlb.c:2541:5
    frame #4: 0x00007fffb7a07cd4
(lldb) 

@Nitr0-G

Nitr0-G commented Jul 30, 2026

Copy link
Copy Markdown

I have run some tests and get a NULL deref in qemu/hw/core/cpu.c:118:

I found this out tonight too, can you check #2377 please?

I think I fixed this problem and some other shit too

@PhilippTakacs

Copy link
Copy Markdown
Contributor

With #2377 my test reaches handle_unaligned_access which just calls raise_exception_ra and the emulation stops with UC_ERR_EXCEPTION. The problem is this code works perfect fine on the current dev branch. I'm working on a PoC.

@Nitr0-G

Nitr0-G commented Jul 30, 2026

Copy link
Copy Markdown

With #2377 my test reaches handle_unaligned_access which just calls raise_exception_ra and the emulation stops with UC_ERR_EXCEPTION. The problem is this code works perfect fine on the current dev branch. I'm working on a PoC.

Yes - qemu/qemu@958e1dd
With old qemu, Unicorn ignored some things that needed to be leveled. I'd be happy to see a PoC. If it really is a bug, I'll fix it as soon as possible.

* port QEMU 7.2 TLB and TB maintenance

Port full TLB entries and preserve translated ARM page attributes for MTE and BTI checks.

Move translation block cache, linking, invalidation, and flush maintenance into tb-maint.c while keeping Unicorn per-engine state and SMC behavior.

Add guarded-page, self-linked TB, invalidation, and engine-isolation coverage.

* fix QEMU 7.2.22 partial ports
@PhilippTakacs

Copy link
Copy Markdown
Contributor

I found the problem, I had a not correct aligned the stack pointer.

@PhilippTakacs

Copy link
Copy Markdown
Contributor

I'm currently working on some improvements related to the tlb (TLB_NOTDIRTY, call all memory hooks, ...). I wounder if I it's better to target this branch to avoid implementing it two times.

@Nitr0-G

Nitr0-G commented Jul 31, 2026

Copy link
Copy Markdown

I'm currently working on some improvements related to the tlb (TLB_NOTDIRTY, call all memory hooks, ...). I wounder if I it's better to target this branch to avoid implementing it two times.

I think yes. @wtdcode

@PhilippTakacs

Copy link
Copy Markdown
Contributor

I have run some tests with our fuzzer/emulator (https://github.com/mogikai/mogi) and found a ~10% time lost using this branch only by running the 3mm benchmark without fuzzig. A quick look at the perf data shows most time is lost in the load_help. I assume either the fast load (avoiding the load_helper) is less used, the tlb is smaller, or the load_helper is significant slower.

@Nitr0-G

Nitr0-G commented Aug 3, 2026

Copy link
Copy Markdown

I have run some tests with our fuzzer/emulator (https://github.com/mogikai/mogi) and found a ~10% time lost using this branch only by running the 3mm benchmark without fuzzig. A quick look at the perf data shows most time is lost in the load_help. I assume either the fast load (avoiding the load_helper) is less used, the tlb is smaller, or the load_helper is significant slower.

I'll test this and try to fix it! Thanks for telling!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants