From 258bec39f3e58fcdb006028e5c5a1801136ef04a Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 5 Dec 2022 12:38:25 +0100 Subject: linux-user: Fix access to /proc/self/exe When accsssing /proc/self/exe from a userspace program, linux-user tries to resolve the name via realpath(), which may fail if the process changed the working directory in the meantime. An example: - a userspace program ist started with ./testprogram - the program runs chdir("/tmp") - then the program calls readlink("/proc/self/exe") - linux-user tries to run realpath("./testprogram") which fails because ./testprogram isn't in /tmp - readlink() will return -ENOENT back to the program Avoid this issue by resolving the full path name of the started process at startup of linux-user and store it in real_exec_path[]. This then simplifies the emulation of readlink() and readlinkat() as well, because they can simply copy the path string to userspace. I noticed this bug because the testsuite of the debian package "pandoc" failed on linux-user while it succeeded on real hardware. The full log is here: https://buildd.debian.org/status/fetch.php?pkg=pandoc&arch=hppa&ver=2.17.1.1-1.1%2Bb1&stamp=1670153210&raw=0 Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: <20221205113825.20615-1-deller@gmx.de> Signed-off-by: Laurent Vivier --- linux-user/main.c | 6 ++++++ linux-user/syscall.c | 38 ++++++++++++++------------------------ 2 files changed, 20 insertions(+), 24 deletions(-) (limited to 'linux-user') diff --git a/linux-user/main.c b/linux-user/main.c index 4ff30ff..798fdc0 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -65,6 +65,7 @@ #endif char *exec_path; +char real_exec_path[PATH_MAX]; int singlestep; static const char *argv0; @@ -739,6 +740,11 @@ int main(int argc, char **argv, char **envp) } } + /* Resolve executable file name to full path name */ + if (realpath(exec_path, real_exec_path)) { + exec_path = real_exec_path; + } + /* * get binfmt_misc flags */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a6c426d..cc650d4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9989,18 +9989,13 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, /* Short circuit this for the magic exe check. */ ret = -TARGET_EINVAL; } else if (is_proc_myself((const char *)p, "exe")) { - char real[PATH_MAX], *temp; - temp = realpath(exec_path, real); - /* Return value is # of bytes that we wrote to the buffer. */ - if (temp == NULL) { - ret = get_errno(-1); - } else { - /* Don't worry about sign mismatch as earlier mapping - * logic would have thrown a bad address error. */ - ret = MIN(strlen(real), arg3); - /* We cannot NUL terminate the string. */ - memcpy(p2, real, ret); - } + /* + * Don't worry about sign mismatch as earlier mapping + * logic would have thrown a bad address error. + */ + ret = MIN(strlen(exec_path), arg3); + /* We cannot NUL terminate the string. */ + memcpy(p2, exec_path, ret); } else { ret = get_errno(readlink(path(p), p2, arg3)); } @@ -10021,18 +10016,13 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, /* Short circuit this for the magic exe check. */ ret = -TARGET_EINVAL; } else if (is_proc_myself((const char *)p, "exe")) { - char real[PATH_MAX], *temp; - temp = realpath(exec_path, real); - /* Return value is # of bytes that we wrote to the buffer. */ - if (temp == NULL) { - ret = get_errno(-1); - } else { - /* Don't worry about sign mismatch as earlier mapping - * logic would have thrown a bad address error. */ - ret = MIN(strlen(real), arg4); - /* We cannot NUL terminate the string. */ - memcpy(p2, real, ret); - } + /* + * Don't worry about sign mismatch as earlier mapping + * logic would have thrown a bad address error. + */ + ret = MIN(strlen(exec_path), arg4); + /* We cannot NUL terminate the string. */ + memcpy(p2, exec_path, ret); } else { ret = get_errno(readlinkat(arg1, path(p), p2, arg4)); } -- cgit v1.1 From d759a62b122dcdf76d6ea10c56c5dff1d04d731d Mon Sep 17 00:00:00 2001 From: Mathis Marion Date: Mon, 20 Feb 2023 09:58:19 +0100 Subject: linux-user: fix timerfd read endianness conversion When reading the expiration count from a timerfd, the endianness of the 64bit value read is the one of the host, just as for eventfds. Signed-off-by: Mathis Marion Reviewed-by: Laurent Vivier Message-Id: <20230220085822.626798-2-Mathis.Marion@silabs.com> Signed-off-by: Laurent Vivier --- linux-user/fd-trans.c | 10 +++++++--- linux-user/fd-trans.h | 1 + linux-user/syscall.c | 8 ++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'linux-user') diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index 7b25468..146aaaa 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -1622,7 +1622,7 @@ TargetFdTrans target_signalfd_trans = { .host_to_target_data = host_to_target_data_signalfd, }; -static abi_long swap_data_eventfd(void *buf, size_t len) +static abi_long swap_data_u64(void *buf, size_t len) { uint64_t *counter = buf; int i; @@ -1640,8 +1640,12 @@ static abi_long swap_data_eventfd(void *buf, size_t len) } TargetFdTrans target_eventfd_trans = { - .host_to_target_data = swap_data_eventfd, - .target_to_host_data = swap_data_eventfd, + .host_to_target_data = swap_data_u64, + .target_to_host_data = swap_data_u64, +}; + +TargetFdTrans target_timerfd_trans = { + .host_to_target_data = swap_data_u64, }; #if defined(CONFIG_INOTIFY) && (defined(TARGET_NR_inotify_init) || \ diff --git a/linux-user/fd-trans.h b/linux-user/fd-trans.h index 1b9fa20..910faaf 100644 --- a/linux-user/fd-trans.h +++ b/linux-user/fd-trans.h @@ -130,6 +130,7 @@ extern TargetFdTrans target_netlink_route_trans; extern TargetFdTrans target_netlink_audit_trans; extern TargetFdTrans target_signalfd_trans; extern TargetFdTrans target_eventfd_trans; +extern TargetFdTrans target_timerfd_trans; #if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \ (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \ defined(__NR_inotify_init1)) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cc650d4..64b71b1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -13108,8 +13108,12 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD) case TARGET_NR_timerfd_create: - return get_errno(timerfd_create(arg1, - target_to_host_bitmask(arg2, fcntl_flags_tbl))); + ret = get_errno(timerfd_create(arg1, + target_to_host_bitmask(arg2, fcntl_flags_tbl))); + if (ret >= 0) { + fd_trans_register(ret, &target_timerfd_trans); + } + return ret; #endif #if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD) -- cgit v1.1 From fa2229dbf8e529f767d86db9e39b7e829c6759ed Mon Sep 17 00:00:00 2001 From: Mathis Marion Date: Mon, 20 Feb 2023 09:58:21 +0100 Subject: linux-user: add target to host netlink conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added conversions for: - IFLA_MTU - IFLA_TXQLEN - IFLA_AF_SPEC AF_INET6 IFLA_INET6_ADDR_GEN_MODE These relate to the libnl functions rtnl_link_set_mtu, rtnl_link_set_txqlen, and rtnl_link_inet6_set_addr_gen_mode. Signed-off-by: Mathis Marion Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230220085822.626798-4-Mathis.Marion@silabs.com> Signed-off-by: Laurent Vivier --- linux-user/fd-trans.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'linux-user') diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index 146aaaa..4852a75 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -1284,6 +1284,49 @@ static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh, return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route); } +static abi_long target_to_host_for_each_nlattr(struct nlattr *nlattr, + size_t len, + abi_long (*target_to_host_nlattr) + (struct nlattr *)) +{ + unsigned short aligned_nla_len; + abi_long ret; + + while (len > sizeof(struct nlattr)) { + if (tswap16(nlattr->nla_len) < sizeof(struct rtattr) || + tswap16(nlattr->nla_len) > len) { + break; + } + nlattr->nla_len = tswap16(nlattr->nla_len); + nlattr->nla_type = tswap16(nlattr->nla_type); + ret = target_to_host_nlattr(nlattr); + if (ret < 0) { + return ret; + } + + aligned_nla_len = NLA_ALIGN(nlattr->nla_len); + if (aligned_nla_len >= len) { + break; + } + len -= aligned_nla_len; + nlattr = (struct nlattr *)(((char *)nlattr) + aligned_nla_len); + } + return 0; +} + +static abi_long target_to_host_data_inet6_nlattr(struct nlattr *nlattr) +{ + switch (nlattr->nla_type) { + /* uint8_t */ + case QEMU_IFLA_INET6_ADDR_GEN_MODE: + break; + default: + qemu_log_mask(LOG_UNIMP, "Unknown target AF_INET6 type: %d\n", + nlattr->nla_type); + } + return 0; +} + static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr, size_t len, abi_long (*target_to_host_rtattr) @@ -1314,16 +1357,35 @@ static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr, return 0; } +static abi_long target_to_host_data_spec_nlattr(struct nlattr *nlattr) +{ + switch (nlattr->nla_type) { + case AF_INET6: + return target_to_host_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len, + target_to_host_data_inet6_nlattr); + default: + qemu_log_mask(LOG_UNIMP, "Unknown target AF_SPEC type: %d\n", + nlattr->nla_type); + break; + } + return 0; +} + static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr) { uint32_t *u32; switch (rtattr->rta_type) { /* uint32_t */ + case QEMU_IFLA_MTU: + case QEMU_IFLA_TXQLEN: case QEMU_IFLA_EXT_MASK: u32 = RTA_DATA(rtattr); *u32 = tswap32(*u32); break; + case QEMU_IFLA_AF_SPEC: + return target_to_host_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len, + target_to_host_data_spec_nlattr); default: qemu_log_mask(LOG_UNIMP, "Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type); -- cgit v1.1 From 9c1da8b5ee7f6e80e6b683e7fb73df1029a7cbbe Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Fri, 24 Feb 2023 01:39:06 +0100 Subject: linux-user: Fix unaligned memory access in prlimit64 syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit target_rlimit64 contains uint64_t fields, so it's 8-byte aligned on some hosts, while some guests may align their respective type on a 4-byte boundary. This may lead to an unaligned access, which is an UB. Fix by defining the fields as abi_ullong. This makes the host alignment match that of the guest, and lets the compiler know that it should emit code that can deal with the guest alignment. While at it, also use __get_user() and __put_user() instead of tswap64(). Fixes: 163a05a8398b ("linux-user: Implement prlimit64 syscall") Reported-by: Richard Henderson Signed-off-by: Ilya Leoshkevich Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230224003907.263914-2-iii@linux.ibm.com> Signed-off-by: Laurent Vivier --- linux-user/generic/target_resource.h | 4 ++-- linux-user/syscall.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'linux-user') diff --git a/linux-user/generic/target_resource.h b/linux-user/generic/target_resource.h index 539d8c4..37d3eb0 100644 --- a/linux-user/generic/target_resource.h +++ b/linux-user/generic/target_resource.h @@ -12,8 +12,8 @@ struct target_rlimit { }; struct target_rlimit64 { - uint64_t rlim_cur; - uint64_t rlim_max; + abi_ullong rlim_cur; + abi_ullong rlim_max; }; #define TARGET_RLIM_INFINITY ((abi_ulong)-1) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 64b71b1..69cc4b6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -12876,8 +12876,8 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) { return -TARGET_EFAULT; } - rnew.rlim_cur = tswap64(target_rnew->rlim_cur); - rnew.rlim_max = tswap64(target_rnew->rlim_max); + __get_user(rnew.rlim_cur, &target_rnew->rlim_cur); + __get_user(rnew.rlim_max, &target_rnew->rlim_max); unlock_user_struct(target_rnew, arg3, 0); rnewp = &rnew; } @@ -12887,8 +12887,8 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) { return -TARGET_EFAULT; } - target_rold->rlim_cur = tswap64(rold.rlim_cur); - target_rold->rlim_max = tswap64(rold.rlim_max); + __put_user(rold.rlim_cur, &target_rold->rlim_cur); + __put_user(rold.rlim_max, &target_rold->rlim_max); unlock_user_struct(target_rold, arg4, 1); } return ret; -- cgit v1.1 From d2796be69d7c14b8675e87af54b1e469bf509fe3 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sat, 4 Feb 2023 22:12:30 -0800 Subject: linux-user: add support for xtensa FDPIC Define xtensa-specific info_is_fdpic and fill in FDPIC-specific registers in the xtensa version of init_thread. Signed-off-by: Max Filippov Message-Id: <20230205061230.544451-1-jcmvbkbc@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5928c14..150d1d4 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1748,6 +1748,15 @@ static inline void init_thread(struct target_pt_regs *regs, regs->windowstart = 1; regs->areg[1] = infop->start_stack; regs->pc = infop->entry; + if (info_is_fdpic(infop)) { + regs->areg[4] = infop->loadmap_addr; + regs->areg[5] = infop->interpreter_loadmap_addr; + if (infop->interpreter_loadmap_addr) { + regs->areg[6] = infop->interpreter_pt_dynamic_addr; + } else { + regs->areg[6] = infop->pt_dynamic_addr; + } + } } /* See linux kernel: arch/xtensa/include/asm/elf.h. */ @@ -2207,11 +2216,16 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot) } } -#ifdef TARGET_ARM +#if defined(TARGET_ARM) static int elf_is_fdpic(struct elfhdr *exec) { return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC; } +#elif defined(TARGET_XTENSA) +static int elf_is_fdpic(struct elfhdr *exec) +{ + return exec->e_ident[EI_OSABI] == ELFOSABI_XTENSA_FDPIC; +} #else /* Default implementation, always false. */ static int elf_is_fdpic(struct elfhdr *exec) -- cgit v1.1 From 25bb27c715f6ea7cd68561112cbfc1dba4ff46bd Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 6 Mar 2023 10:59:29 +0100 Subject: linux-user: fill out task state in /proc/self/stat Some programs want to match an actual task state character. Signed-off-by: Andreas Schwab Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux-user') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 69cc4b6..49a4fee 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8079,6 +8079,9 @@ static int open_self_stat(CPUArchState *cpu_env, int fd) gchar *bin = g_strrstr(ts->bprm->argv[0], "/"); bin = bin ? bin + 1 : ts->bprm->argv[0]; g_string_printf(buf, "(%.15s) ", bin); + } else if (i == 2) { + /* task state */ + g_string_assign(buf, "R "); /* we are running right now */ } else if (i == 3) { /* ppid */ g_string_printf(buf, FMT_pid " ", getppid()); -- cgit v1.1 From 86f04735ac2088d5c069c3d1712212ec7428c562 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 25 Dec 2022 09:23:19 +0100 Subject: linux-user: Fix brk() to release pages The current brk() implementation does not de-allocate pages if a lower address is given compared to earlier brk() calls. But according to the manpage, brk() shall deallocate memory in this case and currently it breaks a real-world application, specifically building the debian gcl package in qemu-user. Fix this issue by reworking the qemu brk() implementation. Tested with the C-code testcase included in qemu commit 4d1de87c750, and by building debian package of gcl in a hppa-linux guest on a x86-64 host. Signed-off-by: Helge Deller Message-Id: Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 69 ++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) (limited to 'linux-user') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 49a4fee..931f9db 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -795,49 +795,52 @@ static inline int host_to_target_sock_type(int host_type) } static abi_ulong target_brk; -static abi_ulong target_original_brk; static abi_ulong brk_page; void target_set_brk(abi_ulong new_brk) { - target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); + target_brk = new_brk; brk_page = HOST_PAGE_ALIGN(target_brk); } -//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0) -#define DEBUGF_BRK(message, args...) - /* do_brk() must return target values and target errnos. */ -abi_long do_brk(abi_ulong new_brk) +abi_long do_brk(abi_ulong brk_val) { abi_long mapped_addr; abi_ulong new_alloc_size; + abi_ulong new_brk, new_host_brk_page; /* brk pointers are always untagged */ - DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk); - - if (!new_brk) { - DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk); + /* return old brk value if brk_val unchanged or zero */ + if (!brk_val || brk_val == target_brk) { return target_brk; } - if (new_brk < target_original_brk) { - DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n", - target_brk); + + new_brk = TARGET_PAGE_ALIGN(brk_val); + new_host_brk_page = HOST_PAGE_ALIGN(brk_val); + + /* brk_val and old target_brk might be on the same page */ + if (new_brk == TARGET_PAGE_ALIGN(target_brk)) { + if (brk_val > target_brk) { + /* empty remaining bytes in (possibly larger) host page */ + memset(g2h_untagged(target_brk), 0, new_host_brk_page - target_brk); + } + target_brk = brk_val; return target_brk; } - /* If the new brk is less than the highest page reserved to the - * target heap allocation, set it and we're almost done... */ - if (new_brk <= brk_page) { - /* Heap contents are initialized to zero, as for anonymous - * mapped pages. */ - if (new_brk > target_brk) { - memset(g2h_untagged(target_brk), 0, new_brk - target_brk); - } - target_brk = new_brk; - DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk); - return target_brk; + /* Release heap if necesary */ + if (new_brk < target_brk) { + /* empty remaining bytes in (possibly larger) host page */ + memset(g2h_untagged(brk_val), 0, new_host_brk_page - brk_val); + + /* free unused host pages and set new brk_page */ + target_munmap(new_host_brk_page, brk_page - new_host_brk_page); + brk_page = new_host_brk_page; + + target_brk = brk_val; + return target_brk; } /* We need to allocate more memory after the brk... Note that @@ -846,10 +849,14 @@ abi_long do_brk(abi_ulong new_brk) * itself); instead we treat "mapped but at wrong address" as * a failure and unmap again. */ - new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page); - mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, + new_alloc_size = new_host_brk_page - brk_page; + if (new_alloc_size) { + mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0)); + } else { + mapped_addr = brk_page; + } if (mapped_addr == brk_page) { /* Heap contents are initialized to zero, as for anonymous @@ -861,10 +868,8 @@ abi_long do_brk(abi_ulong new_brk) * then shrunken). */ memset(g2h_untagged(target_brk), 0, brk_page - target_brk); - target_brk = new_brk; - brk_page = HOST_PAGE_ALIGN(target_brk); - DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n", - target_brk); + target_brk = brk_val; + brk_page = new_host_brk_page; return target_brk; } else if (mapped_addr != -1) { /* Mapped but at wrong address, meaning there wasn't actually @@ -872,10 +877,6 @@ abi_long do_brk(abi_ulong new_brk) */ target_munmap(mapped_addr, new_alloc_size); mapped_addr = -1; - DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk); - } - else { - DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk); } #if defined(TARGET_ALPHA) -- cgit v1.1 From 8e0f5c1b10e18538083e96c0dddbd78c83d5b2fa Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 31 Jan 2023 18:18:36 +0100 Subject: linux-user: Provide print_raw_param64() for 64-bit values Add a new function print_raw_param64() to print 64-bit values in the same way as print_raw_param(). This prevents that qemu_log() is used to work around the problem that print_raw_param() can only print 32-bit values when compiled for 32-bit targets. Additionally convert the existing 64-bit users in print_timespec64(), print_rlimit64() and print_preadwrite64() over to this new function and drop some unneccessary spaces. Suggested-by: Laurent Vivier Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: [lvivier: remove print_preadwrite64 and print_rlimit64 part] Signed-off-by: Laurent Vivier --- linux-user/strace.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'linux-user') diff --git a/linux-user/strace.c b/linux-user/strace.c index 3400106..5218e3f 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -81,6 +81,7 @@ UNUSED static void print_syscall_epilogue(const struct syscallname *); UNUSED static void print_string(abi_long, int); UNUSED static void print_buf(abi_long addr, abi_long len, int last); UNUSED static void print_raw_param(const char *, abi_long, int); +UNUSED static void print_raw_param64(const char *, long long, int last); UNUSED static void print_timeval(abi_ulong, int); UNUSED static void print_timespec(abi_ulong, int); UNUSED static void print_timespec64(abi_ulong, int); @@ -1642,6 +1643,19 @@ print_raw_param(const char *fmt, abi_long param, int last) qemu_log(format, param); } +/* + * Same as print_raw_param() but prints out raw 64-bit parameter. + */ +static void +print_raw_param64(const char *fmt, long long param, int last) +{ + char format[64]; + + (void)snprintf(format, sizeof(format), "%s%s", fmt, get_comma(last)); + qemu_log(format, param); +} + + static void print_pointer(abi_long p, int last) { @@ -1718,10 +1732,8 @@ print_timespec64(abi_ulong ts_addr, int last) print_pointer(ts_addr, last); return; } - qemu_log("{tv_sec = %lld" - ",tv_nsec = %lld}%s", - (long long)tswap64(ts->tv_sec), (long long)tswap64(ts->tv_nsec), - get_comma(last)); + print_raw_param64("{tv_sec=%" PRId64, tswap64(ts->tv_sec), 0); + print_raw_param64("tv_nsec=%" PRId64 "}", tswap64(ts->tv_nsec), last); unlock_user(ts, ts_addr, 0); } else { qemu_log("NULL%s", get_comma(last)); -- cgit v1.1 From dae81a083b13fe1607d369f103b0357a610a3167 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 22 Dec 2022 20:06:39 +0100 Subject: linux-user: Add strace for prlimit64() syscall Add proper prlimit64() strace output. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: <20221222190639.124078-1-deller@gmx.de> [lvivier: use print_raw_param64()] Signed-off-by: Laurent Vivier --- linux-user/strace.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/strace.list | 3 +- 2 files changed, 90 insertions(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/strace.c b/linux-user/strace.c index 5218e3f..e08bd53 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -3866,6 +3866,94 @@ print_futex(CPUArchState *cpu_env, const struct syscallname *name, } #endif +#ifdef TARGET_NR_prlimit64 +static const char *target_ressource_string(abi_ulong r) +{ + #define RET_RES_ENTRY(res) case TARGET_##res: return #res; + switch (r) { + RET_RES_ENTRY(RLIMIT_AS); + RET_RES_ENTRY(RLIMIT_CORE); + RET_RES_ENTRY(RLIMIT_CPU); + RET_RES_ENTRY(RLIMIT_DATA); + RET_RES_ENTRY(RLIMIT_FSIZE); + RET_RES_ENTRY(RLIMIT_LOCKS); + RET_RES_ENTRY(RLIMIT_MEMLOCK); + RET_RES_ENTRY(RLIMIT_MSGQUEUE); + RET_RES_ENTRY(RLIMIT_NICE); + RET_RES_ENTRY(RLIMIT_NOFILE); + RET_RES_ENTRY(RLIMIT_NPROC); + RET_RES_ENTRY(RLIMIT_RSS); + RET_RES_ENTRY(RLIMIT_RTPRIO); +#ifdef RLIMIT_RTTIME + RET_RES_ENTRY(RLIMIT_RTTIME); +#endif + RET_RES_ENTRY(RLIMIT_SIGPENDING); + RET_RES_ENTRY(RLIMIT_STACK); + default: + return NULL; + } + #undef RET_RES_ENTRY +} + +static void +print_rlimit64(abi_ulong rlim_addr, int last) +{ + if (rlim_addr) { + struct target_rlimit64 *rl; + + rl = lock_user(VERIFY_READ, rlim_addr, sizeof(*rl), 1); + if (!rl) { + print_pointer(rlim_addr, last); + return; + } + print_raw_param64("{rlim_cur=%" PRId64, tswap64(rl->rlim_cur), 0); + print_raw_param64("rlim_max=%" PRId64 "}", tswap64(rl->rlim_max), + last); + unlock_user(rl, rlim_addr, 0); + } else { + qemu_log("NULL%s", get_comma(last)); + } +} + +static void +print_prlimit64(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + const char *rlim_name; + + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + rlim_name = target_ressource_string(arg1); + if (rlim_name) { + qemu_log("%s,", rlim_name); + } else { + print_raw_param("%d", arg1, 0); + } + print_rlimit64(arg2, 0); + print_pointer(arg3, 1); + print_syscall_epilogue(name); +} + +static void +print_syscall_ret_prlimit64(CPUArchState *cpu_env, + const struct syscallname *name, + abi_long ret, abi_long arg0, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5) +{ + if (!print_syscall_err(ret)) { + qemu_log(TARGET_ABI_FMT_ld, ret); + if (arg3) { + qemu_log(" ("); + print_rlimit64(arg3, 1); + qemu_log(")"); + } + } + qemu_log("\n"); +} +#endif + #ifdef TARGET_NR_kill static void print_kill(CPUArchState *cpu_env, const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index d8acbee..f776c73 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1074,7 +1074,8 @@ { TARGET_NR_preadv, "preadv" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_prlimit64 -{ TARGET_NR_prlimit64, "prlimit64" , NULL, NULL, NULL }, +{ TARGET_NR_prlimit64, "prlimit64" , NULL, print_prlimit64, + print_syscall_ret_prlimit64 }, #endif #ifdef TARGET_NR_process_vm_readv { TARGET_NR_process_vm_readv, "process_vm_readv" , NULL, NULL, NULL }, -- cgit v1.1 From 44cf6731d6b9a48bcd57392e8cd6f0f712aaa677 Mon Sep 17 00:00:00 2001 From: Mathis Marion Date: Tue, 7 Mar 2023 16:42:55 +0100 Subject: linux-user: fix sockaddr_in6 endianness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sin6_scope_id field uses the host byte order, so there is a conversion to be made when host and target endianness differ. Signed-off-by: Mathis Marion Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230307154256.101528-2-Mathis.Marion@silabs.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'linux-user') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 931f9db..05c8107 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1714,6 +1714,11 @@ static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr, lladdr = (struct target_sockaddr_ll *)addr; lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex); lladdr->sll_hatype = tswap16(lladdr->sll_hatype); + } else if (sa_family == AF_INET6) { + struct sockaddr_in6 *in6addr; + + in6addr = (struct sockaddr_in6 *)addr; + in6addr->sin6_scope_id = tswap32(in6addr->sin6_scope_id); } unlock_user(target_saddr, target_addr, 0); -- cgit v1.1 From 2fe8ed6fe9dd8c50f06c16921b42d6f0e17f9f7c Mon Sep 17 00:00:00 2001 From: Mathis Marion Date: Tue, 7 Mar 2023 16:42:56 +0100 Subject: linux-user: handle netlink flag NLA_F_NESTED Newer kernel versions require this flag to be present contrary to older ones. Depending on the libnl version it is added or not. Typically when using rtnl_link_inet6_set_addr_gen_mode, the netlink packet generated may contain the following attribute: with libnl 3.4 {nla_len=16, nla_type=IFLA_AF_SPEC}, [ {nla_len=12, nla_type=AF_INET6}, [{nla_len=5, nla_type=IFLA_INET6_ADDR_GEN_MODE}, IN6_ADDR_GEN_MODE_NONE] ] with libnl 3.7 {nla_len=16, nla_type=NLA_F_NESTED|IFLA_AF_SPEC}, [ {nla_len=12, nla_type=NLA_F_NESTED|AF_INET6}, [{nla_len=5, nla_type=IFLA_INET6_ADDR_GEN_MODE}, IN6_ADDR_GEN_MODE_NONE]] ] Masking the type is likely needed in other places. Only the above cases are implemented in this patch. Signed-off-by: Mathis Marion Reviewed-by: Laurent Vivier Message-Id: <20230307154256.101528-3-Mathis.Marion@silabs.com> Signed-off-by: Laurent Vivier --- linux-user/fd-trans.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-user') diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index 4852a75..c04a97c 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -1359,7 +1359,7 @@ static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr, static abi_long target_to_host_data_spec_nlattr(struct nlattr *nlattr) { - switch (nlattr->nla_type) { + switch (nlattr->nla_type & NLA_TYPE_MASK) { case AF_INET6: return target_to_host_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len, target_to_host_data_inet6_nlattr); @@ -1375,7 +1375,7 @@ static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr) { uint32_t *u32; - switch (rtattr->rta_type) { + switch (rtattr->rta_type & NLA_TYPE_MASK) { /* uint32_t */ case QEMU_IFLA_MTU: case QEMU_IFLA_TXQLEN: -- cgit v1.1 From fe080593dd4f2c2763f7c27a3ba6e69b64fe3b0c Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 15 Dec 2022 08:27:46 +0100 Subject: linux-user: Add translation for argument of msync() msync() uses the flags MS_ASYNC, MS_INVALIDATE and MS_SYNC, which differ between platforms, specifcally on alpha and hppa. Add a target to host translation for those and wire up a nicer strace output. This fixes the testsuite of the macaulay2 debian package with a hppa-linux guest on a x86-64 host. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/alpha/target_mman.h | 4 ++++ linux-user/generic/target_mman.h | 13 +++++++++++++ linux-user/hppa/target_mman.h | 4 ++++ linux-user/strace.list | 2 +- linux-user/syscall.c | 12 +++++++++++- 5 files changed, 33 insertions(+), 2 deletions(-) (limited to 'linux-user') diff --git a/linux-user/alpha/target_mman.h b/linux-user/alpha/target_mman.h index cd6e3d7..051544f 100644 --- a/linux-user/alpha/target_mman.h +++ b/linux-user/alpha/target_mman.h @@ -3,6 +3,10 @@ #define TARGET_MADV_DONTNEED 6 +#define TARGET_MS_ASYNC 1 +#define TARGET_MS_SYNC 2 +#define TARGET_MS_INVALIDATE 4 + #include "../generic/target_mman.h" #endif diff --git a/linux-user/generic/target_mman.h b/linux-user/generic/target_mman.h index 1436a3c..32bf1a5 100644 --- a/linux-user/generic/target_mman.h +++ b/linux-user/generic/target_mman.h @@ -89,4 +89,17 @@ #define TARGET_MADV_DONTNEED_LOCKED 24 #endif + +#ifndef TARGET_MS_ASYNC +#define TARGET_MS_ASYNC 1 +#endif + +#ifndef TARGET_MS_INVALIDATE +#define TARGET_MS_INVALIDATE 2 +#endif + +#ifndef TARGET_MS_SYNC +#define TARGET_MS_SYNC 4 +#endif + #endif diff --git a/linux-user/hppa/target_mman.h b/linux-user/hppa/target_mman.h index 66dd9f7..f9b6b97 100644 --- a/linux-user/hppa/target_mman.h +++ b/linux-user/hppa/target_mman.h @@ -10,6 +10,10 @@ #define TARGET_MADV_WIPEONFORK 71 #define TARGET_MADV_KEEPONFORK 72 +#define TARGET_MS_SYNC 1 +#define TARGET_MS_ASYNC 2 +#define TARGET_MS_INVALIDATE 4 + #include "../generic/target_mman.h" #endif diff --git a/linux-user/strace.list b/linux-user/strace.list index f776c73..c7808ea 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -656,7 +656,7 @@ { TARGET_NR_msgsnd, "msgsnd" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_msync -{ TARGET_NR_msync, "msync" , NULL, NULL, NULL }, +{ TARGET_NR_msync, "msync" , "%s(%p,%u,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_multiplexer { TARGET_NR_multiplexer, "multiplexer" , NULL, NULL, NULL }, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 05c8107..dad2c33 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -22,6 +22,7 @@ #include "qemu/path.h" #include "qemu/memfd.h" #include "qemu/queue.h" +#include "target_mman.h" #include #include #include @@ -7612,6 +7613,14 @@ static inline int target_to_host_mlockall_arg(int arg) } #endif +static inline int target_to_host_msync_arg(abi_long arg) +{ + return ((arg & TARGET_MS_ASYNC) ? MS_ASYNC : 0) | + ((arg & TARGET_MS_INVALIDATE) ? MS_INVALIDATE : 0) | + ((arg & TARGET_MS_SYNC) ? MS_SYNC : 0) | + (arg & ~(TARGET_MS_ASYNC | TARGET_MS_INVALIDATE | TARGET_MS_SYNC)); +} + #if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) || \ defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) || \ defined(TARGET_NR_newfstatat)) @@ -10128,7 +10137,8 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, /* ??? msync/mlock/munlock are broken for softmmu. */ #ifdef TARGET_NR_msync case TARGET_NR_msync: - return get_errno(msync(g2h(cpu, arg1), arg2, arg3)); + return get_errno(msync(g2h(cpu, arg1), arg2, + target_to_host_msync_arg(arg3))); #endif #ifdef TARGET_NR_mlock case TARGET_NR_mlock: -- cgit v1.1 From 895ce8bb534e66ca418dea62ae67a92dccafb2e1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 29 Nov 2022 12:08:20 +0100 Subject: linux-user: Emulate CLONE_PIDFD flag in clone() Add emulation for the CLONE_PIDFD flag of the clone() syscall. This flag was added in Linux kernel 5.2. Successfully tested on a x86-64 Linux host with hppa-linux target. Can be verified by running the testsuite of the qcoro debian package, which breaks hard and kills the currently logged-in user without this patch. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: [lv: define CLONE_PIDFD if it is not] Signed-off-by: Laurent Vivier --- linux-user/strace.c | 5 +++++ linux-user/syscall.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/strace.c b/linux-user/strace.c index e08bd53..aad2b62 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1111,11 +1111,16 @@ UNUSED static const struct flags mmap_flags[] = { FLAG_END, }; +#ifndef CLONE_PIDFD +# define CLONE_PIDFD 0x00001000 +#endif + UNUSED static const struct flags clone_flags[] = { FLAG_GENERIC(CLONE_VM), FLAG_GENERIC(CLONE_FS), FLAG_GENERIC(CLONE_FILES), FLAG_GENERIC(CLONE_SIGHAND), + FLAG_GENERIC(CLONE_PIDFD), FLAG_GENERIC(CLONE_PTRACE), FLAG_GENERIC(CLONE_VFORK), FLAG_GENERIC(CLONE_PARENT), diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dad2c33..24cea6f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -169,9 +169,13 @@ #define CLONE_IGNORED_FLAGS \ (CLONE_DETACHED | CLONE_IO) +#ifndef CLONE_PIDFD +# define CLONE_PIDFD 0x00001000 +#endif + /* Flags for fork which we can implement within QEMU itself */ #define CLONE_OPTIONAL_FORK_FLAGS \ - (CLONE_SETTLS | CLONE_PARENT_SETTID | \ + (CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_PIDFD | \ CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID) /* Flags for thread creation which we can implement within QEMU itself */ @@ -6730,6 +6734,17 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, return -TARGET_EINVAL; } +#if !defined(__NR_pidfd_open) || !defined(TARGET_NR_pidfd_open) + if (flags & CLONE_PIDFD) { + return -TARGET_EINVAL; + } +#endif + + /* Can not allow CLONE_PIDFD with CLONE_PARENT_SETTID */ + if ((flags & CLONE_PIDFD) && (flags & CLONE_PARENT_SETTID)) { + return -TARGET_EINVAL; + } + if (block_signals()) { return -QEMU_ERESTARTSYS; } @@ -6757,6 +6772,20 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, ts->child_tidptr = child_tidptr; } else { cpu_clone_regs_parent(env, flags); + if (flags & CLONE_PIDFD) { + int pid_fd = 0; +#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open) + int pid_child = ret; + pid_fd = pidfd_open(pid_child, 0); + if (pid_fd >= 0) { + fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL) + | FD_CLOEXEC); + } else { + pid_fd = 0; + } +#endif + put_user_u32(pid_fd, parent_tidptr); + } fork_end(0); } g_assert(!cpu_in_exclusive_context(cpu)); -- cgit v1.1 From 3116f020d455a0bff7bdc86c20dfc1a63a36f729 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:03 -1000 Subject: linux-user/sparc: Tidy syscall trap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use TT_TRAP. For sparc32, 0x88 is the "Slowaris" system call, currently BAD_TRAP in the kernel's ttable_32.S. For sparc64, 0x110 is tl0_linux32, the sparc32 trap, now folded into the TARGET_ABI32 case via TT_TRAP. For sparc64, there does still exist trap 0x111 as tl0_oldlinux64, which was replaced by 0x16d as tl0_linux64 in 1998. Since no one has noticed, don't bother implementing it now. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230216054516.1267305-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index c120c42..d31ea05 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -149,6 +149,12 @@ static void flush_windows(CPUSPARCState *env) #endif } +#ifdef TARGET_ABI32 +#define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */ +#else +#define TARGET_TT_SYSCALL (TT_TRAP + 0x6d) /* tl0_linux64 */ +#endif + void cpu_loop (CPUSPARCState *env) { CPUState *cs = env_cpu(env); @@ -167,13 +173,7 @@ void cpu_loop (CPUSPARCState *env) } switch (trapnr) { -#ifndef TARGET_SPARC64 - case 0x88: - case 0x90: -#else - case 0x110: - case 0x16d: -#endif + case TARGET_TT_SYSCALL: ret = do_syscall (env, env->gregs[1], env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], -- cgit v1.1 From 9cee640a444a5b861d15178a19a26065d77aae8b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:04 -1000 Subject: linux-user/sparc: Tidy syscall error return Reduce ifdefs with #define syscall_cc. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-4-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index d31ea05..051a292 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -149,10 +149,13 @@ static void flush_windows(CPUSPARCState *env) #endif } +/* Avoid ifdefs below for the abi32 and abi64 paths. */ #ifdef TARGET_ABI32 #define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */ +#define syscall_cc psr #else #define TARGET_TT_SYSCALL (TT_TRAP + 0x6d) /* tl0_linux64 */ +#define syscall_cc xcc #endif void cpu_loop (CPUSPARCState *env) @@ -183,18 +186,10 @@ void cpu_loop (CPUSPARCState *env) break; } if ((abi_ulong)ret >= (abi_ulong)(-515)) { -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - env->xcc |= PSR_CARRY; -#else - env->psr |= PSR_CARRY; -#endif + env->syscall_cc |= PSR_CARRY; ret = -ret; } else { -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - env->xcc &= ~PSR_CARRY; -#else - env->psr &= ~PSR_CARRY; -#endif + env->syscall_cc &= ~PSR_CARRY; } env->regwptr[0] = ret; /* next instruction */ -- cgit v1.1 From 88cdb6032f7ff1fb3bab7c517c53cf20095f1e30 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:05 -1000 Subject: linux-user/sparc: Use TT_TRAP for flush windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v9 and pre-v9 code can be unified with this macro. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230216054516.1267305-5-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 051a292..e1d08ff 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -196,15 +196,14 @@ void cpu_loop (CPUSPARCState *env) env->pc = env->npc; env->npc = env->npc + 4; break; - case 0x83: /* flush windows */ -#ifdef TARGET_ABI32 - case 0x103: -#endif + + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ env->pc = env->npc; env->npc = env->npc + 4; break; + #ifndef TARGET_SPARC64 case TT_WIN_OVF: /* window overflow */ save_window(env); -- cgit v1.1 From 6f772241e6d0b154c4a99c8f4c55e9ebe5173a09 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:06 -1000 Subject: linux-user/sparc: Tidy window spill/fill traps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some macros to localize the hw difference between v9 and pre-v9. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230216054516.1267305-6-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index e1d08ff..2bcf325 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -158,6 +158,15 @@ static void flush_windows(CPUSPARCState *env) #define syscall_cc xcc #endif +/* Avoid ifdefs below for the v9 and pre-v9 hw traps. */ +#ifdef TARGET_SPARC64 +#define TARGET_TT_SPILL TT_SPILL +#define TARGET_TT_FILL TT_FILL +#else +#define TARGET_TT_SPILL TT_WIN_OVF +#define TARGET_TT_FILL TT_WIN_UNF +#endif + void cpu_loop (CPUSPARCState *env) { CPUState *cs = env_cpu(env); @@ -204,20 +213,14 @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; -#ifndef TARGET_SPARC64 - case TT_WIN_OVF: /* window overflow */ - save_window(env); - break; - case TT_WIN_UNF: /* window underflow */ - restore_window(env); - break; -#else - case TT_SPILL: /* window overflow */ + case TARGET_TT_SPILL: /* window overflow */ save_window(env); break; - case TT_FILL: /* window underflow */ + case TARGET_TT_FILL: /* window underflow */ restore_window(env); break; + +#ifdef TARGET_SPARC64 #ifndef TARGET_ABI32 case 0x16e: flush_windows(env); -- cgit v1.1 From d6b036378004c27579aa68bf0174e4e8fbfff726 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:07 -1000 Subject: linux-user/sparc: Fix sparc64_{get, set}_context traps These traps are present for sparc64 with ilp32, aka sparc32plus. Enabling them means adjusting the defines over in signal.c, and fixing an incorrect usage of abi_ulong when we really meant the full register, target_ulong. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-7-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 21 ++++++++++----------- linux-user/sparc/signal.c | 36 +++++++++++++++++++----------------- 2 files changed, 29 insertions(+), 28 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 2bcf325..edbc4f3 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -213,25 +213,24 @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; - case TARGET_TT_SPILL: /* window overflow */ - save_window(env); - break; - case TARGET_TT_FILL: /* window underflow */ - restore_window(env); - break; - #ifdef TARGET_SPARC64 -#ifndef TARGET_ABI32 - case 0x16e: + case TT_TRAP + 0x6e: flush_windows(env); sparc64_get_context(env); break; - case 0x16f: + case TT_TRAP + 0x6f: flush_windows(env); sparc64_set_context(env); break; #endif -#endif + + case TARGET_TT_SPILL: /* window overflow */ + save_window(env); + break; + case TARGET_TT_FILL: /* window underflow */ + restore_window(env); + break; + case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index b501750..2be9000 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -503,7 +503,23 @@ long do_rt_sigreturn(CPUSPARCState *env) return -QEMU_ESIGRETURN; } -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) +#ifdef TARGET_ABI32 +void setup_sigtramp(abi_ulong sigtramp_page) +{ + uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0); + assert(tramp != NULL); + + default_sigreturn = sigtramp_page; + install_sigtramp(tramp, TARGET_NR_sigreturn); + + default_rt_sigreturn = sigtramp_page + 8; + install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn); + + unlock_user(tramp, sigtramp_page, 2 * 8); +} +#endif + +#ifdef TARGET_SPARC64 #define SPARC_MC_TSTATE 0 #define SPARC_MC_PC 1 #define SPARC_MC_NPC 2 @@ -575,7 +591,7 @@ void sparc64_set_context(CPUSPARCState *env) struct target_ucontext *ucp; target_mc_gregset_t *grp; target_mc_fpu_t *fpup; - abi_ulong pc, npc, tstate; + target_ulong pc, npc, tstate; unsigned int i; unsigned char fenab; @@ -773,18 +789,4 @@ do_sigsegv: unlock_user_struct(ucp, ucp_addr, 1); force_sig(TARGET_SIGSEGV); } -#else -void setup_sigtramp(abi_ulong sigtramp_page) -{ - uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0); - assert(tramp != NULL); - - default_sigreturn = sigtramp_page; - install_sigtramp(tramp, TARGET_NR_sigreturn); - - default_rt_sigreturn = sigtramp_page + 8; - install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn); - - unlock_user(tramp, sigtramp_page, 2 * 8); -} -#endif +#endif /* TARGET_SPARC64 */ -- cgit v1.1 From 52d104a5a5eaf0440369c20757ff5d170fd0ebc2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:08 -1000 Subject: linux-user/sparc: Handle software breakpoint trap This is 'ta 1' for both v9 and pre-v9. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-8-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index edbc4f3..c14eaea 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -206,6 +206,11 @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; + case TT_TRAP + 0x01: /* breakpoint */ + case EXCP_DEBUG: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); + break; + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ @@ -237,9 +242,6 @@ void cpu_loop (CPUSPARCState *env) case TT_ILL_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); break; - case EXCP_DEBUG: - force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); - break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- cgit v1.1 From 0908007f76bd3af297e6abdf6edb83a18b0938e0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:09 -1000 Subject: linux-user/sparc: Handle division by zero traps In addition to the hw trap vector, there is a software trap assigned for older sparc without hw division instructions. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-9-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index c14eaea..e04c842 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -211,6 +211,11 @@ void cpu_loop (CPUSPARCState *env) force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; + case TT_TRAP + 0x02: /* div0 */ + case TT_DIV_ZERO: + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); + break; + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ -- cgit v1.1 From 6abc58eb9772aad23d12c4c43dda7713576b58ac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:10 -1000 Subject: linux-user/sparc: Handle getcc, setcc, getpsr traps These are really only meaningful for sparc32, but they're still present for backward compatibility for sparc64. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-10-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 62 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index e04c842..a3edb35 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -149,6 +149,51 @@ static void flush_windows(CPUSPARCState *env) #endif } +static void next_instruction(CPUSPARCState *env) +{ + env->pc = env->npc; + env->npc = env->npc + 4; +} + +static uint32_t do_getcc(CPUSPARCState *env) +{ +#ifdef TARGET_SPARC64 + return cpu_get_ccr(env) & 0xf; +#else + return extract32(cpu_get_psr(env), 20, 4); +#endif +} + +static void do_setcc(CPUSPARCState *env, uint32_t icc) +{ +#ifdef TARGET_SPARC64 + cpu_put_ccr(env, (cpu_get_ccr(env) & 0xf0) | (icc & 0xf)); +#else + cpu_put_psr(env, deposit32(cpu_get_psr(env), 20, 4, icc)); +#endif +} + +static uint32_t do_getpsr(CPUSPARCState *env) +{ +#ifdef TARGET_SPARC64 + const uint64_t TSTATE_CWP = 0x1f; + const uint64_t TSTATE_ICC = 0xfull << 32; + const uint64_t TSTATE_XCC = 0xfull << 36; + const uint32_t PSR_S = 0x00000080u; + const uint32_t PSR_V8PLUS = 0xff000000u; + uint64_t tstate = sparc64_tstate(env); + + /* See , tstate_to_psr. */ + return ((tstate & TSTATE_CWP) | + PSR_S | + ((tstate & TSTATE_ICC) >> 12) | + ((tstate & TSTATE_XCC) >> 20) | + PSR_V8PLUS); +#else + return (cpu_get_psr(env) & (PSR_ICC | PSR_CWP)) | PSR_S; +#endif +} + /* Avoid ifdefs below for the abi32 and abi64 paths. */ #ifdef TARGET_ABI32 #define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */ @@ -218,9 +263,20 @@ void cpu_loop (CPUSPARCState *env) case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); - /* next instruction */ - env->pc = env->npc; - env->npc = env->npc + 4; + next_instruction(env); + break; + + case TT_TRAP + 0x20: /* getcc */ + env->gregs[1] = do_getcc(env); + next_instruction(env); + break; + case TT_TRAP + 0x21: /* setcc */ + do_setcc(env, env->gregs[1]); + next_instruction(env); + break; + case TT_TRAP + 0x22: /* getpsr */ + env->gregs[1] = do_getpsr(env); + next_instruction(env); break; #ifdef TARGET_SPARC64 -- cgit v1.1 From 97ff1478d2783b8c0e71540085aec66a70f2d52b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:11 -1000 Subject: linux-user/sparc: Handle priviledged opcode trap For the most part priviledged opcodes are ifdefed out of the user-only sparc translator, which will then incorrectly produce illegal opcode traps. But there are some code paths that properly raise TT_PRIV_INSN, so we must handle it. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-11-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index a3edb35..61b6e81 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -303,6 +303,9 @@ void cpu_loop (CPUSPARCState *env) case TT_ILL_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); break; + case TT_PRIV_INSN: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); + break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- cgit v1.1 From 235f33b81834c5e60a53de47e4907da888448be7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:12 -1000 Subject: linux-user/sparc: Handle privilidged action trap This is raised by using an %asi < 0x80 in user-mode. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-12-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 61b6e81..43f19fb 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -306,6 +306,12 @@ void cpu_loop (CPUSPARCState *env) case TT_PRIV_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; +#ifdef TARGET_SPARC64 + case TT_PRIV_ACT: + /* Note do_privact defers to do_privop. */ + force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); + break; +#endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- cgit v1.1 From c47d7c87bf1cc164306a6bf51d550e5f10bcca02 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:13 -1000 Subject: linux-user/sparc: Handle coprocessor disabled trap Since qemu does not implement a sparc coprocessor, all such instructions raise this trap. Because of that, we never raise the coprocessor exception trap, which would be vector 0x28. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-13-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 43f19fb..bf7e102 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -311,6 +311,10 @@ void cpu_loop (CPUSPARCState *env) /* Note do_privact defers to do_privop. */ force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; +#else + case TT_NCP_INSN: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->pc); + break; #endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); -- cgit v1.1 From 81f04cd34ccd3dab6c796a5fbc439a8061b04ef3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:14 -1000 Subject: linux-user/sparc: Handle unimplemented flush trap For sparc64, TT_UNIMP_FLUSH == TT_ILL_INSN, so this is already handled. For sparc32, the kernel uses SKIP_TRAP. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-14-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index bf7e102..093358a 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -315,6 +315,9 @@ void cpu_loop (CPUSPARCState *env) case TT_NCP_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->pc); break; + case TT_UNIMP_FLUSH: + next_instruction(env); + break; #endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); -- cgit v1.1 From 4ea3af392f85dc2e66059855266b3817b321dc90 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:15 -1000 Subject: linux-user/sparc: Handle floating-point exceptions Raise SIGFPE for ieee exceptions. The other types, such as FSR_FTT_UNIMPFPOP, should not appear, because we enable normal emulation of missing insns at the start of sparc_cpu_realizefn(). Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-15-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 093358a..5a8a71e 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -297,6 +297,28 @@ void cpu_loop (CPUSPARCState *env) restore_window(env); break; + case TT_FP_EXCP: + { + int code = TARGET_FPE_FLTUNK; + target_ulong fsr = env->fsr; + + if ((fsr & FSR_FTT_MASK) == FSR_FTT_IEEE_EXCP) { + if (fsr & FSR_NVC) { + code = TARGET_FPE_FLTINV; + } else if (fsr & FSR_OFC) { + code = TARGET_FPE_FLTOVF; + } else if (fsr & FSR_UFC) { + code = TARGET_FPE_FLTUND; + } else if (fsr & FSR_DZC) { + code = TARGET_FPE_FLTDIV; + } else if (fsr & FSR_NXC) { + code = TARGET_FPE_FLTRES; + } + } + force_sig_fault(TARGET_SIGFPE, code, env->pc); + } + break; + case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; -- cgit v1.1 From e64c6d42b652b4acf10d83e1bc86d4fd4ce28ef2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Feb 2023 19:45:16 -1000 Subject: linux-user/sparc: Handle tag overflow traps This trap is raised by taddcctv and tsubcctv insns. Signed-off-by: Richard Henderson Message-Id: <20230216054516.1267305-16-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/cpu_loop.c | 3 +++ linux-user/sparc/target_signal.h | 2 +- linux-user/syscall_defs.h | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 5a8a71e..b36bb25 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -328,6 +328,9 @@ void cpu_loop (CPUSPARCState *env) case TT_PRIV_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; + case TT_TOVF: + force_sig_fault(TARGET_SIGEMT, TARGET_EMT_TAGOVF, env->pc); + break; #ifdef TARGET_SPARC64 case TT_PRIV_ACT: /* Note do_privact defers to do_privop. */ diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h index 87757f0..f223eb4 100644 --- a/linux-user/sparc/target_signal.h +++ b/linux-user/sparc/target_signal.h @@ -8,7 +8,7 @@ #define TARGET_SIGTRAP 5 #define TARGET_SIGABRT 6 #define TARGET_SIGIOT 6 -#define TARGET_SIGSTKFLT 7 /* actually EMT */ +#define TARGET_SIGEMT 7 #define TARGET_SIGFPE 8 #define TARGET_SIGKILL 9 #define TARGET_SIGBUS 10 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 77864de..614a1cb 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -717,6 +717,11 @@ typedef struct target_siginfo { #define TARGET_TRAP_HWBKPT (4) /* hardware breakpoint/watchpoint */ #define TARGET_TRAP_UNK (5) /* undiagnosed trap */ +/* + * SIGEMT si_codes + */ +#define TARGET_EMT_TAGOVF 1 /* tag overflow */ + #include "target_resource.h" struct target_pollfd { -- cgit v1.1 From 2732c739d846fc7a1972e984d71a3de0d3eef77b Mon Sep 17 00:00:00 2001 From: "fanwj@mail.ustc.edu.cn" Date: Wed, 8 Feb 2023 23:49:12 +0800 Subject: linux-user: fix bug about incorrect base addresss of gdt on i386 and x86_64 On linux user mode, CPUX86State::gdt::base from Different CPUX86State Objects have same value, It is incorrect! Every CPUX86State::gdt::base Must points to independent memory space. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1405 Signed-off-by: fanwenjie Message-Id: <4172b90.58b08.18631b77860.Coremail.fanwj@mail.ustc.edu.cn> [lv: remove unnecessary casts, split overlong line] Signed-off-by: Laurent Vivier --- linux-user/i386/cpu_loop.c | 9 +++++++++ linux-user/main.c | 8 ++++++++ 2 files changed, 17 insertions(+) (limited to 'linux-user') diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 865413c..2d0918a 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -314,8 +314,17 @@ void cpu_loop(CPUX86State *env) } } +static void target_cpu_free(void *obj) +{ + CPUArchState *env = ((CPUState *)obj)->env_ptr; + target_munmap(env->gdt.base, sizeof(uint64_t) * TARGET_GDT_ENTRIES); + g_free(obj); +} + void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) { + CPUState *cpu = env_cpu(env); + OBJECT(cpu)->free = target_cpu_free; env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; env->hflags |= HF_PE_MASK | HF_CPL_MASK; if (env->features[FEAT_1_EDX] & CPUID_SSE) { diff --git a/linux-user/main.c b/linux-user/main.c index 798fdc0..47b0c0f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -238,6 +238,14 @@ CPUArchState *cpu_copy(CPUArchState *env) new_cpu->tcg_cflags = cpu->tcg_cflags; memcpy(new_env, env, sizeof(CPUArchState)); +#if defined(TARGET_I386) || defined(TARGET_X86_64) + new_env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(g2h_untagged(new_env->gdt.base), g2h_untagged(env->gdt.base), + sizeof(uint64_t) * TARGET_GDT_ENTRIES); + OBJECT(new_cpu)->free = OBJECT(cpu)->free; +#endif /* Clone all break/watchpoints. Note: Once we support ptrace with hw-debug register access, make sure -- cgit v1.1