|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
getcpucpuflags: get cpuflags for ia32
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
|
Packit |
c32a2d |
see COPYING and AUTHORS files in distribution or http:#mpg123.org
|
|
Packit |
c32a2d |
initially written by KIMURA Takuhiro (for 3DNow!)
|
|
Packit |
c32a2d |
extended for general use by Thomas Orgis
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
extern int getcpuid(struct cpuflags*)
|
|
Packit |
c32a2d |
or just
|
|
Packit |
c32a2d |
extern int getcpuid(unsigned int*)
|
|
Packit |
c32a2d |
where there is memory for 4 ints
|
|
Packit |
c32a2d |
-> the first set of idflags (basic cpu family info)
|
|
Packit |
c32a2d |
and the idflags, stdflags, std2flags, extflags written to the parameter
|
|
Packit |
c32a2d |
-> 0x00000000 (CPUID instruction not supported)
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#include "mangle.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
.text
|
|
Packit |
c32a2d |
ALIGN4
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
.globl ASM_NAME(getcpuflags)
|
|
Packit |
c32a2d |
/* .type ASM_NAME(getcpuflags),@function */
|
|
Packit |
c32a2d |
ASM_NAME(getcpuflags):
|
|
Packit |
c32a2d |
pushl %ebp
|
|
Packit |
c32a2d |
movl %esp,%ebp
|
|
Packit |
c32a2d |
pushl %edx
|
|
Packit |
c32a2d |
pushl %ecx
|
|
Packit |
c32a2d |
pushl %ebx
|
|
Packit |
c32a2d |
pushl %esi
|
|
Packit |
c32a2d |
/* get the int pointer for storing the flags */
|
|
Packit |
c32a2d |
movl 8(%ebp), %esi
|
|
Packit |
c32a2d |
/* does that one make sense? */
|
|
Packit |
c32a2d |
movl $0x80000000,%eax
|
|
Packit |
c32a2d |
/* now save the flags and do a check for cpuid availability */
|
|
Packit |
c32a2d |
pushfl
|
|
Packit |
c32a2d |
pushfl
|
|
Packit |
c32a2d |
popl %eax
|
|
Packit |
c32a2d |
movl %eax,%ebx
|
|
Packit |
c32a2d |
/* set that bit... */
|
|
Packit |
c32a2d |
xorl $0x00200000,%eax
|
|
Packit |
c32a2d |
pushl %eax
|
|
Packit |
c32a2d |
popfl
|
|
Packit |
c32a2d |
/* ...and read back the flags to see if it is understood */
|
|
Packit |
c32a2d |
pushfl
|
|
Packit |
c32a2d |
popl %eax
|
|
Packit |
c32a2d |
popfl
|
|
Packit |
c32a2d |
cmpl %ebx,%eax
|
|
Packit |
c32a2d |
je .Lnocpuid
|
|
Packit |
c32a2d |
/* In principle, I would have to check the CPU's identify first to be sure how to interpret the extended flags. */
|
|
Packit |
c32a2d |
/* now get the info, first extended */
|
|
Packit |
c32a2d |
movl $0x0, 12(%esi) /* clear value */
|
|
Packit |
c32a2d |
movl $0x0, 16(%esi) /* clear value */
|
|
Packit |
c32a2d |
/* only if supported... */
|
|
Packit |
c32a2d |
movl $0x80000000, %eax
|
|
Packit |
c32a2d |
cpuid
|
|
Packit |
c32a2d |
/* IDT CPUs should not change EAX, generally I hope that non-3DNow cpus do not set a bogus support level here. */
|
|
Packit |
c32a2d |
cmpl $0x80000001, %eax
|
|
Packit |
c32a2d |
jb .Lnoextended /* Skip ext check without minimal support level. */
|
|
Packit |
c32a2d |
/* is supported, get flags value */
|
|
Packit |
c32a2d |
movl $0x80000001,%eax
|
|
Packit |
c32a2d |
cpuid
|
|
Packit |
c32a2d |
movl %edx,12(%esi)
|
|
Packit |
c32a2d |
.Lnoextended:
|
|
Packit |
c32a2d |
/* then the other ones, called last to get the id flags in %eax for ret */
|
|
Packit |
c32a2d |
movl $0x00000001,%eax
|
|
Packit |
c32a2d |
cpuid
|
|
Packit |
c32a2d |
movl %eax, (%esi)
|
|
Packit |
c32a2d |
movl %ecx, 4(%esi)
|
|
Packit |
c32a2d |
movl %edx, 8(%esi)
|
|
Packit |
c32a2d |
/* check if xgetbv instruction is available */
|
|
Packit |
c32a2d |
test $0x04000000, %ecx
|
|
Packit |
c32a2d |
jz .Lend
|
|
Packit |
c32a2d |
test $0x08000000, %ecx
|
|
Packit |
c32a2d |
jz .Lend
|
|
Packit |
c32a2d |
xor %ecx, %ecx
|
|
Packit |
c32a2d |
.byte 0x0f, 0x01, 0xd0 /* xgetbv instruction */
|
|
Packit |
c32a2d |
movl %eax, 16(%esi)
|
|
Packit |
c32a2d |
movl (%esi), %eax
|
|
Packit |
c32a2d |
jmp .Lend
|
|
Packit |
c32a2d |
ALIGN4
|
|
Packit |
c32a2d |
.Lnocpuid:
|
|
Packit |
c32a2d |
/* error: set everything to zero */
|
|
Packit |
c32a2d |
movl $0, %eax
|
|
Packit |
c32a2d |
movl $0, (%esi)
|
|
Packit |
c32a2d |
movl $0, 4(%esi)
|
|
Packit |
c32a2d |
movl $0, 8(%esi)
|
|
Packit |
c32a2d |
movl $0, 12(%esi)
|
|
Packit |
c32a2d |
movl $0, 16(%esi)
|
|
Packit |
c32a2d |
ALIGN4
|
|
Packit |
c32a2d |
.Lend:
|
|
Packit |
c32a2d |
/* return value are the id flags, still stored in %eax */
|
|
Packit |
c32a2d |
popl %esi
|
|
Packit |
c32a2d |
popl %ebx
|
|
Packit |
c32a2d |
popl %ecx
|
|
Packit |
c32a2d |
popl %edx
|
|
Packit |
c32a2d |
movl %ebp,%esp
|
|
Packit |
c32a2d |
popl %ebp
|
|
Packit |
c32a2d |
ret
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
NONEXEC_STACK
|