1 /* $OpenBSD: cpuprobe.c,v 1.3 2022/07/07 00:56:46 daniel 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
cpuid(u_int32_t eax,u_int32_t * regs)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
cpuprobe(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 __asm volatile(
64 "pushfl\n\t"
65 "popl %2\n\t"
66 "xorl %2, %0\n\t"
67 "pushl %0\n\t"
68 "popfl\n\t"
69 "pushfl\n\t"
70 "popl %0\n\t"
71 "xorl %2, %0\n\t" /* If %2 == %0, no cpuid */
72 : "=r" (psl_check)
73 : "0" (PSL_ID), "r" (0)
74 : "cc");
75
76 if (psl_check == PSL_ID) { /* cpuid supported */
77 cpuid_max = cpuid(0, regs); /* Highest std call */
78
79 bcopy(®s[1], cpu_vendor, sizeof(regs[1]));
80 bcopy(®s[3], cpu_vendor + 4, sizeof(regs[3]));
81 bcopy(®s[2], cpu_vendor + 8, sizeof(regs[2]));
82 cpu_vendor[sizeof(cpu_vendor) - 1] = '\0';
83
84 if (cpuid_max >= 1) {
85 u_int32_t id;
86
87 id = cpuid(1, regs); /* Get basic info */
88 cpu_stepping = id & 0x000000f;
89 cpu_model = (id >> 4) & 0x0000000f;
90 cpu_family = (id >> 8) & 0x0000000f;
91
92 feature_ecx = regs[2];
93 feature_edx = regs[3];
94 }
95
96 extended_max = cpuid(0x80000000, regs); /* Highest ext */
97
98 if (extended_max >= 0x80000001) {
99 cpuid(0x80000001, regs);
100 feature_amd = regs[3];
101 if (feature_amd & CPUID_LONG)
102 amd64_supported = 1;
103 }
104
105 cpu_brandstr[0] = '\0';
106 if (extended_max >= 0x80000004) {
107 u_int32_t brand_ints[12];
108
109 cpuid(0x80000002, brand_ints);
110 cpuid(0x80000003, brand_ints + 4);
111 cpuid(0x80000004, brand_ints + 8);
112
113 bcopy(brand_ints, cpu_brandstr,
114 sizeof(cpu_brandstr) - 1);
115
116 cpu_brandstr[sizeof(cpu_brandstr) - 1] = '\0';
117 }
118 }
119
120 printf("%s", amd64_supported ? " amd64" : " i386");
121 }
122
123 void
dump_cpuinfo(void)124 dump_cpuinfo(void)
125 {
126 printf("\"%s\", family %d, model %d, step %d\n",
127 cpu_vendor, cpu_family, cpu_model, cpu_stepping);
128
129 if (*cpu_brandstr)
130 printf("%s\n", cpu_brandstr);
131
132 printf("features: ecx 0x%x, edx 0x%x, amd 0x%x\n",
133 feature_ecx, feature_edx, feature_amd);
134
135 printf("psl_check: 0x%x\n", psl_check);
136 }
137