#include #include #include #include #include #include #define CPUID_HTT 0x10000000 /* In cpuid 1, %ebx */ #define CPUID_HTT_CORES 0x00ff0000 /* AMD extended flags */ #define AMDID_LM 0x20000000 #define AMDID2_CMP 0x00000002 /* AMD 80000008 ecx */ #define AMDID_CMP_CORES 0x000000ff static void cpuid(u_int ax, u_int *p) { __asm __volatile("cpuid" : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) : "0" (ax)); } static void cpuid_count(u_int ax, u_int cx, u_int *p) { __asm __volatile("cpuid" : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) : "0" (ax), "c" (cx)); } u_int cpu_feature; /* Feature flags */ u_int cpu_feature2; /* Feature flags */ u_int amd_feature; /* AMD feature flags */ u_int amd_feature2; /* AMD feature flags */ u_int cpu_high; /* Highest arg to CPUID */ u_int cpu_exthigh; /* Highest arg to extended CPUID */ u_int cpu_id; /* Stepping ID */ u_int cpu_procinfo; /* HyperThreading Info / Brand Index / CLFUSH */ u_int cpu_procinfo2; /* Multicore info */ char cpu_vendor[20]; /* CPU Origin code */ char cpu_brand[48]; char cpu_model[128]; char machine_arch[16]; char * kbitflags(unsigned int num, char *p) { static char nbuf[256]; char *q; int tmp, n; sprintf(nbuf, "%x", num); if (num == 0) return (nbuf); p++; q = nbuf + strlen(nbuf); for (tmp = 0; *p;) { n = *p++; if (num & (1 << (n - 1))) { *q++ = (tmp ? ',' : '<'); for (; (n = *p) > ' '; ++p) *q++ = (n); tmp = 1; } else for (; *p > ' '; ++p) continue; } if (tmp) *q++ = ('>'); *q++ = '\0'; return (nbuf); } int main(int ac, char *av[]) { u_int regs[4]; char *brand; int i, c; size_t s; int qflag = 0; while ((c = getopt(ac, av, "q")) != -1) { switch(c) { case 'q': freopen("/dev/null", "w", stdout); qflag++; break; case '?': fprintf(stderr, "usage: %s [-q]\n", av[0]); fprintf(stderr, "If -q is set, returns true (0) for 64 bit cpus, otherwise false\n"); fprintf(stderr, "use with 'if' in shell scripts. -q produces no stdout.\n"); exit(1); } } cpuid(0, regs); cpu_high = regs[0]; ((u_int *)&cpu_vendor)[0] = regs[1]; ((u_int *)&cpu_vendor)[1] = regs[3]; ((u_int *)&cpu_vendor)[2] = regs[2]; cpu_vendor[12] = '\0'; cpuid(1, regs); cpu_id = regs[0]; /* Step, family, model etc */ cpu_procinfo = regs[1]; cpu_feature = regs[3]; cpu_feature2 = regs[2]; if (strcmp(cpu_vendor, "GenuineIntel") == 0 || strcmp(cpu_vendor, "AuthenticAMD") == 0) { cpuid(0x80000000, regs); cpu_exthigh = regs[0]; } if (cpu_exthigh >= 0x80000001) { cpuid(0x80000001, regs); amd_feature = regs[3] & ~(cpu_feature & 0x0183f3ff); amd_feature2 = regs[2]; } if (cpu_exthigh >= 0x80000008) { cpuid(0x80000008, regs); cpu_procinfo2 = regs[2]; } strcpy(cpu_model, "x86"); if (cpu_exthigh >= 0x80000004) { brand = cpu_brand; for (i = 0x80000002; i < 0x80000005; i++) { cpuid(i, regs); memcpy(brand, regs, sizeof(regs)); brand += sizeof(regs); } } if (strcmp(cpu_vendor, "GenuineIntel") == 0) { strcpy(cpu_model, "Old Intel"); } else if (strcmp(cpu_vendor, "AuthenticAMD") == 0) { strcpy(cpu_model, "Old AMD"); } else { strcpy(cpu_model, "Unknown"); } /* Replace the brand with the one the cpu self identifies with */ brand = cpu_brand; while (*brand == ' ') ++brand; if (*brand != '\0') strcpy(cpu_model, brand); printf("CPU: %s\n", cpu_model); if (*cpu_vendor) printf("Origin=\"%s\"\n", cpu_vendor); if (cpu_id) printf("Id=0x%x\n", cpu_id); if (strcmp(cpu_vendor, "GenuineIntel") == 0 || strcmp(cpu_vendor, "AuthenticAMD") == 0) { printf("Stepping = %u\n", cpu_id & 0xf); if (cpu_high > 0) { u_int cmp = 1, htt = 1; printf("Features=0x%s\n", kbitflags(cpu_feature, "\020" "\001FPU" /* Integral FPU */ "\002VME" /* Extended VM86 mode support */ "\003DE" /* Debugging Extensions (CR4.DE) */ "\004PSE" /* 4MByte page tables */ "\005TSC" /* Timestamp counter */ "\006MSR" /* Machine specific registers */ "\007PAE" /* Physical address extension */ "\010MCE" /* Machine Check support */ "\011CX8" /* CMPEXCH8 instruction */ "\012APIC" /* SMP local APIC */ "\013oldMTRR" /* Previous implementation of MTRR */ "\014SEP" /* Fast System Call */ "\015MTRR" /* Memory Type Range Registers */ "\016PGE" /* PG_G (global bit) support */ "\017MCA" /* Machine Check Architecture */ "\020CMOV" /* CMOV instruction */ "\021PAT" /* Page attributes table */ "\022PSE36" /* 36 bit address space support */ "\023PN" /* Processor Serial number */ "\024CLFLUSH" /* Has the CLFLUSH instruction */ "\025" "\026DTS" /* Debug Trace Store */ "\027ACPI" /* ACPI support */ "\030MMX" /* MMX instructions */ "\031FXSR" /* FXSAVE/FXRSTOR */ "\032SSE" /* Streaming SIMD Extensions */ "\033SSE2" /* Streaming SIMD Extensions #2 */ "\034SS" /* Self snoop */ "\035HTT" /* Hyperthreading (see EBX bit 16-23) */ "\036TM" /* Thermal Monitor clock slowdown */ "\037IA64" /* CPU can execute IA64 instructions */ "\040PBE" /* Pending Break Enable */ )); if (cpu_feature2 != 0) { printf("Features2=0x%s\n", kbitflags(cpu_feature2, "\020" "\001SSE3" /* SSE3 */ "\002" "\003RSVD2" /* "Reserved" bit 2 */ "\004MON" /* MONITOR/MWAIT Instructions */ "\005DS_CPL" /* CPL Qualified Debug Store */ "\006VMX" /* Virtual Machine Extensions */ "\007SMX" /* Safer Mode Extensions */ "\010EST" /* Enhanced SpeedStep */ "\011TM2" /* Thermal Monitor 2 */ "\012SSSE3" /* SSSE3 */ "\013CNXT-ID" /* L1 context ID available */ "\014" "\015" "\016CX16" /* CMPXCHG16B Instruction */ "\017xTPR" /* Send Task Priority Messages*/ "\020PDCM" /* Perf/Debug Capability MSR */ "\021" "\022" "\023DCA" /* Direct Cache Access */ "\024" "\025" "\026" "\027" "\030" "\031" "\032" "\033" "\034" "\035" "\036" "\037" "\040" )); } /* * AMD64 Architecture Programmer's Manual Volume 3: * General-Purpose and System Instructions * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf * * IA-32 Intel Architecture Software Developer's Manual, * Volume 2A: Instruction Set Reference, A-M * ftp://download.intel.com/design/Pentium4/manuals/25366617.pdf */ if (amd_feature != 0) { printf("AMD Features=0x%s\n", kbitflags(amd_feature, "\020" /* in hex */ "\001" /* Same */ "\002" /* Same */ "\003" /* Same */ "\004" /* Same */ "\005" /* Same */ "\006" /* Same */ "\007" /* Same */ "\010" /* Same */ "\011" /* Same */ "\012" /* Same */ "\013" /* Undefined */ "\014SYSCALL" /* Have SYSCALL/SYSRET */ "\015" /* Same */ "\016" /* Same */ "\017" /* Same */ "\020" /* Same */ "\021" /* Same */ "\022" /* Same */ "\023" /* Reserved, unknown */ "\024MP" /* Multiprocessor Capable */ "\025NX" /* Has EFER.NXE, NX */ "\026" /* Undefined */ "\027MMX+" /* AMD MMX Extensions */ "\030" /* Same */ "\031" /* Same */ "\032FFXSR" /* Fast FXSAVE/FXRSTOR */ "\033Page1GB" /* 1-GB large page support */ "\034RDTSCP" /* RDTSCP */ "\035" /* Undefined */ "\036LM" /* 64 bit long mode */ "\0373DNow!+" /* AMD 3DNow! Extensions */ "\0403DNow!" /* AMD 3DNow! */ )); } if (amd_feature2 != 0) { printf("AMD Features2=0x%s\n", kbitflags(amd_feature2, "\020" "\001LAHF" /* LAHF/SAHF in long mode */ "\002CMP" /* CMP legacy */ "\003SVM" /* Secure Virtual Mode */ "\004ExtAPIC" /* Extended APIC register */ "\005CR8" /* CR8 in legacy mode */ "\006" "\007" "\010" "\011Prefetch" /* 3DNow! Prefetch/PrefetchW */ "\012" "\013" "\014" "\015" "\016" "\017" "\020" "\021" "\022" "\023" "\024" "\025" "\026" "\027" "\030" "\031" "\032" "\033" "\034" "\035" "\036" "\037" "\040" )); } if (cpu_feature & CPUID_HTT && strcmp(cpu_vendor, "AuthenticAMD") == 0) cpu_feature &= ~CPUID_HTT; /* * If this CPU supports HTT or CMP then mention the * number of physical/logical cores it contains. */ if (cpu_feature & CPUID_HTT) htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16; if (strcmp(cpu_vendor, "AuthenticAMD") == 0 && (amd_feature2 & AMDID2_CMP)) cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1; else if (strcmp(cpu_vendor, "GenuineIntel") == 0 && (cpu_high >= 4)) { cpuid_count(4, 0, regs); if ((regs[0] & 0x1f) != 0) cmp = ((regs[0] >> 26) & 0x3f) + 1; } if (cmp > 1) printf("Cores per package: %d\n", cmp); if ((htt / cmp) > 1) printf("Logical CPUs per core: %d\n", htt / cmp); printf("64 bit capable: %s\n", (amd_feature & AMDID_LM) ? "Yes" : "No"); s = sizeof(machine_arch); machine_arch[0] = '\0'; sysctlbyname("hw.machine_arch", machine_arch, &s, NULL, 0); printf("64 bit OS: %s\n", strcmp(machine_arch, "amd64") == 0 ? "Yes" : "No"); } } if (qflag) { if (amd_feature & AMDID_LM) exit(0); else exit(1); } exit(0); }