Annotation of sys/arch/i386/stand/libsa/cpuprobe.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cpuprobe.c,v 1.1 2004/06/26 05:19:37 tom 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: }
CVSweb