diff options
Diffstat (limited to 'linux-user/s390x')
-rw-r--r-- | linux-user/s390x/cpu_loop.c | 17 | ||||
-rw-r--r-- | linux-user/s390x/elfload.c | 82 | ||||
-rw-r--r-- | linux-user/s390x/signal.c | 1 | ||||
-rw-r--r-- | linux-user/s390x/target_elf.h | 22 | ||||
-rw-r--r-- | linux-user/s390x/target_proc.h | 2 | ||||
-rw-r--r-- | linux-user/s390x/target_ptrace.h | 18 | ||||
-rw-r--r-- | linux-user/s390x/target_syscall.h | 22 | ||||
-rw-r--r-- | linux-user/s390x/vdso.S | 2 | ||||
-rwxr-xr-x | linux-user/s390x/vdso.so | bin | 3464 -> 3616 bytes |
9 files changed, 131 insertions, 35 deletions
diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index c912444..4929b32 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -64,7 +64,7 @@ void cpu_loop(CPUS390XState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); - process_queued_cpu_work(cs); + qemu_process_cpu_events(cs); switch (trapnr) { case EXCP_INTERRUPT: @@ -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/s390x/vdso.S b/linux-user/s390x/vdso.S index 3332492..c60e9ed 100644 --- a/linux-user/s390x/vdso.S +++ b/linux-user/s390x/vdso.S @@ -52,6 +52,7 @@ vdso_syscall __kernel_getcpu, __NR_getcpu * by all users. Without it we get the fallback signal frame handling. */ +sigreturn_region_start: __kernel_sigreturn: raw_syscall __NR_sigreturn endf __kernel_sigreturn @@ -59,3 +60,4 @@ endf __kernel_sigreturn __kernel_rt_sigreturn: raw_syscall __NR_rt_sigreturn endf __kernel_rt_sigreturn +sigreturn_region_end: diff --git a/linux-user/s390x/vdso.so b/linux-user/s390x/vdso.so Binary files differindex 64130f6..a669a6b 100755 --- a/linux-user/s390x/vdso.so +++ b/linux-user/s390x/vdso.so |