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