Add MIPS Loongson 2F/3A

sparc64 bug fix
 Implement copy_file_range
 Add most IFTUN ioctls
 Fix mremap
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAl/cgy8SHGxhdXJlbnRA
 dml2aWVyLmV1AAoJEPMMOL0/L748h/sP/AipOeydMwKf6Qe1ofWAYLSMKvw1+OYH
 j2PnhGYQGUbz7KJyCB8KmJ8GliUIsnPK4kUqKaIL5nWE5W9pdutuRki9KgzOEmtp
 MLcLVKEMJfD/yILdr6e4F+0M/yqOCmDKU9evi/cvM7248Ll1TAkUuw5WrRBZDtHg
 v1l/RNyvXeSL3gcZjsDXMf3UMQ7itadeg0OeYSwZjC1+1XYkbMqXIrzeUH2QHMcV
 XNklLdF2CQgvaf262WyCOh1jmG8OGD9ih1fb5MpPQnI1C2N/sCFEV/as02rNHdZa
 JUmSUZhw8YKDzK4aTWVnEPaWetWMCTJCxVUWGV/E3ggGmlUIwK+CGh+jkxsTsK5I
 ir3szojhZd7D0NfLjK4Nfuy8lLEkQYH4WKxRE2Dsq7NK9pebfXFCL5x24HDlQeYy
 KDHUEsC+YrgSl/mQ8uwMZonGpNS5PzYMNFZoupND3GvZmHdzvsYpm2WTRi8LcRUm
 74RUyWKH+ajic9/bVYUmJvA00SRkpoxOU4UaUd3O51S6IEBYckWbFGi6KKgw/bNw
 Ngnxk4Zy81IT9Hj5rLc/t0UtMfrlFGqdUjwwGVQEERcu3fBbcONc7QhabUxztmy0
 Qx0G0Rd6fP3l9CHv1YDuR9dVFLUjek48821MpjkuOy/Be1QOdt/1uvEfhsSxFhQL
 zbGKkuOXd54x
 =/9rz
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-6.0-pull-request' into staging

Add MIPS Loongson 2F/3A
sparc64 bug fix
Implement copy_file_range
Add most IFTUN ioctls
Fix mremap

# gpg: Signature made Fri 18 Dec 2020 10:23:43 GMT
# gpg:                using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg:                issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier2/tags/linux-user-for-6.0-pull-request:
  linux-user/sparc: Handle tstate in sparc64_get/set_context()
  linux-user/sparc: Don't restore %g7 in sparc64_set_context()
  linux-user/sparc: Remove unneeded checks of 'err' from sparc64_get_context()
  linux-user/sparc: Correct sparc64_get/set_context() FPU handling
  linux-user: Add most IFTUN ioctls
  linux-user: Implement copy_file_range
  docs/user: Display linux-user binaries nicely
  linux-user: Add support for MIPS Loongson 2F/3A
  linux-user/elfload: Update HWCAP bits from linux 5.7
  linux-user/elfload: Introduce MIPS GET_FEATURE_REG_EQU() macro
  linux-user/elfload: Introduce MIPS GET_FEATURE_REG_SET() macro
  linux-user/elfload: Rename MIPS GET_FEATURE() as GET_FEATURE_INSN()
  linux-user/elfload: Move GET_FEATURE macro out of get_elf_hwcap() body
  linux-user/mmap.c: check range of mremap result in target address space

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-12-31 14:49:02 +00:00
commit 091774bfde
10 changed files with 333 additions and 108 deletions

View File

