Blame src/libmpg123/getcpuflags.S

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