1 /* $OpenBSD: cpuprobe.c,v 1.2 2014/03/29 18:09:29 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Tom Cosgrove <tom.cosgrove@arches-consulting.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <machine/psl.h> 20 #include <machine/specialreg.h> 21 22 #include "libsa.h" 23 24 int amd64_supported; 25 static int cpu_family, cpu_model, cpu_stepping; 26 static int psl_check; 27 static u_int32_t feature_ecx, feature_edx, feature_amd; 28 static char cpu_brandstr[48]; /* Includes term NUL byte */ 29 static char cpu_vendor[13]; /* 12 chars plus NUL term */ 30 31 /* 32 * cpuid instruction. request in eax, result in eax, ebx, ecx, edx. 33 * requires caller to provide u_int32_t regs[4] array. 34 */ 35 u_int32_t 36 cpuid(u_int32_t eax, u_int32_t *regs) 37 { 38 __asm volatile( 39 "cpuid\n\t" 40 "movl %%eax, 0(%2)\n\t" 41 "movl %%ebx, 4(%2)\n\t" 42 "movl %%ecx, 8(%2)\n\t" 43 "movl %%edx, 12(%2)\n\t" 44 : "=a" (eax) 45 : "0" (eax), "S" (regs) 46 : "bx", "cx", "dx"); 47 48 return eax; 49 } 50 51 void 52 cpuprobe(void) 53 { 54 u_int32_t cpuid_max, extended_max; 55 u_int32_t regs[4]; 56 57 /* 58 * The following is a simple check to see if cpuid is supported. 59 * We try to toggle bit 21 (PSL_ID) in eflags. If it works, then 60 * cpuid is supported. If not, there's no cpuid, and we don't 61 * try it (don't want /boot to get an invalid opcode exception). 62 * 63 * XXX The NexGen Nx586 does not support this bit, so this is not 64 * a good method to detect the presence of cpuid on this 65 * processor. That's fine: the purpose here is to detect the 66 * absence of cpuid. We don't mind if the instruction's not 67 * there - this is not intended to determine exactly what 68 * processor is there, just whether it's i386 or amd64. 69 * 70 * The only thing that would cause us grief is a processor which 71 * does not support cpuid but which does allow the PSL_ID bit 72 * in eflags to be toggled. 73 */ 74 __asm volatile( 75 "pushfl\n\t" 76 "popl %2\n\t" 77 "xorl %2, %0\n\t" 78 "pushl %0\n\t" 79 "popfl\n\t" 80 "pushfl\n\t" 81 "popl %0\n\t" 82 "xorl %2, %0\n\t" /* If %2 == %0, no cpuid */ 83 : "=r" (psl_check) 84 : "0" (PSL_ID), "r" (0) 85 : "cc"); 86 87 if (psl_check == PSL_ID) { /* cpuid supported */ 88 cpuid_max = cpuid(0, regs); /* Highest std call */ 89 90 bcopy(®s[1], cpu_vendor, sizeof(regs[1])); 91 bcopy(®s[3], cpu_vendor + 4, sizeof(regs[3])); 92 bcopy(®s[2], cpu_vendor + 8, sizeof(regs[2])); 93 cpu_vendor[sizeof(cpu_vendor) - 1] = '\0'; 94 95 if (cpuid_max >= 1) { 96 u_int32_t id; 97 98 id = cpuid(1, regs); /* Get basic info */ 99 cpu_stepping = id & 0x000000f; 100 cpu_model = (id >> 4) & 0x0000000f; 101 cpu_family = (id >> 8) & 0x0000000f; 102 103 feature_ecx = regs[2]; 104 feature_edx = regs[3]; 105 } 106 107 extended_max = cpuid(0x80000000, regs); /* Highest ext */ 108 109 if (extended_max >= 0x80000001) { 110 cpuid(0x80000001, regs); 111 feature_amd = regs[3]; 112 if (feature_amd & CPUID_LONG) 113 amd64_supported = 1; 114 } 115 116 cpu_brandstr[0] = '\0'; 117 if (extended_max >= 0x80000004) { 118 u_int32_t brand_ints[12]; 119 120 cpuid(0x80000002, brand_ints); 121 cpuid(0x80000003, brand_ints + 4); 122 cpuid(0x80000004, brand_ints + 8); 123 124 bcopy(brand_ints, cpu_brandstr, 125 sizeof(cpu_brandstr) - 1); 126 127 cpu_brandstr[sizeof(cpu_brandstr) - 1] = '\0'; 128 } 129 } 130 131 printf("%s", amd64_supported ? " amd64" : " i386"); 132 } 133 134 void 135 dump_cpuinfo(void) 136 { 137 printf("\"%s\", family %d, model %d, step %d\n", 138 cpu_vendor, cpu_family, cpu_model, cpu_stepping); 139 140 if (*cpu_brandstr) 141 printf("%s\n", cpu_brandstr); 142 143 printf("features: ecx 0x%x, edx 0x%x, amd 0x%x\n", 144 feature_ecx, feature_edx, feature_amd); 145 146 printf("psl_check: 0x%x\n", psl_check); 147 } 148