@ -170,67 +170,80 @@ QEMU_STRACE
Other binaries Other binaries
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
user mode (Alpha) - user mode (Alpha)
``qemu-alpha`` TODO.
user mode (Arm) * ``qemu-alpha`` TODO.
``qemu-armeb`` TODO.
user mode (Arm) - user mode (Arm)
``qemu-arm`` is also capable of running Arm \"Angel\" semihosted ELF
* ``qemu-armeb`` TODO.
* ``qemu-arm`` is also capable of running Arm \"Angel\" semihosted ELF
binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB
configurations), and arm-uclinux bFLT format binaries. configurations), and arm-uclinux bFLT format binaries.
user mode (ColdFire) - user mode (ColdFire)
user mode (M68K)
``qemu-m68k`` is capable of running semihosted binaries using the BDM - 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 (m5xxx-ram-hosted.ld) or m68k-sim (sim.ld) syscall interfaces, and
coldfire uClinux bFLT format binaries. coldfire uClinux bFLT format binaries.
The binary format is detected automatically. The binary format is detected automatically.
user mode (Cris) - user mode (Cris)
``qemu-cris`` TODO.
user mode (i386) * ``qemu-cris`` TODO.
``qemu-i386`` TODO. ``qemu-x86_64`` TODO.
user mode (Microblaze) - user mode (i386)
``qemu-microblaze`` TODO.
user mode (MIPS) * ``qemu-i386`` TODO.
``qemu-mips`` executes 32-bit big endian MIPS binaries (MIPS O32 ABI). * ``qemu-x86_64`` TODO.
``qemu-mipsel`` executes 32-bit little endian MIPS binaries (MIPS O32 - user mode (Microblaze)
* ``qemu-microblaze`` TODO.
- user mode (MIPS)
* ``qemu-mips`` executes 32-bit big endian MIPS binaries (MIPS O32 ABI).
* ``qemu-mipsel`` executes 32-bit little endian MIPS binaries (MIPS O32 ABI).
* ``qemu-mips64`` executes 64-bit big endian MIPS binaries (MIPS N64 ABI).
* ``qemu-mips64el`` executes 64-bit little endian MIPS binaries (MIPS N64
ABI). ABI).
``qemu-mips64`` executes 64-bit big endian MIPS binaries (MIPS N64 ABI). * ``qemu-mipsn32`` executes 32-bit big endian MIPS binaries (MIPS N32 ABI).
``qemu-mips64el`` executes 64-bit little endian MIPS binaries (MIPS N64 * ``qemu-mipsn32el`` executes 32-bit little endian MIPS binaries (MIPS N32
ABI). ABI).
``qemu-mipsn32`` executes 32-bit big endian MIPS binaries (MIPS N32 - user mode (NiosII)
ABI).
``qemu-mipsn32el`` executes 32-bit little endian MIPS binaries (MIPS N32 * ``qemu-nios2`` TODO.
ABI).
user mode (NiosII) - user mode (PowerPC)
``qemu-nios2`` TODO.
user mode (PowerPC) * ``qemu-ppc64abi32`` TODO.
``qemu-ppc64abi32`` TODO. ``qemu-ppc64`` TODO. ``qemu-ppc`` TODO. * ``qemu-ppc64`` TODO.
* ``qemu-ppc`` TODO.
user mode (SH4) - user mode (SH4)
``qemu-sh4eb`` TODO. ``qemu-sh4`` TODO.
user mode (SPARC) * ``qemu-sh4eb`` TODO.
``qemu-sparc`` can execute Sparc32 binaries (Sparc32 CPU, 32 bit ABI). * ``qemu-sh4`` TODO.
``qemu-sparc32plus`` can execute Sparc32 and SPARC32PLUS binaries - 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). (Sparc64 CPU, 32 bit ABI).
``qemu-sparc64`` can execute some Sparc64 (Sparc64 CPU, 64 bit ABI) and * ``qemu-sparc64`` can execute some Sparc64 (Sparc64 CPU, 64 bit ABI) and
SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI). SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI).
BSD User space emulator BSD User space emulator

View File

@ -7,6 +7,7 @@
#include "qemu.h" #include "qemu.h"
#include "disas/disas.h" #include "disas/disas.h"
#include "qemu/bitops.h"
#include "qemu/path.h" #include "qemu/path.h"
#include "qemu/queue.h" #include "qemu/queue.h"
#include "qemu/guest-random.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 { enum {
HWCAP_MIPS_R6 = (1 << 0), HWCAP_MIPS_R6 = (1 << 0),
HWCAP_MIPS_MSA = (1 << 1), 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 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) static uint32_t get_elf_hwcap(void)
{ {
MIPSCPU *cpu = MIPS_CPU(thread_cpu); MIPSCPU *cpu = MIPS_CPU(thread_cpu);
uint32_t hwcaps = 0; uint32_t hwcaps = 0;
#define GET_FEATURE(flag, hwcap) \ GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH,
do { if (cpu->env.insn_flags & (flag)) { hwcaps |= hwcap; } } while (0) 2, HWCAP_MIPS_R6);
GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA);
GET_FEATURE(ISA_MIPS32R6 | ISA_MIPS64R6, HWCAP_MIPS_R6); GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI);
GET_FEATURE(ASE_MSA, HWCAP_MIPS_MSA); GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT);
#undef GET_FEATURE
return hwcaps; return hwcaps;
} }
#undef GET_FEATURE_REG_EQU
#undef GET_FEATURE_REG_SET
#undef GET_FEATURE_INSN
#endif /* TARGET_MIPS */ #endif /* TARGET_MIPS */
#ifdef TARGET_MICROBLAZE #ifdef TARGET_MICROBLAZE

View File

