/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * i386 CPU detection routines, by Phil Frisbie. * * Theuzifan improved the support for Cyrix chips. * * Calin Andrian added 3DNow! detection code. * * See readme.txt for copyright information. */ #include "asmdefs.inc" .text /* int _i_is_486(); * Returns TRUE for 486+, and FALSE for 386. */ FUNC(_i_is_486) pushl %ebp movl %esp, %ebp pushf /* save EFLAGS */ popl %eax /* get EFLAGS */ movl %eax, %edx /* temp storage EFLAGS */ xorl $0x40000, %eax /* change AC bit in EFLAGS */ pushl %eax /* put new EFLAGS value on stack */ popf /* replace current EFLAGS value */ pushf /* get EFLAGS */ popl %eax /* save new EFLAGS in EAX */ cmpl %edx, %eax /* compare temp and new EFLAGS */ jz is406_not_found movl $1, %eax /* 80486 present */ jmp is486_done is406_not_found: movl $0, %eax /* 80486 not present */ is486_done: pushl %edx /* get original EFLAGS */ popf /* restore EFLAGS */ popl %ebp ret /* int _i_is_fpu(); * Returns TRUE is the CPU has floating point hardware. */ FUNC(_i_is_fpu) pushl %ebp movl %esp, %ebp fninit movl $0x5A5A, %eax fnstsw %eax cmpl $0, %eax jne is_fpu_not_found movl $1, %eax jmp is_fpu_done is_fpu_not_found: movl $0, %eax is_fpu_done: popl %ebp ret /* int _i_is_cyrix(); * Returns TRUE if this is a Cyrix processor. */ FUNC(_i_is_cyrix) pushl %ebp movl %esp, %ebp xorw %ax, %ax /* clear eax */ sahf /* bit 1 is always 1 in flags */ movw $5, %ax movw $2, %dx div %dl /* this does not change flags */ lahf /* get flags */ cmpb $2, %ah /* check for change in flags */ jne is_cyrix_not_found movl $1, %eax /* TRUE Cyrix CPU */ jmp is_cyrix_done is_cyrix_not_found: movl $0, %eax /* FALSE NON-Cyrix CPU */ is_cyrix_done: popl %ebp ret /* void _i_cx_w(int index, int value); * Writes to a Cyrix register. */ FUNC(_i_cx_w) pushl %ebp movl %esp, %ebp cli movb ARG1, %al outb %al, $0x22 movb ARG2, %al outb %al, $0x23 sti popl %ebp ret /* char _i_cx_r(int index); * Reads from a Cyrix register. */ FUNC(_i_cx_r) pushl %ebp movl %esp, %ebp cli movb ARG1, %al outb %al, $0x22 xorl %eax, %eax inb $0x23, %al sti popl %ebp ret /* int _i_is_cpuid_supported(); * Checks whether the cpuid instruction is available. */ FUNC(_i_is_cpuid_supported) pushl %ebp movl %esp, %ebp pushfl /* get extended flags */ popl %eax movl %eax, %edx /* save current flags */ xorl $0x200000, %eax /* toggle bit 21 */ pushl %eax /* put new flags on stack */ popfl /* flags updated now in flags */ pushfl /* get extended flags */ popl %eax xorl %edx, %eax /* if bit 21 r/w then supports cpuid */ jz cpuid_not_found movl $1, %eax jmp cpuid_done cpuid_not_found: movl $0, %eax cpuid_done: popl %ebp ret /* void _i_get_cpuid_info(uint32_t cpuid_levels, uint32_t *reg); * This is so easy! */ FUNC(_i_get_cpuid_info) pushl %ebp movl %esp, %ebp pushl %ebx pushl %ecx pushl %edi movl ARG1, %eax /* eax = cpuid_levels */ .byte 0x0F, 0xA2 /* cpuid instruction */ movl ARG2, %edi /* edi = reg */ movl %eax, (%edi) /* store results */ movl %ebx, 4(%edi) movl %ecx, 8(%edi) movl %edx, 12(%edi) popl %edi popl %ecx popl %ebx popl %ebp ret