2 * (C) 2000, 2001 Dave Jones.
3 * Fixes by Arjan van de Ven (arjanv@redhat.com) and
4 * Philipp Rumpf (prumpf@mandrakesoft.com)
6 * Licensed under the terms of the GNU GPL License version 2.
8 * Routines for retrieving cpuid registers.
11 #define _LARGEFILE64_SOURCE
18 #include <sys/types.h>
25 #if defined(__FreeBSD__)
26 # include <sys/ioctl.h>
33 * sched_* calls weren't stable until 2.3.4
34 * AFAIK, there's no macro to check for the .4, so we just
35 * check for the next minor version up. (2.4)
38 #if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 4
39 #error Need at least glibc 2.4
43 /* returns zero on success */
44 static int native_cpuid(unsigned int cpunr, unsigned long long idx,
45 unsigned int *eax, unsigned int *ebx,
46 unsigned int *ecx, unsigned int *edx)
48 cpu_set_t set, tmp_set;
49 unsigned int a = 0, b = 0, c = 0, d = 0;
61 ret = sched_getaffinity(getpid(), sizeof(set), &set);
65 /* man CPU_SET(3): To duplicate a CPU set, use memcpy(3) */
66 memcpy(&tmp_set, &set, sizeof(cpu_set_t));
69 ret = sched_setaffinity(getpid(), sizeof(set), &set);
78 : "0" ((unsigned int)idx));
89 /* Restore initial sched affinity */
90 ret = sched_setaffinity(getpid(), sizeof(tmp_set), &tmp_set);
96 static const char *NATIVE_CPUID_FAILED_MSG = "WARNING: Native cpuid failed\n";
98 #if defined(__FreeBSD__)
99 void cpuid(unsigned int CPU_number, unsigned long long idx,
105 static int nodriver=0;
107 unsigned char buffer[16];
109 cpu_cpuid_args_t args;
112 if (native_cpuid(CPU_number, idx, eax,ebx,ecx,edx))
113 printf("%s", NATIVE_CPUID_FAILED_MSG);
118 /* Ok, use the /dev/CPU interface in preference to the _up code. */
119 (void)snprintf(cpuname,18, "/dev/cpu%d", CPU_number);
120 fh = open(cpuname, O_RDONLY);
122 if (ioctl(fh, CPU_CPUID, &args) != 0) {
126 if (eax!=0) *eax = args.data[0];
127 if (ebx!=0) *ebx = args.data[1];
128 if (ecx!=0) *ecx = args.data[2];
129 if (edx!=0) *edx = args.data[3];
130 if (close(fh) == -1) {
135 /* Something went wrong, just do UP and hope for the best. */
139 if (native_cpuid(CPU_number, idx, eax,ebx,ecx,edx))
140 printf("%s", NATIVE_CPUID_FAILED_MSG);
146 #else /* !__FreeBSD__ */
148 /* Kernel CPUID driver's minimum supported read size
149 * (see linux/arch/i386/kernel/cpuid.c)
151 #define CPUID_CHUNK_SIZE (16)
153 void cpuid(unsigned int CPU_number, unsigned long long idx,
159 static int nodriver=0;
161 unsigned char buffer[CPUID_CHUNK_SIZE];
162 unsigned int *ptr = (unsigned int *)buffer;
166 *eax = (unsigned int) idx;
172 if (native_cpuid(CPU_number, idx, eax,ebx,ecx,edx))
173 printf("%s", NATIVE_CPUID_FAILED_MSG);
177 memset(cpuname, 0, sizeof(cpuname));
179 /* Solaris doesn't (yet) have per-CPU interface */
180 (void)snprintf(cpuname, sizeof(cpuname), "/dev/cpu/self/cpuid");
182 /* Ok, use the /dev/cpu interface in preference to the _up code. */
183 (void)snprintf(cpuname, sizeof(cpuname), "/dev/cpu/%d/cpuid", CPU_number);
185 fh = open(cpuname, O_RDONLY);
188 lseek64(fh, (off64_t)idx, SEEK_CUR);
190 if (read(fh, &buffer[0], CPUID_CHUNK_SIZE) == -1) {
194 if (eax!=0) *eax = *ptr;
195 if (ebx!=0) *ebx = *(++ptr);
196 if (ecx!=0) *ecx = *(++ptr);
197 if (edx!=0) *edx = *(++ptr);
198 if (close(fh) == -1) {
203 /* Something went wrong, just do UP and hope for the best. */
205 if (native_cpuid(CPU_number, idx, eax,ebx,ecx,edx))
206 printf("%s", NATIVE_CPUID_FAILED_MSG);
211 #endif /* __FreeBSD__ */
213 void cpuid4(unsigned int CPU_number, unsigned long long idx,
214 unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
216 cpuid(CPU_number, 4 | (idx << 32), eax, ebx, ecx, edx);
219 /* Some CPUID calls want 'count' to be placed in ecx */
220 void cpuid_count(unsigned int CPU_number, unsigned int op, int count,
221 unsigned int *eax, unsigned int *ebx,
222 unsigned int *ecx, unsigned int *edx)
225 cpuid(CPU_number, op, eax, ebx, ecx, edx);
228 unsigned int cpuid_ebx(unsigned int CPU_number, unsigned int op)
230 unsigned int eax, ebx, ecx, edx;
232 cpuid(CPU_number, op, &eax, &ebx, &ecx, &edx);
238 void dump_raw_cpuid(int cpunum, unsigned int begin, unsigned int end)
241 unsigned int eax, ebx, ecx, edx;
243 /* Dump all the CPUID results in raw hex */
244 for (i = begin; i <= end; i++) {
245 cpuid(cpunum, i, &eax, &ebx, &ecx, &edx);
246 printf("eax in: 0x%08x, eax = %08x ebx = %08x ecx = %08x edx = %08x\n", i, eax, ebx, ecx, edx);