@ -720,3 +720,49 @@
IOCTL(KCOV_DISABLE, 0, TYPE_NULL) IOCTL(KCOV_DISABLE, 0, TYPE_NULL)
IOCTL(KCOV_INIT_TRACE, IOC_R, TYPE_ULONG) IOCTL(KCOV_INIT_TRACE, IOC_R, TYPE_ULONG)
#endif #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

View File

@ -767,17 +767,20 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
} }
if (prot == 0) { if (prot == 0) {
host_addr = mremap(g2h(old_addr), old_size, new_size, flags); 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 */
} else { 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; errno = ENOMEM;
host_addr = MAP_FAILED; host_addr = MAP_FAILED;
} else if (reserved_va && old_size > new_size) {
mmap_reserve(old_addr + old_size, old_size - new_size);
} }
/* Check if address fits target address space */ }
if ((unsigned long)host_addr + new_size > (abi_ulong)-1) { } else {
/* Revert mremap() changes */
host_addr = mremap(g2h(old_addr), new_size, old_size, flags);
errno = ENOMEM; errno = ENOMEM;
host_addr = MAP_FAILED; host_addr = MAP_FAILED;
} }

View File

@ -402,8 +402,10 @@ void sparc64_set_context(CPUSPARCState *env)
abi_ulong ucp_addr; abi_ulong ucp_addr;
struct target_ucontext *ucp; struct target_ucontext *ucp;
target_mc_gregset_t *grp; target_mc_gregset_t *grp;
target_mc_fpu_t *fpup;
abi_ulong pc, npc, tstate; abi_ulong pc, npc, tstate;
unsigned int i; unsigned int i;
unsigned char fenab;
ucp_addr = env->regwptr[WREG_O0]; ucp_addr = env->regwptr[WREG_O0];
if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) { if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
@ -436,16 +438,16 @@ void sparc64_set_context(CPUSPARCState *env)
env->npc = npc; env->npc = npc;
__get_user(env->y, &((*grp)[SPARC_MC_Y])); __get_user(env->y, &((*grp)[SPARC_MC_Y]));
__get_user(tstate, &((*grp)[SPARC_MC_TSTATE])); __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
/* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */
env->asi = (tstate >> 24) & 0xff; env->asi = (tstate >> 24) & 0xff;
cpu_put_ccr(env, tstate >> 32); cpu_put_ccr(env, (tstate >> 32) & 0xff);
cpu_put_cwp64(env, tstate & 0x1f);
__get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1])); __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
__get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2])); __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
__get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3])); __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
__get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4])); __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4]));
__get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5])); __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
__get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6])); __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 * 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_FP], &(ucp->tuc_mcontext.mc_fp));
__get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7)); __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7));
/* FIXME this does not match how the kernel handles the FPU in fpup = &ucp->tuc_mcontext.mc_fpregs;
* its sparc64_set_context implementation. In particular the FPU
* is only restored if fenab is non-zero in: __get_user(fenab, &(fpup->mcfpu_enab));
* __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.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(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs)); __get_user(fprs, &(fpup->mcfpu_fprs));
{ if (fprs & FPRS_DL) {
uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs; for (i = 0; i < 16; i++) {
for (i = 0; i < 64; i++, src++) { __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
if (i & 1) {
__get_user(env->fpr[i/2].l.lower, src);
} else {
__get_user(env->fpr[i/2].l.upper, src);
} }
} }
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); unlock_user_struct(ucp, ucp_addr, 0);
return; return;
do_sigsegv: do_sigsegv:
@ -510,6 +528,8 @@ void sparc64_get_context(CPUSPARCState *env)
goto do_sigsegv; goto do_sigsegv;
} }
memset(ucp, 0, sizeof(*ucp));
mcp = &ucp->tuc_mcontext; mcp = &ucp->tuc_mcontext;
grp = &mcp->mc_gregs; grp = &mcp->mc_gregs;
@ -535,12 +555,9 @@ void sparc64_get_context(CPUSPARCState *env)
for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) { for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
__put_user(*src, dst); __put_user(*src, dst);
} }
if (err)
goto do_sigsegv;
} }
/* XXX: tstate must be saved properly */ __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE]));
// __put_user(env->tstate, &((*grp)[SPARC_MC_TSTATE]));
__put_user(env->pc, &((*grp)[SPARC_MC_PC])); __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
__put_user(env->npc, &((*grp)[SPARC_MC_NPC])); __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
__put_user(env->y, &((*grp)[SPARC_MC_Y])); __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_FP], &(mcp->mc_fp));
__put_user(env->regwptr[WREG_I7], &(mcp->mc_i7)); __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7));
{ /*
uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs; * We don't write out the FPU state. This matches the kernel's
for (i = 0; i < 64; i++, dst++) { * implementation (which has the code for doing this but
if (i & 1) { * hidden behind an "if (fenab)" where fenab is always 0).
__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));
if (err)
goto do_sigsegv;
unlock_user_struct(ucp, ucp_addr, 1); unlock_user_struct(ucp, ucp_addr, 1);
return; return;
do_sigsegv: do_sigsegv:

View File

@ -56,6 +56,7 @@
#include <linux/wireless.h> #include <linux/wireless.h>
#include <linux/icmp.h> #include <linux/icmp.h>
#include <linux/icmpv6.h> #include <linux/icmpv6.h>
#include <linux/if_tun.h>
#include <linux/errqueue.h> #include <linux/errqueue.h>
#include <linux/random.h> #include <linux/random.h>
#ifdef CONFIG_TIMERFD #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, safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
size_t, len, unsigned *, prio, const struct timespec *, timeout) size_t, len, unsigned *, prio, const struct timespec *, timeout)
#endif #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 /* 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 * "third argument might be integer or pointer or not present" behaviour of
* the libc function. * the libc function.
@ -5703,6 +5710,42 @@ static abi_long do_ioctl_drm_i915(const IOCTLEntry *ie, uint8_t *buf_temp,
#endif #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[] = { IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \ #define IOCTL(cmd, access, ...) \
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, { 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)); return get_errno(membarrier(arg1, arg2));
#endif #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: default:
qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num); qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
return -TARGET_ENOSYS; return -TARGET_ENOSYS;

View File

@ -929,6 +929,38 @@ struct target_rtc_pll_info {
#define TARGET_SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ #define TARGET_SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
/* From <linux/if_tun.h> */
#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 <linux/random.h> */ /* From <linux/random.h> */
#define TARGET_RNDGETENTCNT TARGET_IOR('R', 0x00, int) #define TARGET_RNDGETENTCNT TARGET_IOR('R', 0x00, int)

View File

@ -844,6 +844,7 @@ struct CPUMIPSState {
#define CP0C0_MT 7 /* 9..7 */ #define CP0C0_MT 7 /* 9..7 */
#define CP0C0_VI 3 #define CP0C0_VI 3
#define CP0C0_K0 0 /* 2..0 */ #define CP0C0_K0 0 /* 2..0 */
#define CP0C0_AR_LENGTH 3
int32_t CP0_Config1; int32_t CP0_Config1;
#define CP0C1_M 31 #define CP0C1_M 31
#define CP0C1_MMU 25 /* 30..25 */ #define CP0C1_MMU 25 /* 30..25 */

View File

@ -156,6 +156,8 @@ enum {
#define PS_IE (1<<1) #define PS_IE (1<<1)
#define PS_AG (1<<0) /* v9, zero on UA2007 */ #define PS_AG (1<<0) /* v9, zero on UA2007 */
#define FPRS_DL (1 << 0)
#define FPRS_DU (1 << 1)
#define FPRS_FEF (1 << 2) #define FPRS_FEF (1 << 2)
#define HS_PRIV (1<<2) #define HS_PRIV (1<<2)
@ -606,10 +608,6 @@ target_ulong cpu_get_psr(CPUSPARCState *env1);
void cpu_put_psr(CPUSPARCState *env1, target_ulong val); void cpu_put_psr(CPUSPARCState *env1, target_ulong val);
void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val); void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val);
#ifdef TARGET_SPARC64 #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_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl); void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl);
#endif #endif
@ -827,4 +825,24 @@ static inline bool tb_am_enabled(int tb_flags)
#endif #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 #endif

View File

@ -131,9 +131,7 @@ void sparc_cpu_do_interrupt(CPUState *cs)
} }
tsptr = cpu_tsptr(env); tsptr = cpu_tsptr(env);
tsptr->tstate = (cpu_get_ccr(env) << 32) | tsptr->tstate = sparc64_tstate(env);
((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
cpu_get_cwp64(env);
tsptr->tpc = env->pc; tsptr->tpc = env->pc;
tsptr->tnpc = env->npc; tsptr->tnpc = env->npc;
tsptr->tt = intno; tsptr->tt = intno;
@ -148,7 +146,6 @@ void sparc_cpu_do_interrupt(CPUState *cs)
} }
if (env->def.features & CPU_FEATURE_GL) { if (env->def.features & CPU_FEATURE_GL) {
tsptr->tstate |= (env->gl & 7ULL) << 40;
cpu_gl_switch_gregs(env, env->gl + 1); cpu_gl_switch_gregs(env, env->gl + 1);
env->gl++; env->gl++;
} }