From 5d05b046efb079360d0175164ee04947f20f9e66 Mon Sep 17 00:00:00 2001 From: Afonso Bordado Date: Tue, 21 Mar 2023 18:45:20 +0000 Subject: [PATCH] linux-user: Emulate /proc/cpuinfo output for riscv RISC-V does not expose all extensions via hwcaps, thus some userspace applications may want to query these via /proc/cpuinfo. Currently when querying this file the host's file is shown instead which is slightly confusing. Emulate a basic /proc/cpuinfo file with mmu info and an ISA string. --- linux-user/syscall.c | 34 ++++++++++++++++++++++++++++++++-- tests/tcg/riscv64/cpuinfo.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/riscv64/cpuinfo.c diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 333e6b7026..e6d85e0e8a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8231,7 +8231,8 @@ 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_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA) || \ + defined(TARGET_RISCV) static int is_proc(const char *filename, const char *entry) { return strcmp(filename, entry) == 0; @@ -8309,6 +8310,35 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd) } #endif +#if defined(TARGET_RISCV) +static int open_cpuinfo(CPUArchState *cpu_env, int fd) +{ + int i; + int num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + RISCVCPU *cpu = env_archcpu(cpu_env); + const RISCVCPUConfig *cfg = riscv_cpu_cfg((CPURISCVState *) cpu_env); + char *isa_string = riscv_isa_string(cpu); + const char *mmu; + + if (cfg->mmu) { + mmu = (cpu_env->xl == MXL_RV32) ? "sv32" : "sv48"; + } else { + mmu = "none"; + } + + for (i = 0; i < num_cpus; i++) { + dprintf(fd, "processor\t: %d\n", i); + dprintf(fd, "hart\t\t: %d\n", i); + dprintf(fd, "isa\t\t: %s\n", isa_string); + dprintf(fd, "mmu\t\t: %s\n", mmu); + dprintf(fd, "uarch\t\t: qemu\n\n"); + } + + g_free(isa_string); + return 0; +} +#endif + #if defined(TARGET_M68K) static int open_hardware(CPUArchState *cpu_env, int fd) { @@ -8333,7 +8363,7 @@ 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) +#if defined(TARGET_SPARC) || defined(TARGET_HPPA) || defined(TARGET_RISCV) { "/proc/cpuinfo", open_cpuinfo, is_proc }, #endif #if defined(TARGET_M68K) diff --git a/tests/tcg/riscv64/cpuinfo.c b/tests/tcg/riscv64/cpuinfo.c new file mode 100644 index 0000000000..296abd0a8c --- /dev/null +++ b/tests/tcg/riscv64/cpuinfo.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 + +int main(void) +{ + char buffer[BUFFER_SIZE]; + FILE *fp = fopen("/proc/cpuinfo", "r"); + assert(fp != NULL); + + while (fgets(buffer, BUFFER_SIZE, fp) != NULL) { + if (strstr(buffer, "processor") != NULL) { + assert(strstr(buffer, "processor\t: ") == buffer); + } else if (strstr(buffer, "hart") != NULL) { + assert(strstr(buffer, "hart\t\t: ") == buffer); + } else if (strstr(buffer, "isa") != NULL) { + assert(strcmp(buffer, "isa\t\t: rv64imafdc_zicsr_zifencei\n") == 0); + } else if (strstr(buffer, "mmu") != NULL) { + assert(strcmp(buffer, "mmu\t\t: sv48\n") == 0); + } else if (strstr(buffer, "uarch") != NULL) { + assert(strcmp(buffer, "uarch\t\t: qemu\n") == 0); + } + } + + fclose(fp); + return 0; +} -- 2.34.1