aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-10-19 14:39:30 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-10-19 14:39:30 +0100
commitf2a48d696c12aaac12993364371daae9f6233c37 (patch)
tree57a2098280251432d049b2f7f963894f2eae3def /linux-user
parentba6f0fc25e3c14fbb36f4b5a616a89cd3f1de6d0 (diff)
parentf443e3960d9d3340dd286e5fc0b661bb165a8b22 (diff)
Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20171018' into staging
Linux-user updates for Qemu 2.11 # gpg: Signature made Wed 18 Oct 2017 13:20:14 BST # gpg: using RSA key 0xB44890DEDE3C9BC0 # gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>" # gpg: aka "Riku Voipio <riku.voipio@linaro.org>" # Primary key fingerprint: FF82 03C8 C391 98AE 0581 41EF B448 90DE DE3C 9BC0 * remotes/riku/tags/pull-linux-user-20171018: linux-user: Fix TARGET_MTIOCTOP/MTIOCGET/MTIOCPOS values linux-user/main: support dfilter linux-user: Fix target FS_IOC_GETFLAGS and FS_IOC_SETFLAGS numbers linux-user/sh4: Reduce TARGET_VIRT_ADDR_SPACE_BITS to 31 linux-user: Tidy and enforce reserved_va initialization tcg: Fix off-by-one in assert in page_set_flags linux-user: Allow -R values up to 0xffff0000 for 32-bit ARM guests linux-user: remove duplicate break in syscall target/m68k,linux-user: manage FP registers in ucontext linux-user: fix O_TMPFILE handling Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/arm/target_cpu.h4
-rw-r--r--linux-user/elfload.c2
-rw-r--r--linux-user/main.c45
-rw-r--r--linux-user/signal.c43
-rw-r--r--linux-user/strace.c4
-rw-r--r--linux-user/syscall.c3
-rw-r--r--linux-user/syscall_defs.h43
7 files changed, 124 insertions, 20 deletions
diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h
index d888219150..c3eb4b243d 100644
--- a/linux-user/arm/target_cpu.h
+++ b/linux-user/arm/target_cpu.h
@@ -19,6 +19,10 @@
#ifndef ARM_TARGET_CPU_H
#define ARM_TARGET_CPU_H
+/* We need to be able to map the commpage.
+ See validate_guest_space in linux-user/elfload.c. */
+#define MAX_RESERVED_VA 0xffff0000ul
+
static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
{
if (newsp) {
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 79062882ba..3b857fbc9c 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -377,7 +377,7 @@ static int validate_guest_space(unsigned long guest_base,
* then there is no way we can allocate it.
*/
if (test_page_addr >= guest_base
- && test_page_addr <= (guest_base + guest_size)) {
+ && test_page_addr < (guest_base + guest_size)) {
return -1;
}
diff --git a/linux-user/main.c b/linux-user/main.c
index 829f974662..dde04c769a 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -60,23 +60,38 @@ do { \
} \
} while (0)
-#if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
/*
* When running 32-on-64 we should make sure we can fit all of the possible
* guest address space into a contiguous chunk of virtual host memory.
*
* This way we will never overlap with our own libraries or binaries or stack
* or anything else that QEMU maps.
+ *
+ * Many cpus reserve the high bit (or more than one for some 64-bit cpus)
+ * of the address for the kernel. Some cpus rely on this and user space
+ * uses the high bit(s) for pointer tagging and the like. For them, we
+ * must preserve the expected address space.
*/
-# if defined(TARGET_MIPS) || defined(TARGET_NIOS2)
-/*
- * MIPS only supports 31 bits of virtual address space for user space.
- * Nios2 also only supports 31 bits.
- */
-unsigned long reserved_va = 0x77000000;
+#ifndef MAX_RESERVED_VA
+# if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
+# if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
+ (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
+/* There are a number of places where we assign reserved_va to a variable
+ of type abi_ulong and expect it to fit. Avoid the last page. */
+# define MAX_RESERVED_VA (0xfffffffful & TARGET_PAGE_MASK)
+# else
+# define MAX_RESERVED_VA (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
+# endif
# else
-unsigned long reserved_va = 0xf7000000;
+# define MAX_RESERVED_VA 0
# endif
+#endif
+
+/* That said, reserving *too* much vm space via mmap can run into problems
+ with rlimits, oom due to page table creation, etc. We will still try it,
+ if directed by the command-line option, but not by default. */
+#if HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32
+unsigned long reserved_va = MAX_RESERVED_VA;
#else
unsigned long reserved_va;
#endif
@@ -3854,6 +3869,11 @@ static void handle_arg_log(const char *arg)
qemu_set_log(mask);
}
+static void handle_arg_dfilter(const char *arg)
+{
+ qemu_set_dfilter_ranges(arg, NULL);
+}
+
static void handle_arg_log_filename(const char *arg)
{
qemu_set_log_filename(arg, &error_fatal);
@@ -3978,11 +3998,8 @@ static void handle_arg_reserved_va(const char *arg)
unsigned long unshifted = reserved_va;
p++;
reserved_va <<= shift;
- if (((reserved_va >> shift) != unshifted)
-#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
- || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
-#endif
- ) {
+ if (reserved_va >> shift != unshifted
+ || (MAX_RESERVED_VA && reserved_va > MAX_RESERVED_VA)) {
fprintf(stderr, "Reserved virtual address too big\n");
exit(EXIT_FAILURE);
}
@@ -4054,6 +4071,8 @@ static const struct qemu_argument arg_table[] = {
{"d", "QEMU_LOG", true, handle_arg_log,
"item[,...]", "enable logging of specified items "
"(use '-d help' for a list of items)"},
+ {"dfilter", "QEMU_DFILTER", true, handle_arg_dfilter,
+ "range[,...]","filter logging based on address range"},
{"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
"logfile", "write logs to 'logfile' (default stderr)"},
{"p", "QEMU_PAGESIZE", true, handle_arg_pagesize,
diff --git a/linux-user/signal.c b/linux-user/signal.c
index cc0c3fcee9..7a238aaea1 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -5704,6 +5704,24 @@ give_sigsegv:
force_sigsegv(sig);
}
+static inline void target_rt_save_fpu_state(struct target_ucontext *uc,
+ CPUM68KState *env)
+{
+ int i;
+ target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs;
+
+ __put_user(env->fpcr, &fpregs->f_fpcntl[0]);
+ __put_user(env->fpsr, &fpregs->f_fpcntl[1]);
+ /* fpiar is not emulated */
+
+ for (i = 0; i < 8; i++) {
+ uint32_t high = env->fregs[i].d.high << 16;
+ __put_user(high, &fpregs->f_fpregs[i * 3]);
+ __put_user(env->fregs[i].d.low,
+ (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]);
+ }
+}
+
static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
CPUM68KState *env)
{
@@ -5730,9 +5748,32 @@ static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
__put_user(env->pc, &gregs[16]);
__put_user(sr, &gregs[17]);
+ target_rt_save_fpu_state(uc, env);
+
return 0;
}
+static inline void target_rt_restore_fpu_state(CPUM68KState *env,
+ struct target_ucontext *uc)
+{
+ int i;
+ target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs;
+ uint32_t fpcr;
+
+ __get_user(fpcr, &fpregs->f_fpcntl[0]);
+ cpu_m68k_set_fpcr(env, fpcr);
+ __get_user(env->fpsr, &fpregs->f_fpcntl[1]);
+ /* fpiar is not emulated */
+
+ for (i = 0; i < 8; i++) {
+ uint32_t high;
+ __get_user(high, &fpregs->f_fpregs[i * 3]);
+ env->fregs[i].d.high = high >> 16;
+ __get_user(env->fregs[i].d.low,
+ (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]);
+ }
+}
+
static inline int target_rt_restore_ucontext(CPUM68KState *env,
struct target_ucontext *uc)
{
@@ -5764,6 +5805,8 @@ static inline int target_rt_restore_ucontext(CPUM68KState *env,
__get_user(temp, &gregs[17]);
cpu_m68k_set_ccr(env, temp);
+ target_rt_restore_fpu_state(env, uc);
+
return 0;
badframe:
diff --git a/linux-user/strace.c b/linux-user/strace.c
index d821d165ff..bd897a3f20 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -838,6 +838,10 @@ UNUSED static struct flags open_flags[] = {
#ifdef O_PATH
FLAG_TARGET(O_PATH),
#endif
+#ifdef O_TMPFILE
+ FLAG_TARGET(O_TMPFILE),
+ FLAG_TARGET(__O_TMPFILE),
+#endif
FLAG_END,
};
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9d4cc4cf5d..9bf901fa11 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -343,6 +343,9 @@ static bitmask_transtbl fcntl_flags_tbl[] = {
#if defined(O_PATH)
{ TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
#endif
+#if defined(O_TMPFILE)
+ { TARGET_O_TMPFILE, TARGET_O_TMPFILE, O_TMPFILE, O_TMPFILE },
+#endif
/* Don't terminate the list prematurely on 64-bit host+guest. */
#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
{ TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index b3d55e35ac..450960bb54 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1108,8 +1108,8 @@ struct target_pollfd {
/* Note that the ioctl numbers claim type "long" but the actual type
* used by the kernel is "int".
*/
-#define TARGET_FS_IOC_GETFLAGS TARGET_IOR('f', 1, long)
-#define TARGET_FS_IOC_SETFLAGS TARGET_IOW('f', 2, long)
+#define TARGET_FS_IOC_GETFLAGS TARGET_IOR('f', 1, abi_long)
+#define TARGET_FS_IOC_SETFLAGS TARGET_IOW('f', 2, abi_long)
#define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
@@ -2423,7 +2423,7 @@ struct target_statfs64 {
#define TARGET_O_CLOEXEC 010000000
#define TARGET___O_SYNC 000100000
#define TARGET_O_PATH 020000000
-#elif defined(TARGET_ARM) || defined(TARGET_M68K)
+#elif defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_AARCH64)
#define TARGET_O_DIRECTORY 040000 /* must be a directory */
#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
#define TARGET_O_DIRECT 0200000 /* direct disk access hint */
@@ -2520,6 +2520,12 @@ struct target_statfs64 {
#ifndef TARGET_O_PATH
#define TARGET_O_PATH 010000000
#endif
+#ifndef TARGET___O_TMPFILE
+#define TARGET___O_TMPFILE 020000000
+#endif
+#ifndef TARGET_O_TMPFILE
+#define TARGET_O_TMPFILE (TARGET___O_TMPFILE | TARGET_O_DIRECTORY)
+#endif
#ifndef TARGET_O_NDELAY
#define TARGET_O_NDELAY TARGET_O_NONBLOCK
#endif
@@ -2713,9 +2719,34 @@ struct target_f_owner_ex {
#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1)
#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2)
-#define TARGET_MTIOCTOP TARGET_IOW('m', 1, struct mtop)
-#define TARGET_MTIOCGET TARGET_IOR('m', 2, struct mtget)
-#define TARGET_MTIOCPOS TARGET_IOR('m', 3, struct mtpos)
+struct target_mtop {
+ abi_short mt_op;
+ abi_int mt_count;
+};
+
+#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
+typedef abi_long target_kernel_daddr_t;
+#else
+typedef abi_int target_kernel_daddr_t;
+#endif
+
+struct target_mtget {
+ abi_long mt_type;
+ abi_long mt_resid;
+ abi_long mt_dsreg;
+ abi_long mt_gstat;
+ abi_long mt_erreg;
+ target_kernel_daddr_t mt_fileno;
+ target_kernel_daddr_t mt_blkno;
+};
+
+struct target_mtpos {
+ abi_long mt_blkno;
+};
+
+#define TARGET_MTIOCTOP TARGET_IOW('m', 1, struct target_mtop)
+#define TARGET_MTIOCGET TARGET_IOR('m', 2, struct target_mtget)
+#define TARGET_MTIOCPOS TARGET_IOR('m', 3, struct target_mtpos)
struct target_sysinfo {
abi_long uptime; /* Seconds since boot */