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:
commit
091774bfde
|
@ -170,68 +170,81 @@ 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
|
|
||||||
binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB
|
|
||||||
configurations), and arm-uclinux bFLT format binaries.
|
|
||||||
|
|
||||||
user mode (ColdFire)
|
* ``qemu-armeb`` TODO.
|
||||||
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.
|
|
||||||
|
|
||||||
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)
|
- user mode (ColdFire)
|
||||||
``qemu-cris`` TODO.
|
|
||||||
|
|
||||||
user mode (i386)
|
- user mode (M68K)
|
||||||
``qemu-i386`` TODO. ``qemu-x86_64`` TODO.
|
|
||||||
|
|
||||||
user mode (Microblaze)
|
* ``qemu-m68k`` is capable of running semihosted binaries using the BDM
|
||||||
``qemu-microblaze`` TODO.
|
(m5xxx-ram-hosted.ld) or m68k-sim (sim.ld) syscall interfaces, and
|
||||||
|
coldfire uClinux bFLT format binaries.
|
||||||
|
|
||||||
user mode (MIPS)
|
The binary format is detected automatically.
|
||||||
``qemu-mips`` executes 32-bit big endian MIPS binaries (MIPS O32 ABI).
|
|
||||||
|
|
||||||
``qemu-mipsel`` executes 32-bit little endian MIPS binaries (MIPS O32
|
- user mode (Cris)
|
||||||
ABI).
|
|
||||||
|
|
||||||
``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
|
- user mode (i386)
|
||||||
ABI).
|
|
||||||
|
|
||||||
``qemu-mipsn32`` executes 32-bit big endian MIPS binaries (MIPS N32
|
* ``qemu-i386`` TODO.
|
||||||
ABI).
|
* ``qemu-x86_64`` TODO.
|
||||||
|
|
||||||
``qemu-mipsn32el`` executes 32-bit little endian MIPS binaries (MIPS N32
|
- user mode (Microblaze)
|
||||||
ABI).
|
|
||||||
|
|
||||||
user mode (NiosII)
|
* ``qemu-microblaze`` TODO.
|
||||||
``qemu-nios2`` TODO.
|
|
||||||
|
|
||||||
user mode (PowerPC)
|
- user mode (MIPS)
|
||||||
``qemu-ppc64abi32`` TODO. ``qemu-ppc64`` TODO. ``qemu-ppc`` TODO.
|
|
||||||
|
|
||||||
user mode (SH4)
|
* ``qemu-mips`` executes 32-bit big endian MIPS binaries (MIPS O32 ABI).
|
||||||
``qemu-sh4eb`` TODO. ``qemu-sh4`` TODO.
|
|
||||||
|
|
||||||
user mode (SPARC)
|
* ``qemu-mipsel`` executes 32-bit little endian MIPS binaries (MIPS O32 ABI).
|
||||||
``qemu-sparc`` can execute Sparc32 binaries (Sparc32 CPU, 32 bit ABI).
|
|
||||||
|
|
||||||
``qemu-sparc32plus`` can execute Sparc32 and SPARC32PLUS binaries
|
* ``qemu-mips64`` executes 64-bit big endian MIPS binaries (MIPS N64 ABI).
|
||||||
(Sparc64 CPU, 32 bit ABI).
|
|
||||||
|
|
||||||
``qemu-sparc64`` can execute some Sparc64 (Sparc64 CPU, 64 bit ABI) and
|
* ``qemu-mips64el`` executes 64-bit little endian MIPS binaries (MIPS N64
|
||||||
SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI).
|
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
|
BSD User space emulator
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -767,20 +767,23 @@ 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 */
|
||||||
|
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 {
|
} else {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
host_addr = MAP_FAILED;
|
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) {
|
if (host_addr == MAP_FAILED) {
|
||||||
|
|
|
@ -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;
|
||||||
__get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
|
|
||||||
{
|
/*
|
||||||
uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
|
* We use the FPRS from the guest only in deciding whether
|
||||||
for (i = 0; i < 64; i++, src++) {
|
* to restore the upper, lower, or both banks of the FPU regs.
|
||||||
if (i & 1) {
|
* The kernel here writes the FPU register data into the
|
||||||
__get_user(env->fpr[i/2].l.lower, src);
|
* process's current_thread_info state and unconditionally
|
||||||
} else {
|
* clears FPRS and TSTATE_PEF: this disables the FPU so that the
|
||||||
__get_user(env->fpr[i/2].l.upper, src);
|
* 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);
|
unlock_user_struct(ucp, ucp_addr, 0);
|
||||||
return;
|
return;
|
||||||
do_sigsegv:
|
do_sigsegv:
|
||||||
|
@ -509,7 +527,9 @@ void sparc64_get_context(CPUSPARCState *env)
|
||||||
if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
|
if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
|
||||||
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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -156,7 +156,9 @@ 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_FEF (1<<2)
|
#define FPRS_DL (1 << 0)
|
||||||
|
#define FPRS_DU (1 << 1)
|
||||||
|
#define FPRS_FEF (1 << 2)
|
||||||
|
|
||||||
#define HS_PRIV (1<<2)
|
#define HS_PRIV (1<<2)
|
||||||
#endif
|
#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(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
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue