From 2627e4524ea6c6ba14f9d6b298e08c9d4d3cc4fe Mon Sep 17 00:00:00 2001 From: Richard Henderson <richard.henderson@linaro.org> Date: Mon, 6 Feb 2023 09:26:29 -1000 Subject: [PATCH 1/8] accel/tcg: Allow the second page of an instruction to be MMIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an instruction straddles a page boundary, and the first page was ram, but the second page was MMIO, we would abort. Handle this as if both pages are MMIO, by setting the ram_addr_t for the first page to -1. Reported-by: Sid Manning <sidneym@quicinc.com> Reported-by: Jørgen Hansen <Jorgen.Hansen@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- accel/tcg/translator.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index ef5193c67e..1cf404ced0 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -176,8 +176,16 @@ static void *translator_access(CPUArchState *env, DisasContextBase *db, if (host == NULL) { tb_page_addr_t phys_page = get_page_addr_code_hostp(env, base, &db->host_addr[1]); - /* We cannot handle MMIO as second page. */ - assert(phys_page != -1); + + /* + * If the second page is MMIO, treat as if the first page + * was MMIO as well, so that we do not cache the TB. + */ + if (unlikely(phys_page == -1)) { + tb_set_page_addr0(tb, -1); + return NULL; + } + tb_set_page_addr1(tb, phys_page); #ifdef CONFIG_USER_ONLY page_protect(end); From 21a474c41d18eb56186e2022e8e081c2b6011bd3 Mon Sep 17 00:00:00 2001 From: Richard Henderson <richard.henderson@linaro.org> Date: Wed, 1 Feb 2023 10:56:15 -1000 Subject: [PATCH 2/8] linux-user/sparc: Raise SIGILL for all unhandled software traps The linux kernel's trap tables vector all unassigned trap numbers to BAD_TRAP, which then raises SIGILL. Tested-by: Ilya Leoshkevich <iii@linux.ibm.com> Reported-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 434c90a55f..c120c42278 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -248,6 +248,14 @@ void cpu_loop (CPUSPARCState *env) cpu_exec_step_atomic(cs); break; default: + /* + * Most software trap numbers vector to BAD_TRAP. + * Handle anything not explicitly matched above. + */ + if (trapnr >= TT_TRAP && trapnr <= TT_TRAP + 0x7f) { + force_sig_fault(TARGET_SIGILL, ILL_ILLTRP, env->pc); + break; + } fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, 0); exit(EXIT_FAILURE); From 7de0816f699553514016f52a76e26d1c2ae14034 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich <iii@linux.ibm.com> Date: Tue, 14 Feb 2023 15:08:26 +0100 Subject: [PATCH 3/8] linux-user: Always exit from exclusive state in fork_end() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fork()ed processes currently start with current_cpu->in_exclusive_context set, which is, strictly speaking, not correct, but does not cause problems (even assertion failures). With one of the next patches, the code begins to rely on this value, so fix it by always calling end_exclusive() in fork_end(). Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20230214140829.45392-2-iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/main.c | 10 ++++++---- linux-user/syscall.c | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 4290651c3c..4ff30ff980 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -161,13 +161,15 @@ void fork_end(int child) } qemu_init_cpu_list(); gdbserver_fork(thread_cpu); - /* qemu_init_cpu_list() takes care of reinitializing the - * exclusive state, so we don't need to end_exclusive() here. - */ } else { cpu_list_unlock(); - end_exclusive(); } + /* + * qemu_init_cpu_list() reinitialized the child exclusive state, but we + * also need to keep current_cpu consistent, so call end_exclusive() for + * both child and parent. + */ + end_exclusive(); } __thread CPUState *thread_cpu; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1e868e9b0e..a6c426d73c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6752,6 +6752,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, cpu_clone_regs_parent(env, flags); fork_end(0); } + g_assert(!cpu_in_exclusive_context(cpu)); } return ret; } From df8a688032280ecd07ace7c6fbc70f5650cca9af Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich <iii@linux.ibm.com> Date: Tue, 14 Feb 2023 15:08:27 +0100 Subject: [PATCH 4/8] cpus: Make {start,end}_exclusive() recursive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently dying to one of the core_dump_signal()s deadlocks, because dump_core_and_abort() calls start_exclusive() two times: first via stop_all_tasks(), and then via preexit_cleanup() -> qemu_plugin_user_exit(). There are a number of ways to solve this: resume after dumping core; check cpu_in_exclusive_context() in qemu_plugin_user_exit(); or make {start,end}_exclusive() recursive. Pick the last option, since it's the most straightforward one. Fixes: da91c1920242 ("linux-user: Clean up when exiting due to a signal") Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20230214140829.45392-3-iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- cpus-common.c | 12 ++++++++++-- include/hw/core/cpu.h | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 793364dc0e..39f355de98 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -192,6 +192,11 @@ void start_exclusive(void) CPUState *other_cpu; int running_cpus; + if (current_cpu->exclusive_context_count) { + current_cpu->exclusive_context_count++; + return; + } + qemu_mutex_lock(&qemu_cpu_list_lock); exclusive_idle(); @@ -219,13 +224,16 @@ void start_exclusive(void) */ qemu_mutex_unlock(&qemu_cpu_list_lock); - current_cpu->in_exclusive_context = true; + current_cpu->exclusive_context_count = 1; } /* Finish an exclusive operation. */ void end_exclusive(void) { - current_cpu->in_exclusive_context = false; + current_cpu->exclusive_context_count--; + if (current_cpu->exclusive_context_count) { + return; + } qemu_mutex_lock(&qemu_cpu_list_lock); qatomic_set(&pending_cpus, 0); diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 2417597236..671f041bec 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -349,7 +349,7 @@ struct CPUState { bool unplug; bool crash_occurred; bool exit_request; - bool in_exclusive_context; + int exclusive_context_count; uint32_t cflags_next_tb; /* updates protected by BQL */ uint32_t interrupt_request; @@ -758,7 +758,7 @@ void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data */ static inline bool cpu_in_exclusive_context(const CPUState *cpu) { - return cpu->in_exclusive_context; + return cpu->exclusive_context_count; } /** From d7d5601c788b7972d7e62ce2e8af4587db9e2da1 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich <iii@linux.ibm.com> Date: Tue, 14 Feb 2023 15:08:28 +0100 Subject: [PATCH 5/8] linux-user/microblaze: Handle privileged exception Follow what kernel's full_exception() is doing. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20230214140829.45392-4-iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/microblaze/cpu_loop.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index 5ccf9e942e..212e62d0a6 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -25,8 +25,8 @@ void cpu_loop(CPUMBState *env) { + int trapnr, ret, si_code, sig; CPUState *cs = env_cpu(env); - int trapnr, ret, si_code; while (1) { cpu_exec_start(cs); @@ -76,6 +76,7 @@ void cpu_loop(CPUMBState *env) env->iflags &= ~(IMM_FLAG | D_FLAG); switch (env->esr & 31) { case ESR_EC_DIVZERO: + sig = TARGET_SIGFPE; si_code = TARGET_FPE_INTDIV; break; case ESR_EC_FPU: @@ -84,6 +85,7 @@ void cpu_loop(CPUMBState *env) * if there's no recognized bit set. Possibly this * implies that si_code is 0, but follow the structure. */ + sig = TARGET_SIGFPE; si_code = env->fsr; if (si_code & FSR_IO) { si_code = TARGET_FPE_FLTINV; @@ -97,13 +99,17 @@ void cpu_loop(CPUMBState *env) si_code = TARGET_FPE_FLTRES; } break; + case ESR_EC_PRIVINSN: + sig = SIGILL; + si_code = ILL_PRVOPC; + break; default: fprintf(stderr, "Unhandled hw-exception: 0x%x\n", env->esr & ESR_EC_MASK); cpu_dump_state(cs, stderr, 0); exit(EXIT_FAILURE); } - force_sig_fault(TARGET_SIGFPE, si_code, env->pc); + force_sig_fault(sig, si_code, env->pc); break; case EXCP_DEBUG: From c3bef3b4de8e60affa6aa3a46dcfcf3bd09459a1 Mon Sep 17 00:00:00 2001 From: Richard Henderson <richard.henderson@linaro.org> Date: Fri, 30 Dec 2022 07:54:58 -0800 Subject: [PATCH 6/8] target/microblaze: Add gdbstub xml Mirroring the upstream gdb xml files, the two stack boundary registers are separated out. Reviewed-by: Edgar E. Iglesias <edgar@zeroasic.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- configs/targets/microblaze-linux-user.mak | 1 + configs/targets/microblaze-softmmu.mak | 1 + configs/targets/microblazeel-linux-user.mak | 1 + configs/targets/microblazeel-softmmu.mak | 1 + gdb-xml/microblaze-core.xml | 67 +++++++++++++++++++++ gdb-xml/microblaze-stack-protect.xml | 12 ++++ target/microblaze/cpu.c | 7 ++- target/microblaze/cpu.h | 2 + target/microblaze/gdbstub.c | 51 +++++++++++----- 9 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 gdb-xml/microblaze-core.xml create mode 100644 gdb-xml/microblaze-stack-protect.xml diff --git a/configs/targets/microblaze-linux-user.mak b/configs/targets/microblaze-linux-user.mak index 4249a37f65..0a2322c249 100644 --- a/configs/targets/microblaze-linux-user.mak +++ b/configs/targets/microblaze-linux-user.mak @@ -3,3 +3,4 @@ TARGET_SYSTBL_ABI=common TARGET_SYSTBL=syscall.tbl TARGET_BIG_ENDIAN=y TARGET_HAS_BFLT=y +TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml diff --git a/configs/targets/microblaze-softmmu.mak b/configs/targets/microblaze-softmmu.mak index 8385e2d333..e84c0cc728 100644 --- a/configs/targets/microblaze-softmmu.mak +++ b/configs/targets/microblaze-softmmu.mak @@ -2,3 +2,4 @@ TARGET_ARCH=microblaze TARGET_BIG_ENDIAN=y TARGET_SUPPORTS_MTTCG=y TARGET_NEED_FDT=y +TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml diff --git a/configs/targets/microblazeel-linux-user.mak b/configs/targets/microblazeel-linux-user.mak index d0e775d840..270743156a 100644 --- a/configs/targets/microblazeel-linux-user.mak +++ b/configs/targets/microblazeel-linux-user.mak @@ -2,3 +2,4 @@ TARGET_ARCH=microblaze TARGET_SYSTBL_ABI=common TARGET_SYSTBL=syscall.tbl TARGET_HAS_BFLT=y +TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml diff --git a/configs/targets/microblazeel-softmmu.mak b/configs/targets/microblazeel-softmmu.mak index af40391f2f..9b688036bd 100644 --- a/configs/targets/microblazeel-softmmu.mak +++ b/configs/targets/microblazeel-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=microblaze TARGET_SUPPORTS_MTTCG=y TARGET_NEED_FDT=y +TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml diff --git a/gdb-xml/microblaze-core.xml b/gdb-xml/microblaze-core.xml new file mode 100644 index 0000000000..becf77c89c --- /dev/null +++ b/gdb-xml/microblaze-core.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2008 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.microblaze.core"> + <reg name="r0" bitsize="32" regnum="0"/> + <reg name="r1" bitsize="32" type="data_ptr"/> + <reg name="r2" bitsize="32"/> + <reg name="r3" bitsize="32"/> + <reg name="r4" bitsize="32"/> + <reg name="r5" bitsize="32"/> + <reg name="r6" bitsize="32"/> + <reg name="r7" bitsize="32"/> + <reg name="r8" bitsize="32"/> + <reg name="r9" bitsize="32"/> + <reg name="r10" bitsize="32"/> + <reg name="r11" bitsize="32"/> + <reg name="r12" bitsize="32"/> + <reg name="r13" bitsize="32"/> + <reg name="r14" bitsize="32"/> + <reg name="r15" bitsize="32"/> + <reg name="r16" bitsize="32"/> + <reg name="r17" bitsize="32"/> + <reg name="r18" bitsize="32"/> + <reg name="r19" bitsize="32"/> + <reg name="r20" bitsize="32"/> + <reg name="r21" bitsize="32"/> + <reg name="r22" bitsize="32"/> + <reg name="r23" bitsize="32"/> + <reg name="r24" bitsize="32"/> + <reg name="r25" bitsize="32"/> + <reg name="r26" bitsize="32"/> + <reg name="r27" bitsize="32"/> + <reg name="r28" bitsize="32"/> + <reg name="r29" bitsize="32"/> + <reg name="r30" bitsize="32"/> + <reg name="r31" bitsize="32"/> + <reg name="rpc" bitsize="32" type="code_ptr"/> + <reg name="rmsr" bitsize="32"/> + <reg name="rear" bitsize="32"/> + <reg name="resr" bitsize="32"/> + <reg name="rfsr" bitsize="32"/> + <reg name="rbtr" bitsize="32"/> + <reg name="rpvr0" bitsize="32"/> + <reg name="rpvr1" bitsize="32"/> + <reg name="rpvr2" bitsize="32"/> + <reg name="rpvr3" bitsize="32"/> + <reg name="rpvr4" bitsize="32"/> + <reg name="rpvr5" bitsize="32"/> + <reg name="rpvr6" bitsize="32"/> + <reg name="rpvr7" bitsize="32"/> + <reg name="rpvr8" bitsize="32"/> + <reg name="rpvr9" bitsize="32"/> + <reg name="rpvr10" bitsize="32"/> + <reg name="rpvr11" bitsize="32"/> + <reg name="redr" bitsize="32"/> + <reg name="rpid" bitsize="32"/> + <reg name="rzpr" bitsize="32"/> + <reg name="rtlbx" bitsize="32"/> + <reg name="rtlbsx" bitsize="32"/> + <reg name="rtlblo" bitsize="32"/> + <reg name="rtlbhi" bitsize="32"/> +</feature> diff --git a/gdb-xml/microblaze-stack-protect.xml b/gdb-xml/microblaze-stack-protect.xml new file mode 100644 index 0000000000..997301e8a2 --- /dev/null +++ b/gdb-xml/microblaze-stack-protect.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2008 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.microblaze.stack-protect"> + <reg name="rslr" bitsize="32"/> + <reg name="rshr" bitsize="32"/> +</feature> diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 817681f9b2..a2d2f5c340 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -28,6 +28,7 @@ #include "qemu/module.h" #include "hw/qdev-properties.h" #include "exec/exec-all.h" +#include "exec/gdbstub.h" #include "fpu/softfloat-helpers.h" static const struct { @@ -294,6 +295,9 @@ static void mb_cpu_initfn(Object *obj) CPUMBState *env = &cpu->env; cpu_set_cpustate_pointers(cpu); + gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect, + mb_cpu_gdb_write_stack_protect, 2, + "microblaze-stack-protect.xml", 0); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); @@ -422,7 +426,8 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) cc->sysemu_ops = &mb_sysemu_ops; #endif device_class_set_props(dc, mb_properties); - cc->gdb_num_core_regs = 32 + 27; + cc->gdb_num_core_regs = 32 + 25; + cc->gdb_core_xml_file = "microblaze-core.xml"; cc->disas_set_info = mb_disas_set_info; cc->tcg_ops = &mb_tcg_ops; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 1e84dd8f47..e541fbb0b3 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -367,6 +367,8 @@ hwaddr mb_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, MemTxAttrs *attrs); int mb_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +int mb_cpu_gdb_read_stack_protect(CPUArchState *cpu, GByteArray *buf, int reg); +int mb_cpu_gdb_write_stack_protect(CPUArchState *cpu, uint8_t *buf, int reg); static inline uint32_t mb_cpu_read_msr(const CPUMBState *env) { diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 2e6e070051..8143fcae88 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -39,8 +39,11 @@ enum { GDB_PVR0 = 32 + 6, GDB_PVR11 = 32 + 17, GDB_EDR = 32 + 18, - GDB_SLR = 32 + 25, - GDB_SHR = 32 + 26, +}; + +enum { + GDB_SP_SHL, + GDB_SP_SHR, }; int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) @@ -83,12 +86,6 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) case GDB_EDR: val = env->edr; break; - case GDB_SLR: - val = env->slr; - break; - case GDB_SHR: - val = env->shr; - break; default: /* Other SRegs aren't modeled, so report a value of 0 */ val = 0; @@ -97,6 +94,23 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return gdb_get_reg32(mem_buf, val); } +int mb_cpu_gdb_read_stack_protect(CPUMBState *env, GByteArray *mem_buf, int n) +{ + uint32_t val; + + switch (n) { + case GDB_SP_SHL: + val = env->slr; + break; + case GDB_SP_SHR: + val = env->shr; + break; + default: + return 0; + } + return gdb_get_reg32(mem_buf, val); +} + int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); @@ -135,12 +149,21 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) case GDB_EDR: env->edr = tmp; break; - case GDB_SLR: - env->slr = tmp; - break; - case GDB_SHR: - env->shr = tmp; - break; + } + return 4; +} + +int mb_cpu_gdb_write_stack_protect(CPUMBState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case GDB_SP_SHL: + env->slr = ldl_p(mem_buf); + break; + case GDB_SP_SHR: + env->shr = ldl_p(mem_buf); + break; + default: + return 0; } return 4; } From b3c326029554a7d134e26e749240ba2d8ac288b1 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier <pierrick.bouvier@linaro.org> Date: Tue, 21 Feb 2023 16:30:03 +0100 Subject: [PATCH 7/8] util/cacheflush: fix cache on windows-arm64 ctr_el0 access is privileged on this platform and fails as an illegal instruction. Windows does not offer a way to flush data cache from userspace, and only FlushInstructionCache is available in Windows API. The generic implementation of flush_idcache_range uses, __builtin___clear_cache, which already use the FlushInstructionCache function. So we rely on that. Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230221153006.20300-2-pierrick.bouvier@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- util/cacheflush.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/util/cacheflush.c b/util/cacheflush.c index 2c2c73e085..06c2333a60 100644 --- a/util/cacheflush.c +++ b/util/cacheflush.c @@ -121,8 +121,12 @@ static void sys_cache_info(int *isize, int *dsize) static bool have_coherent_icache; #endif -#if defined(__aarch64__) && !defined(CONFIG_DARWIN) -/* Apple does not expose CTR_EL0, so we must use system interfaces. */ +#if defined(__aarch64__) && !defined(CONFIG_DARWIN) && !defined(CONFIG_WIN32) +/* + * Apple does not expose CTR_EL0, so we must use system interfaces. + * Windows neither, but we use a generic implementation of flush_idcache_range + * in this case. + */ static uint64_t save_ctr_el0; static void arch_cache_info(int *isize, int *dsize) { @@ -225,7 +229,11 @@ static void __attribute__((constructor)) init_cache_info(void) /* Caches are coherent and do not require flushing; symbol inline. */ -#elif defined(__aarch64__) +#elif defined(__aarch64__) && !defined(CONFIG_WIN32) +/* + * For Windows, we use generic implementation of flush_idcache_range, that + * performs a call to FlushInstructionCache, through __builtin___clear_cache. + */ #ifdef CONFIG_DARWIN /* Apple does not expose CTR_EL0, so we must use system interfaces. */ From dbd672c87f19949bb62bfb1fb3a97b9729fd7560 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier <pierrick.bouvier@linaro.org> Date: Tue, 21 Feb 2023 16:30:04 +0100 Subject: [PATCH 8/8] sysemu/os-win32: fix setjmp/longjmp on windows-arm64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows implementation of setjmp/longjmp is done in C:/WINDOWS/system32/ucrtbase.dll. Alas, on arm64, it seems to *always* perform stack unwinding, which crashes from generated code. By using alternative implementation built in mingw, we avoid doing stack unwinding and this fixes crash when calling longjmp. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Acked-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230221153006.20300-3-pierrick.bouvier@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/sysemu/os-win32.h | 28 ++++++++++++++++++++++++---- meson.build | 21 +++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 5b38c7bd04..97d0243aee 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -51,14 +51,34 @@ typedef struct sockaddr_un { extern "C" { #endif -#if defined(_WIN64) -/* On w64, setjmp is implemented by _setjmp which needs a second parameter. +#if defined(__aarch64__) +/* + * On windows-arm64, setjmp is available in only one variant, and longjmp always + * does stack unwinding. This crash with generated code. + * Thus, we use another implementation of setjmp (not windows one), coming from + * mingw, which never performs stack unwinding. + */ +#undef setjmp +#undef longjmp +/* + * These functions are not declared in setjmp.h because __aarch64__ defines + * setjmp to _setjmpex instead. However, they are still defined in libmingwex.a, + * which gets linked automatically. + */ +extern int __mingw_setjmp(jmp_buf); +extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int); +#define setjmp(env) __mingw_setjmp(env) +#define longjmp(env, val) __mingw_longjmp(env, val) +#elif defined(_WIN64) +/* + * On windows-x64, setjmp is implemented by _setjmp which needs a second parameter. * If this parameter is NULL, longjump does no stack unwinding. * That is what we need for QEMU. Passing the value of register rsp (default) - * lets longjmp try a stack unwinding which will crash with generated code. */ + * lets longjmp try a stack unwinding which will crash with generated code. + */ # undef setjmp # define setjmp(env) _setjmp(env, NULL) -#endif +#endif /* __aarch64__ */ /* QEMU uses sigsetjmp()/siglongjmp() as the portable way to specify * "longjmp and don't touch the signal masks". Since we know that the * savemask parameter will always be zero we can safely define these diff --git a/meson.build b/meson.build index bc7e5b1d15..6a139e7085 100644 --- a/meson.build +++ b/meson.build @@ -2466,6 +2466,27 @@ if targetos == 'windows' }''', name: '_lock_file and _unlock_file')) endif +if targetos == 'windows' + mingw_has_setjmp_longjmp = cc.links(''' + #include <setjmp.h> + int main(void) { + /* + * These functions are not available in setjmp header, but may be + * available at link time, from libmingwex.a. + */ + extern int __mingw_setjmp(jmp_buf); + extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int); + jmp_buf env; + __mingw_setjmp(env); + __mingw_longjmp(env, 0); + } + ''', name: 'mingw setjmp and longjmp') + + if cpu == 'aarch64' and not mingw_has_setjmp_longjmp + error('mingw must provide setjmp/longjmp for windows-arm64') + endif +endif + ######################## # Target configuration # ########################