/* * This file is part of the coreinfo project. * * It is derived from the x86info project, which is GPLv2-licensed. * * Copyright (C) 2001-2007 Dave Jones <davej@codemonkey.org.uk> * Copyright (C) 2008 Advanced Micro Devices, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "coreinfo.h" #if IS_ENABLED(CONFIG_MODULE_CPUINFO) #include <arch/rdtsc.h> #define VENDOR_INTEL 0x756e6547 #define VENDOR_AMD 0x68747541 #define VENDOR_CYRIX 0x69727943 #define VENDOR_IDT 0x746e6543 #define VENDOR_GEODE 0x646f6547 #define VENDOR_RISE 0x52697365 #define VENDOR_RISE2 0x65736952 #define VENDOR_SIS 0x20536953 /* CPUID 0x00000001 EDX flags */ static const char *generic_cap_flags[] = { "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "psn", "clflsh", NULL, "ds", "acpi", "mmx", "fxsr", "sse", "sse2", "ss", "ht", "tm", NULL, "pbe" }; /* CPUID 0x00000001 ECX flags */ static const char *intel_cap_generic_ecx_flags[] = { "sse3", NULL, NULL, "monitor", "ds-cpl", "vmx", NULL, "est", "tm2", "ssse3", "cntx-id", NULL, NULL, "cx16", "xTPR", NULL, NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /* CPUID 0x80000001 EDX flags */ static const char *intel_cap_extended_edx_flags[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "SYSCALL", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "xd", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "em64t", NULL, NULL, }; /* CPUID 0x80000001 ECX flags */ static const char *intel_cap_extended_ecx_flags[] = { "lahf_lm", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; static const char *amd_cap_generic_ecx_flags[] = { "sse3", NULL, NULL, "mwait", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "cmpxchg16b", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "popcnt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static const char *amd_cap_extended_edx_flags[] = { "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", NULL, "mp", "nx", NULL, "mmxext", "mmx", "fxsr", "ffxsr", "page1gb", "rdtscp", NULL, "lm", "3dnowext", "3dnow" }; /* "mp" defined for CPUs prior to AMD family 0xf */ static const char *amd_cap_extended_ecx_flags[] = { "lahf/sahf", "CmpLegacy", "svm", "ExtApicSpace", "LockMovCr0", "abm", "sse4a", "misalignsse", "3dnowPref", "osvw", "ibs", NULL, "skinit", "wdt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static unsigned long vendor; static unsigned int cpu_khz; static void decode_flags(WINDOW *win, unsigned long reg, const char **flags, int *row) { int i; int lrow = *row; wmove(win, lrow, 2); for (i = 0; i < 32; i++) { if (flags[i] == NULL) continue; if (reg & (1 << i)) wprintw(win, "%s ", flags[i]); if (i && (i % 16) == 0) { lrow++; wmove(win, lrow, 2); } } *row = lrow; } static void get_features(WINDOW *win, int *row) { unsigned long eax, ebx, ecx, edx; int lrow = *row; wmove(win, lrow++, 1); wprintw(win, "Features: "); docpuid(0x00000001, &eax, &ebx, &ecx, &edx); decode_flags(win, edx, generic_cap_flags, &lrow); lrow++; switch (vendor) { case VENDOR_AMD: wmove(win, lrow++, 1); wprintw(win, "AMD Extended Flags: "); decode_flags(win, ecx, amd_cap_generic_ecx_flags, &lrow); docpuid(0x80000001, &eax, &ebx, &ecx, &edx); decode_flags(win, edx, amd_cap_extended_edx_flags, &lrow); decode_flags(win, ecx, amd_cap_extended_ecx_flags, &lrow); break; case VENDOR_INTEL: wmove(win, lrow++, 1); wprintw(win, "Intel Extended Flags: "); decode_flags(win, ecx, intel_cap_generic_ecx_flags, &lrow); docpuid(0x80000001, &eax, &ebx, &ecx, &edx); decode_flags(win, edx, intel_cap_extended_edx_flags, &lrow); decode_flags(win, ecx, intel_cap_extended_ecx_flags, &lrow); break; } *row = lrow; } static void do_name(WINDOW *win, int row) { char name[49], *p; unsigned long eax, ebx, ecx, edx; int i, t; p = name; for (i = 0x80000002; i <= 0x80000004; i++) { docpuid(i, &eax, &ebx, &ecx, &edx); if (eax == 0) break; for (t = 0; t < 4; t++) *p++ = eax >> (8 * t); for (t = 0; t < 4; t++) *p++ = ebx >> (8 * t); for (t = 0; t < 4; t++) *p++ = ecx >> (8 * t); for (t = 0; t < 4; t++) *p++ = edx >> (8 * t); } mvwprintw(win, row, 1, "Processor: %s", name); } static int cpuinfo_module_redraw(WINDOW *win) { unsigned long eax, ebx, ecx, edx; unsigned int brand; char *vstr; int row = 2; print_module_title(win, "CPU Information"); docpuid(0, NULL, &vendor, NULL, NULL); switch (vendor) { case VENDOR_INTEL: vstr = "Intel"; break; case VENDOR_AMD: vstr = "AMD"; break; case VENDOR_CYRIX: vstr = "Cyrix"; break; case VENDOR_IDT: vstr = "IDT"; break; case VENDOR_GEODE: vstr = "NatSemi Geode"; break; case VENDOR_RISE: case VENDOR_RISE2: vstr = "RISE"; break; case VENDOR_SIS: vstr = "SiS"; break; default: vstr = "Unknown"; break; } mvwprintw(win, row++, 1, "Vendor: %s", vstr); do_name(win, row++); docpuid(0x00000001, &eax, &ebx, &ecx, &edx); mvwprintw(win, row++, 1, "Family: %X", (eax >> 8) & 0x0f); mvwprintw(win, row++, 1, "Model: %X", ((eax >> 4) & 0xf) | ((eax >> 16) & 0xf) << 4); mvwprintw(win, row++, 1, "Stepping: %X", eax & 0xf); if (vendor == VENDOR_AMD) { docpuid(0x80000001, &eax, &ebx, &ecx, &edx); brand = ((ebx >> 9) & 0x1f); mvwprintw(win, row++, 1, "Brand: %X", brand); } if (cpu_khz != 0) mvwprintw(win, row++, 1, "CPU Speed: %d Mhz", cpu_khz / 1000); else mvwprintw(win, row++, 1, "CPU Speed: Error"); row++; get_features(win, &row); return 0; } static unsigned int getticks(void) { unsigned long long start, end; /* Read the number of ticks during the period. */ start = rdtsc(); mdelay(100); end = rdtsc(); return (unsigned int)((end - start) / 100); } static int cpuinfo_module_init(void) { cpu_khz = getticks(); return 0; } struct coreinfo_module cpuinfo_module = { .name = "CPU Info", .init = cpuinfo_module_init, .redraw = cpuinfo_module_redraw, }; #else struct coreinfo_module cpuinfo_module = { }; #endif