From: Diego Nieto Cid <dnie...@gmail.com> Hello,
This is a patch to introduce the cpuinfo file to the hierarchy exposed by procfs. I used as guidance the Wikipedia article on the CPUID instruction and the GNU/Linux output to sort each line in the output. There remains a lot of fields that I haven't covered yet and SMP is not supported (in alignment with the output of /proc/stat). But it seems to help in the porting of libgtop to GNU/Hurd, which I started from a copy of Linux implementation. Beside that, I probably need to cache the CPUID provided information as I don't think it would change over time. The output below is what currently is implemented: demo@debian:~/dev/hurd/upstream/hurd/build-tree$ settrans -a test-proc procfs/procfs demo@debian:~/dev/hurd/upstream/hurd/build-tree$ cat ./test-proc/cpuinfo processor : 0 vendor_id : AuthenticAMD cpu family : 25 model : 80 model name : AMD Ryzen 9 5900HX with Radeon Graphics stepping : 0 flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clfsh mmx fxsr sse sse2 htt sse3 pclmulqdq ssse3 cx16 sse4_1 sse4_2 movbe popcnt aes_ni rdrnd So what else do you think should be included in our implementation of cpuinfo? Thanks, Diego -- >8 -- >8 -- >8 -- * procfs/rootdir.c: (rootdir_gc_cpuinfo) new function (rootdir_entries): add entry for cpuinfo file --- procfs/rootdir.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/procfs/rootdir.c b/procfs/rootdir.c index b8a8c4d1..966e2eee 100644 --- a/procfs/rootdir.c +++ b/procfs/rootdir.c @@ -38,6 +38,7 @@ #include "procfs_dir.h" #include "main.h" #include <net/route.h> +#include <cpuid.h> #include "mach_debug_U.h" #include "pfinet_U.h" @@ -696,6 +697,125 @@ out_fclose: fclose (m); return err; } + +static char * features_edx[] = + { + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", + NULL, "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "psn", "clfsh", + NULL, "ds", "acpi", "mmx", "fxsr", "sse", "sse2", "ss", "htt", "tm", + "ia64", "pbe" + }; + +static char * features_ecx[] = + { + "sse3", "pclmulqdq", "dtes64", "monitor", "ds-cpl", "vmx", "smx", "est", + "tm3", "ssse3", "cnxt-id", "sdbg", "fma", "cx16", "xtpr", "pdcm", + NULL, "pcid", "dca", "sse4_1", "sse4_2", "x2apic", "movbe", "popcnt", + "tsc_deadline", "aes_ni", "xsave", "osxsave", "avx", "f16c", "rdrnd", "hypervisor" + }; + + +static error_t +rootdir_gc_cpuinfo (void *hook, char **contents, ssize_t *contents_len) +{ +# define VENDOR_ID_LEN 12 +# define MODEL_NAME_LEN 48 + error_t err = 0; + int ret, index, stepping, model, family, extended_model, extended_family; + unsigned int eax, ebx, ecx, edx; + unsigned int feature_edx, feature_ecx; + char vendor[VENDOR_ID_LEN + 1] = { 0 }; + char model_name[MODEL_NAME_LEN + 1] = { 0 }; + FILE* m; + + m = open_memstream(contents, (size_t *) contents_len); + if (m == NULL) + return errno; + + ret = __get_cpuid(0, &eax, &ebx, &ecx, &edx); + if (ret != 1) + { + err = EIO; + goto out; + } + + memcpy(vendor + 0 * sizeof(unsigned int), (char *) &ebx, sizeof(unsigned int)); + memcpy(vendor + 1 * sizeof(unsigned int), (char *) &edx, sizeof(unsigned int)); + memcpy(vendor + 2 * sizeof(unsigned int), (char *) &ecx, sizeof(unsigned int)); + + ret = __get_cpuid(1, &eax, &ebx, &ecx, &edx); + if (ret != 1) + { + err = EIO; + goto out; + } + + feature_edx = edx; + feature_ecx = ecx; + stepping = eax & 0x0F; + model = (eax & 0xF0) >> 4; + family = (eax & 0xF00) >> 8; + extended_model = (eax & 0xF0000) >> 16; + extended_family = (eax &0xFF00000) >> 20; + + if (family == 6 || family == 15) + model += (extended_model << 4); + if (family == 15) + family += extended_family; + + __get_cpuid(0x80000000, &eax, &ebx, &ecx, &edx); + if (eax >= 0x80000004) + { + __get_cpuid(0x80000002, &eax, &ebx, &ecx, &edx); + memcpy(model_name + 0 * sizeof(unsigned int), (char *) &eax, sizeof(unsigned int)); + memcpy(model_name + 1 * sizeof(unsigned int), (char *) &ebx, sizeof(unsigned int)); + memcpy(model_name + 2 * sizeof(unsigned int), (char *) &ecx, sizeof(unsigned int)); + memcpy(model_name + 3 * sizeof(unsigned int), (char *) &edx, sizeof(unsigned int)); + + __get_cpuid(0x80000003, &eax, &ebx, &ecx, &edx); + memcpy(model_name + 4 * sizeof(unsigned int), (char *) &eax, sizeof(unsigned int)); + memcpy(model_name + 5 * sizeof(unsigned int), (char *) &ebx, sizeof(unsigned int)); + memcpy(model_name + 6 * sizeof(unsigned int), (char *) &ecx, sizeof(unsigned int)); + memcpy(model_name + 7 * sizeof(unsigned int), (char *) &edx, sizeof(unsigned int)); + + __get_cpuid(0x80000004, &eax, &ebx, &ecx, &edx); + memcpy(model_name + 8 * sizeof(unsigned int), (char *) &eax, sizeof(unsigned int)); + memcpy(model_name + 9 * sizeof(unsigned int), (char *) &ebx, sizeof(unsigned int)); + memcpy(model_name + 10 * sizeof(unsigned int), (char *) &ecx, sizeof(unsigned int)); + memcpy(model_name + 11 * sizeof(unsigned int), (char *) &edx, sizeof(unsigned int)); + } + + fprintf(m, + "processor : 0\n" + "vendor_id : %s\n" + "cpu family : %d\n" + "model : %d\n" + "model name : %s\n" + "stepping : %d\n", + vendor, family, model, model_name, stepping); + + fprintf(m, "flags :"); + for (index = 0; index < 32; index++) + { + if (features_edx[index] == NULL) + continue; + if (feature_edx & (1 << index)) + fprintf(m, " %s", features_edx[index]); + } + for (index = 0; index < 32; index++) + { + if (features_ecx[index] == NULL) + continue; + if (feature_ecx & (1 << index)) + fprintf(m, " %s", features_ecx[index]); + } + + fprintf(m, "\n\n"); + +out: + fclose(m); + return err; +} /* Glue logic and entries table */ @@ -888,6 +1008,13 @@ static const struct procfs_dir_entry rootdir_entries[] = { .cleanup_contents = procfs_cleanup_contents_with_free, }, }, + { + .name = "cpuinfo", + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_cpuinfo, + .cleanup_contents = procfs_cleanup_contents_with_free, + }, + }, #ifdef PROFILE /* In order to get a usable gmon.out file, we must apparently use exit(). */ { -- 2.45.2