diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index c5ce99d549..1b43deb0cd 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -2114,7 +2114,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) guest address space. If this assert fires, it probably indicates a missing call to h2g_valid. */ #if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS - assert(end < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); + assert(end <= ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); #endif assert(start < end); assert_memory_lock(); 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 @@ -837,6 +837,10 @@ UNUSED static struct flags open_flags[] = { #endif #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 @@ -342,6 +342,9 @@ static bitmask_transtbl fcntl_flags_tbl[] = { #endif #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 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 */ diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h index 047554ee45..d239069975 100644 --- a/target/mips/mips-defs.h +++ b/target/mips/mips-defs.h @@ -15,7 +15,11 @@ #else #define TARGET_LONG_BITS 32 #define TARGET_PHYS_ADDR_SPACE_BITS 40 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 +# ifdef CONFIG_USER_ONLY +# define TARGET_VIRT_ADDR_SPACE_BITS 31 +# else +# define TARGET_VIRT_ADDR_SPACE_BITS 32 +#endif #endif /* Masks used to mark instructions to indicate which ISA level they diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index 50d803a217..9119eee587 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -226,7 +226,11 @@ qemu_irq *nios2_cpu_pic_init(Nios2CPU *cpu); void nios2_check_interrupts(CPUNios2State *env); #define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 +#ifdef CONFIG_USER_ONLY +# define TARGET_VIRT_ADDR_SPACE_BITS 31 +#else +# define TARGET_VIRT_ADDR_SPACE_BITS 32 +#endif #define cpu_init(cpu_model) cpu_generic_init(TYPE_NIOS2_CPU, cpu_model) diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 79f85d3365..123f34783a 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -45,7 +45,11 @@ #define TARGET_PAGE_BITS 12 /* 4k XXXXX */ #define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 +#ifdef CONFIG_USER_ONLY +# define TARGET_VIRT_ADDR_SPACE_BITS 31 +#else +# define TARGET_VIRT_ADDR_SPACE_BITS 32 +#endif #define SR_MD 30 #define SR_RB 29