Annotation of sys/arch/i386/stand/libsa/cpuprobe.c, Revision 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