diff options
Diffstat (limited to 'linux-user')
| -rw-r--r-- | linux-user/elfload.c | 29 | ||||
| -rw-r--r-- | linux-user/loader.h | 5 | ||||
| -rw-r--r-- | linux-user/s390x/cpu_loop.c | 9 | ||||
| -rw-r--r-- | linux-user/syscall.c | 106 |
4 files changed, 146 insertions, 3 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 418ad92598..d80d68484b 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1583,7 +1583,7 @@ static inline void init_thread(struct target_pt_regs *regs, #define GET_FEATURE(_feat, _hwcap) \ do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0) -static uint32_t get_elf_hwcap(void) +uint32_t get_elf_hwcap(void) { /* * Let's assume we always have esan3 and zarch. @@ -1605,6 +1605,33 @@ static uint32_t get_elf_hwcap(void) return hwcap; } +const char *elf_hwcap_str(uint32_t bit) +{ + static const char *hwcap_str[] = { + [HWCAP_S390_ESAN3] = "esan3", + [HWCAP_S390_ZARCH] = "zarch", + [HWCAP_S390_STFLE] = "stfle", + [HWCAP_S390_MSA] = "msa", + [HWCAP_S390_LDISP] = "ldisp", + [HWCAP_S390_EIMM] = "eimm", + [HWCAP_S390_DFP] = "dfp", + [HWCAP_S390_HPAGE] = "edat", + [HWCAP_S390_ETF3EH] = "etf3eh", + [HWCAP_S390_HIGH_GPRS] = "highgprs", + [HWCAP_S390_TE] = "te", + [HWCAP_S390_VXRS] = "vx", + [HWCAP_S390_VXRS_BCD] = "vxd", + [HWCAP_S390_VXRS_EXT] = "vxe", + [HWCAP_S390_GS] = "gs", + [HWCAP_S390_VXRS_EXT2] = "vxe2", + [HWCAP_S390_VXRS_PDE] = "vxp", + [HWCAP_S390_SORT] = "sort", + [HWCAP_S390_DFLT] = "dflt", + }; + + 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; diff --git a/linux-user/loader.h b/linux-user/loader.h index f375ee0679..59cbeacf24 100644 --- a/linux-user/loader.h +++ b/linux-user/loader.h @@ -56,4 +56,9 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src, extern unsigned long guest_stack_size; +#ifdef TARGET_S390X +uint32_t get_elf_hwcap(void); +const char *elf_hwcap_str(uint32_t bit); +#endif + #endif /* LINUX_USER_LOADER_H */ diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index 285bc60071..8b7ac2879e 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -86,6 +86,15 @@ void cpu_loop(CPUS390XState *env) } else if (ret != -QEMU_ESIGRETURN) { env->regs[2] = ret; } + + if (unlikely(cs->singlestep_enabled)) { + /* + * cpu_tb_exec() did not raise EXCP_DEBUG, because it has seen + * that EXCP_SVC was already pending. + */ + cs->exception_index = EXCP_DEBUG; + } + break; case EXCP_DEBUG: diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 89b58b386b..83685f0aa5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8232,7 +8232,7 @@ void target_exception_dump(CPUArchState *env, const char *fmt, int code) #if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN || \ defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA) || \ - defined(TARGET_RISCV) + defined(TARGET_RISCV) || defined(TARGET_S390X) static int is_proc(const char *filename, const char *entry) { return strcmp(filename, entry) == 0; @@ -8339,6 +8339,107 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd) } #endif +#if defined(TARGET_S390X) +/* + * Emulate what a Linux kernel running in qemu-system-s390x -M accel=tcg would + * show in /proc/cpuinfo. + * + * Skip the following in order to match the missing support in op_ecag(): + * - show_cacheinfo(). + * - show_cpu_topology(). + * - show_cpu_mhz(). + * + * Use fixed values for certain fields: + * - bogomips per cpu - from a qemu-system-s390x run. + * - max thread id = 0, since SMT / SIGP_SET_MULTI_THREADING is not supported. + * + * Keep the code structure close to arch/s390/kernel/processor.c. + */ + +static void show_facilities(int fd) +{ + size_t sizeof_stfl_bytes = 2048; + g_autofree uint8_t *stfl_bytes = g_new0(uint8_t, sizeof_stfl_bytes); + unsigned int bit; + + dprintf(fd, "facilities :"); + s390_get_feat_block(S390_FEAT_TYPE_STFL, stfl_bytes); + for (bit = 0; bit < sizeof_stfl_bytes * 8; bit++) { + if (test_be_bit(bit, stfl_bytes)) { + dprintf(fd, " %d", bit); + } + } + dprintf(fd, "\n"); +} + +static int cpu_ident(unsigned long n) +{ + return deposit32(0, CPU_ID_BITS - CPU_PHYS_ADDR_BITS, CPU_PHYS_ADDR_BITS, + n); +} + +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(); + const char *hwcap_str; + int i; + + dprintf(fd, "vendor_id : IBM/S390\n" + "# processors : %i\n" + "bogomips per cpu: 13370.00\n", + num_cpus); + dprintf(fd, "max thread id : 0\n"); + dprintf(fd, "features\t: "); + for (i = 0; i < sizeof(elf_hwcap) * 8; i++) { + if (!(elf_hwcap & (1 << i))) { + continue; + } + hwcap_str = elf_hwcap_str(i); + if (hwcap_str) { + dprintf(fd, "%s ", hwcap_str); + } + } + dprintf(fd, "\n"); + show_facilities(fd); + for (i = 0; i < num_cpus; i++) { + dprintf(fd, "processor %d: " + "version = %02X, " + "identification = %06X, " + "machine = %04X\n", + i, model->cpu_ver, cpu_ident(i), model->def->type); + } +} + +static void show_cpu_ids(CPUArchState *cpu_env, int fd, unsigned long n) +{ + S390CPUModel *model = env_archcpu(cpu_env)->model; + + dprintf(fd, "version : %02X\n", model->cpu_ver); + dprintf(fd, "identification : %06X\n", cpu_ident(n)); + dprintf(fd, "machine : %04X\n", model->def->type); +} + +static void show_cpuinfo(CPUArchState *cpu_env, int fd, unsigned long n) +{ + dprintf(fd, "\ncpu number : %ld\n", n); + show_cpu_ids(cpu_env, fd, n); +} + +static int open_cpuinfo(CPUArchState *cpu_env, int fd) +{ + int num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + int i; + + show_cpu_summary(cpu_env, fd); + for (i = 0; i < num_cpus; i++) { + show_cpuinfo(cpu_env, fd, i); + } + return 0; +} +#endif + #if defined(TARGET_M68K) static int open_hardware(CPUArchState *cpu_env, int fd) { @@ -8363,7 +8464,8 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int #if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN { "/proc/net/route", open_net_route, is_proc }, #endif -#if defined(TARGET_SPARC) || defined(TARGET_HPPA) || defined(TARGET_RISCV) +#if defined(TARGET_SPARC) || defined(TARGET_HPPA) || \ + defined(TARGET_RISCV) || defined(TARGET_S390X) { "/proc/cpuinfo", open_cpuinfo, is_proc }, #endif #if defined(TARGET_M68K) |