From 1f2355f53c752297789d431575c4ba975219599c Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 12 Mar 2024 01:23:30 +0100 Subject: [PATCH 1/9] meson: Make DEBUG_REMAP a meson option Currently DEBUG_REMAP is a macro that needs to be manually #defined to be activated, which makes it hard to have separate build directories dedicated to testing the code with it. Promote it to a meson option. Signed-off-by: Ilya Leoshkevich Message-Id: <20240312002402.14344-1-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- bsd-user/qemu.h | 6 ++---- linux-user/qemu.h | 4 +--- linux-user/uaccess.c | 4 ++-- meson.build | 4 ++++ meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 1b0a591d2d..8629f0dcde 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -22,8 +22,6 @@ #include "exec/cpu_ldst.h" #include "exec/exec-all.h" -#undef DEBUG_REMAP - #include "exec/user/abitypes.h" extern char **environ; @@ -437,7 +435,7 @@ static inline void *lock_user(int type, abi_ulong guest_addr, long len, if (!access_ok(type, guest_addr, len)) { return NULL; } -#ifdef DEBUG_REMAP +#ifdef CONFIG_DEBUG_REMAP { void *addr; addr = g_malloc(len); @@ -461,7 +459,7 @@ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len) { -#ifdef DEBUG_REMAP +#ifdef CONFIG_DEBUG_REMAP if (!host_ptr) { return; } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 32cd43d9ef..4777856b52 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -4,8 +4,6 @@ #include "cpu.h" #include "exec/cpu_ldst.h" -#undef DEBUG_REMAP - #include "exec/user/abitypes.h" #include "syscall_defs.h" @@ -332,7 +330,7 @@ void *lock_user(int type, abi_ulong guest_addr, ssize_t len, bool copy); /* Unlock an area of guest memory. The first LEN bytes must be flushed back to guest memory. host_ptr = NULL is explicitly allowed and does nothing. */ -#ifndef DEBUG_REMAP +#ifndef CONFIG_DEBUG_REMAP static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, ssize_t len) { diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c index 425cbf677f..27e841e651 100644 --- a/linux-user/uaccess.c +++ b/linux-user/uaccess.c @@ -14,7 +14,7 @@ void *lock_user(int type, abi_ulong guest_addr, ssize_t len, bool copy) return NULL; } host_addr = g2h_untagged(guest_addr); -#ifdef DEBUG_REMAP +#ifdef CONFIG_DEBUG_REMAP if (copy) { host_addr = g_memdup(host_addr, len); } else { @@ -24,7 +24,7 @@ void *lock_user(int type, abi_ulong guest_addr, ssize_t len, bool copy) return host_addr; } -#ifdef DEBUG_REMAP +#ifdef CONFIG_DEBUG_REMAP void unlock_user(void *host_ptr, abi_ulong guest_addr, ssize_t len) { void *host_ptr_conv; diff --git a/meson.build b/meson.build index 95cee7046e..553b940999 100644 --- a/meson.build +++ b/meson.build @@ -2350,6 +2350,7 @@ config_host_data.set('CONFIG_DEBUG_GRAPH_LOCK', get_option('debug_graph_lock')) config_host_data.set('CONFIG_DEBUG_MUTEX', get_option('debug_mutex')) config_host_data.set('CONFIG_DEBUG_STACK_USAGE', get_option('debug_stack_usage')) config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg')) +config_host_data.set('CONFIG_DEBUG_REMAP', get_option('debug_remap')) config_host_data.set('CONFIG_LIVE_BLOCK_MIGRATION', get_option('live_block_migration').allowed()) config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug')) config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed()) @@ -4277,6 +4278,9 @@ if config_all_accel.has_key('CONFIG_TCG') endif summary_info += {'TCG plugins': get_option('plugins')} summary_info += {'TCG debug enabled': get_option('debug_tcg')} + if have_linux_user or have_bsd_user + summary_info += {'syscall buffer debugging support': get_option('debug_remap')} + endif endif summary_info += {'target list': ' '.join(target_dirs)} if have_system diff --git a/meson_options.txt b/meson_options.txt index b5c0bad9e7..adc77bae0c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -85,6 +85,8 @@ option('plugins', type: 'boolean', value: false, description: 'TCG plugins via shared library loading') option('debug_tcg', type: 'boolean', value: false, description: 'TCG debugging') +option('debug_remap', type: 'boolean', value: false, + description: 'syscall buffer debugging support') option('tcg_interpreter', type: 'boolean', value: false, description: 'TCG with bytecode interpreter (slow)') option('safe_stack', type: 'boolean', value: false, diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 5ace33f167..0a29d35fdb 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -29,6 +29,7 @@ meson_options_help() { printf "%s\n" ' --enable-debug-graph-lock' printf "%s\n" ' graph lock debugging support' printf "%s\n" ' --enable-debug-mutex mutex debugging support' + printf "%s\n" ' --enable-debug-remap syscall buffer debugging support' printf "%s\n" ' --enable-debug-stack-usage' printf "%s\n" ' measure coroutine stack usage' printf "%s\n" ' --enable-debug-tcg TCG debugging' @@ -294,6 +295,8 @@ _meson_option_parse() { --disable-debug-graph-lock) printf "%s" -Ddebug_graph_lock=false ;; --enable-debug-mutex) printf "%s" -Ddebug_mutex=true ;; --disable-debug-mutex) printf "%s" -Ddebug_mutex=false ;; + --enable-debug-remap) printf "%s" -Ddebug_remap=true ;; + --disable-debug-remap) printf "%s" -Ddebug_remap=false ;; --enable-debug-stack-usage) printf "%s" -Ddebug_stack_usage=true ;; --disable-debug-stack-usage) printf "%s" -Ddebug_stack_usage=false ;; --enable-debug-tcg) printf "%s" -Ddebug_tcg=true ;; From 04f6fb897a5aeb3e356a7b889869c9962f9c16c7 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sun, 31 Mar 2024 13:07:34 +0300 Subject: [PATCH 2/9] linux-user: do_setsockopt: fix SOL_ALG.ALG_SET_KEY This setsockopt accepts zero-lengh optlen (current qemu implementation does not allow this). Also, there's no need to make a copy of the key, it is enough to use lock_user() (which accepts zero length already). Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2197 Fixes: f31dddd2fc "linux-user: Add support for setsockopt() option SOL_ALG" Signed-off-by: Michael Tokarev Message-Id: <20240331100737.2724186-2-mjt@tls.msk.ru> Signed-off-by: Richard Henderson --- linux-user/syscall.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3df2b94d9a..59fb3e911f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2277,18 +2277,13 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, switch (optname) { case ALG_SET_KEY: { - char *alg_key = g_malloc(optlen); - + char *alg_key = lock_user(VERIFY_READ, optval_addr, optlen, 1); if (!alg_key) { - return -TARGET_ENOMEM; - } - if (copy_from_user(alg_key, optval_addr, optlen)) { - g_free(alg_key); return -TARGET_EFAULT; } ret = get_errno(setsockopt(sockfd, level, optname, alg_key, optlen)); - g_free(alg_key); + unlock_user(alg_key, optval_addr, optlen); break; } case ALG_SET_AEAD_AUTHSIZE: From 124a1341a66287ab8f4ce3de3c98eed6747a639f Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sun, 31 Mar 2024 13:07:35 +0300 Subject: [PATCH 3/9] linux-user: do_setsockopt: make ip_mreq local to the place it is used and inline target_to_host_ip_mreq() ip_mreq is declared at the beginning of do_setsockopt(), while it is used in only one place. Move its declaration to that very place and replace pointer to alloca()-allocated memory with the structure itself. target_to_host_ip_mreq() is used only once, inline it. This change also properly handles TARGET_EFAULT when the address is wrong. Signed-off-by: Michael Tokarev Message-Id: <20240331100737.2724186-3-mjt@tls.msk.ru> [rth: Fix braces, adjust optlen to match host structure size] Signed-off-by: Richard Henderson --- linux-user/syscall.c | 47 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 59fb3e911f..cca9cafe4f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1615,24 +1615,6 @@ static abi_long do_pipe(CPUArchState *cpu_env, abi_ulong pipedes, return get_errno(ret); } -static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, - abi_ulong target_addr, - socklen_t len) -{ - struct target_ip_mreqn *target_smreqn; - - target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1); - if (!target_smreqn) - return -TARGET_EFAULT; - mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr; - mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr; - if (len == sizeof(struct target_ip_mreqn)) - mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex); - unlock_user(target_smreqn, target_addr, 0); - - return 0; -} - static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr, abi_ulong target_addr, socklen_t len) @@ -2067,7 +2049,6 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, { abi_long ret; int val; - struct ip_mreqn *ip_mreq; struct ip_mreq_source *ip_mreq_source; switch(level) { @@ -2111,15 +2092,33 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: + { + struct ip_mreqn ip_mreq; + struct target_ip_mreqn *target_smreqn; + + QEMU_BUILD_BUG_ON(sizeof(struct ip_mreq) != + sizeof(struct target_ip_mreq)); + if (optlen < sizeof (struct target_ip_mreq) || - optlen > sizeof (struct target_ip_mreqn)) + optlen > sizeof (struct target_ip_mreqn)) { return -TARGET_EINVAL; + } - ip_mreq = (struct ip_mreqn *) alloca(optlen); - target_to_host_ip_mreq(ip_mreq, optval_addr, optlen); - ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen)); + target_smreqn = lock_user(VERIFY_READ, optval_addr, optlen, 1); + if (!target_smreqn) { + return -TARGET_EFAULT; + } + ip_mreq.imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr; + ip_mreq.imr_address.s_addr = target_smreqn->imr_address.s_addr; + if (optlen == sizeof(struct target_ip_mreqn)) { + ip_mreq.imr_ifindex = tswapal(target_smreqn->imr_ifindex); + optlen = sizeof(struct ip_mreqn); + } + unlock_user(target_smreqn, optval_addr, 0); + + ret = get_errno(setsockopt(sockfd, level, optname, &ip_mreq, optlen)); break; - + } case IP_BLOCK_SOURCE: case IP_UNBLOCK_SOURCE: case IP_ADD_SOURCE_MEMBERSHIP: From 166bd92e3b4dfcd058013453e4dd94ebe5e87819 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sun, 31 Mar 2024 13:07:36 +0300 Subject: [PATCH 4/9] linux-user: do_setsockopt: make ip_mreq_source local to the place where it is used Signed-off-by: Michael Tokarev Message-Id: <20240331100737.2724186-4-mjt@tls.msk.ru> Signed-off-by: Richard Henderson --- linux-user/syscall.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cca9cafe4f..1fedf16650 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2049,7 +2049,6 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, { abi_long ret; int val; - struct ip_mreq_source *ip_mreq_source; switch(level) { case SOL_TCP: @@ -2123,6 +2122,9 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, case IP_UNBLOCK_SOURCE: case IP_ADD_SOURCE_MEMBERSHIP: case IP_DROP_SOURCE_MEMBERSHIP: + { + struct ip_mreq_source *ip_mreq_source; + if (optlen != sizeof (struct target_ip_mreq_source)) return -TARGET_EINVAL; @@ -2133,7 +2135,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen)); unlock_user (ip_mreq_source, optval_addr, 0); break; - + } default: goto unimplemented; } From 88a722b6ad59bf6ca42c01ac806c54bd94d98642 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sun, 31 Mar 2024 13:07:37 +0300 Subject: [PATCH 5/9] linux-user: do_setsockopt: eliminate goto in switch for SO_SNDTIMEO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's identical code for SO_SNDTIMEO and SO_RCVTIMEO, currently implemented using an ugly goto into another switch case. Eliminate that using arithmetic if, making code flow more natural. Signed-off-by: Michael Tokarev Message-Id: <20240331100737.2724186-5-mjt@tls.msk.ru> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- linux-user/syscall.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1fedf16650..41659b63f5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2301,12 +2301,10 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, case TARGET_SOL_SOCKET: switch (optname) { case TARGET_SO_RCVTIMEO: + case TARGET_SO_SNDTIMEO: { struct timeval tv; - optname = SO_RCVTIMEO; - -set_timeout: if (optlen != sizeof(struct target_timeval)) { return -TARGET_EINVAL; } @@ -2315,13 +2313,12 @@ set_timeout: return -TARGET_EFAULT; } - ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, + optname == TARGET_SO_RCVTIMEO ? + SO_RCVTIMEO : SO_SNDTIMEO, &tv, sizeof(tv))); return ret; } - case TARGET_SO_SNDTIMEO: - optname = SO_SNDTIMEO; - goto set_timeout; case TARGET_SO_ATTACH_FILTER: { struct target_sock_fprog *tfprog; From 7048fc59ef6a9f76693db3bafede6234a3897385 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 3 Apr 2024 11:20:49 +0200 Subject: [PATCH 6/9] linux-user: Add FITRIM ioctl Tiny patch to add the missing FITRIM ioctl. Signed-off-by: Michael Vogt Message-Id: <20240403092048.16023-2-michael.vogt@gmail.com> Signed-off-by: Richard Henderson --- linux-user/ioctls.h | 3 +++ linux-user/syscall_defs.h | 1 + linux-user/syscall_types.h | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 1aec9d5836..d508d0c04a 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -140,6 +140,9 @@ #ifdef FITHAW IOCTL(FITHAW, IOC_W | IOC_R, TYPE_INT) #endif +#ifdef FITRIM + IOCTL(FITRIM, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_fstrim_range))) +#endif IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG)) #ifdef CONFIG_FIEMAP diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 3995487630..a00b617cae 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -945,6 +945,7 @@ struct target_rtc_pll_info { #define TARGET_FIFREEZE TARGET_IOWR('X', 119, abi_int) #define TARGET_FITHAW TARGET_IOWR('X', 120, abi_int) +#define TARGET_FITRIM TARGET_IOWR('X', 121, struct fstrim_range) /* * Note that the ioctl numbers for FS_IOC_ diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index c3b43f8022..6dd7a80ce5 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -341,6 +341,11 @@ STRUCT(file_clone_range, TYPE_ULONGLONG, /* src_length */ TYPE_ULONGLONG) /* dest_offset */ +STRUCT(fstrim_range, + TYPE_ULONGLONG, /* start */ + TYPE_ULONGLONG, /* len */ + TYPE_ULONGLONG) /* minlen */ + STRUCT(fiemap_extent, TYPE_ULONGLONG, /* fe_logical */ TYPE_ULONGLONG, /* fe_physical */ From 5fae5110eedba1110605c88d96cd4a5f057bfca2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Aug 2023 09:19:12 -0700 Subject: [PATCH 7/9] target/m68k: Pass semihosting arg to exit Instead of using d0 (the semihost function number), use d1 (the provide exit status). Signed-off-by: Keith Packard Reviewed-by: Peter Maydell Message-Id: <20230802161914.395443-2-keithp@keithp.com> Signed-off-by: Richard Henderson --- target/m68k/m68k-semi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c index 546cff2246..6fbbd140f3 100644 --- a/target/m68k/m68k-semi.c +++ b/target/m68k/m68k-semi.c @@ -132,8 +132,8 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) args = env->dregs[1]; switch (nr) { case HOSTED_EXIT: - gdb_exit(env->dregs[0]); - exit(env->dregs[0]); + gdb_exit(env->dregs[1]); + exit(env->dregs[1]); case HOSTED_OPEN: GET_ARG(0); From f161e723fdfddfc820c7f19eb6ac76ac6ba6d2a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 3 Oct 2023 15:15:24 -0700 Subject: [PATCH 8/9] target/m68k: Perform the semihosting test during translate Replace EXCP_HALT_INSN by EXCP_SEMIHOSTING. Perform the pre- and post-insn tests during translate, leaving only the actual semihosting operation for the exception. Signed-off-by: Richard Henderson --- target/m68k/cpu.h | 2 +- target/m68k/op_helper.c | 14 ++----------- target/m68k/translate.c | 45 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index e184239a81..b5bbeedb7a 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -66,7 +66,7 @@ #define EXCP_MMU_ACCESS 58 /* MMU Access Level Violation Error */ #define EXCP_RTE 0x100 -#define EXCP_HALT_INSN 0x101 +#define EXCP_SEMIHOSTING 0x101 #define M68K_DTTR0 0 #define M68K_DTTR1 1 diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 125f6c1b08..15bad5dd46 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -202,18 +202,8 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw) /* Return from an exception. */ cf_rte(env); return; - case EXCP_HALT_INSN: - if (semihosting_enabled((env->sr & SR_S) == 0) - && (env->pc & 3) == 0 - && cpu_lduw_code(env, env->pc - 4) == 0x4e71 - && cpu_ldl_code(env, env->pc) == 0x4e7bf000) { - env->pc += 4; - do_m68k_semihosting(env, env->dregs[0]); - return; - } - cs->halted = 1; - cs->exception_index = EXCP_HLT; - cpu_loop_exit(cs); + case EXCP_SEMIHOSTING: + do_m68k_semihosting(env, env->dregs[0]); return; } } diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 8a194f2f21..647bd9d9be 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -26,12 +26,11 @@ #include "qemu/log.h" #include "qemu/qemu-print.h" #include "exec/translator.h" - #include "exec/helper-proto.h" #include "exec/helper-gen.h" - #include "exec/log.h" #include "fpu/softfloat.h" +#include "semihosting/semihost.h" #define HELPER_H "helper.h" #include "exec/helper-info.c.inc" @@ -1401,6 +1400,40 @@ static void gen_jmp_tb(DisasContext *s, int n, target_ulong dest, s->base.is_jmp = DISAS_NORETURN; } +#ifndef CONFIG_USER_ONLY +static bool semihosting_test(DisasContext *s) +{ + uint32_t test; + + if (!semihosting_enabled(IS_USER(s))) { + return false; + } + + /* + * "The semihosting instruction is immediately preceded by a + * nop aligned to a 4-byte boundary..." + * The preceding 2-byte (aligned) nop plus the 2-byte halt/bkpt + * means that we have advanced 4 bytes from the required nop. + */ + if (s->pc % 4 != 0) { + return false; + } + test = translator_lduw(s->env, &s->base, s->pc - 4); + if (test != 0x4e71) { + return false; + } + /* "... and followed by an invalid sentinel instruction movec %sp,0." */ + test = translator_ldl(s->env, &s->base, s->pc); + if (test != 0x4e7bf000) { + return false; + } + + /* Consume the sentinel. */ + s->pc += 4; + return true; +} +#endif /* !CONFIG_USER_ONLY */ + DISAS_INSN(scc) { DisasCompare c; @@ -4465,8 +4498,12 @@ DISAS_INSN(halt) gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE); return; } - - gen_exception(s, s->pc, EXCP_HALT_INSN); + if (semihosting_test(s)) { + gen_exception(s, s->pc, EXCP_SEMIHOSTING); + return; + } + tcg_gen_movi_i32(cpu_halted, 1); + gen_exception(s, s->pc, EXCP_HLT); } DISAS_INSN(stop) From 0815c228bd1e0c24ac064ce299807b32f8e05d83 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 3 Oct 2023 15:26:06 -0700 Subject: [PATCH 9/9] target/m68k: Support semihosting on non-ColdFire targets According to the m68k semihosting spec: "The instruction used to trigger a semihosting request depends on the m68k processor variant. On ColdFire, "halt" is used; on other processors (which don't implement "halt"), "bkpt #0" may be used." Add support for non-CodeFire processors by matching BKPT #0 instructions. Signed-off-by: Keith Packard [rth: Use semihosting_test()] Signed-off-by: Richard Henderson --- target/m68k/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 647bd9d9be..169927552a 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2646,6 +2646,11 @@ DISAS_INSN(bkpt) #if defined(CONFIG_USER_ONLY) gen_exception(s, s->base.pc_next, EXCP_DEBUG); #else + /* BKPT #0 is the alternate semihosting instruction. */ + if ((insn & 7) == 0 && semihosting_test(s)) { + gen_exception(s, s->pc, EXCP_SEMIHOSTING); + return; + } gen_exception(s, s->base.pc_next, EXCP_ILLEGAL); #endif }