aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/aarch64/cpu_loop.c22
-rw-r--r--linux-user/aarch64/elfload.c380
-rw-r--r--linux-user/aarch64/signal.c143
-rw-r--r--linux-user/aarch64/target_elf.h30
-rw-r--r--linux-user/aarch64/target_ptrace.h14
-rw-r--r--linux-user/aarch64/target_syscall.h7
-rw-r--r--linux-user/alpha/cpu_loop.c11
-rw-r--r--linux-user/alpha/elfload.c11
-rw-r--r--linux-user/alpha/target_elf.h8
-rw-r--r--linux-user/alpha/target_syscall.h40
-rw-r--r--linux-user/arm/cpu_loop.c76
-rw-r--r--linux-user/arm/elfload.c277
-rw-r--r--linux-user/arm/target_elf.h27
-rw-r--r--linux-user/arm/target_proc.h4
-rw-r--r--linux-user/arm/target_ptrace.h16
-rw-r--r--linux-user/arm/target_syscall.h8
-rw-r--r--linux-user/elfload.c2089
-rw-r--r--linux-user/fd-trans.h10
-rw-r--r--linux-user/gen-vdso.c43
-rw-r--r--linux-user/hexagon/cpu_loop.c8
-rw-r--r--linux-user/hexagon/elfload.c35
-rw-r--r--linux-user/hexagon/target_elf.h30
-rw-r--r--linux-user/hexagon/target_syscall.h5
-rw-r--r--linux-user/hppa/cpu_loop.c30
-rw-r--r--linux-user/hppa/elfload.c47
-rw-r--r--linux-user/hppa/target_elf.h15
-rw-r--r--linux-user/hppa/target_syscall.h18
-rw-r--r--linux-user/i386/cpu_loop.c48
-rw-r--r--linux-user/i386/elfload.c47
-rw-r--r--linux-user/i386/target_elf.h41
-rw-r--r--linux-user/i386/target_ptrace.h32
-rw-r--r--linux-user/i386/target_syscall.h18
-rw-r--r--linux-user/linuxload.c6
-rw-r--r--linux-user/loader.h38
-rw-r--r--linux-user/loongarch64/cpu_loop.c11
-rw-r--r--linux-user/loongarch64/elfload.c78
-rw-r--r--linux-user/loongarch64/target_elf.h21
-rw-r--r--linux-user/loongarch64/target_ptrace.h15
-rw-r--r--linux-user/loongarch64/target_syscall.h23
-rw-r--r--linux-user/m68k/cpu_loop.c32
-rw-r--r--linux-user/m68k/elfload.c43
-rw-r--r--linux-user/m68k/target_elf.h36
-rw-r--r--linux-user/m68k/target_syscall.h16
-rw-r--r--linux-user/main.c39
-rw-r--r--linux-user/meson.build5
-rw-r--r--linux-user/microblaze/cpu_loop.c39
-rw-r--r--linux-user/microblaze/elfload.c24
-rw-r--r--linux-user/microblaze/signal.c71
-rw-r--r--linux-user/microblaze/target_elf.h22
-rw-r--r--linux-user/microblaze/target_ptrace.h20
-rw-r--r--linux-user/microblaze/target_syscall.h44
-rw-r--r--linux-user/mips/cpu_loop.c16
-rw-r--r--linux-user/mips/elfload.c142
-rw-r--r--linux-user/mips/target_elf.h29
-rw-r--r--linux-user/mips/target_ptrace.h17
-rw-r--r--linux-user/mips/target_signal.h1
-rw-r--r--linux-user/mips/target_syscall.h19
-rw-r--r--linux-user/mips64/elfload.c1
-rw-r--r--linux-user/mips64/target_elf.h51
-rw-r--r--linux-user/mips64/target_ptrace.h16
-rw-r--r--linux-user/mips64/target_syscall.h16
-rw-r--r--linux-user/mmap.c2
-rw-r--r--linux-user/openrisc/cpu_loop.c11
-rw-r--r--linux-user/openrisc/elfload.c21
-rw-r--r--linux-user/openrisc/signal.c3
-rw-r--r--linux-user/openrisc/target_elf.h20
-rw-r--r--linux-user/openrisc/target_ptrace.h13
-rw-r--r--linux-user/openrisc/target_syscall.h11
-rw-r--r--linux-user/plugin-api.c1
-rw-r--r--linux-user/ppc/cpu_loop.c26
-rw-r--r--linux-user/ppc/elfload.c146
-rw-r--r--linux-user/ppc/target_elf.h62
-rw-r--r--linux-user/ppc/target_ptrace.h26
-rw-r--r--linux-user/ppc/target_syscall.h28
-rw-r--r--linux-user/qemu.h8
-rw-r--r--linux-user/riscv/cpu_loop.c15
-rw-r--r--linux-user/riscv/elfload.c23
-rw-r--r--linux-user/riscv/target_elf.h17
-rw-r--r--linux-user/riscv/target_syscall.h35
-rw-r--r--linux-user/s390x/cpu_loop.c15
-rw-r--r--linux-user/s390x/elfload.c82
-rw-r--r--linux-user/s390x/signal.c1
-rw-r--r--linux-user/s390x/target_elf.h22
-rw-r--r--linux-user/s390x/target_proc.h2
-rw-r--r--linux-user/s390x/target_ptrace.h18
-rw-r--r--linux-user/s390x/target_syscall.h22
-rw-r--r--linux-user/sh4/cpu_loop.c10
-rw-r--r--linux-user/sh4/elfload.c53
-rw-r--r--linux-user/sh4/target_elf.h21
-rw-r--r--linux-user/sh4/target_ptrace.h18
-rw-r--r--linux-user/sh4/target_syscall.h11
-rw-r--r--linux-user/signal.c4
-rw-r--r--linux-user/sparc/cpu_loop.c16
-rw-r--r--linux-user/sparc/elfload.c42
-rw-r--r--linux-user/sparc/signal.c2
-rw-r--r--linux-user/sparc/target_elf.h18
-rw-r--r--linux-user/sparc/target_ptrace.h24
-rw-r--r--linux-user/sparc/target_syscall.h19
-rw-r--r--linux-user/strace.c106
-rw-r--r--linux-user/strace.list6
-rw-r--r--linux-user/syscall.c37
-rw-r--r--linux-user/syscall_defs.h4
-rw-r--r--linux-user/user-internals.h1
-rw-r--r--linux-user/x86_64/elfload.c73
-rw-r--r--linux-user/x86_64/target_elf.h24
-rw-r--r--linux-user/x86_64/target_ptrace.h40
-rw-r--r--linux-user/x86_64/target_syscall.h28
-rw-r--r--linux-user/xtensa/cpu_loop.c22
-rw-r--r--linux-user/xtensa/elfload.c31
-rw-r--r--linux-user/xtensa/target_elf.h18
-rw-r--r--linux-user/xtensa/target_ptrace.h22
-rw-r--r--linux-user/xtensa/target_syscall.h35
112 files changed, 2824 insertions, 2972 deletions
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index fea43ce..4c49211 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -137,13 +137,10 @@ void cpu_loop(CPUARMState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
+ CPUARMState *env = cpu_env(cs);
ARMCPU *cpu = env_archcpu(env);
- CPUState *cs = env_cpu(env);
- TaskState *ts = get_task_state(cs);
- struct image_info *info = ts->info;
- int i;
if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
fprintf(stderr,
@@ -151,14 +148,12 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
exit(EXIT_FAILURE);
}
- for (i = 0; i < 31; i++) {
- env->xregs[i] = regs->regs[i];
- }
- env->pc = regs->pc;
- env->xregs[31] = regs->sp;
+ env->pc = info->entry & ~0x3ULL;
+ env->xregs[31] = info->start_stack;
+
#if TARGET_BIG_ENDIAN
env->cp15.sctlr_el[1] |= SCTLR_E0E;
- for (i = 1; i < 4; ++i) {
+ for (int i = 1; i < 4; ++i) {
env->cp15.sctlr_el[i] |= SCTLR_EE;
}
arm_rebuild_hflags(env);
@@ -167,9 +162,4 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
if (cpu_isar_feature(aa64_pauth, cpu)) {
qemu_guest_getrandom_nofail(&env->keys, sizeof(env->keys));
}
-
- ts->stack_base = info->start_stack;
- ts->heap_base = info->brk;
- /* This will be filled in on the first SYS_HEAPINFO call. */
- ts->heap_limit = 0;
}
diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c
new file mode 100644
index 0000000..77d03b5
--- /dev/null
+++ b/linux-user/aarch64/elfload.c
@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target/arm/cpu-features.h"
+#include "target_elf.h"
+#include "elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "any";
+}
+
+enum {
+ ARM_HWCAP_A64_FP = 1 << 0,
+ ARM_HWCAP_A64_ASIMD = 1 << 1,
+ ARM_HWCAP_A64_EVTSTRM = 1 << 2,
+ ARM_HWCAP_A64_AES = 1 << 3,
+ ARM_HWCAP_A64_PMULL = 1 << 4,
+ ARM_HWCAP_A64_SHA1 = 1 << 5,
+ ARM_HWCAP_A64_SHA2 = 1 << 6,
+ ARM_HWCAP_A64_CRC32 = 1 << 7,
+ ARM_HWCAP_A64_ATOMICS = 1 << 8,
+ ARM_HWCAP_A64_FPHP = 1 << 9,
+ ARM_HWCAP_A64_ASIMDHP = 1 << 10,
+ ARM_HWCAP_A64_CPUID = 1 << 11,
+ ARM_HWCAP_A64_ASIMDRDM = 1 << 12,
+ ARM_HWCAP_A64_JSCVT = 1 << 13,
+ ARM_HWCAP_A64_FCMA = 1 << 14,
+ ARM_HWCAP_A64_LRCPC = 1 << 15,
+ ARM_HWCAP_A64_DCPOP = 1 << 16,
+ ARM_HWCAP_A64_SHA3 = 1 << 17,
+ ARM_HWCAP_A64_SM3 = 1 << 18,
+ ARM_HWCAP_A64_SM4 = 1 << 19,
+ ARM_HWCAP_A64_ASIMDDP = 1 << 20,
+ ARM_HWCAP_A64_SHA512 = 1 << 21,
+ ARM_HWCAP_A64_SVE = 1 << 22,
+ ARM_HWCAP_A64_ASIMDFHM = 1 << 23,
+ ARM_HWCAP_A64_DIT = 1 << 24,
+ ARM_HWCAP_A64_USCAT = 1 << 25,
+ ARM_HWCAP_A64_ILRCPC = 1 << 26,
+ ARM_HWCAP_A64_FLAGM = 1 << 27,
+ ARM_HWCAP_A64_SSBS = 1 << 28,
+ ARM_HWCAP_A64_SB = 1 << 29,
+ ARM_HWCAP_A64_PACA = 1 << 30,
+ ARM_HWCAP_A64_PACG = 1ULL << 31,
+ ARM_HWCAP_A64_GCS = 1ULL << 32,
+ ARM_HWCAP_A64_CMPBR = 1ULL << 33,
+ ARM_HWCAP_A64_FPRCVT = 1ULL << 34,
+ ARM_HWCAP_A64_F8MM8 = 1ULL << 35,
+ ARM_HWCAP_A64_F8MM4 = 1ULL << 36,
+ ARM_HWCAP_A64_SVE_F16MM = 1ULL << 37,
+ ARM_HWCAP_A64_SVE_ELTPERM = 1ULL << 38,
+ ARM_HWCAP_A64_SVE_AES2 = 1ULL << 39,
+ ARM_HWCAP_A64_SVE_BFSCALE = 1ULL << 40,
+ ARM_HWCAP_A64_SVE2P2 = 1ULL << 41,
+ ARM_HWCAP_A64_SME2P2 = 1ULL << 42,
+ ARM_HWCAP_A64_SME_SBITPERM = 1ULL << 43,
+ ARM_HWCAP_A64_SME_AES = 1ULL << 44,
+ ARM_HWCAP_A64_SME_SFEXPA = 1ULL << 45,
+ ARM_HWCAP_A64_SME_STMOP = 1ULL << 46,
+ ARM_HWCAP_A64_SME_SMOP4 = 1ULL << 47,
+
+ ARM_HWCAP2_A64_DCPODP = 1 << 0,
+ ARM_HWCAP2_A64_SVE2 = 1 << 1,
+ ARM_HWCAP2_A64_SVEAES = 1 << 2,
+ ARM_HWCAP2_A64_SVEPMULL = 1 << 3,
+ ARM_HWCAP2_A64_SVEBITPERM = 1 << 4,
+ ARM_HWCAP2_A64_SVESHA3 = 1 << 5,
+ ARM_HWCAP2_A64_SVESM4 = 1 << 6,
+ ARM_HWCAP2_A64_FLAGM2 = 1 << 7,
+ ARM_HWCAP2_A64_FRINT = 1 << 8,
+ ARM_HWCAP2_A64_SVEI8MM = 1 << 9,
+ ARM_HWCAP2_A64_SVEF32MM = 1 << 10,
+ ARM_HWCAP2_A64_SVEF64MM = 1 << 11,
+ ARM_HWCAP2_A64_SVEBF16 = 1 << 12,
+ ARM_HWCAP2_A64_I8MM = 1 << 13,
+ ARM_HWCAP2_A64_BF16 = 1 << 14,
+ ARM_HWCAP2_A64_DGH = 1 << 15,
+ ARM_HWCAP2_A64_RNG = 1 << 16,
+ ARM_HWCAP2_A64_BTI = 1 << 17,
+ ARM_HWCAP2_A64_MTE = 1 << 18,
+ ARM_HWCAP2_A64_ECV = 1 << 19,
+ ARM_HWCAP2_A64_AFP = 1 << 20,
+ ARM_HWCAP2_A64_RPRES = 1 << 21,
+ ARM_HWCAP2_A64_MTE3 = 1 << 22,
+ ARM_HWCAP2_A64_SME = 1 << 23,
+ ARM_HWCAP2_A64_SME_I16I64 = 1 << 24,
+ ARM_HWCAP2_A64_SME_F64F64 = 1 << 25,
+ ARM_HWCAP2_A64_SME_I8I32 = 1 << 26,
+ ARM_HWCAP2_A64_SME_F16F32 = 1 << 27,
+ ARM_HWCAP2_A64_SME_B16F32 = 1 << 28,
+ ARM_HWCAP2_A64_SME_F32F32 = 1 << 29,
+ ARM_HWCAP2_A64_SME_FA64 = 1 << 30,
+ ARM_HWCAP2_A64_WFXT = 1ULL << 31,
+ ARM_HWCAP2_A64_EBF16 = 1ULL << 32,
+ ARM_HWCAP2_A64_SVE_EBF16 = 1ULL << 33,
+ ARM_HWCAP2_A64_CSSC = 1ULL << 34,
+ ARM_HWCAP2_A64_RPRFM = 1ULL << 35,
+ ARM_HWCAP2_A64_SVE2P1 = 1ULL << 36,
+ ARM_HWCAP2_A64_SME2 = 1ULL << 37,
+ ARM_HWCAP2_A64_SME2P1 = 1ULL << 38,
+ ARM_HWCAP2_A64_SME_I16I32 = 1ULL << 39,
+ ARM_HWCAP2_A64_SME_BI32I32 = 1ULL << 40,
+ ARM_HWCAP2_A64_SME_B16B16 = 1ULL << 41,
+ ARM_HWCAP2_A64_SME_F16F16 = 1ULL << 42,
+ ARM_HWCAP2_A64_MOPS = 1ULL << 43,
+ ARM_HWCAP2_A64_HBC = 1ULL << 44,
+ ARM_HWCAP2_A64_SVE_B16B16 = 1ULL << 45,
+ ARM_HWCAP2_A64_LRCPC3 = 1ULL << 46,
+ ARM_HWCAP2_A64_LSE128 = 1ULL << 47,
+ ARM_HWCAP2_A64_FPMR = 1ULL << 48,
+ ARM_HWCAP2_A64_LUT = 1ULL << 49,
+ ARM_HWCAP2_A64_FAMINMAX = 1ULL << 50,
+ ARM_HWCAP2_A64_F8CVT = 1ULL << 51,
+ ARM_HWCAP2_A64_F8FMA = 1ULL << 52,
+ ARM_HWCAP2_A64_F8DP4 = 1ULL << 53,
+ ARM_HWCAP2_A64_F8DP2 = 1ULL << 54,
+ ARM_HWCAP2_A64_F8E4M3 = 1ULL << 55,
+ ARM_HWCAP2_A64_F8E5M2 = 1ULL << 56,
+ ARM_HWCAP2_A64_SME_LUTV2 = 1ULL << 57,
+ ARM_HWCAP2_A64_SME_F8F16 = 1ULL << 58,
+ ARM_HWCAP2_A64_SME_F8F32 = 1ULL << 59,
+ ARM_HWCAP2_A64_SME_SF8FMA = 1ULL << 60,
+ ARM_HWCAP2_A64_SME_SF8DP4 = 1ULL << 61,
+ ARM_HWCAP2_A64_SME_SF8DP2 = 1ULL << 62,
+ ARM_HWCAP2_A64_POE = 1ULL << 63,
+};
+
+#define GET_FEATURE_ID(feat, hwcap) \
+ do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ abi_ulong hwcaps = 0;
+
+ hwcaps |= ARM_HWCAP_A64_FP;
+ hwcaps |= ARM_HWCAP_A64_ASIMD;
+ hwcaps |= ARM_HWCAP_A64_CPUID;
+
+ /* probe for the extra features */
+
+ GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
+ GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
+ GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
+ GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
+ GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
+ GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
+ GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
+ GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
+ GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
+ GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
+ GET_FEATURE_ID(aa64_lse, ARM_HWCAP_A64_ATOMICS);
+ GET_FEATURE_ID(aa64_lse2, ARM_HWCAP_A64_USCAT);
+ GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
+ GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
+ GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
+ GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
+ GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
+ GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
+ GET_FEATURE_ID(aa64_dit, ARM_HWCAP_A64_DIT);
+ GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
+ GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
+ GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
+ GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
+ GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
+ GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
+
+ return hwcaps;
+}
+
+abi_ulong get_elf_hwcap2(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ abi_ulong hwcaps = 0;
+
+ GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
+ GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
+ GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
+ GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
+ GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
+ GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
+ GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
+ GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
+ GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
+ GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
+ GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
+ GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
+ GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
+ GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
+ GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
+ GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
+ GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
+ GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
+ GET_FEATURE_ID(aa64_mte3, ARM_HWCAP2_A64_MTE3);
+ GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME |
+ ARM_HWCAP2_A64_SME_F32F32 |
+ ARM_HWCAP2_A64_SME_B16F32 |
+ ARM_HWCAP2_A64_SME_F16F32 |
+ ARM_HWCAP2_A64_SME_I8I32));
+ GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64);
+ GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64);
+ GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
+ GET_FEATURE_ID(aa64_hbc, ARM_HWCAP2_A64_HBC);
+ GET_FEATURE_ID(aa64_mops, ARM_HWCAP2_A64_MOPS);
+ GET_FEATURE_ID(aa64_sve2p1, ARM_HWCAP2_A64_SVE2P1);
+ GET_FEATURE_ID(aa64_sme2, (ARM_HWCAP2_A64_SME2 |
+ ARM_HWCAP2_A64_SME_I16I32 |
+ ARM_HWCAP2_A64_SME_BI32I32));
+ GET_FEATURE_ID(aa64_sme2p1, ARM_HWCAP2_A64_SME2P1);
+ GET_FEATURE_ID(aa64_sme_b16b16, ARM_HWCAP2_A64_SME_B16B16);
+ GET_FEATURE_ID(aa64_sme_f16f16, ARM_HWCAP2_A64_SME_F16F16);
+ GET_FEATURE_ID(aa64_sve_b16b16, ARM_HWCAP2_A64_SVE_B16B16);
+ GET_FEATURE_ID(aa64_cssc, ARM_HWCAP2_A64_CSSC);
+ GET_FEATURE_ID(aa64_lse128, ARM_HWCAP2_A64_LSE128);
+
+ return hwcaps;
+}
+
+const char *elf_hwcap_str(uint32_t bit)
+{
+ static const char * const hwcap_str[] = {
+ [__builtin_ctz(ARM_HWCAP_A64_FP )] = "fp",
+ [__builtin_ctz(ARM_HWCAP_A64_ASIMD )] = "asimd",
+ [__builtin_ctz(ARM_HWCAP_A64_EVTSTRM )] = "evtstrm",
+ [__builtin_ctz(ARM_HWCAP_A64_AES )] = "aes",
+ [__builtin_ctz(ARM_HWCAP_A64_PMULL )] = "pmull",
+ [__builtin_ctz(ARM_HWCAP_A64_SHA1 )] = "sha1",
+ [__builtin_ctz(ARM_HWCAP_A64_SHA2 )] = "sha2",
+ [__builtin_ctz(ARM_HWCAP_A64_CRC32 )] = "crc32",
+ [__builtin_ctz(ARM_HWCAP_A64_ATOMICS )] = "atomics",
+ [__builtin_ctz(ARM_HWCAP_A64_FPHP )] = "fphp",
+ [__builtin_ctz(ARM_HWCAP_A64_ASIMDHP )] = "asimdhp",
+ [__builtin_ctz(ARM_HWCAP_A64_CPUID )] = "cpuid",
+ [__builtin_ctz(ARM_HWCAP_A64_ASIMDRDM)] = "asimdrdm",
+ [__builtin_ctz(ARM_HWCAP_A64_JSCVT )] = "jscvt",
+ [__builtin_ctz(ARM_HWCAP_A64_FCMA )] = "fcma",
+ [__builtin_ctz(ARM_HWCAP_A64_LRCPC )] = "lrcpc",
+ [__builtin_ctz(ARM_HWCAP_A64_DCPOP )] = "dcpop",
+ [__builtin_ctz(ARM_HWCAP_A64_SHA3 )] = "sha3",
+ [__builtin_ctz(ARM_HWCAP_A64_SM3 )] = "sm3",
+ [__builtin_ctz(ARM_HWCAP_A64_SM4 )] = "sm4",
+ [__builtin_ctz(ARM_HWCAP_A64_ASIMDDP )] = "asimddp",
+ [__builtin_ctz(ARM_HWCAP_A64_SHA512 )] = "sha512",
+ [__builtin_ctz(ARM_HWCAP_A64_SVE )] = "sve",
+ [__builtin_ctz(ARM_HWCAP_A64_ASIMDFHM)] = "asimdfhm",
+ [__builtin_ctz(ARM_HWCAP_A64_DIT )] = "dit",
+ [__builtin_ctz(ARM_HWCAP_A64_USCAT )] = "uscat",
+ [__builtin_ctz(ARM_HWCAP_A64_ILRCPC )] = "ilrcpc",
+ [__builtin_ctz(ARM_HWCAP_A64_FLAGM )] = "flagm",
+ [__builtin_ctz(ARM_HWCAP_A64_SSBS )] = "ssbs",
+ [__builtin_ctz(ARM_HWCAP_A64_SB )] = "sb",
+ [__builtin_ctz(ARM_HWCAP_A64_PACA )] = "paca",
+ [__builtin_ctz(ARM_HWCAP_A64_PACG )] = "pacg",
+ [__builtin_ctzll(ARM_HWCAP_A64_GCS )] = "gcs",
+ [__builtin_ctzll(ARM_HWCAP_A64_CMPBR )] = "cmpbr",
+ [__builtin_ctzll(ARM_HWCAP_A64_FPRCVT)] = "fprcvt",
+ [__builtin_ctzll(ARM_HWCAP_A64_F8MM8 )] = "f8mm8",
+ [__builtin_ctzll(ARM_HWCAP_A64_F8MM4 )] = "f8mm4",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE_F16MM)] = "svef16mm",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE_ELTPERM)] = "sveeltperm",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE_AES2)] = "sveaes2",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE_BFSCALE)] = "svebfscale",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE2P2)] = "sve2p2",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME2P2)] = "sme2p2",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_SBITPERM)] = "smesbitperm",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_AES)] = "smeaes",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_SFEXPA)] = "smesfexpa",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_STMOP)] = "smestmop",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_SMOP4)] = "smesmop4",
+ };
+
+ return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
+}
+
+const char *elf_hwcap2_str(uint32_t bit)
+{
+ static const char * const hwcap_str[] = {
+ [__builtin_ctz(ARM_HWCAP2_A64_DCPODP )] = "dcpodp",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVE2 )] = "sve2",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVEAES )] = "sveaes",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVEPMULL )] = "svepmull",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVEBITPERM )] = "svebitperm",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVESHA3 )] = "svesha3",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVESM4 )] = "svesm4",
+ [__builtin_ctz(ARM_HWCAP2_A64_FLAGM2 )] = "flagm2",
+ [__builtin_ctz(ARM_HWCAP2_A64_FRINT )] = "frint",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVEI8MM )] = "svei8mm",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVEF32MM )] = "svef32mm",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVEF64MM )] = "svef64mm",
+ [__builtin_ctz(ARM_HWCAP2_A64_SVEBF16 )] = "svebf16",
+ [__builtin_ctz(ARM_HWCAP2_A64_I8MM )] = "i8mm",
+ [__builtin_ctz(ARM_HWCAP2_A64_BF16 )] = "bf16",
+ [__builtin_ctz(ARM_HWCAP2_A64_DGH )] = "dgh",
+ [__builtin_ctz(ARM_HWCAP2_A64_RNG )] = "rng",
+ [__builtin_ctz(ARM_HWCAP2_A64_BTI )] = "bti",
+ [__builtin_ctz(ARM_HWCAP2_A64_MTE )] = "mte",
+ [__builtin_ctz(ARM_HWCAP2_A64_ECV )] = "ecv",
+ [__builtin_ctz(ARM_HWCAP2_A64_AFP )] = "afp",
+ [__builtin_ctz(ARM_HWCAP2_A64_RPRES )] = "rpres",
+ [__builtin_ctz(ARM_HWCAP2_A64_MTE3 )] = "mte3",
+ [__builtin_ctz(ARM_HWCAP2_A64_SME )] = "sme",
+ [__builtin_ctz(ARM_HWCAP2_A64_SME_I16I64 )] = "smei16i64",
+ [__builtin_ctz(ARM_HWCAP2_A64_SME_F64F64 )] = "smef64f64",
+ [__builtin_ctz(ARM_HWCAP2_A64_SME_I8I32 )] = "smei8i32",
+ [__builtin_ctz(ARM_HWCAP2_A64_SME_F16F32 )] = "smef16f32",
+ [__builtin_ctz(ARM_HWCAP2_A64_SME_B16F32 )] = "smeb16f32",
+ [__builtin_ctz(ARM_HWCAP2_A64_SME_F32F32 )] = "smef32f32",
+ [__builtin_ctz(ARM_HWCAP2_A64_SME_FA64 )] = "smefa64",
+ [__builtin_ctz(ARM_HWCAP2_A64_WFXT )] = "wfxt",
+ [__builtin_ctzll(ARM_HWCAP2_A64_EBF16 )] = "ebf16",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SVE_EBF16 )] = "sveebf16",
+ [__builtin_ctzll(ARM_HWCAP2_A64_CSSC )] = "cssc",
+ [__builtin_ctzll(ARM_HWCAP2_A64_RPRFM )] = "rprfm",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SVE2P1 )] = "sve2p1",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME2 )] = "sme2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME2P1 )] = "sme2p1",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_I16I32 )] = "smei16i32",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_BI32I32)] = "smebi32i32",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_B16B16 )] = "smeb16b16",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_F16F16 )] = "smef16f16",
+ [__builtin_ctzll(ARM_HWCAP2_A64_MOPS )] = "mops",
+ [__builtin_ctzll(ARM_HWCAP2_A64_HBC )] = "hbc",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SVE_B16B16 )] = "sveb16b16",
+ [__builtin_ctzll(ARM_HWCAP2_A64_LRCPC3 )] = "lrcpc3",
+ [__builtin_ctzll(ARM_HWCAP2_A64_LSE128 )] = "lse128",
+ [__builtin_ctzll(ARM_HWCAP2_A64_FPMR )] = "fpmr",
+ [__builtin_ctzll(ARM_HWCAP2_A64_LUT )] = "lut",
+ [__builtin_ctzll(ARM_HWCAP2_A64_FAMINMAX )] = "faminmax",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8CVT )] = "f8cvt",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8FMA )] = "f8fma",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8DP4 )] = "f8dp4",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8DP2 )] = "f8dp2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8E4M3 )] = "f8e4m3",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8E5M2 )] = "f8e5m2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_LUTV2 )] = "smelutv2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_F8F16 )] = "smef8f16",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_F8F32 )] = "smef8f32",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_SF8DP4 )] = "smesf8dp4",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_SF8DP2 )] = "smesf8dp2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_POE )] = "poe",
+ };
+
+ return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
+}
+
+const char *get_elf_platform(CPUState *cs)
+{
+ return TARGET_BIG_ENDIAN ? "aarch64_be" : "aarch64";
+}
+
+bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
+ const uint32_t *data,
+ struct image_info *info,
+ Error **errp)
+{
+ if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
+ if (pr_datasz != sizeof(uint32_t)) {
+ error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
+ return false;
+ }
+ /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
+ info->note_flags = *data;
+ }
+ return true;
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUARMState *env)
+{
+ for (int i = 0; i < 31; i++) {
+ r->pt.regs[i] = tswap64(env->xregs[i]);
+ }
+ r->pt.sp = tswap64(env->xregs[31]);
+ r->pt.pc = tswap64(env->pc);
+ r->pt.pstate = tswap64(pstate_read((CPUARMState *)env));
+}
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index bc7a138..668353b 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -121,6 +121,30 @@ struct target_za_context {
#define TARGET_ZA_SIG_CONTEXT_SIZE(VQ) \
TARGET_ZA_SIG_ZAV_OFFSET(VQ, VQ * TARGET_SVE_VQ_BYTES)
+#define TARGET_TPIDR2_MAGIC 0x54504902
+
+struct target_tpidr2_context {
+ struct target_aarch64_ctx head;
+ uint64_t tpidr2;
+};
+
+#define TARGET_ZT_MAGIC 0x5a544e01
+
+struct target_zt_context {
+ struct target_aarch64_ctx head;
+ uint16_t nregs;
+ uint16_t reserved[3];
+ /* ZTn register data immediately follows */
+};
+
+#define TARGET_ZT_SIG_REG_BYTES (512 / 8)
+#define TARGET_ZT_SIG_REGS_SIZE(n) (TARGET_ZT_SIG_REG_BYTES * (n))
+#define TARGET_ZT_SIG_CONTEXT_SIZE(n) (sizeof(struct target_zt_context) + \
+ TARGET_ZT_SIG_REGS_SIZE(n))
+#define TARGET_ZT_SIG_REGS_OFFSET sizeof(struct target_zt_context)
+QEMU_BUILD_BUG_ON(TARGET_ZT_SIG_REG_BYTES != \
+ sizeof_field(CPUARMState, za_state.zt0));
+
struct target_rt_sigframe {
struct target_siginfo info;
struct target_ucontext uc;
@@ -248,11 +272,41 @@ static void target_setup_za_record(struct target_za_context *za,
for (i = 0; i < vl; ++i) {
uint64_t *z = (void *)za + TARGET_ZA_SIG_ZAV_OFFSET(vq, i);
for (j = 0; j < vq * 2; ++j) {
- __put_user_e(env->zarray[i].d[j], z + j, le);
+ __put_user_e(env->za_state.za[i].d[j], z + j, le);
}
}
}
+static void target_setup_tpidr2_record(struct target_tpidr2_context *tpidr2,
+ CPUARMState *env)
+{
+ __put_user(TARGET_TPIDR2_MAGIC, &tpidr2->head.magic);
+ __put_user(sizeof(struct target_tpidr2_context), &tpidr2->head.size);
+ __put_user(env->cp15.tpidr2_el0, &tpidr2->tpidr2);
+}
+
+static void target_setup_zt_record(struct target_zt_context *zt,
+ CPUARMState *env, int size)
+{
+ uint64_t *z;
+
+ memset(zt, 0, sizeof(*zt));
+ __put_user(TARGET_ZT_MAGIC, &zt->head.magic);
+ __put_user(size, &zt->head.size);
+ /*
+ * The record format allows for multiple ZT regs, but
+ * currently there is only one, ZT0.
+ */
+ __put_user(1, &zt->nregs);
+ assert(size == TARGET_ZT_SIG_CONTEXT_SIZE(1));
+
+ /* ZT0 is the same byte-stream format as SVE regs and ZA */
+ z = (void *)zt + TARGET_ZT_SIG_REGS_OFFSET;
+ for (int i = 0; i < ARRAY_SIZE(env->za_state.zt0); i++) {
+ __put_user_e(env->za_state.zt0[i], z + i, le);
+ }
+}
+
static void target_restore_general_frame(CPUARMState *env,
struct target_rt_sigframe *sf)
{
@@ -397,12 +451,42 @@ static bool target_restore_za_record(CPUARMState *env,
for (i = 0; i < vl; ++i) {
uint64_t *z = (void *)za + TARGET_ZA_SIG_ZAV_OFFSET(vq, i);
for (j = 0; j < vq * 2; ++j) {
- __get_user_e(env->zarray[i].d[j], z + j, le);
+ __get_user_e(env->za_state.za[i].d[j], z + j, le);
}
}
return true;
}
+static void target_restore_tpidr2_record(CPUARMState *env,
+ struct target_tpidr2_context *tpidr2)
+{
+ __get_user(env->cp15.tpidr2_el0, &tpidr2->tpidr2);
+}
+
+static bool target_restore_zt_record(CPUARMState *env,
+ struct target_zt_context *zt, int size,
+ int svcr)
+{
+ uint16_t nregs;
+ uint64_t *z;
+
+ if (!(FIELD_EX64(svcr, SVCR, ZA))) {
+ return false;
+ }
+
+ __get_user(nregs, &zt->nregs);
+
+ if (nregs != 1) {
+ return false;
+ }
+
+ z = (void *)zt + TARGET_ZT_SIG_REGS_OFFSET;
+ for (int i = 0; i < ARRAY_SIZE(env->za_state.zt0); i++) {
+ __get_user_e(env->za_state.zt0[i], z + i, le);
+ }
+ return true;
+}
+
static int target_restore_sigframe(CPUARMState *env,
struct target_rt_sigframe *sf)
{
@@ -410,10 +494,13 @@ static int target_restore_sigframe(CPUARMState *env,
struct target_fpsimd_context *fpsimd = NULL;
struct target_sve_context *sve = NULL;
struct target_za_context *za = NULL;
+ struct target_tpidr2_context *tpidr2 = NULL;
+ struct target_zt_context *zt = NULL;
uint64_t extra_datap = 0;
bool used_extra = false;
int sve_size = 0;
int za_size = 0;
+ int zt_size = 0;
int svcr = 0;
target_restore_general_frame(env, sf);
@@ -460,6 +547,23 @@ static int target_restore_sigframe(CPUARMState *env,
za_size = size;
break;
+ case TARGET_TPIDR2_MAGIC:
+ if (tpidr2 || size != sizeof(struct target_tpidr2_context) ||
+ !cpu_isar_feature(aa64_sme, env_archcpu(env))) {
+ goto err;
+ }
+ tpidr2 = (struct target_tpidr2_context *)ctx;
+ break;
+
+ case TARGET_ZT_MAGIC:
+ if (zt || size != TARGET_ZT_SIG_CONTEXT_SIZE(1) ||
+ !cpu_isar_feature(aa64_sme2, env_archcpu(env))) {
+ goto err;
+ }
+ zt = (struct target_zt_context *)ctx;
+ zt_size = size;
+ break;
+
case TARGET_EXTRA_MAGIC:
if (extra || size != sizeof(struct target_extra_context)) {
goto err;
@@ -497,6 +601,16 @@ static int target_restore_sigframe(CPUARMState *env,
if (za && !target_restore_za_record(env, za, za_size, &svcr)) {
goto err;
}
+ if (tpidr2) {
+ target_restore_tpidr2_record(env, tpidr2);
+ }
+ /*
+ * NB that we must restore ZT after ZA so the check that there's
+ * no ZT record if SVCR.ZA is 0 gets the right value of SVCR.
+ */
+ if (zt && !target_restore_zt_record(env, zt, zt_size, svcr)) {
+ goto err;
+ }
if (env->svcr != svcr) {
env->svcr = svcr;
arm_rebuild_hflags(env);
@@ -568,8 +682,9 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
.total_size = offsetof(struct target_rt_sigframe,
uc.tuc_mcontext.__reserved),
};
- int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0;
- int sve_size = 0, za_size = 0;
+ int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0, tpidr2_ofs = 0;
+ int zt_ofs = 0;
+ int sve_size = 0, za_size = 0, tpidr2_size = 0, zt_size = 0;
struct target_rt_sigframe *frame;
struct target_rt_frame_record *fr;
abi_ulong frame_addr, return_addr;
@@ -585,6 +700,8 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
sve_ofs = alloc_sigframe_space(sve_size, &layout);
}
if (cpu_isar_feature(aa64_sme, env_archcpu(env))) {
+ tpidr2_size = sizeof(struct target_tpidr2_context);
+ tpidr2_ofs = alloc_sigframe_space(tpidr2_size, &layout);
/* ZA state needs saving only if it is enabled. */
if (FIELD_EX64(env->svcr, SVCR, ZA)) {
za_size = TARGET_ZA_SIG_CONTEXT_SIZE(sme_vq(env));
@@ -593,6 +710,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
}
za_ofs = alloc_sigframe_space(za_size, &layout);
}
+ if (cpu_isar_feature(aa64_sme2, env_archcpu(env)) &&
+ FIELD_EX64(env->svcr, SVCR, ZA)) {
+ /* If SME ZA storage is enabled, we must also save SME2 ZT0 */
+ zt_size = TARGET_ZT_SIG_CONTEXT_SIZE(1);
+ zt_ofs = alloc_sigframe_space(zt_size, &layout);
+ }
if (layout.extra_ofs) {
/* Reserve space for the extra end marker. The standard end marker
@@ -644,6 +767,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
if (za_ofs) {
target_setup_za_record((void *)frame + za_ofs, env, za_size);
}
+ if (tpidr2_ofs) {
+ target_setup_tpidr2_record((void *)frame + tpidr2_ofs, env);
+ }
+ if (zt_ofs) {
+ target_setup_zt_record((void *)frame + zt_ofs, env, zt_size);
+ }
/* Set up the stack frame for unwinding. */
fr = (void *)frame + fr_ofs;
@@ -666,8 +795,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
env->btype = 2;
}
- /* Invoke the signal handler with both SM and ZA disabled. */
+ /*
+ * Invoke the signal handler with a clean SME state: both SM and ZA
+ * disabled and TPIDR2_EL0 cleared.
+ */
aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK);
+ env->cp15.tpidr2_el0 = 0;
if (info) {
frame->info = *info;
diff --git a/linux-user/aarch64/target_elf.h b/linux-user/aarch64/target_elf.h
index a7eb962..4cdeb64 100644
--- a/linux-user/aarch64/target_elf.h
+++ b/linux-user/aarch64/target_elf.h
@@ -7,8 +7,30 @@
#ifndef AARCH64_TARGET_ELF_H
#define AARCH64_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "any";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_MACHINE EM_AARCH64
+#define ELF_CLASS ELFCLASS64
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_HWCAP2 1
+#define HAVE_ELF_PLATFORM 1
+#define HAVE_ELF_CORE_DUMP 1
+#define HAVE_ELF_GNU_PROPERTY 1
+
+/*
+ * See linux kernel: arch/arm64/include/asm/elf.h, where
+ * elf_gregset_t is mapped to struct user_pt_regs via sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_user_pt_regs pt;
+} target_elf_gregset_t;
+
+#if TARGET_BIG_ENDIAN
+# define VDSO_HEADER "vdso-be.c.inc"
+#else
+# define VDSO_HEADER "vdso-le.c.inc"
+#endif
+
#endif
diff --git a/linux-user/aarch64/target_ptrace.h b/linux-user/aarch64/target_ptrace.h
new file mode 100644
index 0000000..1068133
--- /dev/null
+++ b/linux-user/aarch64/target_ptrace.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef AARCH64_TARGET_PTRACE_H
+#define AARCH64_TARGET_PTRACE_H
+
+/* See arch/arm64/include/uapi/asm/ptrace.h. */
+struct target_user_pt_regs {
+ uint64_t regs[31];
+ uint64_t sp;
+ uint64_t pc;
+ uint64_t pstate;
+};
+
+#endif /* AARCH64_TARGET_PTRACE_H */
diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h
index c055133..bd05f6c 100644
--- a/linux-user/aarch64/target_syscall.h
+++ b/linux-user/aarch64/target_syscall.h
@@ -1,13 +1,6 @@
#ifndef AARCH64_TARGET_SYSCALL_H
#define AARCH64_TARGET_SYSCALL_H
-struct target_pt_regs {
- uint64_t regs[31];
- uint64_t sp;
- uint64_t pc;
- uint64_t pstate;
-};
-
#if TARGET_BIG_ENDIAN
#define UNAME_MACHINE "aarch64_be"
#else
diff --git a/linux-user/alpha/cpu_loop.c b/linux-user/alpha/cpu_loop.c
index 80ad536..728b649 100644
--- a/linux-user/alpha/cpu_loop.c
+++ b/linux-user/alpha/cpu_loop.c
@@ -173,13 +173,10 @@ void cpu_loop(CPUAlphaState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
+ CPUArchState *env = cpu_env(cs);
- for(i = 0; i < 28; i++) {
- env->ir[i] = ((abi_ulong *)regs)[i];
- }
- env->ir[IR_SP] = regs->usp;
- env->pc = regs->pc;
+ env->pc = info->entry;
+ env->ir[IR_SP] = info->start_stack;
}
diff --git a/linux-user/alpha/elfload.c b/linux-user/alpha/elfload.c
new file mode 100644
index 0000000..1e44475
--- /dev/null
+++ b/linux-user/alpha/elfload.c
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "ev67";
+}
diff --git a/linux-user/alpha/target_elf.h b/linux-user/alpha/target_elf.h
index b77d638..864dc6e 100644
--- a/linux-user/alpha/target_elf.h
+++ b/linux-user/alpha/target_elf.h
@@ -7,8 +7,8 @@
#ifndef ALPHA_TARGET_ELF_H
#define ALPHA_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "ev67";
-}
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_MACHINE EM_ALPHA
+
#endif
diff --git a/linux-user/alpha/target_syscall.h b/linux-user/alpha/target_syscall.h
index fda3a49..53706b7 100644
--- a/linux-user/alpha/target_syscall.h
+++ b/linux-user/alpha/target_syscall.h
@@ -1,46 +1,6 @@
#ifndef ALPHA_TARGET_SYSCALL_H
#define ALPHA_TARGET_SYSCALL_H
-/* default linux values for the selectors */
-#define __USER_DS (1)
-
-struct target_pt_regs {
- abi_ulong r0;
- abi_ulong r1;
- abi_ulong r2;
- abi_ulong r3;
- abi_ulong r4;
- abi_ulong r5;
- abi_ulong r6;
- abi_ulong r7;
- abi_ulong r8;
- abi_ulong r19;
- abi_ulong r20;
- abi_ulong r21;
- abi_ulong r22;
- abi_ulong r23;
- abi_ulong r24;
- abi_ulong r25;
- abi_ulong r26;
- abi_ulong r27;
- abi_ulong r28;
- abi_ulong hae;
-/* JRP - These are the values provided to a0-a2 by PALcode */
- abi_ulong trap_a0;
- abi_ulong trap_a1;
- abi_ulong trap_a2;
-/* These are saved by PAL-code: */
- abi_ulong ps;
- abi_ulong pc;
- abi_ulong gp;
- abi_ulong r16;
- abi_ulong r17;
- abi_ulong r18;
-/* Those is needed by qemu to temporary store the user stack pointer */
- abi_ulong usp;
- abi_ulong unique;
-};
-
#define UNAME_MACHINE "alpha"
#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index e8417d0..9aeb9b0 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -363,6 +363,7 @@ void cpu_loop(CPUARMState *env)
switch (n) {
case ARM_NR_cacheflush:
/* nop */
+ env->regs[0] = 0;
break;
case ARM_NR_set_tls:
cpu_set_tls(env, env->regs[0]);
@@ -479,32 +480,57 @@ void cpu_loop(CPUARMState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- CPUState *cpu = env_cpu(env);
- TaskState *ts = get_task_state(cpu);
- struct image_info *info = ts->info;
- int i;
-
- cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
- CPSRWriteByInstr);
- for(i = 0; i < 16; i++) {
- env->regs[i] = regs->uregs[i];
- }
-#if TARGET_BIG_ENDIAN
- /* Enable BE8. */
- if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
- && (info->elf_flags & EF_ARM_BE8)) {
- env->uncached_cpsr |= CPSR_E;
- env->cp15.sctlr_el[1] |= SCTLR_E0E;
- } else {
- env->cp15.sctlr_el[1] |= SCTLR_B;
+ CPUARMState *env = cpu_env(cs);
+ abi_ptr stack = info->start_stack;
+ abi_ptr entry = info->entry;
+
+ cpsr_write(env, ARM_CPU_MODE_USR | (entry & 1 ? CPSR_T : 0),
+ CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
+
+ env->regs[15] = entry & 0xfffffffe;
+ env->regs[13] = stack;
+
+ /*
+ * Per the SVR4 ABI, r0 contains a pointer to a function to be
+ * registered with atexit. A value of 0 means we have no such handler.
+ */
+ env->regs[0] = 0;
+
+ /* For uClinux PIC binaries. */
+ /* XXX: Linux does this only on ARM with no MMU (do we care?) */
+ env->regs[10] = info->start_data;
+
+ /* Support ARM FDPIC. */
+ if (info_is_fdpic(info)) {
+ /*
+ * As described in the ABI document, r7 points to the loadmap info
+ * prepared by the kernel. If an interpreter is needed, r8 points
+ * to the interpreter loadmap and r9 points to the interpreter
+ * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
+ * r9 points to the main program PT_DYNAMIC info.
+ */
+ env->regs[7] = info->loadmap_addr;
+ if (info->interpreter_loadmap_addr) {
+ /* Executable is dynamically loaded. */
+ env->regs[8] = info->interpreter_loadmap_addr;
+ env->regs[9] = info->interpreter_pt_dynamic_addr;
+ } else {
+ env->regs[8] = 0;
+ env->regs[9] = info->pt_dynamic_addr;
+ }
}
- arm_rebuild_hflags(env);
-#endif
- ts->stack_base = info->start_stack;
- ts->heap_base = info->brk;
- /* This will be filled in on the first SYS_HEAPINFO call. */
- ts->heap_limit = 0;
+ if (TARGET_BIG_ENDIAN) {
+ /* Enable BE8. */
+ if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
+ && (info->elf_flags & EF_ARM_BE8)) {
+ env->uncached_cpsr |= CPSR_E;
+ env->cp15.sctlr_el[1] |= SCTLR_E0E;
+ } else {
+ env->cp15.sctlr_el[1] |= SCTLR_B;
+ }
+ arm_rebuild_hflags(env);
+ }
}
diff --git a/linux-user/arm/elfload.c b/linux-user/arm/elfload.c
new file mode 100644
index 0000000..308ed23
--- /dev/null
+++ b/linux-user/arm/elfload.c
@@ -0,0 +1,277 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "user-internals.h"
+#include "target_elf.h"
+#include "target/arm/cpu-features.h"
+#include "target_elf.h"
+#include "elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "any";
+}
+
+enum
+{
+ ARM_HWCAP_ARM_SWP = 1 << 0,
+ ARM_HWCAP_ARM_HALF = 1 << 1,
+ ARM_HWCAP_ARM_THUMB = 1 << 2,
+ ARM_HWCAP_ARM_26BIT = 1 << 3,
+ ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
+ ARM_HWCAP_ARM_FPA = 1 << 5,
+ ARM_HWCAP_ARM_VFP = 1 << 6,
+ ARM_HWCAP_ARM_EDSP = 1 << 7,
+ ARM_HWCAP_ARM_JAVA = 1 << 8,
+ ARM_HWCAP_ARM_IWMMXT = 1 << 9,
+ ARM_HWCAP_ARM_CRUNCH = 1 << 10,
+ ARM_HWCAP_ARM_THUMBEE = 1 << 11,
+ ARM_HWCAP_ARM_NEON = 1 << 12,
+ ARM_HWCAP_ARM_VFPv3 = 1 << 13,
+ ARM_HWCAP_ARM_VFPv3D16 = 1 << 14,
+ ARM_HWCAP_ARM_TLS = 1 << 15,
+ ARM_HWCAP_ARM_VFPv4 = 1 << 16,
+ ARM_HWCAP_ARM_IDIVA = 1 << 17,
+ ARM_HWCAP_ARM_IDIVT = 1 << 18,
+ ARM_HWCAP_ARM_VFPD32 = 1 << 19,
+ ARM_HWCAP_ARM_LPAE = 1 << 20,
+ ARM_HWCAP_ARM_EVTSTRM = 1 << 21,
+ ARM_HWCAP_ARM_FPHP = 1 << 22,
+ ARM_HWCAP_ARM_ASIMDHP = 1 << 23,
+ ARM_HWCAP_ARM_ASIMDDP = 1 << 24,
+ ARM_HWCAP_ARM_ASIMDFHM = 1 << 25,
+ ARM_HWCAP_ARM_ASIMDBF16 = 1 << 26,
+ ARM_HWCAP_ARM_I8MM = 1 << 27,
+};
+
+enum {
+ ARM_HWCAP2_ARM_AES = 1 << 0,
+ ARM_HWCAP2_ARM_PMULL = 1 << 1,
+ ARM_HWCAP2_ARM_SHA1 = 1 << 2,
+ ARM_HWCAP2_ARM_SHA2 = 1 << 3,
+ ARM_HWCAP2_ARM_CRC32 = 1 << 4,
+ ARM_HWCAP2_ARM_SB = 1 << 5,
+ ARM_HWCAP2_ARM_SSBS = 1 << 6,
+};
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ abi_ulong hwcaps = 0;
+
+ hwcaps |= ARM_HWCAP_ARM_SWP;
+ hwcaps |= ARM_HWCAP_ARM_HALF;
+ hwcaps |= ARM_HWCAP_ARM_THUMB;
+ hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
+
+ /* probe for the extra features */
+#define GET_FEATURE(feat, hwcap) \
+ do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
+
+#define GET_FEATURE_ID(feat, hwcap) \
+ do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
+
+ /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
+ GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
+ GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
+ GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
+ GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
+ GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
+ GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
+ GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
+ GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
+ GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
+
+ if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
+ cpu_isar_feature(aa32_fpdp_v3, cpu)) {
+ hwcaps |= ARM_HWCAP_ARM_VFPv3;
+ if (cpu_isar_feature(aa32_simd_r32, cpu)) {
+ hwcaps |= ARM_HWCAP_ARM_VFPD32;
+ } else {
+ hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
+ }
+ }
+ GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
+ /*
+ * MVFR1.FPHP and .SIMDHP must be in sync, and QEMU uses the same
+ * isar_feature function for both. The kernel reports them as two hwcaps.
+ */
+ GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_FPHP);
+ GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_ASIMDHP);
+ GET_FEATURE_ID(aa32_dp, ARM_HWCAP_ARM_ASIMDDP);
+ GET_FEATURE_ID(aa32_fhm, ARM_HWCAP_ARM_ASIMDFHM);
+ GET_FEATURE_ID(aa32_bf16, ARM_HWCAP_ARM_ASIMDBF16);
+ GET_FEATURE_ID(aa32_i8mm, ARM_HWCAP_ARM_I8MM);
+
+ return hwcaps;
+}
+
+abi_ulong get_elf_hwcap2(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ abi_ulong hwcaps = 0;
+
+ GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
+ GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
+ GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
+ GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
+ GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
+ GET_FEATURE_ID(aa32_sb, ARM_HWCAP2_ARM_SB);
+ GET_FEATURE_ID(aa32_ssbs, ARM_HWCAP2_ARM_SSBS);
+ return hwcaps;
+}
+
+const char *elf_hwcap_str(uint32_t bit)
+{
+ static const char *hwcap_str[] = {
+ [__builtin_ctz(ARM_HWCAP_ARM_SWP )] = "swp",
+ [__builtin_ctz(ARM_HWCAP_ARM_HALF )] = "half",
+ [__builtin_ctz(ARM_HWCAP_ARM_THUMB )] = "thumb",
+ [__builtin_ctz(ARM_HWCAP_ARM_26BIT )] = "26bit",
+ [__builtin_ctz(ARM_HWCAP_ARM_FAST_MULT)] = "fast_mult",
+ [__builtin_ctz(ARM_HWCAP_ARM_FPA )] = "fpa",
+ [__builtin_ctz(ARM_HWCAP_ARM_VFP )] = "vfp",
+ [__builtin_ctz(ARM_HWCAP_ARM_EDSP )] = "edsp",
+ [__builtin_ctz(ARM_HWCAP_ARM_JAVA )] = "java",
+ [__builtin_ctz(ARM_HWCAP_ARM_IWMMXT )] = "iwmmxt",
+ [__builtin_ctz(ARM_HWCAP_ARM_CRUNCH )] = "crunch",
+ [__builtin_ctz(ARM_HWCAP_ARM_THUMBEE )] = "thumbee",
+ [__builtin_ctz(ARM_HWCAP_ARM_NEON )] = "neon",
+ [__builtin_ctz(ARM_HWCAP_ARM_VFPv3 )] = "vfpv3",
+ [__builtin_ctz(ARM_HWCAP_ARM_VFPv3D16 )] = "vfpv3d16",
+ [__builtin_ctz(ARM_HWCAP_ARM_TLS )] = "tls",
+ [__builtin_ctz(ARM_HWCAP_ARM_VFPv4 )] = "vfpv4",
+ [__builtin_ctz(ARM_HWCAP_ARM_IDIVA )] = "idiva",
+ [__builtin_ctz(ARM_HWCAP_ARM_IDIVT )] = "idivt",
+ [__builtin_ctz(ARM_HWCAP_ARM_VFPD32 )] = "vfpd32",
+ [__builtin_ctz(ARM_HWCAP_ARM_LPAE )] = "lpae",
+ [__builtin_ctz(ARM_HWCAP_ARM_EVTSTRM )] = "evtstrm",
+ [__builtin_ctz(ARM_HWCAP_ARM_FPHP )] = "fphp",
+ [__builtin_ctz(ARM_HWCAP_ARM_ASIMDHP )] = "asimdhp",
+ [__builtin_ctz(ARM_HWCAP_ARM_ASIMDDP )] = "asimddp",
+ [__builtin_ctz(ARM_HWCAP_ARM_ASIMDFHM )] = "asimdfhm",
+ [__builtin_ctz(ARM_HWCAP_ARM_ASIMDBF16)] = "asimdbf16",
+ [__builtin_ctz(ARM_HWCAP_ARM_I8MM )] = "i8mm",
+ };
+
+ return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
+}
+
+const char *elf_hwcap2_str(uint32_t bit)
+{
+ static const char *hwcap_str[] = {
+ [__builtin_ctz(ARM_HWCAP2_ARM_AES )] = "aes",
+ [__builtin_ctz(ARM_HWCAP2_ARM_PMULL)] = "pmull",
+ [__builtin_ctz(ARM_HWCAP2_ARM_SHA1 )] = "sha1",
+ [__builtin_ctz(ARM_HWCAP2_ARM_SHA2 )] = "sha2",
+ [__builtin_ctz(ARM_HWCAP2_ARM_CRC32)] = "crc32",
+ [__builtin_ctz(ARM_HWCAP2_ARM_SB )] = "sb",
+ [__builtin_ctz(ARM_HWCAP2_ARM_SSBS )] = "ssbs",
+ };
+
+ return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
+}
+
+const char *get_elf_platform(CPUState *cs)
+{
+ CPUARMState *env = cpu_env(cs);
+
+#if TARGET_BIG_ENDIAN
+# define END "b"
+#else
+# define END "l"
+#endif
+
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ return "v8" END;
+ } else if (arm_feature(env, ARM_FEATURE_V7)) {
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ return "v7m" END;
+ } else {
+ return "v7" END;
+ }
+ } else if (arm_feature(env, ARM_FEATURE_V6)) {
+ return "v6" END;
+ } else if (arm_feature(env, ARM_FEATURE_V5)) {
+ return "v5" END;
+ } else {
+ return "v4" END;
+ }
+
+#undef END
+}
+
+bool init_guest_commpage(void)
+{
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
+ int host_page_size = qemu_real_host_page_size();
+ abi_ptr commpage;
+ void *want;
+ void *addr;
+
+ /*
+ * M-profile allocates maximum of 2GB address space, so can never
+ * allocate the commpage. Skip it.
+ */
+ if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
+ return true;
+ }
+
+ commpage = HI_COMMPAGE & -host_page_size;
+ want = g2h_untagged(commpage);
+ addr = mmap(want, host_page_size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE |
+ (commpage < reserved_va ? MAP_FIXED : MAP_FIXED_NOREPLACE),
+ -1, 0);
+
+ if (addr == MAP_FAILED) {
+ perror("Allocating guest commpage");
+ exit(EXIT_FAILURE);
+ }
+ if (addr != want) {
+ return false;
+ }
+
+ /* Set kernel helper versions; rest of page is 0. */
+ __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
+
+ if (mprotect(addr, host_page_size, PROT_READ)) {
+ perror("Protecting guest commpage");
+ exit(EXIT_FAILURE);
+ }
+
+ page_set_flags(commpage, commpage | (host_page_size - 1),
+ PAGE_READ | PAGE_EXEC | PAGE_VALID);
+ return true;
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUARMState *env)
+{
+ for (int i = 0; i < 16; ++i) {
+ r->pt.regs[i] = tswapal(env->regs[i]);
+ }
+ r->pt.cpsr = tswapal(cpsr_read((CPUARMState *)env));
+ r->pt.orig_r0 = tswapal(env->regs[0]); /* FIXME */
+}
+
+#if TARGET_BIG_ENDIAN
+# include "vdso-be8.c.inc"
+# include "vdso-be32.c.inc"
+#else
+# include "vdso-le.c.inc"
+#endif
+
+const VdsoImageInfo *get_vdso_image_info(uint32_t elf_flags)
+{
+#if TARGET_BIG_ENDIAN
+ return (EF_ARM_EABI_VERSION(elf_flags) >= EF_ARM_EABI_VER4
+ && (elf_flags & EF_ARM_BE8)
+ ? &vdso_be8_image_info
+ : &vdso_be32_image_info);
+#else
+ return &vdso_image_info;
+#endif
+}
diff --git a/linux-user/arm/target_elf.h b/linux-user/arm/target_elf.h
index 58ff6a0..12cdc8e 100644
--- a/linux-user/arm/target_elf.h
+++ b/linux-user/arm/target_elf.h
@@ -7,8 +7,27 @@
#ifndef ARM_TARGET_ELF_H
#define ARM_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "any";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_MACHINE EM_ARM
+#define ELF_CLASS ELFCLASS32
+#define EXSTACK_DEFAULT true
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_HWCAP2 1
+#define HAVE_ELF_PLATFORM 1
+#define HAVE_ELF_CORE_DUMP 1
+#define HAVE_VDSO_IMAGE_INFO 1
+
+#define HI_COMMPAGE ((intptr_t)0xffff0f00u)
+
+/*
+ * See linux kernel: arch/arm/include/asm/elf.h, where
+ * elf_gregset_t is mapped to struct pt_regs via sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_pt_regs pt;
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/arm/target_proc.h b/linux-user/arm/target_proc.h
index ac75af9..a4cd694 100644
--- a/linux-user/arm/target_proc.h
+++ b/linux-user/arm/target_proc.h
@@ -10,8 +10,8 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd)
{
ARMCPU *cpu = env_archcpu(cpu_env);
int arch, midr_rev, midr_part, midr_var, midr_impl;
- target_ulong elf_hwcap = get_elf_hwcap();
- target_ulong elf_hwcap2 = get_elf_hwcap2();
+ target_ulong elf_hwcap = get_elf_hwcap(env_cpu(cpu_env));
+ target_ulong elf_hwcap2 = get_elf_hwcap2(env_cpu(cpu_env));
const char *elf_name;
int num_cpus, len_part, len_var;
diff --git a/linux-user/arm/target_ptrace.h b/linux-user/arm/target_ptrace.h
new file mode 100644
index 0000000..1610b8e
--- /dev/null
+++ b/linux-user/arm/target_ptrace.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef ARM_TARGET_PTRACE_H
+#define ARM_TARGET_PTRACE_H
+
+/*
+ * See arch/arm/include/uapi/asm/ptrace.h.
+ * Instead of an array and ARM_xx defines, use proper fields.
+ */
+struct target_pt_regs {
+ abi_ulong regs[16];
+ abi_ulong cpsr;
+ abi_ulong orig_r0;
+};
+
+#endif /* ARM_TARGET_PTRACE_H */
diff --git a/linux-user/arm/target_syscall.h b/linux-user/arm/target_syscall.h
index 412ad43..8c4ddba 100644
--- a/linux-user/arm/target_syscall.h
+++ b/linux-user/arm/target_syscall.h
@@ -1,14 +1,6 @@
#ifndef ARM_TARGET_SYSCALL_H
#define ARM_TARGET_SYSCALL_H
-/* this struct defines the way the registers are stored on the
- stack during a system call. */
-
-/* uregs[0..15] are r0 to r15; uregs[16] is CPSR; uregs[17] is ORIG_r0 */
-struct target_pt_regs {
- abi_long uregs[18];
-};
-
#define ARM_SYSCALL_BASE 0x900000
#define ARM_THUMB_SYSCALL 0
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index fbfdec2..26c090c 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -28,6 +28,7 @@
#include "qemu/lockable.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
+#include "target_elf.h"
#include "target_signal.h"
#include "tcg/debuginfo.h"
@@ -35,29 +36,10 @@
#include "target/arm/cpu-features.h"
#endif
-#ifdef _ARCH_PPC64
-#undef ARCH_DLINFO
-#undef ELF_PLATFORM
-#undef ELF_HWCAP
-#undef ELF_HWCAP2
-#undef ELF_CLASS
-#undef ELF_DATA
-#undef ELF_ARCH
-#endif
-
#ifndef TARGET_ARCH_HAS_SIGTRAMP_PAGE
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
#endif
-typedef struct {
- const uint8_t *image;
- const uint32_t *relocs;
- unsigned image_size;
- unsigned reloc_count;
- unsigned sigreturn_ofs;
- unsigned rt_sigreturn_ofs;
-} VdsoImageInfo;
-
#define ELF_OSABI ELFOSABI_SYSV
/* from personality.h */
@@ -123,30 +105,12 @@ int info_is_fdpic(struct image_info *info)
return info->personality == PER_LINUX_FDPIC;
}
-/* this flag is uneffective under linux too, should be deleted */
-#ifndef MAP_DENYWRITE
-#define MAP_DENYWRITE 0
-#endif
-
-/* should probably go in elf.h */
-#ifndef ELIBBAD
-#define ELIBBAD 80
-#endif
-
#if TARGET_BIG_ENDIAN
#define ELF_DATA ELFDATA2MSB
#else
#define ELF_DATA ELFDATA2LSB
#endif
-#ifdef TARGET_ABI_MIPSN32
-typedef abi_ullong target_elf_greg_t;
-#define tswapreg(ptr) tswap64(ptr)
-#else
-typedef abi_ulong target_elf_greg_t;
-#define tswapreg(ptr) tswapal(ptr)
-#endif
-
#ifdef USE_UID16
typedef abi_ushort target_uid_t;
typedef abi_ushort target_gid_t;
@@ -156,1893 +120,14 @@ typedef abi_uint target_gid_t;
#endif
typedef abi_int target_pid_t;
-#ifdef TARGET_I386
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
- X86CPU *cpu = X86_CPU(thread_cpu);
-
- return cpu->env.features[FEAT_1_EDX];
-}
-
-#ifdef TARGET_X86_64
-#define ELF_CLASS ELFCLASS64
-#define ELF_ARCH EM_X86_64
-
-#define ELF_PLATFORM "x86_64"
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- regs->rax = 0;
- regs->rsp = infop->start_stack;
- regs->rip = infop->entry;
-}
-
-#define ELF_NREG 27
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-/*
- * Note that ELF_NREG should be 29 as there should be place for
- * TRAPNO and ERR "registers" as well but linux doesn't dump
- * those.
- *
- * See linux kernel: arch/x86/include/asm/elf.h
- */
-static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
-{
- (*regs)[0] = tswapreg(env->regs[15]);
- (*regs)[1] = tswapreg(env->regs[14]);
- (*regs)[2] = tswapreg(env->regs[13]);
- (*regs)[3] = tswapreg(env->regs[12]);
- (*regs)[4] = tswapreg(env->regs[R_EBP]);
- (*regs)[5] = tswapreg(env->regs[R_EBX]);
- (*regs)[6] = tswapreg(env->regs[11]);
- (*regs)[7] = tswapreg(env->regs[10]);
- (*regs)[8] = tswapreg(env->regs[9]);
- (*regs)[9] = tswapreg(env->regs[8]);
- (*regs)[10] = tswapreg(env->regs[R_EAX]);
- (*regs)[11] = tswapreg(env->regs[R_ECX]);
- (*regs)[12] = tswapreg(env->regs[R_EDX]);
- (*regs)[13] = tswapreg(env->regs[R_ESI]);
- (*regs)[14] = tswapreg(env->regs[R_EDI]);
- (*regs)[15] = tswapreg(get_task_state(env_cpu_const(env))->orig_ax);
- (*regs)[16] = tswapreg(env->eip);
- (*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff);
- (*regs)[18] = tswapreg(env->eflags);
- (*regs)[19] = tswapreg(env->regs[R_ESP]);
- (*regs)[20] = tswapreg(env->segs[R_SS].selector & 0xffff);
- (*regs)[21] = tswapreg(env->segs[R_FS].selector & 0xffff);
- (*regs)[22] = tswapreg(env->segs[R_GS].selector & 0xffff);
- (*regs)[23] = tswapreg(env->segs[R_DS].selector & 0xffff);
- (*regs)[24] = tswapreg(env->segs[R_ES].selector & 0xffff);
- (*regs)[25] = tswapreg(env->segs[R_FS].selector & 0xffff);
- (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff);
-}
-
-#if ULONG_MAX > UINT32_MAX
-#define INIT_GUEST_COMMPAGE
-static bool init_guest_commpage(void)
-{
- /*
- * The vsyscall page is at a high negative address aka kernel space,
- * which means that we cannot actually allocate it with target_mmap.
- * We still should be able to use page_set_flags, unless the user
- * has specified -R reserved_va, which would trigger an assert().
- */
- if (reserved_va != 0 &&
- TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE - 1 > reserved_va) {
- error_report("Cannot allocate vsyscall page");
- exit(EXIT_FAILURE);
- }
- page_set_flags(TARGET_VSYSCALL_PAGE,
- TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
- PAGE_EXEC | PAGE_VALID);
- return true;
-}
-#endif
-#else
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_386
-
-#define ELF_PLATFORM get_elf_platform()
-#define EXSTACK_DEFAULT true
-
-static const char *get_elf_platform(void)
-{
- static char elf_platform[] = "i386";
- int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
- if (family > 6) {
- family = 6;
- }
- if (family >= 3) {
- elf_platform[1] = '0' + family;
- }
- return elf_platform;
-}
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->esp = infop->start_stack;
- regs->eip = infop->entry;
-
- /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
- starts %edx contains a pointer to a function which might be
- registered using `atexit'. This provides a mean for the
- dynamic linker to call DT_FINI functions for shared libraries
- that have been loaded before the code runs.
-
- A value of 0 tells we have no such handler. */
- regs->edx = 0;
-}
-
-#define ELF_NREG 17
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-/*
- * Note that ELF_NREG should be 19 as there should be place for
- * TRAPNO and ERR "registers" as well but linux doesn't dump
- * those.
- *
- * See linux kernel: arch/x86/include/asm/elf.h
- */
-static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
-{
- (*regs)[0] = tswapreg(env->regs[R_EBX]);
- (*regs)[1] = tswapreg(env->regs[R_ECX]);
- (*regs)[2] = tswapreg(env->regs[R_EDX]);
- (*regs)[3] = tswapreg(env->regs[R_ESI]);
- (*regs)[4] = tswapreg(env->regs[R_EDI]);
- (*regs)[5] = tswapreg(env->regs[R_EBP]);
- (*regs)[6] = tswapreg(env->regs[R_EAX]);
- (*regs)[7] = tswapreg(env->segs[R_DS].selector & 0xffff);
- (*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff);
- (*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff);
- (*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff);
- (*regs)[11] = tswapreg(get_task_state(env_cpu_const(env))->orig_ax);
- (*regs)[12] = tswapreg(env->eip);
- (*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff);
- (*regs)[14] = tswapreg(env->eflags);
- (*regs)[15] = tswapreg(env->regs[R_ESP]);
- (*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
-}
-
-/*
- * i386 is the only target which supplies AT_SYSINFO for the vdso.
- * All others only supply AT_SYSINFO_EHDR.
- */
-#define DLINFO_ARCH_ITEMS (vdso_info != NULL)
-#define ARCH_DLINFO \
- do { \
- if (vdso_info) { \
- NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry); \
- } \
- } while (0)
-
-#endif /* TARGET_X86_64 */
-
-#define VDSO_HEADER "vdso.c.inc"
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#endif /* TARGET_I386 */
-
-#ifdef TARGET_ARM
-
-#ifndef TARGET_AARCH64
-/* 32 bit ARM definitions */
-
-#define ELF_ARCH EM_ARM
-#define ELF_CLASS ELFCLASS32
-#define EXSTACK_DEFAULT true
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- abi_long stack = infop->start_stack;
- memset(regs, 0, sizeof(*regs));
-
- regs->uregs[16] = ARM_CPU_MODE_USR;
- if (infop->entry & 1) {
- regs->uregs[16] |= CPSR_T;
- }
- regs->uregs[15] = infop->entry & 0xfffffffe;
- regs->uregs[13] = infop->start_stack;
- /* FIXME - what to for failure of get_user()? */
- get_user_ual(regs->uregs[2], stack + 8); /* envp */
- get_user_ual(regs->uregs[1], stack + 4); /* envp */
- /* XXX: it seems that r0 is zeroed after ! */
- regs->uregs[0] = 0;
- /* For uClinux PIC binaries. */
- /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
- regs->uregs[10] = infop->start_data;
-
- /* Support ARM FDPIC. */
- if (info_is_fdpic(infop)) {
- /* As described in the ABI document, r7 points to the loadmap info
- * prepared by the kernel. If an interpreter is needed, r8 points
- * to the interpreter loadmap and r9 points to the interpreter
- * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
- * r9 points to the main program PT_DYNAMIC info.
- */
- regs->uregs[7] = infop->loadmap_addr;
- if (infop->interpreter_loadmap_addr) {
- /* Executable is dynamically loaded. */
- regs->uregs[8] = infop->interpreter_loadmap_addr;
- regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
- } else {
- regs->uregs[8] = 0;
- regs->uregs[9] = infop->pt_dynamic_addr;
- }
- }
-}
-
-#define ELF_NREG 18
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
-{
- (*regs)[0] = tswapreg(env->regs[0]);
- (*regs)[1] = tswapreg(env->regs[1]);
- (*regs)[2] = tswapreg(env->regs[2]);
- (*regs)[3] = tswapreg(env->regs[3]);
- (*regs)[4] = tswapreg(env->regs[4]);
- (*regs)[5] = tswapreg(env->regs[5]);
- (*regs)[6] = tswapreg(env->regs[6]);
- (*regs)[7] = tswapreg(env->regs[7]);
- (*regs)[8] = tswapreg(env->regs[8]);
- (*regs)[9] = tswapreg(env->regs[9]);
- (*regs)[10] = tswapreg(env->regs[10]);
- (*regs)[11] = tswapreg(env->regs[11]);
- (*regs)[12] = tswapreg(env->regs[12]);
- (*regs)[13] = tswapreg(env->regs[13]);
- (*regs)[14] = tswapreg(env->regs[14]);
- (*regs)[15] = tswapreg(env->regs[15]);
-
- (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
- (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-enum
-{
- ARM_HWCAP_ARM_SWP = 1 << 0,
- ARM_HWCAP_ARM_HALF = 1 << 1,
- ARM_HWCAP_ARM_THUMB = 1 << 2,
- ARM_HWCAP_ARM_26BIT = 1 << 3,
- ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
- ARM_HWCAP_ARM_FPA = 1 << 5,
- ARM_HWCAP_ARM_VFP = 1 << 6,
- ARM_HWCAP_ARM_EDSP = 1 << 7,
- ARM_HWCAP_ARM_JAVA = 1 << 8,
- ARM_HWCAP_ARM_IWMMXT = 1 << 9,
- ARM_HWCAP_ARM_CRUNCH = 1 << 10,
- ARM_HWCAP_ARM_THUMBEE = 1 << 11,
- ARM_HWCAP_ARM_NEON = 1 << 12,
- ARM_HWCAP_ARM_VFPv3 = 1 << 13,
- ARM_HWCAP_ARM_VFPv3D16 = 1 << 14,
- ARM_HWCAP_ARM_TLS = 1 << 15,
- ARM_HWCAP_ARM_VFPv4 = 1 << 16,
- ARM_HWCAP_ARM_IDIVA = 1 << 17,
- ARM_HWCAP_ARM_IDIVT = 1 << 18,
- ARM_HWCAP_ARM_VFPD32 = 1 << 19,
- ARM_HWCAP_ARM_LPAE = 1 << 20,
- ARM_HWCAP_ARM_EVTSTRM = 1 << 21,
- ARM_HWCAP_ARM_FPHP = 1 << 22,
- ARM_HWCAP_ARM_ASIMDHP = 1 << 23,
- ARM_HWCAP_ARM_ASIMDDP = 1 << 24,
- ARM_HWCAP_ARM_ASIMDFHM = 1 << 25,
- ARM_HWCAP_ARM_ASIMDBF16 = 1 << 26,
- ARM_HWCAP_ARM_I8MM = 1 << 27,
-};
-
-enum {
- ARM_HWCAP2_ARM_AES = 1 << 0,
- ARM_HWCAP2_ARM_PMULL = 1 << 1,
- ARM_HWCAP2_ARM_SHA1 = 1 << 2,
- ARM_HWCAP2_ARM_SHA2 = 1 << 3,
- ARM_HWCAP2_ARM_CRC32 = 1 << 4,
- ARM_HWCAP2_ARM_SB = 1 << 5,
- ARM_HWCAP2_ARM_SSBS = 1 << 6,
-};
-
-/* The commpage only exists for 32 bit kernels */
-
-#define HI_COMMPAGE (intptr_t)0xffff0f00u
-
-static bool init_guest_commpage(void)
-{
- ARMCPU *cpu = ARM_CPU(thread_cpu);
- int host_page_size = qemu_real_host_page_size();
- abi_ptr commpage;
- void *want;
- void *addr;
-
- /*
- * M-profile allocates maximum of 2GB address space, so can never
- * allocate the commpage. Skip it.
- */
- if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
- return true;
- }
-
- commpage = HI_COMMPAGE & -host_page_size;
- want = g2h_untagged(commpage);
- addr = mmap(want, host_page_size, PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE |
- (commpage < reserved_va ? MAP_FIXED : MAP_FIXED_NOREPLACE),
- -1, 0);
-
- if (addr == MAP_FAILED) {
- perror("Allocating guest commpage");
- exit(EXIT_FAILURE);
- }
- if (addr != want) {
- return false;
- }
-
- /* Set kernel helper versions; rest of page is 0. */
- __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
-
- if (mprotect(addr, host_page_size, PROT_READ)) {
- perror("Protecting guest commpage");
- exit(EXIT_FAILURE);
- }
-
- page_set_flags(commpage, commpage | (host_page_size - 1),
- PAGE_READ | PAGE_EXEC | PAGE_VALID);
- return true;
-}
-
-#define ELF_HWCAP get_elf_hwcap()
-#define ELF_HWCAP2 get_elf_hwcap2()
-
-uint32_t get_elf_hwcap(void)
-{
- ARMCPU *cpu = ARM_CPU(thread_cpu);
- uint32_t hwcaps = 0;
-
- hwcaps |= ARM_HWCAP_ARM_SWP;
- hwcaps |= ARM_HWCAP_ARM_HALF;
- hwcaps |= ARM_HWCAP_ARM_THUMB;
- hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
-
- /* probe for the extra features */
-#define GET_FEATURE(feat, hwcap) \
- do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
-
-#define GET_FEATURE_ID(feat, hwcap) \
- do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
-
- /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
- GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
- GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
- GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
- GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
- GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
- GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
- GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
- GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
- GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
-
- if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
- cpu_isar_feature(aa32_fpdp_v3, cpu)) {
- hwcaps |= ARM_HWCAP_ARM_VFPv3;
- if (cpu_isar_feature(aa32_simd_r32, cpu)) {
- hwcaps |= ARM_HWCAP_ARM_VFPD32;
- } else {
- hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
- }
- }
- GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
- /*
- * MVFR1.FPHP and .SIMDHP must be in sync, and QEMU uses the same
- * isar_feature function for both. The kernel reports them as two hwcaps.
- */
- GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_FPHP);
- GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_ASIMDHP);
- GET_FEATURE_ID(aa32_dp, ARM_HWCAP_ARM_ASIMDDP);
- GET_FEATURE_ID(aa32_fhm, ARM_HWCAP_ARM_ASIMDFHM);
- GET_FEATURE_ID(aa32_bf16, ARM_HWCAP_ARM_ASIMDBF16);
- GET_FEATURE_ID(aa32_i8mm, ARM_HWCAP_ARM_I8MM);
-
- return hwcaps;
-}
-
-uint64_t get_elf_hwcap2(void)
-{
- ARMCPU *cpu = ARM_CPU(thread_cpu);
- uint64_t hwcaps = 0;
-
- GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
- GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
- GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
- GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
- GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
- GET_FEATURE_ID(aa32_sb, ARM_HWCAP2_ARM_SB);
- GET_FEATURE_ID(aa32_ssbs, ARM_HWCAP2_ARM_SSBS);
- return hwcaps;
-}
-
-const char *elf_hwcap_str(uint32_t bit)
-{
- static const char *hwcap_str[] = {
- [__builtin_ctz(ARM_HWCAP_ARM_SWP )] = "swp",
- [__builtin_ctz(ARM_HWCAP_ARM_HALF )] = "half",
- [__builtin_ctz(ARM_HWCAP_ARM_THUMB )] = "thumb",
- [__builtin_ctz(ARM_HWCAP_ARM_26BIT )] = "26bit",
- [__builtin_ctz(ARM_HWCAP_ARM_FAST_MULT)] = "fast_mult",
- [__builtin_ctz(ARM_HWCAP_ARM_FPA )] = "fpa",
- [__builtin_ctz(ARM_HWCAP_ARM_VFP )] = "vfp",
- [__builtin_ctz(ARM_HWCAP_ARM_EDSP )] = "edsp",
- [__builtin_ctz(ARM_HWCAP_ARM_JAVA )] = "java",
- [__builtin_ctz(ARM_HWCAP_ARM_IWMMXT )] = "iwmmxt",
- [__builtin_ctz(ARM_HWCAP_ARM_CRUNCH )] = "crunch",
- [__builtin_ctz(ARM_HWCAP_ARM_THUMBEE )] = "thumbee",
- [__builtin_ctz(ARM_HWCAP_ARM_NEON )] = "neon",
- [__builtin_ctz(ARM_HWCAP_ARM_VFPv3 )] = "vfpv3",
- [__builtin_ctz(ARM_HWCAP_ARM_VFPv3D16 )] = "vfpv3d16",
- [__builtin_ctz(ARM_HWCAP_ARM_TLS )] = "tls",
- [__builtin_ctz(ARM_HWCAP_ARM_VFPv4 )] = "vfpv4",
- [__builtin_ctz(ARM_HWCAP_ARM_IDIVA )] = "idiva",
- [__builtin_ctz(ARM_HWCAP_ARM_IDIVT )] = "idivt",
- [__builtin_ctz(ARM_HWCAP_ARM_VFPD32 )] = "vfpd32",
- [__builtin_ctz(ARM_HWCAP_ARM_LPAE )] = "lpae",
- [__builtin_ctz(ARM_HWCAP_ARM_EVTSTRM )] = "evtstrm",
- [__builtin_ctz(ARM_HWCAP_ARM_FPHP )] = "fphp",
- [__builtin_ctz(ARM_HWCAP_ARM_ASIMDHP )] = "asimdhp",
- [__builtin_ctz(ARM_HWCAP_ARM_ASIMDDP )] = "asimddp",
- [__builtin_ctz(ARM_HWCAP_ARM_ASIMDFHM )] = "asimdfhm",
- [__builtin_ctz(ARM_HWCAP_ARM_ASIMDBF16)] = "asimdbf16",
- [__builtin_ctz(ARM_HWCAP_ARM_I8MM )] = "i8mm",
- };
-
- return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
-}
-
-const char *elf_hwcap2_str(uint32_t bit)
-{
- static const char *hwcap_str[] = {
- [__builtin_ctz(ARM_HWCAP2_ARM_AES )] = "aes",
- [__builtin_ctz(ARM_HWCAP2_ARM_PMULL)] = "pmull",
- [__builtin_ctz(ARM_HWCAP2_ARM_SHA1 )] = "sha1",
- [__builtin_ctz(ARM_HWCAP2_ARM_SHA2 )] = "sha2",
- [__builtin_ctz(ARM_HWCAP2_ARM_CRC32)] = "crc32",
- [__builtin_ctz(ARM_HWCAP2_ARM_SB )] = "sb",
- [__builtin_ctz(ARM_HWCAP2_ARM_SSBS )] = "ssbs",
- };
-
- return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
-}
-
-#undef GET_FEATURE
-#undef GET_FEATURE_ID
-
-#define ELF_PLATFORM get_elf_platform()
-
-static const char *get_elf_platform(void)
-{
- CPUARMState *env = cpu_env(thread_cpu);
-
-#if TARGET_BIG_ENDIAN
-# define END "b"
-#else
-# define END "l"
-#endif
-
- if (arm_feature(env, ARM_FEATURE_V8)) {
- return "v8" END;
- } else if (arm_feature(env, ARM_FEATURE_V7)) {
- if (arm_feature(env, ARM_FEATURE_M)) {
- return "v7m" END;
- } else {
- return "v7" END;
- }
- } else if (arm_feature(env, ARM_FEATURE_V6)) {
- return "v6" END;
- } else if (arm_feature(env, ARM_FEATURE_V5)) {
- return "v5" END;
- } else {
- return "v4" END;
- }
-
-#undef END
-}
-
-#if TARGET_BIG_ENDIAN
-#include "elf.h"
-#include "vdso-be8.c.inc"
-#include "vdso-be32.c.inc"
-
-static const VdsoImageInfo *vdso_image_info(uint32_t elf_flags)
-{
- return (EF_ARM_EABI_VERSION(elf_flags) >= EF_ARM_EABI_VER4
- && (elf_flags & EF_ARM_BE8)
- ? &vdso_be8_image_info
- : &vdso_be32_image_info);
-}
-#define vdso_image_info vdso_image_info
-#else
-# define VDSO_HEADER "vdso-le.c.inc"
-#endif
-
-#else
-/* 64 bit ARM definitions */
-
-#define ELF_ARCH EM_AARCH64
-#define ELF_CLASS ELFCLASS64
-#if TARGET_BIG_ENDIAN
-# define ELF_PLATFORM "aarch64_be"
-#else
-# define ELF_PLATFORM "aarch64"
-#endif
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- abi_long stack = infop->start_stack;
- memset(regs, 0, sizeof(*regs));
-
- regs->pc = infop->entry & ~0x3ULL;
- regs->sp = stack;
-}
-
-#define ELF_NREG 34
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs,
- const CPUARMState *env)
-{
- int i;
-
- for (i = 0; i < 32; i++) {
- (*regs)[i] = tswapreg(env->xregs[i]);
- }
- (*regs)[32] = tswapreg(env->pc);
- (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-enum {
- ARM_HWCAP_A64_FP = 1 << 0,
- ARM_HWCAP_A64_ASIMD = 1 << 1,
- ARM_HWCAP_A64_EVTSTRM = 1 << 2,
- ARM_HWCAP_A64_AES = 1 << 3,
- ARM_HWCAP_A64_PMULL = 1 << 4,
- ARM_HWCAP_A64_SHA1 = 1 << 5,
- ARM_HWCAP_A64_SHA2 = 1 << 6,
- ARM_HWCAP_A64_CRC32 = 1 << 7,
- ARM_HWCAP_A64_ATOMICS = 1 << 8,
- ARM_HWCAP_A64_FPHP = 1 << 9,
- ARM_HWCAP_A64_ASIMDHP = 1 << 10,
- ARM_HWCAP_A64_CPUID = 1 << 11,
- ARM_HWCAP_A64_ASIMDRDM = 1 << 12,
- ARM_HWCAP_A64_JSCVT = 1 << 13,
- ARM_HWCAP_A64_FCMA = 1 << 14,
- ARM_HWCAP_A64_LRCPC = 1 << 15,
- ARM_HWCAP_A64_DCPOP = 1 << 16,
- ARM_HWCAP_A64_SHA3 = 1 << 17,
- ARM_HWCAP_A64_SM3 = 1 << 18,
- ARM_HWCAP_A64_SM4 = 1 << 19,
- ARM_HWCAP_A64_ASIMDDP = 1 << 20,
- ARM_HWCAP_A64_SHA512 = 1 << 21,
- ARM_HWCAP_A64_SVE = 1 << 22,
- ARM_HWCAP_A64_ASIMDFHM = 1 << 23,
- ARM_HWCAP_A64_DIT = 1 << 24,
- ARM_HWCAP_A64_USCAT = 1 << 25,
- ARM_HWCAP_A64_ILRCPC = 1 << 26,
- ARM_HWCAP_A64_FLAGM = 1 << 27,
- ARM_HWCAP_A64_SSBS = 1 << 28,
- ARM_HWCAP_A64_SB = 1 << 29,
- ARM_HWCAP_A64_PACA = 1 << 30,
- ARM_HWCAP_A64_PACG = 1UL << 31,
-
- ARM_HWCAP2_A64_DCPODP = 1 << 0,
- ARM_HWCAP2_A64_SVE2 = 1 << 1,
- ARM_HWCAP2_A64_SVEAES = 1 << 2,
- ARM_HWCAP2_A64_SVEPMULL = 1 << 3,
- ARM_HWCAP2_A64_SVEBITPERM = 1 << 4,
- ARM_HWCAP2_A64_SVESHA3 = 1 << 5,
- ARM_HWCAP2_A64_SVESM4 = 1 << 6,
- ARM_HWCAP2_A64_FLAGM2 = 1 << 7,
- ARM_HWCAP2_A64_FRINT = 1 << 8,
- ARM_HWCAP2_A64_SVEI8MM = 1 << 9,
- ARM_HWCAP2_A64_SVEF32MM = 1 << 10,
- ARM_HWCAP2_A64_SVEF64MM = 1 << 11,
- ARM_HWCAP2_A64_SVEBF16 = 1 << 12,
- ARM_HWCAP2_A64_I8MM = 1 << 13,
- ARM_HWCAP2_A64_BF16 = 1 << 14,
- ARM_HWCAP2_A64_DGH = 1 << 15,
- ARM_HWCAP2_A64_RNG = 1 << 16,
- ARM_HWCAP2_A64_BTI = 1 << 17,
- ARM_HWCAP2_A64_MTE = 1 << 18,
- ARM_HWCAP2_A64_ECV = 1 << 19,
- ARM_HWCAP2_A64_AFP = 1 << 20,
- ARM_HWCAP2_A64_RPRES = 1 << 21,
- ARM_HWCAP2_A64_MTE3 = 1 << 22,
- ARM_HWCAP2_A64_SME = 1 << 23,
- ARM_HWCAP2_A64_SME_I16I64 = 1 << 24,
- ARM_HWCAP2_A64_SME_F64F64 = 1 << 25,
- ARM_HWCAP2_A64_SME_I8I32 = 1 << 26,
- ARM_HWCAP2_A64_SME_F16F32 = 1 << 27,
- ARM_HWCAP2_A64_SME_B16F32 = 1 << 28,
- ARM_HWCAP2_A64_SME_F32F32 = 1 << 29,
- ARM_HWCAP2_A64_SME_FA64 = 1 << 30,
- ARM_HWCAP2_A64_WFXT = 1ULL << 31,
- ARM_HWCAP2_A64_EBF16 = 1ULL << 32,
- ARM_HWCAP2_A64_SVE_EBF16 = 1ULL << 33,
- ARM_HWCAP2_A64_CSSC = 1ULL << 34,
- ARM_HWCAP2_A64_RPRFM = 1ULL << 35,
- ARM_HWCAP2_A64_SVE2P1 = 1ULL << 36,
- ARM_HWCAP2_A64_SME2 = 1ULL << 37,
- ARM_HWCAP2_A64_SME2P1 = 1ULL << 38,
- ARM_HWCAP2_A64_SME_I16I32 = 1ULL << 39,
- ARM_HWCAP2_A64_SME_BI32I32 = 1ULL << 40,
- ARM_HWCAP2_A64_SME_B16B16 = 1ULL << 41,
- ARM_HWCAP2_A64_SME_F16F16 = 1ULL << 42,
- ARM_HWCAP2_A64_MOPS = 1ULL << 43,
- ARM_HWCAP2_A64_HBC = 1ULL << 44,
-};
-
-#define ELF_HWCAP get_elf_hwcap()
-#define ELF_HWCAP2 get_elf_hwcap2()
-
-#define GET_FEATURE_ID(feat, hwcap) \
- do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
-
-uint32_t get_elf_hwcap(void)
-{
- ARMCPU *cpu = ARM_CPU(thread_cpu);
- uint32_t hwcaps = 0;
-
- hwcaps |= ARM_HWCAP_A64_FP;
- hwcaps |= ARM_HWCAP_A64_ASIMD;
- hwcaps |= ARM_HWCAP_A64_CPUID;
-
- /* probe for the extra features */
-
- GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
- GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
- GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
- GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
- GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
- GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
- GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
- GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
- GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
- GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
- GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
- GET_FEATURE_ID(aa64_lse2, ARM_HWCAP_A64_USCAT);
- GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
- GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
- GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
- GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
- GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
- GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
- GET_FEATURE_ID(aa64_dit, ARM_HWCAP_A64_DIT);
- GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
- GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
- GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
- GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
- GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
- GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
-
- return hwcaps;
-}
-
-uint64_t get_elf_hwcap2(void)
-{
- ARMCPU *cpu = ARM_CPU(thread_cpu);
- uint64_t hwcaps = 0;
-
- GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
- GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
- GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
- GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
- GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
- GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
- GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
- GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
- GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
- GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
- GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
- GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
- GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
- GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
- GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
- GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
- GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
- GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
- GET_FEATURE_ID(aa64_mte3, ARM_HWCAP2_A64_MTE3);
- GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME |
- ARM_HWCAP2_A64_SME_F32F32 |
- ARM_HWCAP2_A64_SME_B16F32 |
- ARM_HWCAP2_A64_SME_F16F32 |
- ARM_HWCAP2_A64_SME_I8I32));
- GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64);
- GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64);
- GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
- GET_FEATURE_ID(aa64_hbc, ARM_HWCAP2_A64_HBC);
- GET_FEATURE_ID(aa64_mops, ARM_HWCAP2_A64_MOPS);
-
- return hwcaps;
-}
-
-const char *elf_hwcap_str(uint32_t bit)
-{
- static const char *hwcap_str[] = {
- [__builtin_ctz(ARM_HWCAP_A64_FP )] = "fp",
- [__builtin_ctz(ARM_HWCAP_A64_ASIMD )] = "asimd",
- [__builtin_ctz(ARM_HWCAP_A64_EVTSTRM )] = "evtstrm",
- [__builtin_ctz(ARM_HWCAP_A64_AES )] = "aes",
- [__builtin_ctz(ARM_HWCAP_A64_PMULL )] = "pmull",
- [__builtin_ctz(ARM_HWCAP_A64_SHA1 )] = "sha1",
- [__builtin_ctz(ARM_HWCAP_A64_SHA2 )] = "sha2",
- [__builtin_ctz(ARM_HWCAP_A64_CRC32 )] = "crc32",
- [__builtin_ctz(ARM_HWCAP_A64_ATOMICS )] = "atomics",
- [__builtin_ctz(ARM_HWCAP_A64_FPHP )] = "fphp",
- [__builtin_ctz(ARM_HWCAP_A64_ASIMDHP )] = "asimdhp",
- [__builtin_ctz(ARM_HWCAP_A64_CPUID )] = "cpuid",
- [__builtin_ctz(ARM_HWCAP_A64_ASIMDRDM)] = "asimdrdm",
- [__builtin_ctz(ARM_HWCAP_A64_JSCVT )] = "jscvt",
- [__builtin_ctz(ARM_HWCAP_A64_FCMA )] = "fcma",
- [__builtin_ctz(ARM_HWCAP_A64_LRCPC )] = "lrcpc",
- [__builtin_ctz(ARM_HWCAP_A64_DCPOP )] = "dcpop",
- [__builtin_ctz(ARM_HWCAP_A64_SHA3 )] = "sha3",
- [__builtin_ctz(ARM_HWCAP_A64_SM3 )] = "sm3",
- [__builtin_ctz(ARM_HWCAP_A64_SM4 )] = "sm4",
- [__builtin_ctz(ARM_HWCAP_A64_ASIMDDP )] = "asimddp",
- [__builtin_ctz(ARM_HWCAP_A64_SHA512 )] = "sha512",
- [__builtin_ctz(ARM_HWCAP_A64_SVE )] = "sve",
- [__builtin_ctz(ARM_HWCAP_A64_ASIMDFHM)] = "asimdfhm",
- [__builtin_ctz(ARM_HWCAP_A64_DIT )] = "dit",
- [__builtin_ctz(ARM_HWCAP_A64_USCAT )] = "uscat",
- [__builtin_ctz(ARM_HWCAP_A64_ILRCPC )] = "ilrcpc",
- [__builtin_ctz(ARM_HWCAP_A64_FLAGM )] = "flagm",
- [__builtin_ctz(ARM_HWCAP_A64_SSBS )] = "ssbs",
- [__builtin_ctz(ARM_HWCAP_A64_SB )] = "sb",
- [__builtin_ctz(ARM_HWCAP_A64_PACA )] = "paca",
- [__builtin_ctz(ARM_HWCAP_A64_PACG )] = "pacg",
- };
-
- return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
-}
-
-const char *elf_hwcap2_str(uint32_t bit)
-{
- static const char *hwcap_str[] = {
- [__builtin_ctz(ARM_HWCAP2_A64_DCPODP )] = "dcpodp",
- [__builtin_ctz(ARM_HWCAP2_A64_SVE2 )] = "sve2",
- [__builtin_ctz(ARM_HWCAP2_A64_SVEAES )] = "sveaes",
- [__builtin_ctz(ARM_HWCAP2_A64_SVEPMULL )] = "svepmull",
- [__builtin_ctz(ARM_HWCAP2_A64_SVEBITPERM )] = "svebitperm",
- [__builtin_ctz(ARM_HWCAP2_A64_SVESHA3 )] = "svesha3",
- [__builtin_ctz(ARM_HWCAP2_A64_SVESM4 )] = "svesm4",
- [__builtin_ctz(ARM_HWCAP2_A64_FLAGM2 )] = "flagm2",
- [__builtin_ctz(ARM_HWCAP2_A64_FRINT )] = "frint",
- [__builtin_ctz(ARM_HWCAP2_A64_SVEI8MM )] = "svei8mm",
- [__builtin_ctz(ARM_HWCAP2_A64_SVEF32MM )] = "svef32mm",
- [__builtin_ctz(ARM_HWCAP2_A64_SVEF64MM )] = "svef64mm",
- [__builtin_ctz(ARM_HWCAP2_A64_SVEBF16 )] = "svebf16",
- [__builtin_ctz(ARM_HWCAP2_A64_I8MM )] = "i8mm",
- [__builtin_ctz(ARM_HWCAP2_A64_BF16 )] = "bf16",
- [__builtin_ctz(ARM_HWCAP2_A64_DGH )] = "dgh",
- [__builtin_ctz(ARM_HWCAP2_A64_RNG )] = "rng",
- [__builtin_ctz(ARM_HWCAP2_A64_BTI )] = "bti",
- [__builtin_ctz(ARM_HWCAP2_A64_MTE )] = "mte",
- [__builtin_ctz(ARM_HWCAP2_A64_ECV )] = "ecv",
- [__builtin_ctz(ARM_HWCAP2_A64_AFP )] = "afp",
- [__builtin_ctz(ARM_HWCAP2_A64_RPRES )] = "rpres",
- [__builtin_ctz(ARM_HWCAP2_A64_MTE3 )] = "mte3",
- [__builtin_ctz(ARM_HWCAP2_A64_SME )] = "sme",
- [__builtin_ctz(ARM_HWCAP2_A64_SME_I16I64 )] = "smei16i64",
- [__builtin_ctz(ARM_HWCAP2_A64_SME_F64F64 )] = "smef64f64",
- [__builtin_ctz(ARM_HWCAP2_A64_SME_I8I32 )] = "smei8i32",
- [__builtin_ctz(ARM_HWCAP2_A64_SME_F16F32 )] = "smef16f32",
- [__builtin_ctz(ARM_HWCAP2_A64_SME_B16F32 )] = "smeb16f32",
- [__builtin_ctz(ARM_HWCAP2_A64_SME_F32F32 )] = "smef32f32",
- [__builtin_ctz(ARM_HWCAP2_A64_SME_FA64 )] = "smefa64",
- [__builtin_ctz(ARM_HWCAP2_A64_WFXT )] = "wfxt",
- [__builtin_ctzll(ARM_HWCAP2_A64_EBF16 )] = "ebf16",
- [__builtin_ctzll(ARM_HWCAP2_A64_SVE_EBF16 )] = "sveebf16",
- [__builtin_ctzll(ARM_HWCAP2_A64_CSSC )] = "cssc",
- [__builtin_ctzll(ARM_HWCAP2_A64_RPRFM )] = "rprfm",
- [__builtin_ctzll(ARM_HWCAP2_A64_SVE2P1 )] = "sve2p1",
- [__builtin_ctzll(ARM_HWCAP2_A64_SME2 )] = "sme2",
- [__builtin_ctzll(ARM_HWCAP2_A64_SME2P1 )] = "sme2p1",
- [__builtin_ctzll(ARM_HWCAP2_A64_SME_I16I32 )] = "smei16i32",
- [__builtin_ctzll(ARM_HWCAP2_A64_SME_BI32I32)] = "smebi32i32",
- [__builtin_ctzll(ARM_HWCAP2_A64_SME_B16B16 )] = "smeb16b16",
- [__builtin_ctzll(ARM_HWCAP2_A64_SME_F16F16 )] = "smef16f16",
- [__builtin_ctzll(ARM_HWCAP2_A64_MOPS )] = "mops",
- [__builtin_ctzll(ARM_HWCAP2_A64_HBC )] = "hbc",
- };
-
- return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
-}
-
-#undef GET_FEATURE_ID
-
-#if TARGET_BIG_ENDIAN
-# define VDSO_HEADER "vdso-be.c.inc"
-#else
-# define VDSO_HEADER "vdso-le.c.inc"
-#endif
-
-#endif /* not TARGET_AARCH64 */
-
-#endif /* TARGET_ARM */
-
-#ifdef TARGET_SPARC
-
-#ifndef TARGET_SPARC64
-# define ELF_CLASS ELFCLASS32
-# define ELF_ARCH EM_SPARC
-#elif defined(TARGET_ABI32)
-# define ELF_CLASS ELFCLASS32
-# define elf_check_arch(x) ((x) == EM_SPARC32PLUS || (x) == EM_SPARC)
-#else
-# define ELF_CLASS ELFCLASS64
-# define ELF_ARCH EM_SPARCV9
-#endif
-
-#include "elf.h"
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
- /* There are not many sparc32 hwcap bits -- we have all of them. */
- uint32_t r = HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
- HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV;
-
-#ifdef TARGET_SPARC64
- CPUSPARCState *env = cpu_env(thread_cpu);
- uint32_t features = env->def.features;
-
- r |= HWCAP_SPARC_V9 | HWCAP_SPARC_V8PLUS;
- /* 32x32 multiply and divide are efficient. */
- r |= HWCAP_SPARC_MUL32 | HWCAP_SPARC_DIV32;
- /* We don't have an internal feature bit for this. */
- r |= HWCAP_SPARC_POPC;
- r |= features & CPU_FEATURE_FSMULD ? HWCAP_SPARC_FSMULD : 0;
- r |= features & CPU_FEATURE_VIS1 ? HWCAP_SPARC_VIS : 0;
- r |= features & CPU_FEATURE_VIS2 ? HWCAP_SPARC_VIS2 : 0;
- r |= features & CPU_FEATURE_FMAF ? HWCAP_SPARC_FMAF : 0;
- r |= features & CPU_FEATURE_VIS3 ? HWCAP_SPARC_VIS3 : 0;
- r |= features & CPU_FEATURE_IMA ? HWCAP_SPARC_IMA : 0;
-#endif
-
- return r;
-}
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- /* Note that target_cpu_copy_regs does not read psr/tstate. */
- regs->pc = infop->entry;
- regs->npc = regs->pc + 4;
- regs->y = 0;
- regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
- - TARGET_STACK_BIAS);
-}
-#endif /* TARGET_SPARC */
-
-#ifdef TARGET_PPC
-
-#define ELF_MACHINE PPC_ELF_MACHINE
-
-#if defined(TARGET_PPC64)
-
-#define elf_check_arch(x) ( (x) == EM_PPC64 )
-
-#define ELF_CLASS ELFCLASS64
-
-#else
-
-#define ELF_CLASS ELFCLASS32
-#define EXSTACK_DEFAULT true
-
-#endif
-
-#define ELF_ARCH EM_PPC
-
-/* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
- See arch/powerpc/include/asm/cputable.h. */
-enum {
- QEMU_PPC_FEATURE_32 = 0x80000000,
- QEMU_PPC_FEATURE_64 = 0x40000000,
- QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
- QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
- QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
- QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
- QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
- QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
- QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
- QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
- QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
- QEMU_PPC_FEATURE_NO_TB = 0x00100000,
- QEMU_PPC_FEATURE_POWER4 = 0x00080000,
- QEMU_PPC_FEATURE_POWER5 = 0x00040000,
- QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
- QEMU_PPC_FEATURE_CELL = 0x00010000,
- QEMU_PPC_FEATURE_BOOKE = 0x00008000,
- QEMU_PPC_FEATURE_SMT = 0x00004000,
- QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
- QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
- QEMU_PPC_FEATURE_PA6T = 0x00000800,
- QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
- QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
- QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
- QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
- QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
-
- QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
- QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
-
- /* Feature definitions in AT_HWCAP2. */
- QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
- QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
- QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
- QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
- QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
- QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
- QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
- QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
- QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
- QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
- QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
- QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
- QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
- QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */
- QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */
-};
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
- PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
- uint32_t features = 0;
-
- /* We don't have to be terribly complete here; the high points are
- Altivec/FP/SPE support. Anything else is just a bonus. */
-#define GET_FEATURE(flag, feature) \
- do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
-#define GET_FEATURE2(flags, feature) \
- do { \
- if ((cpu->env.insns_flags2 & flags) == flags) { \
- features |= feature; \
- } \
- } while (0)
- GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
- GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
- GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
- GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
- GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
- GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
- GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
- GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
- GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
- GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
- GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
- PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
- QEMU_PPC_FEATURE_ARCH_2_06);
-#undef GET_FEATURE
-#undef GET_FEATURE2
-
- return features;
-}
-
-#define ELF_HWCAP2 get_elf_hwcap2()
-
-static uint32_t get_elf_hwcap2(void)
-{
- PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
- uint32_t features = 0;
-
-#define GET_FEATURE(flag, feature) \
- do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
-#define GET_FEATURE2(flag, feature) \
- do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
-
- GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
- GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
- GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
- PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
- QEMU_PPC_FEATURE2_VEC_CRYPTO);
- GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
- QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128);
- GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 |
- QEMU_PPC_FEATURE2_MMA);
-
-#undef GET_FEATURE
-#undef GET_FEATURE2
-
- return features;
-}
-
-/*
- * The requirements here are:
- * - keep the final alignment of sp (sp & 0xf)
- * - make sure the 32-bit value at the first 16 byte aligned position of
- * AUXV is greater than 16 for glibc compatibility.
- * AT_IGNOREPPC is used for that.
- * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
- * even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
- */
-#define DLINFO_ARCH_ITEMS 5
-#define ARCH_DLINFO \
- do { \
- PowerPCCPU *cpu = POWERPC_CPU(thread_cpu); \
- /* \
- * Handle glibc compatibility: these magic entries must \
- * be at the lowest addresses in the final auxv. \
- */ \
- NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
- NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
- NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
- NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
- NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
- } while (0)
-
-static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
-{
- _regs->gpr[1] = infop->start_stack;
-#if defined(TARGET_PPC64)
- if (get_ppc64_abi(infop) < 2) {
- uint64_t val;
- get_user_u64(val, infop->entry + 8);
- _regs->gpr[2] = val + infop->load_bias;
- get_user_u64(val, infop->entry);
- infop->entry = val + infop->load_bias;
- } else {
- _regs->gpr[12] = infop->entry; /* r12 set to global entry address */
- }
-#endif
- _regs->nip = infop->entry;
-}
-
-/* See linux kernel: arch/powerpc/include/asm/elf.h. */
-#define ELF_NREG 48
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
-{
- int i;
- target_ulong ccr = 0;
-
- for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
- (*regs)[i] = tswapreg(env->gpr[i]);
- }
-
- (*regs)[32] = tswapreg(env->nip);
- (*regs)[33] = tswapreg(env->msr);
- (*regs)[35] = tswapreg(env->ctr);
- (*regs)[36] = tswapreg(env->lr);
- (*regs)[37] = tswapreg(cpu_read_xer(env));
-
- ccr = ppc_get_cr(env);
- (*regs)[38] = tswapreg(ccr);
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#ifndef TARGET_PPC64
-# define VDSO_HEADER "vdso-32.c.inc"
-#elif TARGET_BIG_ENDIAN
-# define VDSO_HEADER "vdso-64.c.inc"
-#else
-# define VDSO_HEADER "vdso-64le.c.inc"
-#endif
-
-#endif
-
-#ifdef TARGET_LOONGARCH64
-
-#define ELF_CLASS ELFCLASS64
-#define ELF_ARCH EM_LOONGARCH
-#define EXSTACK_DEFAULT true
-
-#define elf_check_arch(x) ((x) == EM_LOONGARCH)
-
-#define VDSO_HEADER "vdso.c.inc"
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- /*Set crmd PG,DA = 1,0 */
- regs->csr.crmd = 2 << 3;
- regs->csr.era = infop->entry;
- regs->regs[3] = infop->start_stack;
-}
-
-/* See linux kernel: arch/loongarch/include/asm/elf.h */
-#define ELF_NREG 45
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-enum {
- TARGET_EF_R0 = 0,
- TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33,
- TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34,
-};
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs,
- const CPULoongArchState *env)
-{
- int i;
-
- (*regs)[TARGET_EF_R0] = 0;
-
- for (i = 1; i < ARRAY_SIZE(env->gpr); i++) {
- (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]);
- }
-
- (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc);
- (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV);
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#define ELF_HWCAP get_elf_hwcap()
-
-/* See arch/loongarch/include/uapi/asm/hwcap.h */
-enum {
- HWCAP_LOONGARCH_CPUCFG = (1 << 0),
- HWCAP_LOONGARCH_LAM = (1 << 1),
- HWCAP_LOONGARCH_UAL = (1 << 2),
- HWCAP_LOONGARCH_FPU = (1 << 3),
- HWCAP_LOONGARCH_LSX = (1 << 4),
- HWCAP_LOONGARCH_LASX = (1 << 5),
- HWCAP_LOONGARCH_CRC32 = (1 << 6),
- HWCAP_LOONGARCH_COMPLEX = (1 << 7),
- HWCAP_LOONGARCH_CRYPTO = (1 << 8),
- HWCAP_LOONGARCH_LVZ = (1 << 9),
- HWCAP_LOONGARCH_LBT_X86 = (1 << 10),
- HWCAP_LOONGARCH_LBT_ARM = (1 << 11),
- HWCAP_LOONGARCH_LBT_MIPS = (1 << 12),
-};
-
-static uint32_t get_elf_hwcap(void)
-{
- LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu);
- uint32_t hwcaps = 0;
-
- hwcaps |= HWCAP_LOONGARCH_CRC32;
-
- if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) {
- hwcaps |= HWCAP_LOONGARCH_UAL;
- }
-
- if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) {
- hwcaps |= HWCAP_LOONGARCH_FPU;
- }
-
- if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) {
- hwcaps |= HWCAP_LOONGARCH_LAM;
- }
-
- if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
- hwcaps |= HWCAP_LOONGARCH_LSX;
- }
-
- if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
- hwcaps |= HWCAP_LOONGARCH_LASX;
- }
-
- return hwcaps;
-}
-
-#define ELF_PLATFORM "loongarch"
-
-#endif /* TARGET_LOONGARCH64 */
-
-#ifdef TARGET_MIPS
-
-#ifdef TARGET_MIPS64
-#define ELF_CLASS ELFCLASS64
-#else
-#define ELF_CLASS ELFCLASS32
-#endif
-#define ELF_ARCH EM_MIPS
-#define EXSTACK_DEFAULT true
-
-#ifdef TARGET_ABI_MIPSN32
-#define elf_check_abi(x) ((x) & EF_MIPS_ABI2)
-#else
-#define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
-#endif
-
-#define ELF_BASE_PLATFORM get_elf_base_platform()
-
-#define MATCH_PLATFORM_INSN(_flags, _base_platform) \
- do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
- { return _base_platform; } } while (0)
-
-static const char *get_elf_base_platform(void)
-{
- MIPSCPU *cpu = MIPS_CPU(thread_cpu);
-
- /* 64 bit ISAs goes first */
- MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
- MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
- MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
- MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
- MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
- MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
- MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
-
- /* 32 bit ISAs */
- MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
- MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
- MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
- MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
- MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
-
- /* Fallback */
- return "mips";
-}
-#undef MATCH_PLATFORM_INSN
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->cp0_status = 2 << CP0St_KSU;
- regs->cp0_epc = infop->entry;
- regs->regs[29] = infop->start_stack;
-}
-
-/* See linux kernel: arch/mips/include/asm/elf.h. */
-#define ELF_NREG 45
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-/* See linux kernel: arch/mips/include/asm/reg.h. */
-enum {
-#ifdef TARGET_MIPS64
- TARGET_EF_R0 = 0,
-#else
- TARGET_EF_R0 = 6,
-#endif
- TARGET_EF_R26 = TARGET_EF_R0 + 26,
- TARGET_EF_R27 = TARGET_EF_R0 + 27,
- TARGET_EF_LO = TARGET_EF_R0 + 32,
- TARGET_EF_HI = TARGET_EF_R0 + 33,
- TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
- TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
- TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
- TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
-};
-
-/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */
-static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
-{
- int i;
-
- for (i = 0; i < TARGET_EF_R0; i++) {
- (*regs)[i] = 0;
- }
- (*regs)[TARGET_EF_R0] = 0;
-
- for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
- (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
- }
-
- (*regs)[TARGET_EF_R26] = 0;
- (*regs)[TARGET_EF_R27] = 0;
- (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
- (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
- (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
- (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
- (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
- (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-/* See arch/mips/include/uapi/asm/hwcap.h. */
-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;
-
- 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
-
-#define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_MICROBLAZE
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->pc = infop->entry;
- regs->r1 = infop->start_stack;
-
-}
-
-#define ELF_EXEC_PAGESIZE 4096
-
-#define USE_ELF_CORE_DUMP
-#define ELF_NREG 38
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */
-static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
-{
- int i, pos = 0;
-
- for (i = 0; i < 32; i++) {
- (*regs)[pos++] = tswapreg(env->regs[i]);
- }
-
- (*regs)[pos++] = tswapreg(env->pc);
- (*regs)[pos++] = tswapreg(mb_cpu_read_msr(env));
- (*regs)[pos++] = 0;
- (*regs)[pos++] = tswapreg(env->ear);
- (*regs)[pos++] = 0;
- (*regs)[pos++] = tswapreg(env->esr);
-}
-
-#endif /* TARGET_MICROBLAZE */
-
-#ifdef TARGET_OPENRISC
-
-#define ELF_ARCH EM_OPENRISC
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->pc = infop->entry;
- regs->gpr[1] = infop->start_stack;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 8192
-
-/* See linux kernel arch/openrisc/include/asm/elf.h. */
-#define ELF_NREG 34 /* gprs and pc, sr */
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs,
- const CPUOpenRISCState *env)
-{
- int i;
-
- for (i = 0; i < 32; i++) {
- (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
- }
- (*regs)[32] = tswapreg(env->pc);
- (*regs)[33] = tswapreg(cpu_get_sr(env));
-}
-#define ELF_HWCAP 0
-#define ELF_PLATFORM NULL
-
-#endif /* TARGET_OPENRISC */
-
-#ifdef TARGET_SH4
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_SH
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- /* Check other registers XXXXX */
- regs->pc = infop->entry;
- regs->regs[15] = infop->start_stack;
-}
-
-/* See linux kernel: arch/sh/include/asm/elf.h. */
-#define ELF_NREG 23
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-/* See linux kernel: arch/sh/include/asm/ptrace.h. */
-enum {
- TARGET_REG_PC = 16,
- TARGET_REG_PR = 17,
- TARGET_REG_SR = 18,
- TARGET_REG_GBR = 19,
- TARGET_REG_MACH = 20,
- TARGET_REG_MACL = 21,
- TARGET_REG_SYSCALL = 22
-};
-
-static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
- const CPUSH4State *env)
-{
- int i;
-
- for (i = 0; i < 16; i++) {
- (*regs)[i] = tswapreg(env->gregs[i]);
- }
-
- (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
- (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
- (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
- (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
- (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
- (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
- (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-enum {
- SH_CPU_HAS_FPU = 0x0001, /* Hardware FPU support */
- SH_CPU_HAS_P2_FLUSH_BUG = 0x0002, /* Need to flush the cache in P2 area */
- SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
- SH_CPU_HAS_DSP = 0x0008, /* SH-DSP: DSP support */
- SH_CPU_HAS_PERF_COUNTER = 0x0010, /* Hardware performance counters */
- SH_CPU_HAS_PTEA = 0x0020, /* PTEA register */
- SH_CPU_HAS_LLSC = 0x0040, /* movli.l/movco.l */
- SH_CPU_HAS_L2_CACHE = 0x0080, /* Secondary cache / URAM */
- SH_CPU_HAS_OP32 = 0x0100, /* 32-bit instruction support */
- SH_CPU_HAS_PTEAEX = 0x0200, /* PTE ASID Extension support */
-};
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
- SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
- uint32_t hwcap = 0;
-
- hwcap |= SH_CPU_HAS_FPU;
-
- if (cpu->env.features & SH_FEATURE_SH4A) {
- hwcap |= SH_CPU_HAS_LLSC;
- }
-
- return hwcap;
-}
-
-#endif
-
-#ifdef TARGET_M68K
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_68K
-
-/* ??? Does this need to do anything?
- #define ELF_PLAT_INIT(_r) */
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->usp = infop->start_stack;
- regs->sr = 0;
- regs->pc = infop->entry;
-}
-
-/* See linux kernel: arch/m68k/include/asm/elf.h. */
-#define ELF_NREG 20
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
-{
- (*regs)[0] = tswapreg(env->dregs[1]);
- (*regs)[1] = tswapreg(env->dregs[2]);
- (*regs)[2] = tswapreg(env->dregs[3]);
- (*regs)[3] = tswapreg(env->dregs[4]);
- (*regs)[4] = tswapreg(env->dregs[5]);
- (*regs)[5] = tswapreg(env->dregs[6]);
- (*regs)[6] = tswapreg(env->dregs[7]);
- (*regs)[7] = tswapreg(env->aregs[0]);
- (*regs)[8] = tswapreg(env->aregs[1]);
- (*regs)[9] = tswapreg(env->aregs[2]);
- (*regs)[10] = tswapreg(env->aregs[3]);
- (*regs)[11] = tswapreg(env->aregs[4]);
- (*regs)[12] = tswapreg(env->aregs[5]);
- (*regs)[13] = tswapreg(env->aregs[6]);
- (*regs)[14] = tswapreg(env->dregs[0]);
- (*regs)[15] = tswapreg(env->aregs[7]);
- (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
- (*regs)[17] = tswapreg(env->sr);
- (*regs)[18] = tswapreg(env->pc);
- (*regs)[19] = 0; /* FIXME: regs->format | regs->vector */
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 8192
-
-#endif
-
-#ifdef TARGET_ALPHA
-
-#define ELF_CLASS ELFCLASS64
-#define ELF_ARCH EM_ALPHA
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->pc = infop->entry;
- regs->ps = 8;
- regs->usp = infop->start_stack;
-}
-
-#define ELF_EXEC_PAGESIZE 8192
-
-#endif /* TARGET_ALPHA */
-
-#ifdef TARGET_S390X
-
-#define ELF_CLASS ELFCLASS64
-#define ELF_DATA ELFDATA2MSB
-#define ELF_ARCH EM_S390
-
-#include "elf.h"
-
-#define ELF_HWCAP get_elf_hwcap()
-
-#define GET_FEATURE(_feat, _hwcap) \
- do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
-
-uint32_t get_elf_hwcap(void)
-{
- /*
- * Let's assume we always have esan3 and zarch.
- * 31-bit processes can use 64-bit registers (high gprs).
- */
- uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
-
- GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
- GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
- GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
- GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
- if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
- s390_has_feat(S390_FEAT_ETF3_ENH)) {
- hwcap |= HWCAP_S390_ETF3EH;
- }
- GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
- GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
- GET_FEATURE(S390_FEAT_VECTOR_ENH2, HWCAP_S390_VXRS_EXT2);
-
- return hwcap;
-}
-
-const char *elf_hwcap_str(uint32_t bit)
-{
- static const char *hwcap_str[] = {
- [HWCAP_S390_NR_ESAN3] = "esan3",
- [HWCAP_S390_NR_ZARCH] = "zarch",
- [HWCAP_S390_NR_STFLE] = "stfle",
- [HWCAP_S390_NR_MSA] = "msa",
- [HWCAP_S390_NR_LDISP] = "ldisp",
- [HWCAP_S390_NR_EIMM] = "eimm",
- [HWCAP_S390_NR_DFP] = "dfp",
- [HWCAP_S390_NR_HPAGE] = "edat",
- [HWCAP_S390_NR_ETF3EH] = "etf3eh",
- [HWCAP_S390_NR_HIGH_GPRS] = "highgprs",
- [HWCAP_S390_NR_TE] = "te",
- [HWCAP_S390_NR_VXRS] = "vx",
- [HWCAP_S390_NR_VXRS_BCD] = "vxd",
- [HWCAP_S390_NR_VXRS_EXT] = "vxe",
- [HWCAP_S390_NR_GS] = "gs",
- [HWCAP_S390_NR_VXRS_EXT2] = "vxe2",
- [HWCAP_S390_NR_VXRS_PDE] = "vxp",
- [HWCAP_S390_NR_SORT] = "sort",
- [HWCAP_S390_NR_DFLT] = "dflt",
- [HWCAP_S390_NR_NNPA] = "nnpa",
- [HWCAP_S390_NR_PCI_MIO] = "pcimio",
- [HWCAP_S390_NR_SIE] = "sie",
- };
-
- return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
-}
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- regs->psw.addr = infop->entry;
- regs->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
- PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | \
- PSW_MASK_32;
- regs->gprs[15] = infop->start_stack;
-}
-
-/* See linux kernel: arch/s390/include/uapi/asm/ptrace.h (s390_regs). */
-#define ELF_NREG 27
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-enum {
- TARGET_REG_PSWM = 0,
- TARGET_REG_PSWA = 1,
- TARGET_REG_GPRS = 2,
- TARGET_REG_ARS = 18,
- TARGET_REG_ORIG_R2 = 26,
-};
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs,
- const CPUS390XState *env)
-{
- int i;
- uint32_t *aregs;
-
- (*regs)[TARGET_REG_PSWM] = tswapreg(env->psw.mask);
- (*regs)[TARGET_REG_PSWA] = tswapreg(env->psw.addr);
- for (i = 0; i < 16; i++) {
- (*regs)[TARGET_REG_GPRS + i] = tswapreg(env->regs[i]);
- }
- aregs = (uint32_t *)&((*regs)[TARGET_REG_ARS]);
- for (i = 0; i < 16; i++) {
- aregs[i] = tswap32(env->aregs[i]);
- }
- (*regs)[TARGET_REG_ORIG_R2] = 0;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#define VDSO_HEADER "vdso.c.inc"
-
-#endif /* TARGET_S390X */
-
-#ifdef TARGET_RISCV
-
-#define ELF_ARCH EM_RISCV
-
-#ifdef TARGET_RISCV32
-#define ELF_CLASS ELFCLASS32
-#define VDSO_HEADER "vdso-32.c.inc"
-#else
-#define ELF_CLASS ELFCLASS64
-#define VDSO_HEADER "vdso-64.c.inc"
-#endif
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
-#define MISA_BIT(EXT) (1 << (EXT - 'A'))
- RISCVCPU *cpu = RISCV_CPU(thread_cpu);
- uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A')
- | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C')
- | MISA_BIT('V');
-
- return cpu->env.misa_ext & mask;
-#undef MISA_BIT
-}
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->sepc = infop->entry;
- regs->sp = infop->start_stack;
-}
-
-#define ELF_EXEC_PAGESIZE 4096
-
-#endif /* TARGET_RISCV */
-
-#ifdef TARGET_HPPA
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_PARISC
-#define ELF_PLATFORM "PARISC"
-#define STACK_GROWS_DOWN 0
-#define STACK_ALIGNMENT 64
-
-#define VDSO_HEADER "vdso.c.inc"
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->iaoq[0] = infop->entry | PRIV_USER;
- regs->iaoq[1] = regs->iaoq[0] + 4;
- regs->gr[23] = 0;
- regs->gr[24] = infop->argv;
- regs->gr[25] = infop->argc;
- /* The top-of-stack contains a linkage buffer. */
- regs->gr[30] = infop->start_stack + 64;
- regs->gr[31] = infop->entry;
-}
-
-#define LO_COMMPAGE 0
-
-static bool init_guest_commpage(void)
-{
- /* If reserved_va, then we have already mapped 0 page on the host. */
- if (!reserved_va) {
- void *want, *addr;
-
- want = g2h_untagged(LO_COMMPAGE);
- addr = mmap(want, TARGET_PAGE_SIZE, PROT_NONE,
- MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0);
- if (addr == MAP_FAILED) {
- perror("Allocating guest commpage");
- exit(EXIT_FAILURE);
- }
- if (addr != want) {
- return false;
- }
- }
-
- /*
- * On Linux, page zero is normally marked execute only + gateway.
- * Normal read or write is supposed to fail (thus PROT_NONE above),
- * but specific offsets have kernel code mapped to raise permissions
- * and implement syscalls. Here, simply mark the page executable.
- * Special case the entry points during translation (see do_page_zero).
- */
- page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
- PAGE_EXEC | PAGE_VALID);
- return true;
-}
-
-#endif /* TARGET_HPPA */
-
-#ifdef TARGET_XTENSA
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_XTENSA
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->windowbase = 0;
- regs->windowstart = 1;
- regs->areg[1] = infop->start_stack;
- regs->pc = infop->entry;
- if (info_is_fdpic(infop)) {
- regs->areg[4] = infop->loadmap_addr;
- regs->areg[5] = infop->interpreter_loadmap_addr;
- if (infop->interpreter_loadmap_addr) {
- regs->areg[6] = infop->interpreter_pt_dynamic_addr;
- } else {
- regs->areg[6] = infop->pt_dynamic_addr;
- }
- }
-}
-
-/* See linux kernel: arch/xtensa/include/asm/elf.h. */
-#define ELF_NREG 128
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-enum {
- TARGET_REG_PC,
- TARGET_REG_PS,
- TARGET_REG_LBEG,
- TARGET_REG_LEND,
- TARGET_REG_LCOUNT,
- TARGET_REG_SAR,
- TARGET_REG_WINDOWSTART,
- TARGET_REG_WINDOWBASE,
- TARGET_REG_THREADPTR,
- TARGET_REG_AR0 = 64,
-};
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs,
- const CPUXtensaState *env)
-{
- unsigned i;
-
- (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
- (*regs)[TARGET_REG_PS] = tswapreg(env->sregs[PS] & ~PS_EXCM);
- (*regs)[TARGET_REG_LBEG] = tswapreg(env->sregs[LBEG]);
- (*regs)[TARGET_REG_LEND] = tswapreg(env->sregs[LEND]);
- (*regs)[TARGET_REG_LCOUNT] = tswapreg(env->sregs[LCOUNT]);
- (*regs)[TARGET_REG_SAR] = tswapreg(env->sregs[SAR]);
- (*regs)[TARGET_REG_WINDOWSTART] = tswapreg(env->sregs[WINDOW_START]);
- (*regs)[TARGET_REG_WINDOWBASE] = tswapreg(env->sregs[WINDOW_BASE]);
- (*regs)[TARGET_REG_THREADPTR] = tswapreg(env->uregs[THREADPTR]);
- xtensa_sync_phys_from_window((CPUXtensaState *)env);
- for (i = 0; i < env->config->nareg; ++i) {
- (*regs)[TARGET_REG_AR0 + i] = tswapreg(env->phys_regs[i]);
- }
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#endif /* TARGET_XTENSA */
-
-#ifdef TARGET_HEXAGON
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_HEXAGON
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->sepc = infop->entry;
- regs->sp = infop->start_stack;
-}
-
-#endif /* TARGET_HEXAGON */
-
-#ifndef ELF_BASE_PLATFORM
-#define ELF_BASE_PLATFORM (NULL)
-#endif
-
-#ifndef ELF_PLATFORM
-#define ELF_PLATFORM (NULL)
-#endif
-
-#ifndef ELF_MACHINE
-#define ELF_MACHINE ELF_ARCH
-#endif
-
-#ifndef elf_check_arch
-#define elf_check_arch(x) ((x) == ELF_ARCH)
+#ifndef elf_check_machine
+#define elf_check_machine(x) ((x) == ELF_MACHINE)
#endif
#ifndef elf_check_abi
#define elf_check_abi(x) (1)
#endif
-#ifndef ELF_HWCAP
-#define ELF_HWCAP 0
-#endif
-
#ifndef STACK_GROWS_DOWN
#define STACK_GROWS_DOWN 1
#endif
@@ -2062,59 +147,36 @@ static inline void init_thread(struct target_pt_regs *regs,
#define EXSTACK_DEFAULT false
#endif
-#include "elf.h"
-
-/* We must delay the following stanzas until after "elf.h". */
-#if defined(TARGET_AARCH64)
-
-static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
- const uint32_t *data,
- struct image_info *info,
- Error **errp)
-{
- if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
- if (pr_datasz != sizeof(uint32_t)) {
- error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
- return false;
- }
- /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
- info->note_flags = *data;
- }
- return true;
-}
-#define ARCH_USE_GNU_PROPERTY 1
-
-#else
+/*
+ * Provide fallback definitions that the target may omit.
+ * One way or another, we'll get a link error if the setting of
+ * HAVE_* doesn't match the implementation.
+ */
+#ifndef HAVE_ELF_HWCAP
+abi_ulong get_elf_hwcap(CPUState *cs) { return 0; }
+#endif
+#ifndef HAVE_ELF_HWCAP2
+abi_ulong get_elf_hwcap2(CPUState *cs) { g_assert_not_reached(); }
+#define HAVE_ELF_HWCAP2 0
+#endif
+#ifndef HAVE_ELF_PLATFORM
+const char *get_elf_platform(CPUState *cs) { return NULL; }
+#endif
+#ifndef HAVE_ELF_BASE_PLATFORM
+const char *get_elf_base_platform(CPUState *cs) { return NULL; }
+#endif
-static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
- const uint32_t *data,
- struct image_info *info,
- Error **errp)
+#ifndef HAVE_ELF_GNU_PROPERTY
+bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
+ const uint32_t *data, struct image_info *info,
+ Error **errp)
{
g_assert_not_reached();
}
-#define ARCH_USE_GNU_PROPERTY 0
-
+#define HAVE_ELF_GNU_PROPERTY 0
#endif
-struct exec
-{
- unsigned int a_info; /* Use macros N_MAGIC, etc for access */
- unsigned int a_text; /* length of text, in bytes */
- unsigned int a_data; /* length of data, in bytes */
- unsigned int a_bss; /* length of uninitialized data area, in bytes */
- unsigned int a_syms; /* length of symbol table data in file, in bytes */
- unsigned int a_entry; /* start address */
- unsigned int a_trsize; /* length of relocation info for text, in bytes */
- unsigned int a_drsize; /* length of relocation info for data, in bytes */
-};
-
-
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#define OMAGIC 0407
-#define NMAGIC 0410
-#define ZMAGIC 0413
-#define QMAGIC 0314
+#include "elf.h"
#define DLINFO_ITEMS 16
@@ -2209,9 +271,9 @@ static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags)
}
#endif
-#ifdef USE_ELF_CORE_DUMP
+#ifdef HAVE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUArchState *);
-#endif /* USE_ELF_CORE_DUMP */
+#endif /* HAVE_ELF_CORE_DUMP */
static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
abi_ulong load_bias);
@@ -2232,7 +294,7 @@ static bool elf_check_ident(struct elfhdr *ehdr)
This has to wait until after bswapping the header. */
static bool elf_check_ehdr(struct elfhdr *ehdr)
{
- return (elf_check_arch(ehdr->e_machine)
+ return (elf_check_machine(ehdr->e_machine)
&& elf_check_abi(ehdr->e_flags)
&& ehdr->e_ehsize == sizeof(struct elfhdr)
&& ehdr->e_phentsize == sizeof(struct elf_phdr)
@@ -2515,7 +577,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
}
u_base_platform = 0;
- k_base_platform = ELF_BASE_PLATFORM;
+ k_base_platform = get_elf_base_platform(thread_cpu);
if (k_base_platform) {
size_t len = strlen(k_base_platform) + 1;
if (STACK_GROWS_DOWN) {
@@ -2531,7 +593,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
}
u_platform = 0;
- k_platform = ELF_PLATFORM;
+ k_platform = get_elf_platform(thread_cpu);
if (k_platform) {
size_t len = strlen(k_platform) + 1;
if (STACK_GROWS_DOWN) {
@@ -2583,9 +645,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
#ifdef DLINFO_ARCH_ITEMS
size += DLINFO_ARCH_ITEMS * 2;
#endif
-#ifdef ELF_HWCAP2
- size += 2;
-#endif
+ if (HAVE_ELF_HWCAP2) {
+ size += 2;
+ }
info->auxv_len = size * n;
size += envc + argc + 2;
@@ -2639,16 +701,15 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
- NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+ NEW_AUX_ENT(AT_HWCAP, get_elf_hwcap(thread_cpu));
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
NEW_AUX_ENT(AT_EXECFN, info->file_string);
-#ifdef ELF_HWCAP2
- NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
-#endif
-
+ if (HAVE_ELF_HWCAP2) {
+ NEW_AUX_ENT(AT_HWCAP2, get_elf_hwcap(thread_cpu));
+ }
if (u_base_platform) {
NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
}
@@ -2694,8 +755,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
#else
#define HI_COMMPAGE 0
#define LO_COMMPAGE -1
-#ifndef INIT_GUEST_COMMPAGE
-#define init_guest_commpage() true
+#ifndef HAVE_GUEST_COMMPAGE
+bool init_guest_commpage(void) { return true; }
#endif
#endif
@@ -3130,7 +1191,7 @@ static bool parse_elf_properties(const ImageSource *src,
uint32_t prev_type;
/* Unless the arch requires properties, ignore them. */
- if (!ARCH_USE_GNU_PROPERTY) {
+ if (!HAVE_ELF_GNU_PROPERTY) {
return true;
}
@@ -3553,14 +1614,17 @@ static void load_elf_interp(const char *filename, struct image_info *info,
load_elf_image(filename, &src, info, &ehdr, NULL);
}
-#ifndef vdso_image_info
+#ifndef HAVE_VDSO_IMAGE_INFO
+const VdsoImageInfo *get_vdso_image_info(uint32_t elf_flags)
+{
#ifdef VDSO_HEADER
#include VDSO_HEADER
-#define vdso_image_info(flags) &vdso_image_info
+ return &vdso_image_info;
#else
-#define vdso_image_info(flags) NULL
-#endif /* VDSO_HEADER */
-#endif /* vdso_image_info */
+ return NULL;
+#endif
+}
+#endif /* HAVE_VDSO_IMAGE_INFO */
static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso)
{
@@ -3891,7 +1955,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
* Load a vdso if available, which will amongst other things contain the
* signal trampolines. Otherwise, allocate a separate page for them.
*/
- const VdsoImageInfo *vdso = vdso_image_info(info->elf_flags);
+ const VdsoImageInfo *vdso = get_vdso_image_info(info->elf_flags);
if (vdso) {
load_elf_vdso(&vdso_info, vdso);
info->vdso = vdso_info.load_bias;
@@ -3922,14 +1986,14 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
g_free(elf_interpreter);
}
-#ifdef USE_ELF_CORE_DUMP
+#ifdef HAVE_ELF_CORE_DUMP
bprm->core_dump = &elf_core_dump;
#endif
return 0;
}
-#ifdef USE_ELF_CORE_DUMP
+#ifdef HAVE_ELF_CORE_DUMP
/*
* Definitions to generate Intel SVR4-like core files.
@@ -3945,23 +2009,18 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
* Core dump code is copied from linux kernel (fs/binfmt_elf.c).
*
* Porting ELF coredump for target is (quite) simple process. First you
- * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
+ * define HAVE_ELF_CORE_DUMP in target ELF code (where init_thread() for
* the target resides):
*
- * #define USE_ELF_CORE_DUMP
+ * #define HAVE_ELF_CORE_DUMP
*
- * Next you define type of register set used for dumping. ELF specification
- * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
- *
- * typedef <target_regtype> target_elf_greg_t;
- * #define ELF_NREG <number of registers>
- * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
+ * Next you define type of register set used for dumping:
+ * typedef struct target_elf_gregset_t { ... } target_elf_gregset_t;
*
* Last step is to implement target specific function that copies registers
* from given cpu into just specified register set. Prototype is:
*
- * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
- * const CPUArchState *env);
+ * void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUArchState *env);
*
* Parameters:
* regs - copy register values into here (allocated and zeroed by caller)
@@ -4059,8 +2118,7 @@ static void bswap_note(struct elf_note *en)
/*
* Calculate file (dump) size of given memory region.
*/
-static size_t vma_dump_size(target_ulong start, target_ulong end,
- unsigned long flags)
+static size_t vma_dump_size(vaddr start, vaddr end, int flags)
{
/* The area must be readable. */
if (!(flags & PAGE_READ)) {
@@ -4253,14 +2311,14 @@ static int dump_write(int fd, const void *ptr, size_t size)
return (0);
}
-static int wmr_page_unprotect_regions(void *opaque, target_ulong start,
- target_ulong end, unsigned long flags)
+static int wmr_page_unprotect_regions(void *opaque, vaddr start,
+ vaddr end, int flags)
{
if ((flags & (PAGE_WRITE | PAGE_WRITE_ORG)) == PAGE_WRITE_ORG) {
size_t step = MAX(TARGET_PAGE_SIZE, qemu_real_host_page_size());
while (1) {
- page_unprotect(start, 0);
+ page_unprotect(NULL, start, 0);
if (end - start <= step) {
break;
}
@@ -4275,8 +2333,8 @@ typedef struct {
size_t size;
} CountAndSizeRegions;
-static int wmr_count_and_size_regions(void *opaque, target_ulong start,
- target_ulong end, unsigned long flags)
+static int wmr_count_and_size_regions(void *opaque, vaddr start,
+ vaddr end, int flags)
{
CountAndSizeRegions *css = opaque;
@@ -4290,8 +2348,8 @@ typedef struct {
off_t offset;
} FillRegionPhdr;
-static int wmr_fill_region_phdr(void *opaque, target_ulong start,
- target_ulong end, unsigned long flags)
+static int wmr_fill_region_phdr(void *opaque, vaddr start,
+ vaddr end, int flags)
{
FillRegionPhdr *d = opaque;
struct elf_phdr *phdr = d->phdr;
@@ -4306,15 +2364,15 @@ static int wmr_fill_region_phdr(void *opaque, target_ulong start,
phdr->p_flags = (flags & PAGE_READ ? PF_R : 0)
| (flags & PAGE_WRITE_ORG ? PF_W : 0)
| (flags & PAGE_EXEC ? PF_X : 0);
- phdr->p_align = ELF_EXEC_PAGESIZE;
+ phdr->p_align = TARGET_PAGE_SIZE;
bswap_phdr(phdr, 1);
d->phdr = phdr + 1;
return 0;
}
-static int wmr_write_region(void *opaque, target_ulong start,
- target_ulong end, unsigned long flags)
+static int wmr_write_region(void *opaque, vaddr start,
+ vaddr end, int flags)
{
int fd = *(int *)opaque;
size_t size = vma_dump_size(start, end, flags);
@@ -4414,7 +2472,7 @@ static int elf_core_dump(int signr, const CPUArchState *env)
offset += size_note("CORE", sizeof(struct target_elf_prpsinfo));
offset += size_note("CORE", sizeof(struct target_elf_prstatus)) * cpus;
note_size = offset - note_offset;
- data_offset = ROUND_UP(offset, ELF_EXEC_PAGESIZE);
+ data_offset = TARGET_PAGE_ALIGN(offset);
/* Do not dump if the corefile size exceeds the limit. */
if (dumpsize.rlim_cur != RLIM_INFINITY
@@ -4493,9 +2551,4 @@ static int elf_core_dump(int signr, const CPUArchState *env)
}
return ret;
}
-#endif /* USE_ELF_CORE_DUMP */
-
-void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- init_thread(regs, infop);
-}
+#endif /* HAVE_ELF_CORE_DUMP */
diff --git a/linux-user/fd-trans.h b/linux-user/fd-trans.h
index 910faaf..e14f960 100644
--- a/linux-user/fd-trans.h
+++ b/linux-user/fd-trans.h
@@ -36,6 +36,16 @@ static inline void fd_trans_init(void)
qemu_mutex_init(&target_fd_trans_lock);
}
+static inline void fd_trans_prefork(void)
+{
+ qemu_mutex_lock(&target_fd_trans_lock);
+}
+
+static inline void fd_trans_postfork(void)
+{
+ qemu_mutex_unlock(&target_fd_trans_lock);
+}
+
static inline TargetFdDataFunc fd_trans_target_to_host_data(int fd)
{
if (fd < 0) {
diff --git a/linux-user/gen-vdso.c b/linux-user/gen-vdso.c
index 721f38d..aeaa927 100644
--- a/linux-user/gen-vdso.c
+++ b/linux-user/gen-vdso.c
@@ -56,13 +56,14 @@ static unsigned rt_sigreturn_addr;
int main(int argc, char **argv)
{
- FILE *inf, *outf;
+ FILE *inf = NULL, *outf = NULL;
long total_len;
const char *prefix = "vdso";
const char *inf_name;
const char *outf_name = NULL;
- unsigned char *buf;
+ unsigned char *buf = NULL;
bool need_bswap;
+ int ret = EXIT_FAILURE;
while (1) {
int opt = getopt(argc, argv, "o:p:r:s:");
@@ -112,9 +113,21 @@ int main(int argc, char **argv)
* We expect the vdso to be small, on the order of one page,
* therefore we do not expect a partial read.
*/
- fseek(inf, 0, SEEK_END);
+ if (fseek(inf, 0, SEEK_END) < 0) {
+ goto perror_inf;
+ }
total_len = ftell(inf);
- fseek(inf, 0, SEEK_SET);
+ if (total_len < 0) {
+ goto perror_inf;
+ }
+ if (fseek(inf, 0, SEEK_SET) < 0) {
+ goto perror_inf;
+ }
+
+ if (total_len < EI_NIDENT) {
+ fprintf(stderr, "%s: file too small (truncated?)\n", inf_name);
+ return EXIT_FAILURE;
+ }
buf = malloc(total_len);
if (buf == NULL) {
@@ -129,7 +142,6 @@ int main(int argc, char **argv)
fprintf(stderr, "%s: incomplete read\n", inf_name);
return EXIT_FAILURE;
}
- fclose(inf);
/*
* Identify which elf flavor we're processing.
@@ -205,19 +217,24 @@ int main(int argc, char **argv)
fprintf(outf, " .rt_sigreturn_ofs = 0x%x,\n", rt_sigreturn_addr);
fprintf(outf, "};\n");
- /*
- * Everything should have gone well.
- */
- if (fclose(outf)) {
- goto perror_outf;
+ ret = EXIT_SUCCESS;
+
+ cleanup:
+ free(buf);
+
+ if (outf && fclose(outf) != 0) {
+ ret = EXIT_FAILURE;
+ }
+ if (inf && fclose(inf) != 0) {
+ ret = EXIT_FAILURE;
}
- return EXIT_SUCCESS;
+ return ret;
perror_inf:
perror(inf_name);
- return EXIT_FAILURE;
+ goto cleanup;
perror_outf:
perror(outf_name);
- return EXIT_FAILURE;
+ goto cleanup;
}
diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c
index e18a018..25c97ed 100644
--- a/linux-user/hexagon/cpu_loop.c
+++ b/linux-user/hexagon/cpu_loop.c
@@ -79,9 +79,11 @@ void cpu_loop(CPUHexagonState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- env->gpr[HEX_REG_PC] = regs->sepc;
- env->gpr[HEX_REG_SP] = regs->sp;
+ CPUArchState *env = cpu_env(cs);
+
+ env->gpr[HEX_REG_PC] = info->entry;
+ env->gpr[HEX_REG_SP] = info->start_stack;
env->gpr[HEX_REG_USR] = 0x56000;
}
diff --git a/linux-user/hexagon/elfload.c b/linux-user/hexagon/elfload.c
new file mode 100644
index 0000000..d8b5450
--- /dev/null
+++ b/linux-user/hexagon/elfload.c
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ static char buf[32];
+ int err;
+
+ /* For now, treat anything newer than v5 as a v73 */
+ /* FIXME - Disable instructions that are newer than the specified arch */
+ if (eflags == 0x04 || /* v5 */
+ eflags == 0x05 || /* v55 */
+ eflags == 0x60 || /* v60 */
+ eflags == 0x61 || /* v61 */
+ eflags == 0x62 || /* v62 */
+ eflags == 0x65 || /* v65 */
+ eflags == 0x66 || /* v66 */
+ eflags == 0x67 || /* v67 */
+ eflags == 0x8067 || /* v67t */
+ eflags == 0x68 || /* v68 */
+ eflags == 0x69 || /* v69 */
+ eflags == 0x71 || /* v71 */
+ eflags == 0x8071 || /* v71t */
+ eflags == 0x73 /* v73 */
+ ) {
+ return "v73";
+ }
+
+ err = snprintf(buf, sizeof(buf), "unknown (0x%x)", eflags);
+ return err >= 0 && err < sizeof(buf) ? buf : "unknown";
+}
diff --git a/linux-user/hexagon/target_elf.h b/linux-user/hexagon/target_elf.h
index 36056fc..f81ae38 100644
--- a/linux-user/hexagon/target_elf.h
+++ b/linux-user/hexagon/target_elf.h
@@ -18,33 +18,7 @@
#ifndef HEXAGON_TARGET_ELF_H
#define HEXAGON_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- static char buf[32];
- int err;
-
- /* For now, treat anything newer than v5 as a v73 */
- /* FIXME - Disable instructions that are newer than the specified arch */
- if (eflags == 0x04 || /* v5 */
- eflags == 0x05 || /* v55 */
- eflags == 0x60 || /* v60 */
- eflags == 0x61 || /* v61 */
- eflags == 0x62 || /* v62 */
- eflags == 0x65 || /* v65 */
- eflags == 0x66 || /* v66 */
- eflags == 0x67 || /* v67 */
- eflags == 0x8067 || /* v67t */
- eflags == 0x68 || /* v68 */
- eflags == 0x69 || /* v69 */
- eflags == 0x71 || /* v71 */
- eflags == 0x8071 || /* v71t */
- eflags == 0x73 /* v73 */
- ) {
- return "v73";
- }
-
- err = snprintf(buf, sizeof(buf), "unknown (0x%x)", eflags);
- return err >= 0 && err < sizeof(buf) ? buf : "unknown";
-}
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_HEXAGON
#endif
diff --git a/linux-user/hexagon/target_syscall.h b/linux-user/hexagon/target_syscall.h
index 7f91a4a..d9c9473 100644
--- a/linux-user/hexagon/target_syscall.h
+++ b/linux-user/hexagon/target_syscall.h
@@ -18,11 +18,6 @@
#ifndef HEXAGON_TARGET_SYSCALL_H
#define HEXAGON_TARGET_SYSCALL_H
-struct target_pt_regs {
- abi_long sepc;
- abi_long sp;
-};
-
#define UNAME_MACHINE "hexagon"
#define UNAME_MINIMUM_RELEASE "4.15.0"
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
index 890e758..3af5065 100644
--- a/linux-user/hppa/cpu_loop.c
+++ b/linux-user/hppa/cpu_loop.c
@@ -112,7 +112,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env)
void cpu_loop(CPUHPPAState *env)
{
CPUState *cs = env_cpu(env);
- abi_ulong ret;
+ abi_ulong ret, si_code = 0;
int trapnr;
while (1) {
@@ -169,7 +169,15 @@ void cpu_loop(CPUHPPAState *env)
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_CONDTRAP, env->iaoq_f);
break;
case EXCP_ASSIST:
- force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
+ #define set_si_code(mask, val) \
+ if (env->fr[0] & mask) { si_code = val; }
+ set_si_code(R_FPSR_FLG_I_MASK, TARGET_FPE_FLTRES);
+ set_si_code(R_FPSR_FLG_U_MASK, TARGET_FPE_FLTUND);
+ set_si_code(R_FPSR_FLG_O_MASK, TARGET_FPE_FLTOVF);
+ set_si_code(R_FPSR_FLG_Z_MASK, TARGET_FPE_FLTDIV);
+ set_si_code(R_FPSR_FLG_V_MASK, TARGET_FPE_FLTINV);
+ #undef set_si_code
+ force_sig_fault(TARGET_SIGFPE, si_code, env->iaoq_f);
break;
case EXCP_BREAK:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);
@@ -188,12 +196,16 @@ void cpu_loop(CPUHPPAState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
- for (i = 1; i < 32; i++) {
- env->gr[i] = regs->gr[i];
- }
- env->iaoq_f = regs->iaoq[0];
- env->iaoq_b = regs->iaoq[1];
+ CPUArchState *env = cpu_env(cs);
+
+ env->iaoq_f = info->entry | PRIV_USER;
+ env->iaoq_b = env->iaoq_f + 4;
+ env->gr[23] = 0;
+ env->gr[24] = info->argv;
+ env->gr[25] = info->argc;
+ /* The top-of-stack contains a linkage buffer. */
+ env->gr[30] = info->start_stack + 64;
+ env->gr[31] = info->entry;
}
diff --git a/linux-user/hppa/elfload.c b/linux-user/hppa/elfload.c
new file mode 100644
index 0000000..018034f
--- /dev/null
+++ b/linux-user/hppa/elfload.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "hppa";
+}
+
+const char *get_elf_platform(CPUState *cs)
+{
+ return "PARISC";
+}
+
+bool init_guest_commpage(void)
+{
+ /* If reserved_va, then we have already mapped 0 page on the host. */
+ if (!reserved_va) {
+ void *want, *addr;
+
+ want = g2h_untagged(LO_COMMPAGE);
+ addr = mmap(want, TARGET_PAGE_SIZE, PROT_NONE,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0);
+ if (addr == MAP_FAILED) {
+ perror("Allocating guest commpage");
+ exit(EXIT_FAILURE);
+ }
+ if (addr != want) {
+ return false;
+ }
+ }
+
+ /*
+ * On Linux, page zero is normally marked execute only + gateway.
+ * Normal read or write is supposed to fail (thus PROT_NONE above),
+ * but specific offsets have kernel code mapped to raise permissions
+ * and implement syscalls. Here, simply mark the page executable.
+ * Special case the entry points during translation (see do_page_zero).
+ */
+ page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
+ PAGE_EXEC | PAGE_VALID);
+ return true;
+}
diff --git a/linux-user/hppa/target_elf.h b/linux-user/hppa/target_elf.h
index 19cae8b..76930c9 100644
--- a/linux-user/hppa/target_elf.h
+++ b/linux-user/hppa/target_elf.h
@@ -7,8 +7,15 @@
#ifndef HPPA_TARGET_ELF_H
#define HPPA_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "hppa";
-}
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_PARISC
+
+#define HAVE_ELF_PLATFORM 1
+
+#define LO_COMMPAGE 0
+#define STACK_GROWS_DOWN 0
+#define STACK_ALIGNMENT 64
+#define VDSO_HEADER "vdso.c.inc"
+
#endif
diff --git a/linux-user/hppa/target_syscall.h b/linux-user/hppa/target_syscall.h
index 9a8f8ca..4b21e85 100644
--- a/linux-user/hppa/target_syscall.h
+++ b/linux-user/hppa/target_syscall.h
@@ -1,24 +1,6 @@
#ifndef HPPA_TARGET_SYSCALL_H
#define HPPA_TARGET_SYSCALL_H
-struct target_pt_regs {
- target_ulong gr[32];
- uint64_t fr[32];
- target_ulong sr[8];
- target_ulong iasq[2];
- target_ulong iaoq[2];
- target_ulong cr27;
- target_ulong __pad0;
- target_ulong orig_r28;
- target_ulong ksp;
- target_ulong kpc;
- target_ulong sar;
- target_ulong iir;
- target_ulong isr;
- target_ulong ior;
- target_ulong ipsw;
-};
-
#define UNAME_MACHINE "parisc"
#define UNAME_MINIMUM_RELEASE "2.6.32"
#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index d96d555..7b2d8b0 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -331,11 +331,10 @@ static void target_cpu_free(void *obj)
g_free(obj);
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cpu, struct image_info *info)
{
- CPUState *cpu = env_cpu(env);
+ CPUArchState *env = cpu_env(cpu);
bool is64 = (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) != 0;
- int i;
OBJECT(cpu)->free = target_cpu_free;
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
@@ -361,28 +360,25 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
/* flags setup : we activate the IRQs by default as in user mode */
env->eflags |= IF_MASK;
- /* linux register setup */
-#ifndef TARGET_ABI32
- env->regs[R_EAX] = regs->rax;
- env->regs[R_EBX] = regs->rbx;
- env->regs[R_ECX] = regs->rcx;
- env->regs[R_EDX] = regs->rdx;
- env->regs[R_ESI] = regs->rsi;
- env->regs[R_EDI] = regs->rdi;
- env->regs[R_EBP] = regs->rbp;
- env->regs[R_ESP] = regs->rsp;
- env->eip = regs->rip;
-#else
- env->regs[R_EAX] = regs->eax;
- env->regs[R_EBX] = regs->ebx;
- env->regs[R_ECX] = regs->ecx;
- env->regs[R_EDX] = regs->edx;
- env->regs[R_ESI] = regs->esi;
- env->regs[R_EDI] = regs->edi;
- env->regs[R_EBP] = regs->ebp;
- env->regs[R_ESP] = regs->esp;
- env->eip = regs->eip;
-#endif
+ /*
+ * Linux register setup.
+ *
+ * SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+ * starts %edx contains a pointer to a function which might be
+ * registered using `atexit'. This provides a mean for the
+ * dynamic linker to call DT_FINI functions for shared libraries
+ * that have been loaded before the code runs.
+ * A value of 0 tells we have no such handler.
+ *
+ * This applies to x86_64 as well as i386.
+ *
+ * That said, the kernel's ELF_PLAT_INIT simply zeros all of the general
+ * registers. Note that x86_cpu_reset_hold will set %edx to cpuid_version;
+ * clear all general registers defensively.
+ */
+ memset(env->regs, 0, sizeof(env->regs));
+ env->regs[R_ESP] = info->start_stack;
+ env->eip = info->entry;
/* linux interrupt setup */
#ifndef TARGET_ABI32
@@ -394,7 +390,7 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
idt_table = g2h_untagged(env->idt.base);
- for (i = 0; i < 20; i++) {
+ for (int i = 0; i < 20; i++) {
set_idt(i, 0, is64);
}
set_idt(3, 3, is64);
diff --git a/linux-user/i386/elfload.c b/linux-user/i386/elfload.c
new file mode 100644
index 0000000..26b1200
--- /dev/null
+++ b/linux-user/i386/elfload.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "max";
+}
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ return cpu_env(cs)->features[FEAT_1_EDX];
+}
+
+const char *get_elf_platform(CPUState *cs)
+{
+ static const char elf_platform[4][5] = { "i386", "i486", "i586", "i686" };
+ int family = object_property_get_int(OBJECT(cs), "family", NULL);
+
+ family = MAX(MIN(family, 6), 3);
+ return elf_platform[family - 3];
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUX86State *env)
+{
+ r->pt.bx = tswapal(env->regs[R_EBX]);
+ r->pt.cx = tswapal(env->regs[R_ECX]);
+ r->pt.dx = tswapal(env->regs[R_EDX]);
+ r->pt.si = tswapal(env->regs[R_ESI]);
+ r->pt.di = tswapal(env->regs[R_EDI]);
+ r->pt.bp = tswapal(env->regs[R_EBP]);
+ r->pt.ax = tswapal(env->regs[R_EAX]);
+ r->pt.ds = tswapal(env->segs[R_DS].selector & 0xffff);
+ r->pt.es = tswapal(env->segs[R_ES].selector & 0xffff);
+ r->pt.fs = tswapal(env->segs[R_FS].selector & 0xffff);
+ r->pt.gs = tswapal(env->segs[R_GS].selector & 0xffff);
+ r->pt.orig_ax = tswapal(get_task_state(env_cpu_const(env))->orig_ax);
+ r->pt.ip = tswapal(env->eip);
+ r->pt.cs = tswapal(env->segs[R_CS].selector & 0xffff);
+ r->pt.flags = tswapal(env->eflags);
+ r->pt.sp = tswapal(env->regs[R_ESP]);
+ r->pt.ss = tswapal(env->segs[R_SS].selector & 0xffff);
+}
diff --git a/linux-user/i386/target_elf.h b/linux-user/i386/target_elf.h
index 238a9ab..eafac8f 100644
--- a/linux-user/i386/target_elf.h
+++ b/linux-user/i386/target_elf.h
@@ -7,8 +7,41 @@
#ifndef I386_TARGET_ELF_H
#define I386_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "max";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_386
+#define EXSTACK_DEFAULT true
+#define VDSO_HEADER "vdso.c.inc"
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_PLATFORM 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * See linux kernel: arch/x86/include/asm/elf.h, where elf_gregset_t
+ * is mapped to struct user_regs_struct via sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_user_regs_struct pt;
+} target_elf_gregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_machine(x) ((x) == EM_386 || (x) == EM_486)
+
+/*
+ * i386 is the only target which supplies AT_SYSINFO for the vdso.
+ * All others only supply AT_SYSINFO_EHDR.
+ */
+#define DLINFO_ARCH_ITEMS (vdso_info != NULL)
+#define ARCH_DLINFO \
+ do { \
+ if (vdso_info) { \
+ NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry); \
+ } \
+ } while (0)
+
#endif
diff --git a/linux-user/i386/target_ptrace.h b/linux-user/i386/target_ptrace.h
new file mode 100644
index 0000000..bc57926
--- /dev/null
+++ b/linux-user/i386/target_ptrace.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef I386_TARGET_PTRACE_H
+#define I386_TARGET_PTRACE_H
+
+/*
+ * Note that arch/x86/include/uapi/asm/ptrace.h (struct pt_regs) and
+ * arch/x86/include/asm/user_32.h (struct user_regs_struct) have the
+ * same layout, though the exact types differ (int vs long vs unsigned).
+ * Define user_regs_struct because that's what's actually used.
+ */
+struct target_user_regs_struct {
+ abi_ulong bx;
+ abi_ulong cx;
+ abi_ulong dx;
+ abi_ulong si;
+ abi_ulong di;
+ abi_ulong bp;
+ abi_ulong ax;
+ abi_ulong ds;
+ abi_ulong es;
+ abi_ulong fs;
+ abi_ulong gs;
+ abi_ulong orig_ax;
+ abi_ulong ip;
+ abi_ulong cs;
+ abi_ulong flags;
+ abi_ulong sp;
+ abi_ulong ss;
+};
+
+#endif /* I386_TARGET_PTRACE_H */
diff --git a/linux-user/i386/target_syscall.h b/linux-user/i386/target_syscall.h
index aaade06..c214a90 100644
--- a/linux-user/i386/target_syscall.h
+++ b/linux-user/i386/target_syscall.h
@@ -5,24 +5,6 @@
#define __USER_CS (0x23)
#define __USER_DS (0x2B)
-struct target_pt_regs {
- long ebx;
- long ecx;
- long edx;
- long esi;
- long edi;
- long ebp;
- long eax;
- int xds;
- int xes;
- long orig_eax;
- long eip;
- int xcs;
- long eflags;
- long esp;
- int xss;
-};
-
/* ioctls */
#define TARGET_LDT_ENTRIES 8192
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 37f132b..85d7009 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -139,8 +139,7 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
}
int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
- struct target_pt_regs *regs, struct image_info *infop,
- struct linux_binprm *bprm)
+ struct image_info *infop, struct linux_binprm *bprm)
{
int retval;
@@ -175,8 +174,7 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
return retval;
}
- /* Success. Initialize important registers. */
- do_init_thread(regs, infop);
+ /* Success. */
return 0;
}
diff --git a/linux-user/loader.h b/linux-user/loader.h
index e102e6f..e42b8fa 100644
--- a/linux-user/loader.h
+++ b/linux-user/loader.h
@@ -82,12 +82,10 @@ struct linux_binprm {
int (*core_dump)(int, const CPUArchState *); /* coredump routine */
};
-void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr);
int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
- struct target_pt_regs *regs, struct image_info *infop,
- struct linux_binprm *);
+ struct image_info *infop, struct linux_binprm *);
uint32_t get_elf_eflags(int fd);
int load_elf_binary(struct linux_binprm *bprm, struct image_info *info);
@@ -98,13 +96,35 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src,
extern unsigned long guest_stack_size;
-#if defined(TARGET_S390X) || defined(TARGET_AARCH64) || defined(TARGET_ARM)
-uint32_t get_elf_hwcap(void);
+/* Note that Elf32 and Elf64 use uint32_t for e_flags. */
+const char *get_elf_cpu_model(uint32_t eflags);
+
+abi_ulong get_elf_hwcap(CPUState *cs);
+abi_ulong get_elf_hwcap2(CPUState *cs);
const char *elf_hwcap_str(uint32_t bit);
-#endif
-#if defined(TARGET_AARCH64) || defined(TARGET_ARM)
-uint64_t get_elf_hwcap2(void);
const char *elf_hwcap2_str(uint32_t bit);
-#endif
+const char *get_elf_platform(CPUState *cs);
+const char *get_elf_base_platform(CPUState *cs);
+bool init_guest_commpage(void);
+
+struct target_elf_gregset_t;
+void elf_core_copy_regs(struct target_elf_gregset_t *, const CPUArchState *);
+
+typedef struct {
+ const uint8_t *image;
+ const uint32_t *relocs;
+ unsigned image_size;
+ unsigned reloc_count;
+ unsigned sigreturn_ofs;
+ unsigned rt_sigreturn_ofs;
+} VdsoImageInfo;
+
+/* Note that both Elf32_Word and Elf64_Word are uint32_t. */
+const VdsoImageInfo *get_vdso_image_info(uint32_t elf_flags);
+
+bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
+ const uint32_t *data,
+ struct image_info *info,
+ Error **errp);
#endif /* LINUX_USER_LOADER_H */
diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c
index ec8a06c..a0a4cbb 100644
--- a/linux-user/loongarch64/cpu_loop.c
+++ b/linux-user/loongarch64/cpu_loop.c
@@ -120,13 +120,10 @@ void cpu_loop(CPULoongArchState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
-
- for (i = 0; i < 32; i++) {
- env->gpr[i] = regs->regs[i];
- }
- env->pc = regs->csr.era;
+ CPUArchState *env = cpu_env(cs);
+ env->pc = info->entry;
+ env->gpr[3] = info->start_stack;
}
diff --git a/linux-user/loongarch64/elfload.c b/linux-user/loongarch64/elfload.c
new file mode 100644
index 0000000..ce3bd0c
--- /dev/null
+++ b/linux-user/loongarch64/elfload.c
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "la464";
+}
+
+/* See arch/loongarch/include/uapi/asm/hwcap.h */
+enum {
+ HWCAP_LOONGARCH_CPUCFG = (1 << 0),
+ HWCAP_LOONGARCH_LAM = (1 << 1),
+ HWCAP_LOONGARCH_UAL = (1 << 2),
+ HWCAP_LOONGARCH_FPU = (1 << 3),
+ HWCAP_LOONGARCH_LSX = (1 << 4),
+ HWCAP_LOONGARCH_LASX = (1 << 5),
+ HWCAP_LOONGARCH_CRC32 = (1 << 6),
+ HWCAP_LOONGARCH_COMPLEX = (1 << 7),
+ HWCAP_LOONGARCH_CRYPTO = (1 << 8),
+ HWCAP_LOONGARCH_LVZ = (1 << 9),
+ HWCAP_LOONGARCH_LBT_X86 = (1 << 10),
+ HWCAP_LOONGARCH_LBT_ARM = (1 << 11),
+ HWCAP_LOONGARCH_LBT_MIPS = (1 << 12),
+};
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ abi_ulong hwcaps = 0;
+
+ hwcaps |= HWCAP_LOONGARCH_CRC32;
+
+ if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) {
+ hwcaps |= HWCAP_LOONGARCH_UAL;
+ }
+
+ if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) {
+ hwcaps |= HWCAP_LOONGARCH_FPU;
+ }
+
+ if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) {
+ hwcaps |= HWCAP_LOONGARCH_LAM;
+ }
+
+ if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
+ hwcaps |= HWCAP_LOONGARCH_LSX;
+ }
+
+ if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
+ hwcaps |= HWCAP_LOONGARCH_LASX;
+ }
+
+ return hwcaps;
+}
+
+const char *get_elf_platform(CPUState *cs)
+{
+ return "loongarch";
+}
+
+#define tswapreg(ptr) tswapal(ptr)
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPULoongArchState *env)
+{
+ r->pt.regs[0] = 0;
+
+ for (int i = 1; i < ARRAY_SIZE(env->gpr); i++) {
+ r->pt.regs[i] = tswapreg(env->gpr[i]);
+ }
+
+ r->pt.csr_era = tswapreg(env->pc);
+ r->pt.csr_badv = tswapreg(env->CSR_BADV);
+}
diff --git a/linux-user/loongarch64/target_elf.h b/linux-user/loongarch64/target_elf.h
index 95c3f05..3aa8c83 100644
--- a/linux-user/loongarch64/target_elf.h
+++ b/linux-user/loongarch64/target_elf.h
@@ -5,8 +5,21 @@
#ifndef LOONGARCH_TARGET_ELF_H
#define LOONGARCH_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "la464";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_MACHINE EM_LOONGARCH
+#define EXSTACK_DEFAULT true
+#define VDSO_HEADER "vdso.c.inc"
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_PLATFORM 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/* See linux kernel: arch/loongarch/include/asm/elf.h */
+typedef struct target_elf_gregset_t {
+ struct target_user_pt_regs pt;
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/loongarch64/target_ptrace.h b/linux-user/loongarch64/target_ptrace.h
new file mode 100644
index 0000000..2578e09
--- /dev/null
+++ b/linux-user/loongarch64/target_ptrace.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef LOONGARCH64_TARGET_PTRACE_H
+#define LOONGARCH64_TARGET_PTRACE_H
+
+/* See arch/loongarch/include/uapi/asm/ptrace.h. */
+struct target_user_pt_regs {
+ abi_ulong regs[32];
+ abi_ulong orig_a0;
+ abi_ulong csr_era;
+ abi_ulong csr_badv;
+ abi_ulong reserved[10];
+};
+
+#endif /* LOONGARCH64_TARGET_PTRACE_H */
diff --git a/linux-user/loongarch64/target_syscall.h b/linux-user/loongarch64/target_syscall.h
index 39f229b..f7ced7b 100644
--- a/linux-user/loongarch64/target_syscall.h
+++ b/linux-user/loongarch64/target_syscall.h
@@ -8,29 +8,6 @@
#include "qemu/units.h"
-/*
- * this struct defines the way the registers are stored on the
- * stack during a system call.
- */
-
-struct target_pt_regs {
- /* Saved main processor registers. */
- target_ulong regs[32];
-
- /* Saved special registers. */
- struct {
- target_ulong era;
- target_ulong badv;
- target_ulong crmd;
- target_ulong prmd;
- target_ulong euen;
- target_ulong ecfg;
- target_ulong estat;
- } csr;
- target_ulong orig_a0;
- target_ulong __last[0];
-};
-
#define UNAME_MACHINE "loongarch64"
#define UNAME_MINIMUM_RELEASE "5.19.0"
diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c
index 5da91b9..aca0bf2 100644
--- a/linux-user/m68k/cpu_loop.c
+++ b/linux-user/m68k/cpu_loop.c
@@ -92,33 +92,11 @@ void cpu_loop(CPUM68KState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- CPUState *cpu = env_cpu(env);
- TaskState *ts = get_task_state(cpu);
- struct image_info *info = ts->info;
+ CPUArchState *env = cpu_env(cs);
- env->pc = regs->pc;
- env->dregs[0] = regs->d0;
- env->dregs[1] = regs->d1;
- env->dregs[2] = regs->d2;
- env->dregs[3] = regs->d3;
- env->dregs[4] = regs->d4;
- env->dregs[5] = regs->d5;
- env->dregs[6] = regs->d6;
- env->dregs[7] = regs->d7;
- env->aregs[0] = regs->a0;
- env->aregs[1] = regs->a1;
- env->aregs[2] = regs->a2;
- env->aregs[3] = regs->a3;
- env->aregs[4] = regs->a4;
- env->aregs[5] = regs->a5;
- env->aregs[6] = regs->a6;
- env->aregs[7] = regs->usp;
- env->sr = regs->sr;
-
- ts->stack_base = info->start_stack;
- ts->heap_base = info->brk;
- /* This will be filled in on the first SYS_HEAPINFO call. */
- ts->heap_limit = 0;
+ env->pc = info->entry;
+ env->aregs[7] = info->start_stack;
+ env->sr = 0;
}
diff --git a/linux-user/m68k/elfload.c b/linux-user/m68k/elfload.c
new file mode 100644
index 0000000..423d1f6
--- /dev/null
+++ b/linux-user/m68k/elfload.c
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "elf.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ if (eflags == 0 || (eflags & EF_M68K_M68000)) {
+ /* 680x0 */
+ return "m68040";
+ }
+
+ /* Coldfire */
+ return "any";
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUM68KState *env)
+{
+ r->d1 = tswapal(env->dregs[1]);
+ r->d2 = tswapal(env->dregs[2]);
+ r->d3 = tswapal(env->dregs[3]);
+ r->d4 = tswapal(env->dregs[4]);
+ r->d5 = tswapal(env->dregs[5]);
+ r->d6 = tswapal(env->dregs[6]);
+ r->d7 = tswapal(env->dregs[7]);
+ r->a0 = tswapal(env->aregs[0]);
+ r->a1 = tswapal(env->aregs[1]);
+ r->a2 = tswapal(env->aregs[2]);
+ r->a3 = tswapal(env->aregs[3]);
+ r->a4 = tswapal(env->aregs[4]);
+ r->a5 = tswapal(env->aregs[5]);
+ r->a6 = tswapal(env->aregs[6]);
+ r->d0 = tswapal(env->dregs[0]);
+ r->usp = tswapal(env->aregs[7]);
+ r->orig_d0 = tswapal(env->dregs[0]); /* FIXME */
+ r->sr = tswapal(env->sr);
+ r->pc = tswapal(env->pc);
+ /* FIXME: regs->format | regs->vector */
+}
diff --git a/linux-user/m68k/target_elf.h b/linux-user/m68k/target_elf.h
index 998fe0f..b997fa0 100644
--- a/linux-user/m68k/target_elf.h
+++ b/linux-user/m68k/target_elf.h
@@ -7,14 +7,32 @@
#ifndef M68K_TARGET_ELF_H
#define M68K_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- if (eflags == 0 || (eflags & EF_M68K_M68000)) {
- /* 680x0 */
- return "m68040";
- }
- /* Coldfire */
- return "any";
-}
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_68K
+
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * See linux kernel: arch/m68k/include/asm/elf.h, where
+ * elf_gregset_t is mapped to struct user_regs_struct via sizeof.
+ *
+ * Note that user_regs_struct has
+ * short stkadj, sr;
+ * ...
+ * short fmtvec, __fill;
+ * but ELF_CORE_COPY_REGS writes to unsigned longs.
+ * Therefore adjust the sr and fmtvec fields to match.
+ */
+typedef struct target_elf_gregset_t {
+ abi_ulong d1, d2, d3, d4, d5, d6, d7;
+ abi_ulong a0, a1, a2, a3, a4, a5, a6;
+ abi_ulong d0;
+ abi_ulong usp;
+ abi_ulong orig_d0;
+ abi_ulong sr;
+ abi_ulong pc;
+ abi_ulong fmtvec;
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/m68k/target_syscall.h b/linux-user/m68k/target_syscall.h
index 8d4ddbd..3ca0231 100644
--- a/linux-user/m68k/target_syscall.h
+++ b/linux-user/m68k/target_syscall.h
@@ -1,22 +1,6 @@
#ifndef M68K_TARGET_SYSCALL_H
#define M68K_TARGET_SYSCALL_H
-/* this struct defines the way the registers are stored on the
- stack during a system call. */
-
-struct target_pt_regs {
- abi_long d1, d2, d3, d4, d5, d6, d7;
- abi_long a0, a1, a2, a3, a4, a5, a6;
- abi_ulong d0;
- abi_ulong usp;
- abi_ulong orig_d0;
- int16_t stkadj;
- uint16_t sr;
- abi_ulong pc;
- uint16_t fntvex;
- uint16_t __fill;
-};
-
#define UNAME_MACHINE "m68k"
#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/main.c b/linux-user/main.c
index e2ec597..7b0ccb6 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -40,16 +40,15 @@
#include "qemu/plugin.h"
#include "user/guest-base.h"
#include "user/page-protection.h"
-#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "gdbstub/user.h"
+#include "accel/accel-ops.h"
#include "tcg/startup.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
#include "qemu/guest-random.h"
#include "elf.h"
#include "trace/control.h"
-#include "target_elf.h"
#include "user/cpu_loop.h"
#include "crypto/init.h"
#include "fd-trans.h"
@@ -123,6 +122,7 @@ static const char *last_log_filename;
#endif
unsigned long reserved_va;
+unsigned long guest_addr_max;
static void usage(int exitcode);
@@ -149,12 +149,14 @@ void fork_start(void)
cpu_list_lock();
qemu_plugin_user_prefork_lock();
gdbserver_fork_start();
+ fd_trans_prefork();
}
void fork_end(pid_t pid)
{
bool child = pid == 0;
+ fd_trans_postfork();
qemu_plugin_user_postfork(child);
mmap_fork_end(child);
if (child) {
@@ -338,16 +340,6 @@ static void handle_arg_ld_prefix(const char *arg)
interp_prefix = strdup(arg);
}
-static void handle_arg_pagesize(const char *arg)
-{
- unsigned size, want = qemu_real_host_page_size();
-
- if (qemu_strtoui(arg, NULL, 10, &size) || size != want) {
- warn_report("Deprecated page size option cannot "
- "change host page size (%u)", want);
- }
-}
-
static void handle_arg_seed(const char *arg)
{
seed_optarg = arg;
@@ -520,8 +512,6 @@ static const struct qemu_argument arg_table[] = {
"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,
- "pagesize", "deprecated change to host page size"},
{"one-insn-per-tb",
"QEMU_ONE_INSN_PER_TB", false, handle_arg_one_insn_per_tb,
"", "run with one guest instruction per emulated TB"},
@@ -694,7 +684,6 @@ static int parse_args(int argc, char **argv)
int main(int argc, char **argv, char **envp)
{
- struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
struct linux_binprm bprm;
TaskState *ts;
@@ -760,9 +749,6 @@ int main(int argc, char **argv, char **envp)
trace_init_file();
qemu_plugin_load_list(&plugins, &error_fatal);
- /* Zero out regs */
- memset(regs, 0, sizeof(struct target_pt_regs));
-
/* Zero out image_info */
memset(info, 0, sizeof(struct image_info));
@@ -806,7 +792,7 @@ int main(int argc, char **argv, char **envp)
}
if (cpu_model == NULL) {
- cpu_model = cpu_get_model(get_elf_eflags(execfd));
+ cpu_model = get_elf_cpu_model(get_elf_eflags(execfd));
}
cpu_type = parse_cpu_option(cpu_model);
@@ -820,7 +806,7 @@ int main(int argc, char **argv, char **envp)
opt_one_insn_per_tb, &error_abort);
object_property_set_int(OBJECT(accel), "tb-size",
opt_tb_size, &error_abort);
- ac->init_machine(NULL);
+ ac->init_machine(accel, NULL);
}
/*
@@ -859,6 +845,13 @@ int main(int argc, char **argv, char **envp)
/* MAX_RESERVED_VA + 1 is a large power of 2, so is aligned. */
reserved_va = max_reserved_va;
}
+ if (reserved_va != 0) {
+ guest_addr_max = reserved_va;
+ } else if (MIN(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32) {
+ guest_addr_max = UINT32_MAX;
+ } else {
+ guest_addr_max = ~0ul;
+ }
/*
* Temporarily disable
@@ -979,8 +972,8 @@ int main(int argc, char **argv, char **envp)
fd_trans_init();
- ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs,
- info, &bprm);
+ ret = loader_exec(execfd, exec_path, target_argv, target_environ,
+ info, &bprm);
if (ret != 0) {
printf("Error while loading %s: %s\n", exec_path, strerror(-ret));
_exit(EXIT_FAILURE);
@@ -1032,7 +1025,7 @@ int main(int argc, char **argv, char **envp)
the real value of GUEST_BASE into account. */
tcg_prologue_init();
- target_cpu_copy_regs(env, regs);
+ init_main_thread(cpu, info);
if (gdbstub) {
gdbserver_start(gdbstub, &error_fatal);
diff --git a/linux-user/meson.build b/linux-user/meson.build
index f47a213..efca843 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -27,7 +27,10 @@ linux_user_ss.add(libdw)
linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c'))
linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
linux_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', if_true: files('semihost.c'))
-linux_user_ss.add(when: 'CONFIG_TCG_PLUGINS', if_true: files('plugin-api.c'))
+
+if get_option('plugins')
+ linux_user_ss.add(files('plugin-api.c'))
+endif
syscall_nr_generators = {}
diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c
index 87236c1..d827796 100644
--- a/linux-user/microblaze/cpu_loop.c
+++ b/linux-user/microblaze/cpu_loop.c
@@ -127,39 +127,10 @@ void cpu_loop(CPUMBState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- env->regs[0] = regs->r0;
- env->regs[1] = regs->r1;
- env->regs[2] = regs->r2;
- env->regs[3] = regs->r3;
- env->regs[4] = regs->r4;
- env->regs[5] = regs->r5;
- env->regs[6] = regs->r6;
- env->regs[7] = regs->r7;
- env->regs[8] = regs->r8;
- env->regs[9] = regs->r9;
- env->regs[10] = regs->r10;
- env->regs[11] = regs->r11;
- env->regs[12] = regs->r12;
- env->regs[13] = regs->r13;
- env->regs[14] = regs->r14;
- env->regs[15] = regs->r15;
- env->regs[16] = regs->r16;
- env->regs[17] = regs->r17;
- env->regs[18] = regs->r18;
- env->regs[19] = regs->r19;
- env->regs[20] = regs->r20;
- env->regs[21] = regs->r21;
- env->regs[22] = regs->r22;
- env->regs[23] = regs->r23;
- env->regs[24] = regs->r24;
- env->regs[25] = regs->r25;
- env->regs[26] = regs->r26;
- env->regs[27] = regs->r27;
- env->regs[28] = regs->r28;
- env->regs[29] = regs->r29;
- env->regs[30] = regs->r30;
- env->regs[31] = regs->r31;
- env->pc = regs->pc;
+ CPUArchState *env = cpu_env(cs);
+
+ env->pc = info->entry;
+ env->regs[1] = info->start_stack;
}
diff --git a/linux-user/microblaze/elfload.c b/linux-user/microblaze/elfload.c
new file mode 100644
index 0000000..7eb1b26
--- /dev/null
+++ b/linux-user/microblaze/elfload.c
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "any";
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUMBState *env)
+{
+ for (int i = 0; i < 32; i++) {
+ r->pt.r[i] = tswapal(env->regs[i]);
+ }
+
+ r->pt.pc = tswapal(env->pc);
+ r->pt.msr = tswapal(mb_cpu_read_msr(env));
+ r->pt.ear = tswapal(env->ear);
+ r->pt.esr = tswapal(env->esr);
+}
diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c
index f6d47d7..e874e4d 100644
--- a/linux-user/microblaze/signal.c
+++ b/linux-user/microblaze/signal.c
@@ -21,6 +21,7 @@
#include "user-internals.h"
#include "signal-common.h"
#include "linux-user/trace.h"
+#include "target_ptrace.h"
struct target_sigcontext {
struct target_pt_regs regs; /* needs to be first */
@@ -50,75 +51,17 @@ struct target_rt_sigframe {
static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
{
- __put_user(env->regs[0], &sc->regs.r0);
- __put_user(env->regs[1], &sc->regs.r1);
- __put_user(env->regs[2], &sc->regs.r2);
- __put_user(env->regs[3], &sc->regs.r3);
- __put_user(env->regs[4], &sc->regs.r4);
- __put_user(env->regs[5], &sc->regs.r5);
- __put_user(env->regs[6], &sc->regs.r6);
- __put_user(env->regs[7], &sc->regs.r7);
- __put_user(env->regs[8], &sc->regs.r8);
- __put_user(env->regs[9], &sc->regs.r9);
- __put_user(env->regs[10], &sc->regs.r10);
- __put_user(env->regs[11], &sc->regs.r11);
- __put_user(env->regs[12], &sc->regs.r12);
- __put_user(env->regs[13], &sc->regs.r13);
- __put_user(env->regs[14], &sc->regs.r14);
- __put_user(env->regs[15], &sc->regs.r15);
- __put_user(env->regs[16], &sc->regs.r16);
- __put_user(env->regs[17], &sc->regs.r17);
- __put_user(env->regs[18], &sc->regs.r18);
- __put_user(env->regs[19], &sc->regs.r19);
- __put_user(env->regs[20], &sc->regs.r20);
- __put_user(env->regs[21], &sc->regs.r21);
- __put_user(env->regs[22], &sc->regs.r22);
- __put_user(env->regs[23], &sc->regs.r23);
- __put_user(env->regs[24], &sc->regs.r24);
- __put_user(env->regs[25], &sc->regs.r25);
- __put_user(env->regs[26], &sc->regs.r26);
- __put_user(env->regs[27], &sc->regs.r27);
- __put_user(env->regs[28], &sc->regs.r28);
- __put_user(env->regs[29], &sc->regs.r29);
- __put_user(env->regs[30], &sc->regs.r30);
- __put_user(env->regs[31], &sc->regs.r31);
+ for (int i = 0; i < 32; ++i) {
+ __put_user(env->regs[i], &sc->regs.r[i]);
+ }
__put_user(env->pc, &sc->regs.pc);
}
static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
{
- __get_user(env->regs[0], &sc->regs.r0);
- __get_user(env->regs[1], &sc->regs.r1);
- __get_user(env->regs[2], &sc->regs.r2);
- __get_user(env->regs[3], &sc->regs.r3);
- __get_user(env->regs[4], &sc->regs.r4);
- __get_user(env->regs[5], &sc->regs.r5);
- __get_user(env->regs[6], &sc->regs.r6);
- __get_user(env->regs[7], &sc->regs.r7);
- __get_user(env->regs[8], &sc->regs.r8);
- __get_user(env->regs[9], &sc->regs.r9);
- __get_user(env->regs[10], &sc->regs.r10);
- __get_user(env->regs[11], &sc->regs.r11);
- __get_user(env->regs[12], &sc->regs.r12);
- __get_user(env->regs[13], &sc->regs.r13);
- __get_user(env->regs[14], &sc->regs.r14);
- __get_user(env->regs[15], &sc->regs.r15);
- __get_user(env->regs[16], &sc->regs.r16);
- __get_user(env->regs[17], &sc->regs.r17);
- __get_user(env->regs[18], &sc->regs.r18);
- __get_user(env->regs[19], &sc->regs.r19);
- __get_user(env->regs[20], &sc->regs.r20);
- __get_user(env->regs[21], &sc->regs.r21);
- __get_user(env->regs[22], &sc->regs.r22);
- __get_user(env->regs[23], &sc->regs.r23);
- __get_user(env->regs[24], &sc->regs.r24);
- __get_user(env->regs[25], &sc->regs.r25);
- __get_user(env->regs[26], &sc->regs.r26);
- __get_user(env->regs[27], &sc->regs.r27);
- __get_user(env->regs[28], &sc->regs.r28);
- __get_user(env->regs[29], &sc->regs.r29);
- __get_user(env->regs[30], &sc->regs.r30);
- __get_user(env->regs[31], &sc->regs.r31);
+ for (int i = 0; i < 32; ++i) {
+ __get_user(env->regs[i], &sc->regs.r[i]);
+ }
__get_user(env->pc, &sc->regs.pc);
}
diff --git a/linux-user/microblaze/target_elf.h b/linux-user/microblaze/target_elf.h
index 8a8f1de..7b3ef70 100644
--- a/linux-user/microblaze/target_elf.h
+++ b/linux-user/microblaze/target_elf.h
@@ -7,8 +7,22 @@
#ifndef MICROBLAZE_TARGET_ELF_H
#define MICROBLAZE_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "any";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_MICROBLAZE
+
+#define elf_check_machine(x) ((x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
+
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * See linux kernel: arch/microblaze/include/asm/elf.h, where
+ * elf_gregset_t is mapped to struct pt_regs via sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_pt_regs pt;
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/microblaze/target_ptrace.h b/linux-user/microblaze/target_ptrace.h
new file mode 100644
index 0000000..ead913e
--- /dev/null
+++ b/linux-user/microblaze/target_ptrace.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef MICROBLAZE_TARGET_PTRACE_H
+#define MICROBLAZE_TARGET_PTRACE_H
+
+/* We use microblaze_reg_t to keep things similar to the kernel sources. */
+typedef uint32_t microblaze_reg_t;
+
+struct target_pt_regs {
+ /* Note the kernel enumerates all 32 registers. */
+ microblaze_reg_t r[32];
+ microblaze_reg_t pc;
+ microblaze_reg_t msr;
+ microblaze_reg_t ear;
+ microblaze_reg_t esr;
+ microblaze_reg_t fsr;
+ uint32_t kernel_mode;
+};
+
+#endif /* MICROBLAZE_TARGET_PTRACE_H */
diff --git a/linux-user/microblaze/target_syscall.h b/linux-user/microblaze/target_syscall.h
index 43362a1..66f5a9e 100644
--- a/linux-user/microblaze/target_syscall.h
+++ b/linux-user/microblaze/target_syscall.h
@@ -4,50 +4,6 @@
#define UNAME_MACHINE "microblaze"
#define UNAME_MINIMUM_RELEASE "2.6.32"
-/* We use microblaze_reg_t to keep things similar to the kernel sources. */
-typedef uint32_t microblaze_reg_t;
-
-struct target_pt_regs {
- microblaze_reg_t r0;
- microblaze_reg_t r1;
- microblaze_reg_t r2;
- microblaze_reg_t r3;
- microblaze_reg_t r4;
- microblaze_reg_t r5;
- microblaze_reg_t r6;
- microblaze_reg_t r7;
- microblaze_reg_t r8;
- microblaze_reg_t r9;
- microblaze_reg_t r10;
- microblaze_reg_t r11;
- microblaze_reg_t r12;
- microblaze_reg_t r13;
- microblaze_reg_t r14;
- microblaze_reg_t r15;
- microblaze_reg_t r16;
- microblaze_reg_t r17;
- microblaze_reg_t r18;
- microblaze_reg_t r19;
- microblaze_reg_t r20;
- microblaze_reg_t r21;
- microblaze_reg_t r22;
- microblaze_reg_t r23;
- microblaze_reg_t r24;
- microblaze_reg_t r25;
- microblaze_reg_t r26;
- microblaze_reg_t r27;
- microblaze_reg_t r28;
- microblaze_reg_t r29;
- microblaze_reg_t r30;
- microblaze_reg_t r31;
- microblaze_reg_t pc;
- microblaze_reg_t msr;
- microblaze_reg_t ear;
- microblaze_reg_t esr;
- microblaze_reg_t fsr;
- uint32_t kernel_mode;
-};
-
#define TARGET_CLONE_BACKWARDS
#define TARGET_MCL_CURRENT 1
#define TARGET_MCL_FUTURE 2
diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c
index 6405806..e67b8a2 100644
--- a/linux-user/mips/cpu_loop.c
+++ b/linux-user/mips/cpu_loop.c
@@ -211,12 +211,9 @@ done_syscall:
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- CPUState *cpu = env_cpu(env);
- TaskState *ts = get_task_state(cpu);
- struct image_info *info = ts->info;
- int i;
+ CPUArchState *env = cpu_env(cs);
struct mode_req {
bool single;
@@ -245,12 +242,11 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
struct mode_req prog_req;
struct mode_req interp_req;
+ target_ulong entry = info->entry;
- for(i = 0; i < 32; i++) {
- env->active_tc.gpr[i] = regs->regs[i];
- }
- env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
- if (regs->cp0_epc & 1) {
+ env->active_tc.gpr[29] = info->start_stack;
+ env->active_tc.PC = entry & ~(target_ulong)1;
+ if (entry & 1) {
env->hflags |= MIPS_HFLAG_M16;
}
diff --git a/linux-user/mips/elfload.c b/linux-user/mips/elfload.c
new file mode 100644
index 0000000..e0c50f5
--- /dev/null
+++ b/linux-user/mips/elfload.c
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "elf.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+#ifdef TARGET_MIPS64
+ switch (eflags & EF_MIPS_MACH) {
+ case EF_MIPS_MACH_OCTEON:
+ case EF_MIPS_MACH_OCTEON2:
+ case EF_MIPS_MACH_OCTEON3:
+ return "Octeon68XX";
+ case EF_MIPS_MACH_LS2E:
+ return "Loongson-2E";
+ case EF_MIPS_MACH_LS2F:
+ return "Loongson-2F";
+ case EF_MIPS_MACH_LS3A:
+ return "Loongson-3A1000";
+ default:
+ break;
+ }
+ switch (eflags & EF_MIPS_ARCH) {
+ case EF_MIPS_ARCH_64R6:
+ return "I6400";
+ case EF_MIPS_ARCH_64R2:
+ return "MIPS64R2-generic";
+ default:
+ break;
+ }
+ return "5KEf";
+#else
+ if ((eflags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
+ return "mips32r6-generic";
+ }
+ if (eflags & EF_MIPS_NAN2008) {
+ return "P5600";
+ }
+ return "24Kf";
+#endif
+}
+
+/* See arch/mips/include/uapi/asm/hwcap.h. */
+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 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)
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ abi_ulong hwcaps = 0;
+
+ 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
+
+#define MATCH_PLATFORM_INSN(_flags, _base_platform) \
+ do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
+ { return _base_platform; } } while (0)
+
+const char *get_elf_base_platform(CPUState *cs)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+
+ /* 64 bit ISAs goes first */
+ MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
+ MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
+ MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
+ MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
+ MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
+ MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
+ MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
+
+ /* 32 bit ISAs */
+ MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
+ MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
+ MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
+ MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
+ MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
+
+ /* Fallback */
+ return "mips";
+}
+
+#undef MATCH_PLATFORM_INSN
+
+/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUMIPSState *env)
+{
+ for (int i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
+ r->pt.regs[i] = tswapl(env->active_tc.gpr[i]);
+ }
+
+ r->pt.regs[26] = 0;
+ r->pt.regs[27] = 0;
+ r->pt.lo = tswapl(env->active_tc.LO[0]);
+ r->pt.hi = tswapl(env->active_tc.HI[0]);
+ r->pt.cp0_epc = tswapl(env->active_tc.PC);
+ r->pt.cp0_badvaddr = tswapl(env->CP0_BadVAddr);
+ r->pt.cp0_status = tswapl(env->CP0_Status);
+ r->pt.cp0_cause = tswapl(env->CP0_Cause);
+}
diff --git a/linux-user/mips/target_elf.h b/linux-user/mips/target_elf.h
index 71a3231..157306f 100644
--- a/linux-user/mips/target_elf.h
+++ b/linux-user/mips/target_elf.h
@@ -7,14 +7,23 @@
#ifndef MIPS_TARGET_ELF_H
#define MIPS_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- if ((eflags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
- return "mips32r6-generic";
- }
- if (eflags & EF_MIPS_NAN2008) {
- return "P5600";
- }
- return "24Kf";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_MIPS
+#define EXSTACK_DEFAULT true
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_BASE_PLATFORM 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/* See linux kernel: arch/mips/include/asm/elf.h. */
+typedef struct target_elf_gregset_t {
+ union {
+ abi_ulong reserved[45];
+ struct target_pt_regs pt;
+ };
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/mips/target_ptrace.h b/linux-user/mips/target_ptrace.h
new file mode 100644
index 0000000..2f63b27
--- /dev/null
+++ b/linux-user/mips/target_ptrace.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef MIPS_TARGET_PTRACE_H
+#define MIPS_TARGET_PTRACE_H
+
+struct target_pt_regs {
+ abi_ulong pad0[6];
+ abi_ulong regs[32];
+ abi_ulong lo;
+ abi_ulong hi;
+ abi_ulong cp0_epc;
+ abi_ulong cp0_badvaddr;
+ abi_ulong cp0_status;
+ abi_ulong cp0_cause;
+};
+
+#endif /* MIPS_TARGET_PTRACE_H */
diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h
index fa542c1..4481426 100644
--- a/linux-user/mips/target_signal.h
+++ b/linux-user/mips/target_signal.h
@@ -64,7 +64,6 @@ typedef struct target_sigaltstack {
#define TARGET_SA_NODEFER 0x40000000
#define TARGET_SA_RESTART 0x10000000
#define TARGET_SA_RESETHAND 0x80000000
-#define TARGET_SA_RESTORER 0x04000000 /* Only for O32 */
#define TARGET_MINSIGSTKSZ 2048
diff --git a/linux-user/mips/target_syscall.h b/linux-user/mips/target_syscall.h
index 08ead67..dfcdf32 100644
--- a/linux-user/mips/target_syscall.h
+++ b/linux-user/mips/target_syscall.h
@@ -1,25 +1,6 @@
#ifndef MIPS_TARGET_SYSCALL_H
#define MIPS_TARGET_SYSCALL_H
-/* this struct defines the way the registers are stored on the
- stack during a system call. */
-
-struct target_pt_regs {
- /* Pad bytes for argument save space on the stack. */
- abi_ulong pad0[6];
-
- /* Saved main processor registers. */
- abi_ulong regs[32];
-
- /* Saved special registers. */
- abi_ulong cp0_status;
- abi_ulong lo;
- abi_ulong hi;
- abi_ulong cp0_badvaddr;
- abi_ulong cp0_cause;
- abi_ulong cp0_epc;
-};
-
#define UNAME_MACHINE "mips"
#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/mips64/elfload.c b/linux-user/mips64/elfload.c
new file mode 100644
index 0000000..b719555
--- /dev/null
+++ b/linux-user/mips64/elfload.c
@@ -0,0 +1 @@
+#include "../mips/elfload.c"
diff --git a/linux-user/mips64/target_elf.h b/linux-user/mips64/target_elf.h
index 502af9d..061471a 100644
--- a/linux-user/mips64/target_elf.h
+++ b/linux-user/mips64/target_elf.h
@@ -7,30 +7,29 @@
#ifndef MIPS64_TARGET_ELF_H
#define MIPS64_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- switch (eflags & EF_MIPS_MACH) {
- case EF_MIPS_MACH_OCTEON:
- case EF_MIPS_MACH_OCTEON2:
- case EF_MIPS_MACH_OCTEON3:
- return "Octeon68XX";
- case EF_MIPS_MACH_LS2E:
- return "Loongson-2E";
- case EF_MIPS_MACH_LS2F:
- return "Loongson-2F";
- case EF_MIPS_MACH_LS3A:
- return "Loongson-3A1000";
- default:
- break;
- }
- switch (eflags & EF_MIPS_ARCH) {
- case EF_MIPS_ARCH_64R6:
- return "I6400";
- case EF_MIPS_ARCH_64R2:
- return "MIPS64R2-generic";
- default:
- break;
- }
- return "5KEf";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_MACHINE EM_MIPS
+#define EXSTACK_DEFAULT true
+
+#ifdef TARGET_ABI_MIPSN32
+#define elf_check_abi(x) ((x) & EF_MIPS_ABI2)
+#else
+#define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
+#endif
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_BASE_PLATFORM 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/* See linux kernel: arch/mips/include/asm/elf.h. */
+typedef struct target_elf_gregset_t {
+ union {
+ target_ulong reserved[45];
+ struct target_pt_regs pt;
+ };
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/mips64/target_ptrace.h b/linux-user/mips64/target_ptrace.h
new file mode 100644
index 0000000..41f0bf6
--- /dev/null
+++ b/linux-user/mips64/target_ptrace.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef MIPS64_TARGET_PTRACE_H
+#define MIPS64_TARGET_PTRACE_H
+
+struct target_pt_regs {
+ target_ulong regs[32];
+ target_ulong lo;
+ target_ulong hi;
+ target_ulong cp0_epc;
+ target_ulong cp0_badvaddr;
+ target_ulong cp0_status;
+ target_ulong cp0_cause;
+};
+
+#endif /* MIPS64_TARGET_PTRACE_H */
diff --git a/linux-user/mips64/target_syscall.h b/linux-user/mips64/target_syscall.h
index 358dc2d..9135bf5 100644
--- a/linux-user/mips64/target_syscall.h
+++ b/linux-user/mips64/target_syscall.h
@@ -1,22 +1,6 @@
#ifndef MIPS64_TARGET_SYSCALL_H
#define MIPS64_TARGET_SYSCALL_H
-/* this struct defines the way the registers are stored on the
- stack during a system call. */
-
-struct target_pt_regs {
- /* Saved main processor registers. */
- target_ulong regs[32];
-
- /* Saved special registers. */
- target_ulong cp0_status;
- target_ulong lo;
- target_ulong hi;
- target_ulong cp0_badvaddr;
- target_ulong cp0_cause;
- target_ulong cp0_epc;
-};
-
#define UNAME_MACHINE "mips64"
#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index f88a80c..002e1e6 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -645,7 +645,7 @@ static abi_long mmap_h_eq_g(abi_ulong start, abi_ulong len,
*
* However, this case is rather common with executable images,
* so the workaround is important for even trivial tests, whereas
- * the mmap of of a file being extended is less common.
+ * the mmap of a file being extended is less common.
*/
static abi_long mmap_h_lt_g(abi_ulong start, abi_ulong len, int host_prot,
int mmap_flags, int page_flags, int fd,
diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c
index 306b4f8..8c72347 100644
--- a/linux-user/openrisc/cpu_loop.c
+++ b/linux-user/openrisc/cpu_loop.c
@@ -83,13 +83,10 @@ void cpu_loop(CPUOpenRISCState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
+ CPUArchState *env = cpu_env(cs);
- for (i = 0; i < 32; i++) {
- cpu_set_gpr(env, i, regs->gpr[i]);
- }
- env->pc = regs->pc;
- cpu_set_sr(env, regs->sr);
+ env->pc = info->entry;
+ cpu_set_gpr(env, 1, info->start_stack);
}
diff --git a/linux-user/openrisc/elfload.c b/linux-user/openrisc/elfload.c
new file mode 100644
index 0000000..6bf02bf
--- /dev/null
+++ b/linux-user/openrisc/elfload.c
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "any";
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUOpenRISCState *env)
+{
+ for (int i = 0; i < 32; i++) {
+ r->pt.gpr[i] = tswapal(cpu_get_gpr(env, i));
+ }
+ r->pt.pc = tswapal(env->pc);
+ r->pt.sr = tswapal(cpu_get_sr(env));
+}
diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c
index cb74a9f..4024909 100644
--- a/linux-user/openrisc/signal.c
+++ b/linux-user/openrisc/signal.c
@@ -21,9 +21,10 @@
#include "user-internals.h"
#include "signal-common.h"
#include "linux-user/trace.h"
+#include "target_ptrace.h"
typedef struct target_sigcontext {
- struct target_pt_regs regs;
+ struct target_user_regs_struct regs;
abi_ulong oldmask;
} target_sigcontext;
diff --git a/linux-user/openrisc/target_elf.h b/linux-user/openrisc/target_elf.h
index 265ecd3..e8554f5 100644
--- a/linux-user/openrisc/target_elf.h
+++ b/linux-user/openrisc/target_elf.h
@@ -7,8 +7,20 @@
#ifndef OPENRISC_TARGET_ELF_H
#define OPENRISC_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "any";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_MACHINE EM_OPENRISC
+#define ELF_CLASS ELFCLASS32
+
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * See linux kernel: arch/openrisc/include/uapi/asm/elf.h, where
+ * elf_gregset_t is mapped to struct user_regs_struct via sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_user_regs_struct pt;
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/openrisc/target_ptrace.h b/linux-user/openrisc/target_ptrace.h
new file mode 100644
index 0000000..563c648
--- /dev/null
+++ b/linux-user/openrisc/target_ptrace.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef OPENRISC_TARGET_PTRACE_H
+#define OPENRISC_TARGET_PTRACE_H
+
+/* See arch/openrisc/include/uapi/asm/ptrace.h. */
+struct target_user_regs_struct {
+ abi_ulong gpr[32];
+ abi_ulong pc;
+ abi_ulong sr;
+};
+
+#endif /* OPENRISC_TARGET_PTRACE_H */
diff --git a/linux-user/openrisc/target_syscall.h b/linux-user/openrisc/target_syscall.h
index 7fe5b73..c8394e9 100644
--- a/linux-user/openrisc/target_syscall.h
+++ b/linux-user/openrisc/target_syscall.h
@@ -1,17 +1,6 @@
#ifndef OPENRISC_TARGET_SYSCALL_H
#define OPENRISC_TARGET_SYSCALL_H
-/* Note that in linux/arch/openrisc/include/uapi/asm/ptrace.h,
- * this is called user_regs_struct. Given that this is what
- * is used within struct sigcontext we need this definition.
- * However, elfload.c wants this name.
- */
-struct target_pt_regs {
- abi_ulong gpr[32];
- abi_ulong pc;
- abi_ulong sr;
-};
-
#define UNAME_MACHINE "openrisc"
#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/plugin-api.c b/linux-user/plugin-api.c
index 66755df..8d6fbb6 100644
--- a/linux-user/plugin-api.c
+++ b/linux-user/plugin-api.c
@@ -12,4 +12,5 @@
#include "qemu/osdep.h"
#include "qemu.h"
+#include "loader.h"
#include "common-user/plugin-api.c.inc"
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 2a0efaf..22885ff 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -378,21 +378,31 @@ void cpu_loop(CPUPPCState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
+ CPUArchState *env = cpu_env(cs);
+ abi_ptr entry = info->entry;
+
+ env->gpr[1] = info->start_stack;
+
+#ifdef TARGET_PPC64
+ if (get_ppc64_abi(info) < 2) {
+ uint64_t val;
+ get_user_u64(val, entry + 8);
+ env->gpr[2] = val + info->load_bias;
+ get_user_u64(val, entry);
+ entry = val + info->load_bias;
+ } else {
+ env->gpr[12] = entry; /* r12 set to global entry address */
+ }
-#if defined(TARGET_PPC64)
int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
#if defined(TARGET_ABI32)
ppc_store_msr(env, env->msr & ~((target_ulong)1 << flag));
#else
ppc_store_msr(env, env->msr | (target_ulong)1 << flag);
#endif
-#endif
+#endif /* TARGET_PPC64 */
- env->nip = regs->nip;
- for(i = 0; i < 32; i++) {
- env->gpr[i] = regs->gpr[i];
- }
+ env->nip = entry;
}
diff --git a/linux-user/ppc/elfload.c b/linux-user/ppc/elfload.c
new file mode 100644
index 0000000..0d54da9
--- /dev/null
+++ b/linux-user/ppc/elfload.c
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+#ifdef TARGET_PPC64
+ return "POWER9";
+#else
+ return "750";
+#endif
+}
+
+/*
+ * Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
+ * See arch/powerpc/include/asm/cputable.h.
+ */
+enum {
+ QEMU_PPC_FEATURE_32 = 0x80000000,
+ QEMU_PPC_FEATURE_64 = 0x40000000,
+ QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
+ QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
+ QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
+ QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
+ QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
+ QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
+ QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
+ QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
+ QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
+ QEMU_PPC_FEATURE_NO_TB = 0x00100000,
+ QEMU_PPC_FEATURE_POWER4 = 0x00080000,
+ QEMU_PPC_FEATURE_POWER5 = 0x00040000,
+ QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
+ QEMU_PPC_FEATURE_CELL = 0x00010000,
+ QEMU_PPC_FEATURE_BOOKE = 0x00008000,
+ QEMU_PPC_FEATURE_SMT = 0x00004000,
+ QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
+ QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
+ QEMU_PPC_FEATURE_PA6T = 0x00000800,
+ QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
+ QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
+ QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
+ QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
+ QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
+
+ QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
+ QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
+
+ /* Feature definitions in AT_HWCAP2. */
+ QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
+ QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
+ QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
+ QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
+ QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
+ QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
+ QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
+ QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
+ QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
+ QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
+ QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
+ QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
+ QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
+ QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */
+ QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */
+};
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ uint32_t features = 0;
+
+ /*
+ * We don't have to be terribly complete here; the high points are
+ * Altivec/FP/SPE support. Anything else is just a bonus.
+ */
+#define GET_FEATURE(flag, feature) \
+ do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
+#define GET_FEATURE2(flags, feature) \
+ do { \
+ if ((cpu->env.insns_flags2 & flags) == flags) { \
+ features |= feature; \
+ } \
+ } while (0)
+ GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
+ GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
+ GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
+ GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
+ GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
+ GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
+ GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
+ GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
+ GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
+ GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
+ GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
+ PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
+ QEMU_PPC_FEATURE_ARCH_2_06);
+
+#undef GET_FEATURE
+#undef GET_FEATURE2
+
+ return features;
+}
+
+abi_ulong get_elf_hwcap2(CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ uint32_t features = 0;
+
+#define GET_FEATURE(flag, feature) \
+ do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
+#define GET_FEATURE2(flag, feature) \
+ do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
+
+ GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
+ GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
+ GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
+ PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
+ QEMU_PPC_FEATURE2_VEC_CRYPTO);
+ GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
+ QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128);
+ GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 |
+ QEMU_PPC_FEATURE2_MMA);
+
+#undef GET_FEATURE
+#undef GET_FEATURE2
+
+ return features;
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUPPCState *env)
+{
+ for (int i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ r->pt.gpr[i] = tswapal(env->gpr[i]);
+ }
+
+ r->pt.nip = tswapal(env->nip);
+ r->pt.msr = tswapal(env->msr);
+ r->pt.ctr = tswapal(env->ctr);
+ r->pt.link = tswapal(env->lr);
+ r->pt.xer = tswapal(cpu_read_xer(env));
+ r->pt.ccr = tswapal(ppc_get_cr(env));
+}
diff --git a/linux-user/ppc/target_elf.h b/linux-user/ppc/target_elf.h
index 0616618..22854cf 100644
--- a/linux-user/ppc/target_elf.h
+++ b/linux-user/ppc/target_elf.h
@@ -7,12 +7,64 @@
#ifndef PPC_TARGET_ELF_H
#define PPC_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
+
+#include "target_ptrace.h"
+
+#define ELF_MACHINE PPC_ELF_MACHINE
+
#ifdef TARGET_PPC64
- return "POWER9";
+# define ELF_CLASS ELFCLASS64
+#else
+# define ELF_CLASS ELFCLASS32
+# define EXSTACK_DEFAULT true
+#endif
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_HWCAP2 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * The size of 48 words is set in arch/powerpc/include/uapi/asm/elf.h.
+ * However PPC_ELF_CORE_COPY_REGS in arch/powerpc/include/asm/elf.h
+ * open-codes a memcpy from struct pt_regs, then zeros the rest.
+ */
+typedef struct target_elf_gregset_t {
+ union {
+ struct target_pt_regs pt;
+ abi_ulong reserved[48];
+ };
+} target_elf_gregset_t;
+
+#ifndef TARGET_PPC64
+# define VDSO_HEADER "vdso-32.c.inc"
+#elif TARGET_BIG_ENDIAN
+# define VDSO_HEADER "vdso-64.c.inc"
#else
- return "750";
+# define VDSO_HEADER "vdso-64le.c.inc"
#endif
-}
+
+/*
+ * The requirements here are:
+ * - keep the final alignment of sp (sp & 0xf)
+ * - make sure the 32-bit value at the first 16 byte aligned position of
+ * AUXV is greater than 16 for glibc compatibility.
+ * AT_IGNOREPPC is used for that.
+ * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
+ * even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
+ */
+#define DLINFO_ARCH_ITEMS 5
+#define ARCH_DLINFO \
+ do { \
+ PowerPCCPU *cpu = POWERPC_CPU(thread_cpu); \
+ /* \
+ * Handle glibc compatibility: these magic entries must \
+ * be at the lowest addresses in the final auxv. \
+ */ \
+ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
+ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
+ NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
+ NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
+ NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
+ } while (0)
+
#endif
diff --git a/linux-user/ppc/target_ptrace.h b/linux-user/ppc/target_ptrace.h
new file mode 100644
index 0000000..df77bfd
--- /dev/null
+++ b/linux-user/ppc/target_ptrace.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef PPC_TARGET_PTRACE_H
+#define PPC_TARGET_PTRACE_H
+
+struct target_pt_regs {
+ abi_ulong gpr[32];
+ abi_ulong nip;
+ abi_ulong msr;
+ abi_ulong orig_gpr3; /* Used for restarting system calls */
+ abi_ulong ctr;
+ abi_ulong link;
+ abi_ulong xer;
+ abi_ulong ccr;
+#if defined(TARGET_PPC64)
+ abi_ulong softe;
+#else
+ abi_ulong mq; /* 601 only (not used at present) */
+#endif
+ abi_ulong trap; /* Reason for being here */
+ abi_ulong dar; /* Fault registers */
+ abi_ulong dsisr;
+ abi_ulong result; /* Result of a system call */
+};
+
+#endif /* PPC_TARGET_PTRACE_H */
diff --git a/linux-user/ppc/target_syscall.h b/linux-user/ppc/target_syscall.h
index 77b36d0..976b4bb 100644
--- a/linux-user/ppc/target_syscall.h
+++ b/linux-user/ppc/target_syscall.h
@@ -20,34 +20,6 @@
#ifndef PPC_TARGET_SYSCALL_H
#define PPC_TARGET_SYSCALL_H
-/* XXX: ABSOLUTELY BUGGY:
- * for now, this is quite just a cut-and-paste from i386 target...
- */
-
-/* default linux values for the selectors */
-#define __USER_DS (1)
-
-struct target_pt_regs {
- abi_ulong gpr[32];
- abi_ulong nip;
- abi_ulong msr;
- abi_ulong orig_gpr3; /* Used for restarting system calls */
- abi_ulong ctr;
- abi_ulong link;
- abi_ulong xer;
- abi_ulong ccr;
-#if defined(TARGET_PPC64)
- abi_ulong softe;
-#else
- abi_ulong mq; /* 601 only (not used at present) */
-#endif
- /* Used on APUS to hold IPL value. */
- abi_ulong trap; /* Reason for being here */
- abi_ulong dar; /* Fault registers */
- abi_ulong dsisr;
- abi_ulong result; /* Result of a system call */
-};
-
/* ioctls */
struct target_revectored_struct {
abi_ulong __map[8]; /* 256 bits */
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 0b19fa4..e4dca0c 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -122,12 +122,6 @@ struct TaskState {
#ifdef TARGET_M68K
abi_ulong tp_value;
#endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_RISCV)
- /* Extra fields for semihosted binaries. */
- abi_ulong heap_base;
- abi_ulong heap_limit;
-#endif
- abi_ulong stack_base;
int used; /* non zero if used */
struct image_info *info;
struct linux_binprm *bprm;
@@ -365,4 +359,6 @@ void *lock_user_string(abi_ulong guest_addr);
/* Clone cpu state */
CPUArchState *cpu_copy(CPUArchState *env);
+void init_main_thread(CPUState *cs, struct image_info *info);
+
#endif /* QEMU_H */
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index 3ac8bbf..b316281 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -94,23 +94,16 @@ void cpu_loop(CPURISCVState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- CPUState *cpu = env_cpu(env);
- TaskState *ts = get_task_state(cpu);
- struct image_info *info = ts->info;
+ CPUArchState *env = cpu_env(cs);
- env->pc = regs->sepc;
- env->gpr[xSP] = regs->sp;
+ env->pc = info->entry;
+ env->gpr[xSP] = info->start_stack;
env->elf_flags = info->elf_flags;
if ((env->misa_ext & RVE) && !(env->elf_flags & EF_RISCV_RVE)) {
error_report("Incompatible ELF: RVE cpu requires RVE ABI binary");
exit(EXIT_FAILURE);
}
-
- ts->stack_base = info->start_stack;
- ts->heap_base = info->brk;
- /* This will be filled in on the first SYS_HEAPINFO call. */
- ts->heap_limit = 0;
}
diff --git a/linux-user/riscv/elfload.c b/linux-user/riscv/elfload.c
new file mode 100644
index 0000000..2e7d622
--- /dev/null
+++ b/linux-user/riscv/elfload.c
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "max";
+}
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+#define MISA_BIT(EXT) (1 << (EXT - 'A'))
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A')
+ | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C')
+ | MISA_BIT('V');
+
+ return cpu->env.misa_ext & mask;
+#undef MISA_BIT
+}
diff --git a/linux-user/riscv/target_elf.h b/linux-user/riscv/target_elf.h
index dedd595..dbbfdf5 100644
--- a/linux-user/riscv/target_elf.h
+++ b/linux-user/riscv/target_elf.h
@@ -7,8 +7,17 @@
#ifndef RISCV_TARGET_ELF_H
#define RISCV_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "max";
-}
+
+#define ELF_MACHINE EM_RISCV
+
+#ifdef TARGET_RISCV32
+#define ELF_CLASS ELFCLASS32
+#define VDSO_HEADER "vdso-32.c.inc"
+#else
+#define ELF_CLASS ELFCLASS64
+#define VDSO_HEADER "vdso-64.c.inc"
+#endif
+
+#define HAVE_ELF_HWCAP 1
+
#endif
diff --git a/linux-user/riscv/target_syscall.h b/linux-user/riscv/target_syscall.h
index 7601f10..69a7b75 100644
--- a/linux-user/riscv/target_syscall.h
+++ b/linux-user/riscv/target_syscall.h
@@ -8,41 +8,6 @@
#ifndef LINUX_USER_RISCV_TARGET_SYSCALL_H
#define LINUX_USER_RISCV_TARGET_SYSCALL_H
-struct target_pt_regs {
- abi_long sepc;
- abi_long ra;
- abi_long sp;
- abi_long gp;
- abi_long tp;
- abi_long t0;
- abi_long t1;
- abi_long t2;
- abi_long s0;
- abi_long s1;
- abi_long a0;
- abi_long a1;
- abi_long a2;
- abi_long a3;
- abi_long a4;
- abi_long a5;
- abi_long a6;
- abi_long a7;
- abi_long s2;
- abi_long s3;
- abi_long s4;
- abi_long s5;
- abi_long s6;
- abi_long s7;
- abi_long s8;
- abi_long s9;
- abi_long s10;
- abi_long s11;
- abi_long t3;
- abi_long t4;
- abi_long t5;
- abi_long t6;
-};
-
#ifdef TARGET_RISCV32
#define UNAME_MACHINE "riscv32"
#define UNAME_MINIMUM_RELEASE "5.4.0"
diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c
index c912444..49e4454 100644
--- a/linux-user/s390x/cpu_loop.c
+++ b/linux-user/s390x/cpu_loop.c
@@ -180,12 +180,13 @@ void cpu_loop(CPUS390XState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
- for (i = 0; i < 16; i++) {
- env->regs[i] = regs->gprs[i];
- }
- env->psw.mask = regs->psw.mask;
- env->psw.addr = regs->psw.addr;
+ CPUArchState *env = cpu_env(cs);
+
+ env->psw.addr = info->entry;
+ env->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT |
+ PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 |
+ PSW_MASK_32;
+ env->regs[15] = info->start_stack;
}
diff --git a/linux-user/s390x/elfload.c b/linux-user/s390x/elfload.c
new file mode 100644
index 0000000..2710927
--- /dev/null
+++ b/linux-user/s390x/elfload.c
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "elf.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "qemu";
+}
+
+#define GET_FEATURE(_feat, _hwcap) \
+ do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ /*
+ * Let's assume we always have esan3 and zarch.
+ * 31-bit processes can use 64-bit registers (high gprs).
+ */
+ uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
+
+ GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
+ GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
+ GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
+ GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
+ if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
+ s390_has_feat(S390_FEAT_ETF3_ENH)) {
+ hwcap |= HWCAP_S390_ETF3EH;
+ }
+ GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
+ GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
+ GET_FEATURE(S390_FEAT_VECTOR_ENH2, HWCAP_S390_VXRS_EXT2);
+
+ return hwcap;
+}
+
+const char *elf_hwcap_str(uint32_t bit)
+{
+ static const char *hwcap_str[] = {
+ [HWCAP_S390_NR_ESAN3] = "esan3",
+ [HWCAP_S390_NR_ZARCH] = "zarch",
+ [HWCAP_S390_NR_STFLE] = "stfle",
+ [HWCAP_S390_NR_MSA] = "msa",
+ [HWCAP_S390_NR_LDISP] = "ldisp",
+ [HWCAP_S390_NR_EIMM] = "eimm",
+ [HWCAP_S390_NR_DFP] = "dfp",
+ [HWCAP_S390_NR_HPAGE] = "edat",
+ [HWCAP_S390_NR_ETF3EH] = "etf3eh",
+ [HWCAP_S390_NR_HIGH_GPRS] = "highgprs",
+ [HWCAP_S390_NR_TE] = "te",
+ [HWCAP_S390_NR_VXRS] = "vx",
+ [HWCAP_S390_NR_VXRS_BCD] = "vxd",
+ [HWCAP_S390_NR_VXRS_EXT] = "vxe",
+ [HWCAP_S390_NR_GS] = "gs",
+ [HWCAP_S390_NR_VXRS_EXT2] = "vxe2",
+ [HWCAP_S390_NR_VXRS_PDE] = "vxp",
+ [HWCAP_S390_NR_SORT] = "sort",
+ [HWCAP_S390_NR_DFLT] = "dflt",
+ [HWCAP_S390_NR_NNPA] = "nnpa",
+ [HWCAP_S390_NR_PCI_MIO] = "pcimio",
+ [HWCAP_S390_NR_SIE] = "sie",
+ };
+
+ return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUS390XState *env)
+{
+ r->pt.psw.mask = tswapal(env->psw.mask);
+ r->pt.psw.addr = tswapal(env->psw.addr);
+ for (int i = 0; i < 16; i++) {
+ r->pt.gprs[i] = tswapal(env->regs[i]);
+ }
+ for (int i = 0; i < 16; i++) {
+ r->pt.acrs[i] = tswap32(env->aregs[i]);
+ }
+ r->pt.orig_gpr2 = 0;
+}
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index df49c24..96d1c8d 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -22,6 +22,7 @@
#include "signal-common.h"
#include "linux-user/trace.h"
#include "vdso-asmoffset.h"
+#include "target_ptrace.h"
#define __NUM_GPRS 16
#define __NUM_FPRS 16
diff --git a/linux-user/s390x/target_elf.h b/linux-user/s390x/target_elf.h
index 8114b59..ef5edbd 100644
--- a/linux-user/s390x/target_elf.h
+++ b/linux-user/s390x/target_elf.h
@@ -7,8 +7,22 @@
#ifndef S390X_TARGET_ELF_H
#define S390X_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "qemu";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_MACHINE EM_S390
+#define VDSO_HEADER "vdso.c.inc"
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * See linux kernel: arch/s390/include/asm/elf.h, where
+ * elf_gregset_t is typedef'd to struct s390_regs.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_s390_regs pt;
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/s390x/target_proc.h b/linux-user/s390x/target_proc.h
index a4a4821..60cc22d 100644
--- a/linux-user/s390x/target_proc.h
+++ b/linux-user/s390x/target_proc.h
@@ -48,7 +48,7 @@ static void show_cpu_summary(CPUArchState *cpu_env, int fd)
{
S390CPUModel *model = env_archcpu(cpu_env)->model;
int num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
- uint32_t elf_hwcap = get_elf_hwcap();
+ uint32_t elf_hwcap = get_elf_hwcap(env_cpu(cpu_env));
const char *hwcap_str;
int i;
diff --git a/linux-user/s390x/target_ptrace.h b/linux-user/s390x/target_ptrace.h
new file mode 100644
index 0000000..a5ceb75
--- /dev/null
+++ b/linux-user/s390x/target_ptrace.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef S390X_TARGET_PTRACE_H
+#define S390X_TARGET_PTRACE_H
+
+typedef struct {
+ abi_ulong mask;
+ abi_ulong addr;
+} target_psw_t;
+
+struct target_s390_regs {
+ target_psw_t psw;
+ abi_ulong gprs[16];
+ abi_uint acrs[16];
+ abi_ulong orig_gpr2;
+};
+
+#endif /* S390X_TARGET_PTRACE_H */
diff --git a/linux-user/s390x/target_syscall.h b/linux-user/s390x/target_syscall.h
index 4018988..f01f9a0 100644
--- a/linux-user/s390x/target_syscall.h
+++ b/linux-user/s390x/target_syscall.h
@@ -1,28 +1,6 @@
#ifndef S390X_TARGET_SYSCALL_H
#define S390X_TARGET_SYSCALL_H
-/* this typedef defines how a Program Status Word looks like */
-typedef struct {
- abi_ulong mask;
- abi_ulong addr;
-} __attribute__ ((aligned(8))) target_psw_t;
-
-/*
- * The pt_regs struct defines the way the registers are stored on
- * the stack during a system call.
- */
-
-#define TARGET_NUM_GPRS 16
-
-struct target_pt_regs {
- abi_ulong args[1];
- target_psw_t psw;
- abi_ulong gprs[TARGET_NUM_GPRS];
- abi_ulong orig_gpr2;
- unsigned short ilen;
- unsigned short trap;
-};
-
#define UNAME_MACHINE "s390x"
#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/sh4/cpu_loop.c b/linux-user/sh4/cpu_loop.c
index ee9eff3..259ea1c 100644
--- a/linux-user/sh4/cpu_loop.c
+++ b/linux-user/sh4/cpu_loop.c
@@ -81,12 +81,10 @@ void cpu_loop(CPUSH4State *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
+ CPUArchState *env = cpu_env(cs);
- for(i = 0; i < 16; i++) {
- env->gregs[i] = regs->regs[i];
- }
- env->pc = regs->pc;
+ env->pc = info->entry;
+ env->gregs[15] = info->start_stack;
}
diff --git a/linux-user/sh4/elfload.c b/linux-user/sh4/elfload.c
new file mode 100644
index 0000000..ddf2aaa
--- /dev/null
+++ b/linux-user/sh4/elfload.c
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "sh7785";
+}
+
+enum {
+ SH_CPU_HAS_FPU = 0x0001, /* Hardware FPU support */
+ SH_CPU_HAS_P2_FLUSH_BUG = 0x0002, /* Need to flush the cache in P2 area */
+ SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
+ SH_CPU_HAS_DSP = 0x0008, /* SH-DSP: DSP support */
+ SH_CPU_HAS_PERF_COUNTER = 0x0010, /* Hardware performance counters */
+ SH_CPU_HAS_PTEA = 0x0020, /* PTEA register */
+ SH_CPU_HAS_LLSC = 0x0040, /* movli.l/movco.l */
+ SH_CPU_HAS_L2_CACHE = 0x0080, /* Secondary cache / URAM */
+ SH_CPU_HAS_OP32 = 0x0100, /* 32-bit instruction support */
+ SH_CPU_HAS_PTEAEX = 0x0200, /* PTE ASID Extension support */
+};
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ SuperHCPU *cpu = SUPERH_CPU(cs);
+ abi_ulong hwcap = 0;
+
+ hwcap |= SH_CPU_HAS_FPU;
+
+ if (cpu->env.features & SH_FEATURE_SH4A) {
+ hwcap |= SH_CPU_HAS_LLSC;
+ }
+
+ return hwcap;
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUSH4State *env)
+{
+ for (int i = 0; i < 16; i++) {
+ r->pt.regs[i] = tswapal(env->gregs[i]);
+ }
+
+ r->pt.pc = tswapal(env->pc);
+ r->pt.pr = tswapal(env->pr);
+ r->pt.sr = tswapal(env->sr);
+ r->pt.gbr = tswapal(env->gbr);
+ r->pt.mach = tswapal(env->mach);
+ r->pt.macl = tswapal(env->macl);
+}
diff --git a/linux-user/sh4/target_elf.h b/linux-user/sh4/target_elf.h
index f485e0c..d9e253d 100644
--- a/linux-user/sh4/target_elf.h
+++ b/linux-user/sh4/target_elf.h
@@ -7,8 +7,21 @@
#ifndef SH4_TARGET_ELF_H
#define SH4_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "sh7785";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_SH
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * See linux kernel: arch/sh/include/asm/elf.h, where
+ * elf_gregset_t is mapped to struct pt_regs via sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_pt_regs pt;
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/sh4/target_ptrace.h b/linux-user/sh4/target_ptrace.h
new file mode 100644
index 0000000..b802185
--- /dev/null
+++ b/linux-user/sh4/target_ptrace.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef SH4_TARGET_PTRACE_H
+#define SH4_TARGET_PTRACE_H
+
+/* See arch/sh/include/uapi/asm/ptrace_32.h. */
+struct target_pt_regs {
+ abi_ulong regs[16];
+ abi_ulong pc;
+ abi_ulong pr;
+ abi_ulong sr;
+ abi_ulong gbr;
+ abi_ulong mach;
+ abi_ulong macl;
+ abi_long tra;
+};
+
+#endif /* SH4_TARGET_PTRACE_H */
diff --git a/linux-user/sh4/target_syscall.h b/linux-user/sh4/target_syscall.h
index 14839885..2f35577 100644
--- a/linux-user/sh4/target_syscall.h
+++ b/linux-user/sh4/target_syscall.h
@@ -1,17 +1,6 @@
#ifndef SH4_TARGET_SYSCALL_H
#define SH4_TARGET_SYSCALL_H
-struct target_pt_regs {
- unsigned long regs[16];
- unsigned long pc;
- unsigned long pr;
- unsigned long sr;
- unsigned long gbr;
- unsigned long mach;
- unsigned long macl;
- long tra;
-};
-
#define UNAME_MACHINE "sh4"
#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 4dafc2c..cd0e739 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -750,7 +750,7 @@ void force_sigsegv(int oldsig)
}
#endif
-void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
+void cpu_loop_exit_sigsegv(CPUState *cpu, vaddr addr,
MMUAccessType access_type, bool maperr, uintptr_t ra)
{
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
@@ -766,7 +766,7 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
cpu_loop_exit_restore(cpu, ra);
}
-void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
+void cpu_loop_exit_sigbus(CPUState *cpu, vaddr addr,
MMUAccessType access_type, uintptr_t ra)
{
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c
index 68f1e8e..7d30cd1 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -357,14 +357,12 @@ void cpu_loop (CPUSPARCState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
- env->pc = regs->pc;
- env->npc = regs->npc;
- env->y = regs->y;
- for(i = 0; i < 8; i++)
- env->gregs[i] = regs->u_regs[i];
- for(i = 0; i < 8; i++)
- env->regwptr[i] = regs->u_regs[i + 8];
+ CPUArchState *env = cpu_env(cs);
+
+ env->pc = info->entry;
+ env->npc = env->pc + 4;
+ env->regwptr[WREG_SP] = (info->start_stack - 16 * sizeof(abi_ulong)
+ - TARGET_STACK_BIAS);
}
diff --git a/linux-user/sparc/elfload.c b/linux-user/sparc/elfload.c
new file mode 100644
index 0000000..32ca1b0
--- /dev/null
+++ b/linux-user/sparc/elfload.c
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+#ifdef TARGET_SPARC64
+ return "TI UltraSparc II";
+#else
+ return "Fujitsu MB86904";
+#endif
+}
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ /* There are not many sparc32 hwcap bits -- we have all of them. */
+ uint32_t r = HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
+ HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV;
+
+#ifdef TARGET_SPARC64
+ CPUSPARCState *env = cpu_env(cs);
+ uint32_t features = env->def.features;
+
+ r |= HWCAP_SPARC_V9 | HWCAP_SPARC_V8PLUS;
+ /* 32x32 multiply and divide are efficient. */
+ r |= HWCAP_SPARC_MUL32 | HWCAP_SPARC_DIV32;
+ /* We don't have an internal feature bit for this. */
+ r |= HWCAP_SPARC_POPC;
+ r |= features & CPU_FEATURE_FSMULD ? HWCAP_SPARC_FSMULD : 0;
+ r |= features & CPU_FEATURE_VIS1 ? HWCAP_SPARC_VIS : 0;
+ r |= features & CPU_FEATURE_VIS2 ? HWCAP_SPARC_VIS2 : 0;
+ r |= features & CPU_FEATURE_FMAF ? HWCAP_SPARC_FMAF : 0;
+ r |= features & CPU_FEATURE_VIS3 ? HWCAP_SPARC_VIS3 : 0;
+ r |= features & CPU_FEATURE_IMA ? HWCAP_SPARC_IMA : 0;
+#endif
+
+ return r;
+}
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index 8181b8b..d339f89 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -21,6 +21,8 @@
#include "user-internals.h"
#include "signal-common.h"
#include "linux-user/trace.h"
+#include "target_ptrace.h"
+
/* A Sparc register window */
struct target_reg_window {
diff --git a/linux-user/sparc/target_elf.h b/linux-user/sparc/target_elf.h
index a510ceb..7827767 100644
--- a/linux-user/sparc/target_elf.h
+++ b/linux-user/sparc/target_elf.h
@@ -7,12 +7,18 @@
#ifndef SPARC_TARGET_ELF_H
#define SPARC_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
-#ifdef TARGET_SPARC64
- return "TI UltraSparc II";
+
+#ifndef TARGET_SPARC64
+# define ELF_CLASS ELFCLASS32
+# define ELF_MACHINE EM_SPARC
+#elif defined(TARGET_ABI32)
+# define ELF_CLASS ELFCLASS32
+# define elf_check_machine(x) ((x) == EM_SPARC32PLUS || (x) == EM_SPARC)
#else
- return "Fujitsu MB86904";
+# define ELF_CLASS ELFCLASS64
+# define ELF_MACHINE EM_SPARCV9
#endif
-}
+
+#define HAVE_ELF_HWCAP 1
+
#endif
diff --git a/linux-user/sparc/target_ptrace.h b/linux-user/sparc/target_ptrace.h
new file mode 100644
index 0000000..a4d5416
--- /dev/null
+++ b/linux-user/sparc/target_ptrace.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef SPARC_TARGET_PTRACE_H
+#define SPARC_TARGET_PTRACE_H
+
+/* See arch/sparc/include/uapi/asm/ptrace.h. */
+struct target_pt_regs {
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ abi_ulong u_regs[16];
+ abi_ulong tstate;
+ abi_ulong pc;
+ abi_ulong npc;
+ uint32_t y;
+ uint32_t magic;
+#else
+ abi_ulong psr;
+ abi_ulong pc;
+ abi_ulong npc;
+ abi_ulong y;
+ abi_ulong u_regs[16];
+#endif
+};
+
+#endif /* SPARC_TARGET_PTRACE_H */
diff --git a/linux-user/sparc/target_syscall.h b/linux-user/sparc/target_syscall.h
index e421165..a90ed29 100644
--- a/linux-user/sparc/target_syscall.h
+++ b/linux-user/sparc/target_syscall.h
@@ -1,25 +1,6 @@
#ifndef SPARC_TARGET_SYSCALL_H
#define SPARC_TARGET_SYSCALL_H
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-struct target_pt_regs {
- abi_ulong u_regs[16];
- abi_ulong tstate;
- abi_ulong pc;
- abi_ulong npc;
- uint32_t y;
- uint32_t magic;
-};
-#else
-struct target_pt_regs {
- abi_ulong psr;
- abi_ulong pc;
- abi_ulong npc;
- abi_ulong y;
- abi_ulong u_regs[16];
-};
-#endif
-
#ifdef TARGET_SPARC64
# define UNAME_MACHINE "sparc64"
#else
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 3b744cc..1233ebc 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -499,113 +499,119 @@ print_socket_type(int type)
static void
print_socket_protocol(int domain, int type, int protocol)
{
- if (domain == AF_PACKET ||
- (domain == AF_INET && type == TARGET_SOCK_PACKET)) {
+ const char *name = NULL;
+
+ switch (domain) {
+ case AF_PACKET:
switch (protocol) {
- case 0x0003:
- qemu_log("ETH_P_ALL");
+ case 3:
+ name = "ETH_P_ALL";
break;
- default:
- qemu_log("%d", protocol);
}
- return;
- }
+ break;
- if (domain == PF_NETLINK) {
+ case PF_NETLINK:
switch (protocol) {
case NETLINK_ROUTE:
- qemu_log("NETLINK_ROUTE");
+ name = "NETLINK_ROUTE";
break;
case NETLINK_UNUSED:
- qemu_log("NETLINK_UNUSED");
+ name = "NETLINK_UNUSED";
break;
case NETLINK_USERSOCK:
- qemu_log("NETLINK_USERSOCK");
+ name = "NETLINK_USERSOCK";
break;
case NETLINK_FIREWALL:
- qemu_log("NETLINK_FIREWALL");
+ name = "NETLINK_FIREWALL";
break;
case NETLINK_SOCK_DIAG:
- qemu_log("NETLINK_SOCK_DIAG");
+ name = "NETLINK_SOCK_DIAG";
break;
case NETLINK_NFLOG:
- qemu_log("NETLINK_NFLOG");
+ name = "NETLINK_NFLOG";
break;
case NETLINK_XFRM:
- qemu_log("NETLINK_XFRM");
+ name = "NETLINK_XFRM";
break;
case NETLINK_SELINUX:
- qemu_log("NETLINK_SELINUX");
+ name = "NETLINK_SELINUX";
break;
case NETLINK_ISCSI:
- qemu_log("NETLINK_ISCSI");
+ name = "NETLINK_ISCSI";
break;
case NETLINK_AUDIT:
- qemu_log("NETLINK_AUDIT");
+ name = "NETLINK_AUDIT";
break;
case NETLINK_FIB_LOOKUP:
- qemu_log("NETLINK_FIB_LOOKUP");
+ name = "NETLINK_FIB_LOOKUP";
break;
case NETLINK_CONNECTOR:
- qemu_log("NETLINK_CONNECTOR");
+ name = "NETLINK_CONNECTOR";
break;
case NETLINK_NETFILTER:
- qemu_log("NETLINK_NETFILTER");
+ name = "NETLINK_NETFILTER";
break;
case NETLINK_IP6_FW:
- qemu_log("NETLINK_IP6_FW");
+ name = "NETLINK_IP6_FW";
break;
case NETLINK_DNRTMSG:
- qemu_log("NETLINK_DNRTMSG");
+ name = "NETLINK_DNRTMSG";
break;
case NETLINK_KOBJECT_UEVENT:
- qemu_log("NETLINK_KOBJECT_UEVENT");
+ name = "NETLINK_KOBJECT_UEVENT";
break;
case NETLINK_GENERIC:
- qemu_log("NETLINK_GENERIC");
+ name = "NETLINK_GENERIC";
break;
case NETLINK_SCSITRANSPORT:
- qemu_log("NETLINK_SCSITRANSPORT");
+ name = "NETLINK_SCSITRANSPORT";
break;
case NETLINK_ECRYPTFS:
- qemu_log("NETLINK_ECRYPTFS");
+ name = "NETLINK_ECRYPTFS";
break;
case NETLINK_RDMA:
- qemu_log("NETLINK_RDMA");
+ name = "NETLINK_RDMA";
break;
case NETLINK_CRYPTO:
- qemu_log("NETLINK_CRYPTO");
+ name = "NETLINK_CRYPTO";
break;
case NETLINK_SMC:
- qemu_log("NETLINK_SMC");
+ name = "NETLINK_SMC";
break;
- default:
- qemu_log("%d", protocol);
+ }
+ break;
+
+ case AF_INET:
+ case AF_INET6:
+ switch (protocol) {
+ case 3:
+ if (domain == AF_INET && type == TARGET_SOCK_PACKET) {
+ name = "ETH_P_ALL";
+ }
+ break;
+ case IPPROTO_IP:
+ name = "IPPROTO_IP";
+ break;
+ case IPPROTO_TCP:
+ name = "IPPROTO_TCP";
+ break;
+ case IPPROTO_UDP:
+ name = "IPPROTO_UDP";
+ break;
+ case IPPROTO_RAW:
+ name = "IPPROTO_RAW";
break;
}
- return;
+ break;
}
- switch (protocol) {
- case IPPROTO_IP:
- qemu_log("IPPROTO_IP");
- break;
- case IPPROTO_TCP:
- qemu_log("IPPROTO_TCP");
- break;
- case IPPROTO_UDP:
- qemu_log("IPPROTO_UDP");
- break;
- case IPPROTO_RAW:
- qemu_log("IPPROTO_RAW");
- break;
- default:
+ if (name) {
+ qemu_log("%s", name);
+ } else {
qemu_log("%d", protocol);
- break;
}
}
-
#ifdef TARGET_NR__newselect
static void
print_fdset(int n, abi_ulong target_fds_addr)
diff --git a/linux-user/strace.list b/linux-user/strace.list
index fdf94ef..51b5ead 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1716,3 +1716,9 @@
{ TARGET_NR_clock_gettime64, "clock_gettime64" , NULL, print_clock_gettime64,
print_syscall_ret_clock_gettime64 },
#endif
+#ifdef TARGET_NR_riscv_hwprobe
+{ TARGET_NR_riscv_hwprobe, "riscv_hwprobe" , "%s(%p,%d,%d,%d,%d,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_rseq
+{ TARGET_NR_rseq, "rseq" , "%s(%p,%u,%d,%#x)", NULL, NULL },
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 5826ac3..91360a0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -790,6 +790,10 @@ safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff,
int, outfd, loff_t *, poutoff, size_t, length,
unsigned int, flags)
#endif
+#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2)
+safe_syscall4(int, fchmodat2, int, dfd, const char *, filename,
+ unsigned short, mode, 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
@@ -6743,10 +6747,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
int pid_child = ret;
pid_fd = pidfd_open(pid_child, 0);
if (pid_fd >= 0) {
- fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL)
- | FD_CLOEXEC);
+ qemu_set_cloexec(pid_fd);
} else {
- pid_fd = 0;
+ pid_fd = 0;
}
#endif
put_user_u32(pid_fd, parent_tidptr);
@@ -8135,8 +8138,8 @@ static void open_self_maps_4(const struct open_self_maps_data *d,
* Callback for walk_memory_regions, when read_self_maps() fails.
* Proceed without the benefit of host /proc/self/maps cross-check.
*/
-static int open_self_maps_3(void *opaque, target_ulong guest_start,
- target_ulong guest_end, unsigned long flags)
+static int open_self_maps_3(void *opaque, vaddr guest_start,
+ vaddr guest_end, int flags)
{
static const MapInfo mi = { .is_priv = true };
@@ -8147,8 +8150,8 @@ static int open_self_maps_3(void *opaque, target_ulong guest_start,
/*
* Callback for walk_memory_regions, when read_self_maps() succeeds.
*/
-static int open_self_maps_2(void *opaque, target_ulong guest_start,
- target_ulong guest_end, unsigned long flags)
+static int open_self_maps_2(void *opaque, vaddr guest_start,
+ vaddr guest_end, int flags)
{
const struct open_self_maps_data *d = opaque;
uintptr_t host_start = (uintptr_t)g2h_untagged(guest_start);
@@ -8235,6 +8238,9 @@ static int open_self_stat(CPUArchState *cpu_env, int fd)
} else if (i == 3) {
/* ppid */
g_string_printf(buf, FMT_pid " ", getppid());
+ } else if (i == 4) {
+ /* pgid */
+ g_string_printf(buf, FMT_pid " ", getpgrp());
} else if (i == 19) {
/* num_threads */
int cpus = 0;
@@ -10711,6 +10717,15 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
unlock_user(p, arg2, 0);
return ret;
#endif
+#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2)
+ case TARGET_NR_fchmodat2:
+ if (!(p = lock_user_string(arg2))) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(safe_fchmodat2(arg1, p, arg3, arg4));
+ unlock_user(p, arg2, 0);
+ return ret;
+#endif
case TARGET_NR_getpriority:
/* Note that negative values are valid for getpriority, so we must
differentiate based on errno settings. */
@@ -11627,10 +11642,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
case TARGET_NR_nanosleep:
{
struct timespec req, rem;
- target_to_host_timespec(&req, arg1);
+ if (target_to_host_timespec(&req, arg1)) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(safe_nanosleep(&req, &rem));
if (is_error(ret) && arg2) {
- host_to_target_timespec(arg2, &rem);
+ if (host_to_target_timespec(arg2, &rem)) {
+ return -TARGET_EFAULT;
+ }
}
}
return ret;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 5d22759..df26a2d 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -515,10 +515,6 @@ struct target_sigaction {
abi_ulong _sa_handler;
#endif
target_sigset_t sa_mask;
-#ifdef TARGET_ARCH_HAS_SA_RESTORER
- /* ??? This is always present, but ignored unless O32. */
- abi_ulong sa_restorer;
-#endif
};
#else
struct target_old_sigaction {
diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
index 4aa253b..691b9a1 100644
--- a/linux-user/user-internals.h
+++ b/linux-user/user-internals.h
@@ -19,7 +19,6 @@
#define LINUX_USER_USER_INTERNALS_H
#include "user/thunk.h"
-#include "exec/exec-all.h"
#include "qemu/log.h"
extern char *exec_path;
diff --git a/linux-user/x86_64/elfload.c b/linux-user/x86_64/elfload.c
new file mode 100644
index 0000000..1e7000c
--- /dev/null
+++ b/linux-user/x86_64/elfload.c
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "max";
+}
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ return cpu_env(cs)->features[FEAT_1_EDX];
+}
+
+const char *get_elf_platform(CPUState *cs)
+{
+ return "x86_64";
+}
+
+bool init_guest_commpage(void)
+{
+ /*
+ * The vsyscall page is at a high negative address aka kernel space,
+ * which means that we cannot actually allocate it with target_mmap.
+ * We still should be able to use page_set_flags, unless the user
+ * has specified -R reserved_va, which would trigger an assert().
+ */
+ if (reserved_va != 0 &&
+ TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE - 1 > reserved_va) {
+ error_report("Cannot allocate vsyscall page");
+ exit(EXIT_FAILURE);
+ }
+ page_set_flags(TARGET_VSYSCALL_PAGE,
+ TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
+ PAGE_EXEC | PAGE_VALID);
+ return true;
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUX86State *env)
+{
+ r->pt.r15 = tswapal(env->regs[15]);
+ r->pt.r14 = tswapal(env->regs[14]);
+ r->pt.r13 = tswapal(env->regs[13]);
+ r->pt.r12 = tswapal(env->regs[12]);
+ r->pt.bp = tswapal(env->regs[R_EBP]);
+ r->pt.bx = tswapal(env->regs[R_EBX]);
+ r->pt.r11 = tswapal(env->regs[11]);
+ r->pt.r10 = tswapal(env->regs[10]);
+ r->pt.r9 = tswapal(env->regs[9]);
+ r->pt.r8 = tswapal(env->regs[8]);
+ r->pt.ax = tswapal(env->regs[R_EAX]);
+ r->pt.cx = tswapal(env->regs[R_ECX]);
+ r->pt.dx = tswapal(env->regs[R_EDX]);
+ r->pt.si = tswapal(env->regs[R_ESI]);
+ r->pt.di = tswapal(env->regs[R_EDI]);
+ r->pt.orig_ax = tswapal(get_task_state(env_cpu_const(env))->orig_ax);
+ r->pt.ip = tswapal(env->eip);
+ r->pt.cs = tswapal(env->segs[R_CS].selector & 0xffff);
+ r->pt.flags = tswapal(env->eflags);
+ r->pt.sp = tswapal(env->regs[R_ESP]);
+ r->pt.ss = tswapal(env->segs[R_SS].selector & 0xffff);
+ r->pt.fs_base = tswapal(env->segs[R_FS].base);
+ r->pt.gs_base = tswapal(env->segs[R_GS].base);
+ r->pt.ds = tswapal(env->segs[R_DS].selector & 0xffff);
+ r->pt.es = tswapal(env->segs[R_ES].selector & 0xffff);
+ r->pt.fs = tswapal(env->segs[R_FS].selector & 0xffff);
+ r->pt.gs = tswapal(env->segs[R_GS].selector & 0xffff);
+}
diff --git a/linux-user/x86_64/target_elf.h b/linux-user/x86_64/target_elf.h
index 3f628f8..840bddf 100644
--- a/linux-user/x86_64/target_elf.h
+++ b/linux-user/x86_64/target_elf.h
@@ -7,8 +7,24 @@
#ifndef X86_64_TARGET_ELF_H
#define X86_64_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "max";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_MACHINE EM_X86_64
+#define VDSO_HEADER "vdso.c.inc"
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_PLATFORM 1
+#define HAVE_ELF_CORE_DUMP 1
+#define HAVE_GUEST_COMMPAGE 1
+
+/*
+ * See linux kernel: arch/x86/include/asm/elf.h, where
+ * elf_gregset_t is mapped to struct user_regs_struct via sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_user_regs_struct pt;
+} target_elf_gregset_t;
+
#endif
diff --git a/linux-user/x86_64/target_ptrace.h b/linux-user/x86_64/target_ptrace.h
new file mode 100644
index 0000000..3352712
--- /dev/null
+++ b/linux-user/x86_64/target_ptrace.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef X86_64_TARGET_PTRACE_H
+#define X86_64_TARGET_PTRACE_H
+
+/*
+ * The struct pt_regs in arch/x86/include/uapi/asm/ptrace.h has missing
+ * register values and is not used. See arch/x86/include/asm/user_64.h.
+ */
+struct target_user_regs_struct {
+ abi_ulong r15;
+ abi_ulong r14;
+ abi_ulong r13;
+ abi_ulong r12;
+ abi_ulong bp;
+ abi_ulong bx;
+ abi_ulong r11;
+ abi_ulong r10;
+ abi_ulong r9;
+ abi_ulong r8;
+ abi_ulong ax;
+ abi_ulong cx;
+ abi_ulong dx;
+ abi_ulong si;
+ abi_ulong di;
+ abi_ulong orig_ax;
+ abi_ulong ip;
+ abi_ulong cs;
+ abi_ulong flags;
+ abi_ulong sp;
+ abi_ulong ss;
+ abi_ulong fs_base;
+ abi_ulong gs_base;
+ abi_ulong ds;
+ abi_ulong es;
+ abi_ulong fs;
+ abi_ulong gs;
+};
+
+#endif /* X86_64_TARGET_PTRACE_H */
diff --git a/linux-user/x86_64/target_syscall.h b/linux-user/x86_64/target_syscall.h
index fb55834..68f55f8 100644
--- a/linux-user/x86_64/target_syscall.h
+++ b/linux-user/x86_64/target_syscall.h
@@ -4,34 +4,6 @@
#define __USER_CS (0x33)
#define __USER_DS (0x2B)
-struct target_pt_regs {
- abi_ulong r15;
- abi_ulong r14;
- abi_ulong r13;
- abi_ulong r12;
- abi_ulong rbp;
- abi_ulong rbx;
-/* arguments: non interrupts/non tracing syscalls only save up to here */
- abi_ulong r11;
- abi_ulong r10;
- abi_ulong r9;
- abi_ulong r8;
- abi_ulong rax;
- abi_ulong rcx;
- abi_ulong rdx;
- abi_ulong rsi;
- abi_ulong rdi;
- abi_ulong orig_rax;
-/* end of arguments */
-/* cpu exception frame or undefined */
- abi_ulong rip;
- abi_ulong cs;
- abi_ulong eflags;
- abi_ulong rsp;
- abi_ulong ss;
-/* top of stack page */
-};
-
/* Maximum number of LDT entries supported. */
#define TARGET_LDT_ENTRIES 8192
/* The size of each LDT entry. */
diff --git a/linux-user/xtensa/cpu_loop.c b/linux-user/xtensa/cpu_loop.c
index c0fcf74..43a194f 100644
--- a/linux-user/xtensa/cpu_loop.c
+++ b/linux-user/xtensa/cpu_loop.c
@@ -238,12 +238,22 @@ void cpu_loop(CPUXtensaState *env)
}
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
{
- int i;
- for (i = 0; i < 16; ++i) {
- env->regs[i] = regs->areg[i];
+ CPUArchState *env = cpu_env(cs);
+
+ env->sregs[WINDOW_BASE] = 0;
+ env->sregs[WINDOW_START] = 1;
+ env->regs[1] = info->start_stack;
+ env->pc = info->entry;
+
+ if (info_is_fdpic(info)) {
+ env->regs[4] = info->loadmap_addr;
+ env->regs[5] = info->interpreter_loadmap_addr;
+ if (info->interpreter_loadmap_addr) {
+ env->regs[6] = info->interpreter_pt_dynamic_addr;
+ } else {
+ env->regs[6] = info->pt_dynamic_addr;
+ }
}
- env->sregs[WINDOW_START] = regs->windowstart;
- env->pc = regs->pc;
}
diff --git a/linux-user/xtensa/elfload.c b/linux-user/xtensa/elfload.c
new file mode 100644
index 0000000..68aeed8
--- /dev/null
+++ b/linux-user/xtensa/elfload.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return XTENSA_DEFAULT_CPU_MODEL;
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUXtensaState *env)
+{
+ r->pt.pc = tswap32(env->pc);
+ r->pt.ps = tswap32(env->sregs[PS] & ~PS_EXCM);
+ r->pt.lbeg = tswap32(env->sregs[LBEG]);
+ r->pt.lend = tswap32(env->sregs[LEND]);
+ r->pt.lcount = tswap32(env->sregs[LCOUNT]);
+ r->pt.sar = tswap32(env->sregs[SAR]);
+ r->pt.windowstart = tswap32(env->sregs[WINDOW_START]);
+ r->pt.windowbase = tswap32(env->sregs[WINDOW_BASE]);
+ r->pt.threadptr = tswap32(env->uregs[THREADPTR]);
+
+ xtensa_sync_phys_from_window((CPUXtensaState *)env);
+
+ for (unsigned i = 0; i < env->config->nareg; ++i) {
+ r->pt.a[i] = tswap32(env->phys_regs[i]);
+ }
+}
diff --git a/linux-user/xtensa/target_elf.h b/linux-user/xtensa/target_elf.h
index a9a3fab..1bf8f2a 100644
--- a/linux-user/xtensa/target_elf.h
+++ b/linux-user/xtensa/target_elf.h
@@ -8,9 +8,19 @@
#ifndef XTENSA_TARGET_ELF_H
#define XTENSA_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return XTENSA_DEFAULT_CPU_MODEL;
-}
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_XTENSA
+
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * See linux kernel: arch/xtensa/include/asm/elf.h, where elf_gregset_t
+ * is mapped to struct user_pt_regs via typedef and sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_user_pt_regs pt;
+} target_elf_gregset_t;
#endif
diff --git a/linux-user/xtensa/target_ptrace.h b/linux-user/xtensa/target_ptrace.h
new file mode 100644
index 0000000..32443d0
--- /dev/null
+++ b/linux-user/xtensa/target_ptrace.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef XTENSA_TARGET_PTRACE_H
+#define XTENSA_TARGET_PTRACE_H
+
+/* See arch/xtensa/include/uapi/asm/ptrace.h. */
+struct target_user_pt_regs {
+ uint32_t pc;
+ uint32_t ps;
+ uint32_t lbeg;
+ uint32_t lend;
+ uint32_t lcount;
+ uint32_t sar;
+ uint32_t windowstart;
+ uint32_t windowbase;
+ uint32_t threadptr;
+ uint32_t syscall;
+ uint32_t reserved[6 + 48];
+ uint32_t a[64];
+};
+
+#endif /* XTENSA_TARGET_PTRACE_H */
diff --git a/linux-user/xtensa/target_syscall.h b/linux-user/xtensa/target_syscall.h
index afc86a1..5d4352a 100644
--- a/linux-user/xtensa/target_syscall.h
+++ b/linux-user/xtensa/target_syscall.h
@@ -8,41 +8,6 @@
#define MMAP_SHIFT TARGET_PAGE_BITS
-typedef uint32_t xtensa_reg_t;
-typedef struct {
-} xtregs_opt_t; /* TODO */
-
-struct target_pt_regs {
- xtensa_reg_t pc; /* 4 */
- xtensa_reg_t ps; /* 8 */
- xtensa_reg_t depc; /* 12 */
- xtensa_reg_t exccause; /* 16 */
- xtensa_reg_t excvaddr; /* 20 */
- xtensa_reg_t debugcause; /* 24 */
- xtensa_reg_t wmask; /* 28 */
- xtensa_reg_t lbeg; /* 32 */
- xtensa_reg_t lend; /* 36 */
- xtensa_reg_t lcount; /* 40 */
- xtensa_reg_t sar; /* 44 */
- xtensa_reg_t windowbase; /* 48 */
- xtensa_reg_t windowstart; /* 52 */
- xtensa_reg_t syscall; /* 56 */
- xtensa_reg_t icountlevel; /* 60 */
- xtensa_reg_t scompare1; /* 64 */
- xtensa_reg_t threadptr; /* 68 */
-
- /* Additional configurable registers that are used by the compiler. */
- xtregs_opt_t xtregs_opt;
-
- /* Make sure the areg field is 16 bytes aligned. */
- int align[0] __attribute__ ((aligned(16)));
-
- /* current register frame.
- * Note: The ESF for kernel exceptions ends after 16 registers!
- */
- xtensa_reg_t areg[16];
-};
-
#define TARGET_MCL_CURRENT 1
#define TARGET_MCL_FUTURE 2
#define TARGET_MCL_ONFAULT 4