Message ID | 20230601162541.689621-5-iii@linux.ibm.com |
---|---|
State | New |
Headers | show |
Series | linux-user: Emulate /proc/cpuinfo on s390x | expand |
On Thu, 2023-06-01 at 18:25 +0200, Ilya Leoshkevich wrote: > Some s390x userspace programs are confused when seeing a foreign > /proc/cpuinfo [1]. Add the emulation for s390x; follow the respective > kernel code structure where possible. > > [1] https://bugzilla.redhat.com/show_bug.cgi?id=2211472 > > Reported-by: Tulio Magno Quites Machado Filho <tuliom@redhat.com> > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > linux-user/syscall.c | 106 > ++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 105 insertions(+), 1 deletion(-) > @@ -8364,7 +8467,8 @@ int do_guest_openat(CPUArchState *cpu_env, int > dirfd, const char *pathname, > #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) I'll need to add #if defined(TARGET_S390X) for is_proc, otherwise the build will fail on s390x hosts. I will include this in v2.
On 01.06.23 18:25, Ilya Leoshkevich wrote: > Some s390x userspace programs are confused when seeing a foreign > /proc/cpuinfo [1]. Add the emulation for s390x; follow the respective > kernel code structure where possible. > > [1] https://bugzilla.redhat.com/show_bug.cgi?id=2211472 > Would be nice to have an example output here. > Reported-by: Tulio Magno Quites Machado Filho <tuliom@redhat.com> > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > linux-user/syscall.c | 106 ++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 105 insertions(+), 1 deletion(-) > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 3e6ed51ce62..d142e09dc70 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -8339,6 +8339,109 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd) > } > #endif > [...] > + > +static void show_cpuinfo(CPUArchState *cpu_env, int fd, unsigned long n) > +{ > + if (n == 0) { > + show_cpu_summary(cpu_env, fd); > + } > + dprintf(fd, "\ncpu number : %ld\n", n); > + show_cpu_ids(cpu_env, fd, n); > +} Considering the n==0 special case, it might be cleaner to just place that code directly into open_cpuinfo and get rid of show_cpuinfo(). > + > +static int open_cpuinfo(CPUArchState *cpu_env, int fd) > +{ > + int num_cpus = sysconf(_SC_NPROCESSORS_ONLN); > + int i; > + > + 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) > { > @@ -8364,7 +8467,8 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, > #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) In general, looks very good to me, thanks! With the fixup: Reviewed-by: David Hildenbrand <david@redhat.com>
On Fri, 2023-06-02 at 14:34 +0200, David Hildenbrand wrote: > On 01.06.23 18:25, Ilya Leoshkevich wrote: > > Some s390x userspace programs are confused when seeing a foreign > > /proc/cpuinfo [1]. Add the emulation for s390x; follow the > > respective > > kernel code structure where possible. > > > > [1] https://bugzilla.redhat.com/show_bug.cgi?id=2211472 > > > > Would be nice to have an example output here. > > > Reported-by: Tulio Magno Quites Machado Filho <tuliom@redhat.com> > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > > --- > > linux-user/syscall.c | 106 > > ++++++++++++++++++++++++++++++++++++++++++- > > 1 file changed, 105 insertions(+), 1 deletion(-) > > > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > > index 3e6ed51ce62..d142e09dc70 100644 > > --- a/linux-user/syscall.c > > +++ b/linux-user/syscall.c > > @@ -8339,6 +8339,109 @@ static int open_cpuinfo(CPUArchState > > *cpu_env, int fd) > > } > > #endif > > > > [...] > > > + > > +static void show_cpuinfo(CPUArchState *cpu_env, int fd, unsigned > > long n) > > +{ > > + if (n == 0) { > > + show_cpu_summary(cpu_env, fd); > > + } > > + dprintf(fd, "\ncpu number : %ld\n", n); > > + show_cpu_ids(cpu_env, fd, n); > > +} > > Considering the n==0 special case, it might be cleaner to just place > that code directly into open_cpuinfo and get rid of show_cpuinfo(). Will do. This was copied from the kernel, where a similar check actually made sense, but in the QEMU context we don't really need it. > > + > > +static int open_cpuinfo(CPUArchState *cpu_env, int fd) > > +{ > > + int num_cpus = sysconf(_SC_NPROCESSORS_ONLN); > > + int i; > > + > > + 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) > > { > > @@ -8364,7 +8467,8 @@ int do_guest_openat(CPUArchState *cpu_env, > > int dirfd, const char *pathname, > > #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) > > In general, looks very good to me, thanks! With the fixup: > > Reviewed-by: David Hildenbrand <david@redhat.com> >
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3e6ed51ce62..d142e09dc70 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8339,6 +8339,109 @@ 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) +{ + if (n == 0) { + show_cpu_summary(cpu_env, fd); + } + 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; + + 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) { @@ -8364,7 +8467,8 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, #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)
Some s390x userspace programs are confused when seeing a foreign /proc/cpuinfo [1]. Add the emulation for s390x; follow the respective kernel code structure where possible. [1] https://bugzilla.redhat.com/show_bug.cgi?id=2211472 Reported-by: Tulio Magno Quites Machado Filho <tuliom@redhat.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> --- linux-user/syscall.c | 106 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-)