cpuinfo_module.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 /* It is derived from the x86info project, which is GPLv2-licensed. */ 4 5 #include "coreinfo.h" 6 7 #if CONFIG(MODULE_CPUINFO) 8 #include <arch/rdtsc.h> 9 10 #define VENDOR_INTEL 0x756e6547 11 #define VENDOR_AMD 0x68747541 12 #define VENDOR_CYRIX 0x69727943 13 #define VENDOR_IDT 0x746e6543 14 #define VENDOR_GEODE 0x646f6547 15 #define VENDOR_RISE 0x52697365 16 #define VENDOR_RISE2 0x65736952 17 #define VENDOR_SIS 0x20536953 18 19 /* CPUID 0x00000001 EDX flags */ 20 static const char *generic_cap_flags[] = { 21 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", 22 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", 23 "pat", "pse36", "psn", "clflsh", NULL, "ds", "acpi", "mmx", 24 "fxsr", "sse", "sse2", "ss", "ht", "tm", NULL, "pbe" 25 }; 26 27 /* CPUID 0x00000001 ECX flags */ 28 static const char *intel_cap_generic_ecx_flags[] = { 29 "sse3", NULL, NULL, "monitor", "ds-cpl", "vmx", NULL, "est", 30 "tm2", "ssse3", "cntx-id", NULL, NULL, "cx16", "xTPR", NULL, 31 NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL, 32 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 33 }; 34 35 /* CPUID 0x80000001 EDX flags */ 36 static const char *intel_cap_extended_edx_flags[] = { 37 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 38 NULL, NULL, NULL, "SYSCALL", NULL, NULL, NULL, NULL, 39 NULL, NULL, NULL, NULL, "xd", NULL, NULL, NULL, 40 NULL, NULL, NULL, NULL, NULL, "em64t", NULL, NULL, 41 }; 42 43 /* CPUID 0x80000001 ECX flags */ 44 static const char *intel_cap_extended_ecx_flags[] = { 45 "lahf_lm", NULL, NULL, NULL, NULL, NULL, NULL, NULL, 46 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 47 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 48 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 49 }; 50 51 static const char *amd_cap_generic_ecx_flags[] = { 52 "sse3", NULL, NULL, "mwait", NULL, NULL, NULL, NULL, 53 NULL, NULL, NULL, NULL, NULL, "cmpxchg16b", NULL, NULL, 54 NULL, NULL, NULL, NULL, NULL, NULL, NULL, "popcnt", 55 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 56 }; 57 58 static const char *amd_cap_extended_edx_flags[] = { 59 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", 60 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", 61 "pat", "pse36", NULL, "mp", "nx", NULL, "mmxext", "mmx", 62 "fxsr", "ffxsr", "page1gb", "rdtscp", 63 NULL, "lm", "3dnowext", "3dnow" 64 }; /* "mp" defined for CPUs prior to AMD family 0xf */ 65 66 static const char *amd_cap_extended_ecx_flags[] = { 67 "lahf/sahf", "CmpLegacy", "svm", "ExtApicSpace", 68 "LockMovCr0", "abm", "sse4a", "misalignsse", 69 "3dnowPref", "osvw", "ibs", NULL, "skinit", "wdt", NULL, NULL, 70 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 71 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 72 }; 73 74 static uint32_t vendor; 75 static unsigned int cpu_khz; 76 77 static void decode_flags(WINDOW *win, unsigned long reg, const char **flags, 78 int *row) 79 { 80 int i; 81 int lrow = *row; 82 83 wmove(win, lrow, 2); 84 85 for (i = 0; i < 32; i++) { 86 if (flags[i] == NULL) 87 continue; 88 89 if (reg & (1 << i)) 90 wprintw(win, "%s ", flags[i]); 91 92 if (i && (i % 16) == 0) { 93 lrow++; 94 wmove(win, lrow, 2); 95 } 96 } 97 98 *row = lrow; 99 } 100 101 static void get_features(WINDOW *win, int *row) 102 { 103 uint32_t eax, ebx, ecx, edx; 104 int lrow = *row; 105 106 wmove(win, lrow++, 1); 107 wprintw(win, "Features: "); 108 109 docpuid(0x00000001, &eax, &ebx, &ecx, &edx); 110 decode_flags(win, edx, generic_cap_flags, &lrow); 111 112 lrow++; 113 114 switch (vendor) { 115 case VENDOR_AMD: 116 wmove(win, lrow++, 1); 117 wprintw(win, "AMD Extended Flags: "); 118 decode_flags(win, ecx, amd_cap_generic_ecx_flags, &lrow); 119 docpuid(0x80000001, &eax, &ebx, &ecx, &edx); 120 decode_flags(win, edx, amd_cap_extended_edx_flags, &lrow); 121 decode_flags(win, ecx, amd_cap_extended_ecx_flags, &lrow); 122 break; 123 case VENDOR_INTEL: 124 wmove(win, lrow++, 1); 125 wprintw(win, "Intel Extended Flags: "); 126 decode_flags(win, ecx, intel_cap_generic_ecx_flags, &lrow); 127 docpuid(0x80000001, &eax, &ebx, &ecx, &edx); 128 decode_flags(win, edx, intel_cap_extended_edx_flags, &lrow); 129 decode_flags(win, ecx, intel_cap_extended_ecx_flags, &lrow); 130 break; 131 } 132 133 *row = lrow; 134 } 135 136 static void do_name(WINDOW *win, int row) 137 { 138 char name[49], *p; 139 uint32_t eax, ebx, ecx, edx; 140 int t; 141 142 p = name; 143 144 for (uint32_t i = 0x80000002; i <= 0x80000004; i++) { 145 docpuid(i, &eax, &ebx, &ecx, &edx); 146 147 if (eax == 0) 148 break; 149 150 for (t = 0; t < 4; t++) 151 *p++ = eax >> (8 * t); 152 for (t = 0; t < 4; t++) 153 *p++ = ebx >> (8 * t); 154 for (t = 0; t < 4; t++) 155 *p++ = ecx >> (8 * t); 156 for (t = 0; t < 4; t++) 157 *p++ = edx >> (8 * t); 158 } 159 160 mvwprintw(win, row, 1, "Processor: %s", name); 161 } 162 163 static int cpuinfo_module_redraw(WINDOW *win) 164 { 165 uint32_t eax, ebx, ecx, edx; 166 unsigned int brand; 167 char *vstr; 168 int row = 2; 169 170 print_module_title(win, "CPU Information"); 171 172 docpuid(0, NULL, &vendor, NULL, NULL); 173 174 switch (vendor) { 175 case VENDOR_INTEL: 176 vstr = "Intel"; 177 break; 178 case VENDOR_AMD: 179 vstr = "AMD"; 180 break; 181 case VENDOR_CYRIX: 182 vstr = "Cyrix"; 183 break; 184 case VENDOR_IDT: 185 vstr = "IDT"; 186 break; 187 case VENDOR_GEODE: 188 vstr = "NatSemi Geode"; 189 break; 190 case VENDOR_RISE: 191 case VENDOR_RISE2: 192 vstr = "RISE"; 193 break; 194 case VENDOR_SIS: 195 vstr = "SiS"; 196 break; 197 default: 198 vstr = "Unknown"; 199 break; 200 } 201 202 mvwprintw(win, row++, 1, "Vendor: %s", vstr); 203 204 do_name(win, row++); 205 206 docpuid(0x00000001, &eax, &ebx, &ecx, &edx); 207 208 mvwprintw(win, row++, 1, "Family: %X", (eax >> 8) & 0x0f); 209 mvwprintw(win, row++, 1, "Model: %X", 210 ((eax >> 4) & 0xf) | ((eax >> 16) & 0xf) << 4); 211 212 mvwprintw(win, row++, 1, "Stepping: %X", eax & 0xf); 213 214 if (vendor == VENDOR_AMD) { 215 docpuid(0x80000001, &eax, &ebx, &ecx, &edx); 216 brand = ((ebx >> 9) & 0x1f); 217 218 mvwprintw(win, row++, 1, "Brand: %X", brand); 219 } 220 221 if (cpu_khz != 0) 222 mvwprintw(win, row++, 1, "CPU Speed: %d MHz", cpu_khz / 1000); 223 else 224 mvwprintw(win, row++, 1, "CPU Speed: Error"); 225 226 row++; 227 get_features(win, &row); 228 229 return 0; 230 } 231 232 static unsigned int getticks(void) 233 { 234 unsigned long long start, end; 235 236 /* Read the number of ticks during the period. */ 237 start = rdtsc(); 238 mdelay(100); 239 end = rdtsc(); 240 241 return (unsigned int)((end - start) / 100); 242 } 243 244 static int cpuinfo_module_init(void) 245 { 246 cpu_khz = getticks(); 247 return 0; 248 } 249 250 struct coreinfo_module cpuinfo_module = { 251 .name = "CPU Info", 252 .init = cpuinfo_module_init, 253 .redraw = cpuinfo_module_redraw, 254 }; 255 256 #else 257 258 struct coreinfo_module cpuinfo_module = { 259 }; 260 261 #endif