/ payloads / coreinfo / cpuinfo_module.c
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