diff --git a/docs/user/main.rst b/docs/user/main.rst index bd99b0fdbe..8dfe232a3a 100644 --- a/docs/user/main.rst +++ b/docs/user/main.rst @@ -170,68 +170,81 @@ QEMU_STRACE Other binaries ~~~~~~~~~~~~~~ -user mode (Alpha) -``qemu-alpha`` TODO. +- user mode (Alpha) -user mode (Arm) -``qemu-armeb`` TODO. + * ``qemu-alpha`` TODO. -user mode (Arm) -``qemu-arm`` is also capable of running Arm \"Angel\" semihosted ELF -binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB -configurations), and arm-uclinux bFLT format binaries. +- user mode (Arm) -user mode (ColdFire) -user mode (M68K) -``qemu-m68k`` is capable of running semihosted binaries using the BDM -(m5xxx-ram-hosted.ld) or m68k-sim (sim.ld) syscall interfaces, and -coldfire uClinux bFLT format binaries. + * ``qemu-armeb`` TODO. -The binary format is detected automatically. + * ``qemu-arm`` is also capable of running Arm \"Angel\" semihosted ELF + binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB + configurations), and arm-uclinux bFLT format binaries. -user mode (Cris) -``qemu-cris`` TODO. +- user mode (ColdFire) -user mode (i386) -``qemu-i386`` TODO. ``qemu-x86_64`` TODO. +- user mode (M68K) -user mode (Microblaze) -``qemu-microblaze`` TODO. + * ``qemu-m68k`` is capable of running semihosted binaries using the BDM + (m5xxx-ram-hosted.ld) or m68k-sim (sim.ld) syscall interfaces, and + coldfire uClinux bFLT format binaries. -user mode (MIPS) -``qemu-mips`` executes 32-bit big endian MIPS binaries (MIPS O32 ABI). + The binary format is detected automatically. -``qemu-mipsel`` executes 32-bit little endian MIPS binaries (MIPS O32 -ABI). +- user mode (Cris) -``qemu-mips64`` executes 64-bit big endian MIPS binaries (MIPS N64 ABI). + * ``qemu-cris`` TODO. -``qemu-mips64el`` executes 64-bit little endian MIPS binaries (MIPS N64 -ABI). +- user mode (i386) -``qemu-mipsn32`` executes 32-bit big endian MIPS binaries (MIPS N32 -ABI). + * ``qemu-i386`` TODO. + * ``qemu-x86_64`` TODO. -``qemu-mipsn32el`` executes 32-bit little endian MIPS binaries (MIPS N32 -ABI). +- user mode (Microblaze) -user mode (NiosII) -``qemu-nios2`` TODO. + * ``qemu-microblaze`` TODO. -user mode (PowerPC) -``qemu-ppc64abi32`` TODO. ``qemu-ppc64`` TODO. ``qemu-ppc`` TODO. +- user mode (MIPS) -user mode (SH4) -``qemu-sh4eb`` TODO. ``qemu-sh4`` TODO. + * ``qemu-mips`` executes 32-bit big endian MIPS binaries (MIPS O32 ABI). -user mode (SPARC) -``qemu-sparc`` can execute Sparc32 binaries (Sparc32 CPU, 32 bit ABI). + * ``qemu-mipsel`` executes 32-bit little endian MIPS binaries (MIPS O32 ABI). -``qemu-sparc32plus`` can execute Sparc32 and SPARC32PLUS binaries -(Sparc64 CPU, 32 bit ABI). + * ``qemu-mips64`` executes 64-bit big endian MIPS binaries (MIPS N64 ABI). -``qemu-sparc64`` can execute some Sparc64 (Sparc64 CPU, 64 bit ABI) and -SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI). + * ``qemu-mips64el`` executes 64-bit little endian MIPS binaries (MIPS N64 + ABI). + + * ``qemu-mipsn32`` executes 32-bit big endian MIPS binaries (MIPS N32 ABI). + + * ``qemu-mipsn32el`` executes 32-bit little endian MIPS binaries (MIPS N32 + ABI). + +- user mode (NiosII) + + * ``qemu-nios2`` TODO. + +- user mode (PowerPC) + + * ``qemu-ppc64abi32`` TODO. + * ``qemu-ppc64`` TODO. + * ``qemu-ppc`` TODO. + +- user mode (SH4) + + * ``qemu-sh4eb`` TODO. + * ``qemu-sh4`` TODO. + +- user mode (SPARC) + + * ``qemu-sparc`` can execute Sparc32 binaries (Sparc32 CPU, 32 bit ABI). + + * ``qemu-sparc32plus`` can execute Sparc32 and SPARC32PLUS binaries + (Sparc64 CPU, 32 bit ABI). + + * ``qemu-sparc64`` can execute some Sparc64 (Sparc64 CPU, 64 bit ABI) and + SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI). BSD User space emulator ----------------------- diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 0b02a92602..a64050713f 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -7,6 +7,7 @@ #include "qemu.h" #include "disas/disas.h" +#include "qemu/bitops.h" #include "qemu/path.h" #include "qemu/queue.h" #include "qemu/guest-random.h" @@ -985,26 +986,54 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *e enum { HWCAP_MIPS_R6 = (1 << 0), HWCAP_MIPS_MSA = (1 << 1), + HWCAP_MIPS_CRC32 = (1 << 2), + HWCAP_MIPS_MIPS16 = (1 << 3), + HWCAP_MIPS_MDMX = (1 << 4), + HWCAP_MIPS_MIPS3D = (1 << 5), + HWCAP_MIPS_SMARTMIPS = (1 << 6), + HWCAP_MIPS_DSP = (1 << 7), + HWCAP_MIPS_DSP2 = (1 << 8), + HWCAP_MIPS_DSP3 = (1 << 9), + HWCAP_MIPS_MIPS16E2 = (1 << 10), + HWCAP_LOONGSON_MMI = (1 << 11), + HWCAP_LOONGSON_EXT = (1 << 12), + HWCAP_LOONGSON_EXT2 = (1 << 13), + HWCAP_LOONGSON_CPUCFG = (1 << 14), }; #define ELF_HWCAP get_elf_hwcap() +#define GET_FEATURE_INSN(_flag, _hwcap) \ + do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0) + +#define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \ + do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0) + +#define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \ + do { \ + if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \ + hwcaps |= _hwcap; \ + } \ + } while (0) + static uint32_t get_elf_hwcap(void) { MIPSCPU *cpu = MIPS_CPU(thread_cpu); uint32_t hwcaps = 0; -#define GET_FEATURE(flag, hwcap) \ - do { if (cpu->env.insn_flags & (flag)) { hwcaps |= hwcap; } } while (0) - - GET_FEATURE(ISA_MIPS32R6 | ISA_MIPS64R6, HWCAP_MIPS_R6); - GET_FEATURE(ASE_MSA, HWCAP_MIPS_MSA); - -#undef GET_FEATURE + GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH, + 2, HWCAP_MIPS_R6); + GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA); + GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI); + GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT); return hwcaps; } +#undef GET_FEATURE_REG_EQU +#undef GET_FEATURE_REG_SET +#undef GET_FEATURE_INSN + #endif /* TARGET_MIPS */ #ifdef TARGET_MICROBLAZE diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 8efb4d38c0..661b5daa9f 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -720,3 +720,49 @@ IOCTL(KCOV_DISABLE, 0, TYPE_NULL) IOCTL(KCOV_INIT_TRACE, IOC_R, TYPE_ULONG) #endif + + IOCTL(TUNSETDEBUG, IOC_W, TYPE_INT) + IOCTL(TUNSETIFF, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNSETPERSIST, IOC_W, TYPE_INT) + IOCTL(TUNSETOWNER, IOC_W, TYPE_INT) + IOCTL(TUNSETLINK, IOC_W, TYPE_INT) + IOCTL(TUNSETGROUP, IOC_W, TYPE_INT) + IOCTL(TUNGETFEATURES, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETOFFLOAD, IOC_W, TYPE_LONG) + IOCTL_SPECIAL(TUNSETTXFILTER, IOC_W, do_ioctl_TUNSETTXFILTER, + /* + * We can't represent `struct tun_filter` in thunk so leaving + * it uninterpreted. do_ioctl_TUNSETTXFILTER will do the + * conversion. + */ + TYPE_PTRVOID) + IOCTL(TUNGETIFF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNGETSNDBUF, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETSNDBUF, IOC_W, MK_PTR(TYPE_INT)) + /* + * TUNATTACHFILTER and TUNDETACHFILTER are not supported. Linux kernel keeps a + * user pointer in TUNATTACHFILTER, which we are not able to correctly handle. + */ + IOCTL(TUNGETVNETHDRSZ, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETVNETHDRSZ, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNSETQUEUE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNSETIFINDEX , IOC_W, MK_PTR(TYPE_INT)) + /* TUNGETFILTER is not supported: see TUNATTACHFILTER. */ + IOCTL(TUNSETVNETLE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNGETVNETLE, IOC_R, MK_PTR(TYPE_INT)) +#ifdef TUNSETVNETBE + IOCTL(TUNSETVNETBE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNGETVNETBE, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETSTEERINGEBPF + IOCTL(TUNSETSTEERINGEBPF, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETFILTEREBPF + IOCTL(TUNSETFILTEREBPF, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETCARRIER + IOCTL(TUNSETCARRIER, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNGETDEVNETNS + IOCTL(TUNGETDEVNETNS, IOC_R, TYPE_NULL) +#endif diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 00c05e6a0f..810653c503 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -767,20 +767,23 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, } if (prot == 0) { host_addr = mremap(g2h(old_addr), old_size, new_size, flags); - if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) { - mmap_reserve(old_addr + old_size, old_size - new_size); + + if (host_addr != MAP_FAILED) { + /* Check if address fits target address space */ + if (!guest_range_valid(h2g(host_addr), new_size)) { + /* Revert mremap() changes */ + host_addr = mremap(g2h(old_addr), new_size, old_size, + flags); + errno = ENOMEM; + host_addr = MAP_FAILED; + } else if (reserved_va && old_size > new_size) { + mmap_reserve(old_addr + old_size, old_size - new_size); + } } } else { errno = ENOMEM; host_addr = MAP_FAILED; } - /* Check if address fits target address space */ - if ((unsigned long)host_addr + new_size > (abi_ulong)-1) { - /* Revert mremap() changes */ - host_addr = mremap(g2h(old_addr), new_size, old_size, flags); - errno = ENOMEM; - host_addr = MAP_FAILED; - } } if (host_addr == MAP_FAILED) { diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index d12adc8e6f..d27b7a3af7 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -402,8 +402,10 @@ void sparc64_set_context(CPUSPARCState *env) abi_ulong ucp_addr; struct target_ucontext *ucp; target_mc_gregset_t *grp; + target_mc_fpu_t *fpup; abi_ulong pc, npc, tstate; unsigned int i; + unsigned char fenab; ucp_addr = env->regwptr[WREG_O0]; if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) { @@ -436,16 +438,16 @@ void sparc64_set_context(CPUSPARCState *env) env->npc = npc; __get_user(env->y, &((*grp)[SPARC_MC_Y])); __get_user(tstate, &((*grp)[SPARC_MC_TSTATE])); + /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */ env->asi = (tstate >> 24) & 0xff; - cpu_put_ccr(env, tstate >> 32); - cpu_put_cwp64(env, tstate & 0x1f); + cpu_put_ccr(env, (tstate >> 32) & 0xff); __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1])); __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2])); __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3])); __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4])); __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5])); __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6])); - __get_user(env->gregs[7], (&(*grp)[SPARC_MC_G7])); + /* Skip g7 as that's the thread register in userspace */ /* * Note that unlike the kernel, we didn't need to mess with the @@ -467,26 +469,42 @@ void sparc64_set_context(CPUSPARCState *env) __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp)); __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7)); - /* FIXME this does not match how the kernel handles the FPU in - * its sparc64_set_context implementation. In particular the FPU - * is only restored if fenab is non-zero in: - * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab)); - */ - __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs)); - { - uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs; - for (i = 0; i < 64; i++, src++) { - if (i & 1) { - __get_user(env->fpr[i/2].l.lower, src); - } else { - __get_user(env->fpr[i/2].l.upper, src); + fpup = &ucp->tuc_mcontext.mc_fpregs; + + __get_user(fenab, &(fpup->mcfpu_enab)); + if (fenab) { + abi_ulong fprs; + + /* + * We use the FPRS from the guest only in deciding whether + * to restore the upper, lower, or both banks of the FPU regs. + * The kernel here writes the FPU register data into the + * process's current_thread_info state and unconditionally + * clears FPRS and TSTATE_PEF: this disables the FPU so that the + * next FPU-disabled trap will copy the data out of + * current_thread_info and into the real FPU registers. + * QEMU doesn't need to handle lazy-FPU-state-restoring like that, + * so we always load the data directly into the FPU registers + * and leave FPRS and TSTATE_PEF alone (so the FPU stays enabled). + * Note that because we (and the kernel) always write zeroes for + * the fenab and fprs in sparc64_get_context() none of this code + * will execute unless the guest manually constructed or changed + * the context structure. + */ + __get_user(fprs, &(fpup->mcfpu_fprs)); + if (fprs & FPRS_DL) { + for (i = 0; i < 16; i++) { + __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i])); } } + if (fprs & FPRS_DU) { + for (i = 16; i < 32; i++) { + __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i])); + } + } + __get_user(env->fsr, &(fpup->mcfpu_fsr)); + __get_user(env->gsr, &(fpup->mcfpu_gsr)); } - __get_user(env->fsr, - &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr)); - __get_user(env->gsr, - &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr)); unlock_user_struct(ucp, ucp_addr, 0); return; do_sigsegv: @@ -509,7 +527,9 @@ void sparc64_get_context(CPUSPARCState *env) if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) { goto do_sigsegv; } - + + memset(ucp, 0, sizeof(*ucp)); + mcp = &ucp->tuc_mcontext; grp = &mcp->mc_gregs; @@ -535,12 +555,9 @@ void sparc64_get_context(CPUSPARCState *env) for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) { __put_user(*src, dst); } - if (err) - goto do_sigsegv; } - /* XXX: tstate must be saved properly */ - // __put_user(env->tstate, &((*grp)[SPARC_MC_TSTATE])); + __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE])); __put_user(env->pc, &((*grp)[SPARC_MC_PC])); __put_user(env->npc, &((*grp)[SPARC_MC_NPC])); __put_user(env->y, &((*grp)[SPARC_MC_Y])); @@ -572,22 +589,12 @@ void sparc64_get_context(CPUSPARCState *env) __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp)); __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7)); - { - uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs; - for (i = 0; i < 64; i++, dst++) { - if (i & 1) { - __put_user(env->fpr[i/2].l.lower, dst); - } else { - __put_user(env->fpr[i/2].l.upper, dst); - } - } - } - __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr)); - __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr)); - __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs)); + /* + * We don't write out the FPU state. This matches the kernel's + * implementation (which has the code for doing this but + * hidden behind an "if (fenab)" where fenab is always 0). + */ - if (err) - goto do_sigsegv; unlock_user_struct(ucp, ucp_addr, 1); return; do_sigsegv: diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7bf99beb18..d182890ff0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_TIMERFD @@ -813,6 +814,12 @@ safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr, safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr, size_t, len, unsigned *, prio, const struct timespec *, timeout) #endif +#if defined(TARGET_NR_copy_file_range) && defined(__NR_copy_file_range) +safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff, + int, outfd, loff_t *, poutoff, size_t, length, + unsigned int, flags) +#endif + /* We do ioctl like this rather than via safe_syscall3 to preserve the * "third argument might be integer or pointer or not present" behaviour of * the libc function. @@ -5703,6 +5710,42 @@ static abi_long do_ioctl_drm_i915(const IOCTLEntry *ie, uint8_t *buf_temp, #endif +static abi_long do_ioctl_TUNSETTXFILTER(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, int cmd, abi_long arg) +{ + struct tun_filter *filter = (struct tun_filter *)buf_temp; + struct tun_filter *target_filter; + char *target_addr; + + assert(ie->access == IOC_W); + + target_filter = lock_user(VERIFY_READ, arg, sizeof(*target_filter), 1); + if (!target_filter) { + return -TARGET_EFAULT; + } + filter->flags = tswap16(target_filter->flags); + filter->count = tswap16(target_filter->count); + unlock_user(target_filter, arg, 0); + + if (filter->count) { + if (offsetof(struct tun_filter, addr) + filter->count * ETH_ALEN > + MAX_STRUCT_SIZE) { + return -TARGET_EFAULT; + } + + target_addr = lock_user(VERIFY_READ, + arg + offsetof(struct tun_filter, addr), + filter->count * ETH_ALEN, 1); + if (!target_addr) { + return -TARGET_EFAULT; + } + memcpy(filter->addr, target_addr, filter->count * ETH_ALEN); + unlock_user(target_addr, arg + offsetof(struct tun_filter, addr), 0); + } + + return get_errno(safe_ioctl(fd, ie->host_cmd, filter)); +} + IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, @@ -13065,6 +13108,42 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return get_errno(membarrier(arg1, arg2)); #endif +#if defined(TARGET_NR_copy_file_range) && defined(__NR_copy_file_range) + case TARGET_NR_copy_file_range: + { + loff_t inoff, outoff; + loff_t *pinoff = NULL, *poutoff = NULL; + + if (arg2) { + if (get_user_u64(inoff, arg2)) { + return -TARGET_EFAULT; + } + pinoff = &inoff; + } + if (arg4) { + if (get_user_u64(outoff, arg4)) { + return -TARGET_EFAULT; + } + poutoff = &outoff; + } + ret = get_errno(safe_copy_file_range(arg1, pinoff, arg3, poutoff, + arg5, arg6)); + if (!is_error(ret) && ret > 0) { + if (arg2) { + if (put_user_u64(inoff, arg2)) { + return -TARGET_EFAULT; + } + } + if (arg4) { + if (put_user_u64(outoff, arg4)) { + return -TARGET_EFAULT; + } + } + } + } + return ret; +#endif + default: qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num); return -TARGET_ENOSYS; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index b934d0b606..a00bfc2647 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -929,6 +929,38 @@ struct target_rtc_pll_info { #define TARGET_SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +/* From */ + +#define TARGET_TUNSETDEBUG TARGET_IOW('T', 201, int) +#define TARGET_TUNSETIFF TARGET_IOW('T', 202, int) +#define TARGET_TUNSETPERSIST TARGET_IOW('T', 203, int) +#define TARGET_TUNSETOWNER TARGET_IOW('T', 204, int) +#define TARGET_TUNSETLINK TARGET_IOW('T', 205, int) +#define TARGET_TUNSETGROUP TARGET_IOW('T', 206, int) +#define TARGET_TUNGETFEATURES TARGET_IOR('T', 207, unsigned int) +#define TARGET_TUNSETOFFLOAD TARGET_IOW('T', 208, unsigned int) +#define TARGET_TUNSETTXFILTER TARGET_IOW('T', 209, unsigned int) +#define TARGET_TUNGETIFF TARGET_IOR('T', 210, unsigned int) +#define TARGET_TUNGETSNDBUF TARGET_IOR('T', 211, int) +#define TARGET_TUNSETSNDBUF TARGET_IOW('T', 212, int) +/* + * TUNATTACHFILTER and TUNDETACHFILTER are not supported. Linux kernel keeps a + * user pointer in TUNATTACHFILTER, which we are not able to correctly handle. + */ +#define TARGET_TUNGETVNETHDRSZ TARGET_IOR('T', 215, int) +#define TARGET_TUNSETVNETHDRSZ TARGET_IOW('T', 216, int) +#define TARGET_TUNSETQUEUE TARGET_IOW('T', 217, int) +#define TARGET_TUNSETIFINDEX TARGET_IOW('T', 218, unsigned int) +/* TUNGETFILTER is not supported: see TUNATTACHFILTER. */ +#define TARGET_TUNSETVNETLE TARGET_IOW('T', 220, int) +#define TARGET_TUNGETVNETLE TARGET_IOR('T', 221, int) +#define TARGET_TUNSETVNETBE TARGET_IOW('T', 222, int) +#define TARGET_TUNGETVNETBE TARGET_IOR('T', 223, int) +#define TARGET_TUNSETSTEERINGEBPF TARGET_IOR('T', 224, int) +#define TARGET_TUNSETFILTEREBPF TARGET_IOR('T', 225, int) +#define TARGET_TUNSETCARRIER TARGET_IOW('T', 226, int) +#define TARGET_TUNGETDEVNETNS TARGET_IO('T', 227) + /* From */ #define TARGET_RNDGETENTCNT TARGET_IOR('R', 0x00, int) diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 3ac21d0e9c..4cbc31c3e8 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -844,6 +844,7 @@ struct CPUMIPSState { #define CP0C0_MT 7 /* 9..7 */ #define CP0C0_VI 3 #define CP0C0_K0 0 /* 2..0 */ +#define CP0C0_AR_LENGTH 3 int32_t CP0_Config1; #define CP0C1_M 31 #define CP0C1_MMU 25 /* 30..25 */ diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index b9369398f2..4b2290650b 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -156,7 +156,9 @@ enum { #define PS_IE (1<<1) #define PS_AG (1<<0) /* v9, zero on UA2007 */ -#define FPRS_FEF (1<<2) +#define FPRS_DL (1 << 0) +#define FPRS_DU (1 << 1) +#define FPRS_FEF (1 << 2) #define HS_PRIV (1<<2) #endif @@ -606,10 +608,6 @@ target_ulong cpu_get_psr(CPUSPARCState *env1); void cpu_put_psr(CPUSPARCState *env1, target_ulong val); void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val); #ifdef TARGET_SPARC64 -target_ulong cpu_get_ccr(CPUSPARCState *env1); -void cpu_put_ccr(CPUSPARCState *env1, target_ulong val); -target_ulong cpu_get_cwp64(CPUSPARCState *env1); -void cpu_put_cwp64(CPUSPARCState *env1, int cwp); void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate); void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl); #endif @@ -827,4 +825,24 @@ static inline bool tb_am_enabled(int tb_flags) #endif } +#ifdef TARGET_SPARC64 +/* win_helper.c */ +target_ulong cpu_get_ccr(CPUSPARCState *env1); +void cpu_put_ccr(CPUSPARCState *env1, target_ulong val); +target_ulong cpu_get_cwp64(CPUSPARCState *env1); +void cpu_put_cwp64(CPUSPARCState *env1, int cwp); + +static inline uint64_t sparc64_tstate(CPUSPARCState *env) +{ + uint64_t tstate = (cpu_get_ccr(env) << 32) | + ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) | + cpu_get_cwp64(env); + + if (env->def.features & CPU_FEATURE_GL) { + tstate |= (env->gl & 7ULL) << 40; + } + return tstate; +} +#endif + #endif diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c index ba95bf228c..7fb8ab211c 100644 --- a/target/sparc/int64_helper.c +++ b/target/sparc/int64_helper.c @@ -131,9 +131,7 @@ void sparc_cpu_do_interrupt(CPUState *cs) } tsptr = cpu_tsptr(env); - tsptr->tstate = (cpu_get_ccr(env) << 32) | - ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) | - cpu_get_cwp64(env); + tsptr->tstate = sparc64_tstate(env); tsptr->tpc = env->pc; tsptr->tnpc = env->npc; tsptr->tt = intno; @@ -148,7 +146,6 @@ void sparc_cpu_do_interrupt(CPUState *cs) } if (env->def.features & CPU_FEATURE_GL) { - tsptr->tstate |= (env->gl & 7ULL) << 40; cpu_gl_switch_gregs(env, env->gl + 1); env->gl++; }