PROWAREtech

articles » current » assembly » x64 » cpuid-library

x64 Assembly: CPUID/CPU Capabilities Library

A C/C++ library written in assembly that wraps the functionality of CPUID

This code was compiled and linked using the Microsoft Macro Assembler for Visual Studio 2022.

This library is available in x86 Assembly.

This library uses the CPUID instruction to check a CPU for AVX, AVX2, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 and Hyper-threading. It also retrieves the CPU brand and the logical processor count. Note: the logical processor count is only valid on older CPU's as this function is deprecated. It official use if for "Maximum number of addressable IDs for logical processors in this physical package," which means the number will be greater than or equal to the number of logical processors of the CPU.


_TEXT	SEGMENT


cpu_id_supported PROC
	
	push rbx         ; save rbx for the caller
	pushfq           ; push rflags on the stack
	pop rax          ; pop them into rax
	mov rbx, rax     ; save to rbx for restoring afterwards
	xor rax, 200000h ; toggle bit 21
	push rax         ; push the toggled rflags
	popfq            ; pop them back into rflags
	pushfq           ; push rflags
	pop rax          ; pop them back into rax
	cmp rax, rbx     ; see if bit 21 was reset
	jz not_supported
	
	mov eax, 1
	jmp exit
	
not_supported:
	xor eax, eax

exit:
	pop rbx
	ret
cpu_id_supported ENDP


cpu_processor_features_edx PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx
	
	mov eax, 1
	cpuid
	mov eax, edx

	pop rbx

exit:
	ret
cpu_processor_features_edx ENDP


cpu_processor_features_ecx PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx
	
	mov eax, 1
	cpuid
	mov eax, ecx

	pop rbx

exit:
	ret
cpu_processor_features_ecx ENDP


cpu_processor_features_ebx PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx
	
	mov eax, 1
	cpuid
	mov eax, ebx

	pop rbx

exit:
	ret
cpu_processor_features_ebx ENDP


cpu_processor_features_eax PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx
	
	mov eax, 1
	cpuid

	pop rbx

exit:
	ret
cpu_processor_features_eax ENDP


cpu_brand_part0 PROC
	
	push rbx

	call cpu_id_supported
	cmp eax, 0
	je exit

	mov eax, 80000000h
	cpuid
	cmp eax, 80000004h
	jnge not_supported

	mov eax, 80000002h
	cpuid

	xchg rbx, rax
	shl rax, 32
	shl rbx, 32
	shr rbx, 32
	or  rax, rbx

	jmp exit

not_supported:
	xor rax, rax
	
exit:
	pop rbx
	ret

cpu_brand_part0 ENDP


cpu_brand_part1 PROC
	
	push rbx

	call cpu_id_supported
	cmp eax, 0
	je exit

	mov eax, 80000000h
	cpuid
	cmp eax, 80000004h
	jnge not_supported

	mov eax, 80000002h
	cpuid

	mov rax, rdx
	shl rax, 32
	shl rcx, 32
	shr rcx, 32
	or  rax, rcx

	jmp exit
	

not_supported:
	xor eax, eax
	
exit:
	pop rbx
	ret

cpu_brand_part1 ENDP


cpu_brand_part2 PROC
	
	push rbx

	call cpu_id_supported
	cmp eax, 0
	je exit

	mov eax, 80000000h
	cpuid
	cmp eax, 80000004h
	jnge not_supported

	mov eax, 80000003h
	cpuid

	xchg rbx, rax
	shl rax, 32
	shl rbx, 32
	shr rbx, 32
	or  rax, rbx

	jmp exit
	

not_supported:
	xor eax, eax
	
exit:
	pop rbx
	ret

cpu_brand_part2 ENDP


cpu_brand_part3 PROC
	
	push rbx

	call cpu_id_supported
	cmp eax, 0
	je exit

	mov eax, 80000000h
	cpuid
	cmp eax, 80000004h
	jnge not_supported

	mov eax, 80000003h
	cpuid

	mov rax, rdx
	shl rax, 32
	shl rcx, 32
	shr rcx, 32
	or  rax, rcx

	jmp exit
	

not_supported:
	xor eax, eax
	
exit:
	pop rbx
	ret

cpu_brand_part3 ENDP


cpu_brand_part4 PROC
	
	push rbx

	call cpu_id_supported
	cmp eax, 0
	je exit

	mov eax, 80000000h
	cpuid
	cmp eax, 80000004h
	jnge not_supported

	mov eax, 80000004h
	cpuid

	xchg rbx, rax
	shl rax, 32
	shl rbx, 32
	shr rbx, 32
	or  rax, rbx

	jmp exit
	

not_supported:
	xor eax, eax
	
exit:
	pop rbx
	ret

cpu_brand_part4 ENDP


cpu_brand_part5 PROC
	
	push rbx

	call cpu_id_supported
	cmp eax, 0
	je exit

	mov eax, 80000000h
	cpuid
	cmp eax, 80000004h
	jnge not_supported

	mov eax, 80000004h
	cpuid

	mov rax, rdx
	shl rax, 32
	shl rcx, 32
	shr rcx, 32
	or  rax, rcx

	jmp exit
	

not_supported:
	xor eax, eax
	
exit:
	pop rbx
	ret

cpu_brand_part5 ENDP


cpu_avx PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx
	
	mov eax, 1
	cpuid
	shr ecx, 28
	and ecx, 1
	mov eax, ecx

	pop rbx

exit:
	ret
cpu_avx ENDP


cpu_avx2 PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx

	xor rbx, rbx
	
	mov eax, 7
	cpuid
	shr ebx, 5
	and ebx, 1
	mov eax, ebx

	pop rbx

exit:
	ret
cpu_avx2 ENDP


cpu_mmx PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx
	
	mov eax, 1
	cpuid
	shr edx, 23
	and edx, 1
	mov eax, edx

	pop rbx

exit:
	ret
cpu_mmx ENDP


cpu_sse PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx
	
	mov eax, 1
	cpuid
	shr edx, 25
	and edx, 1
	mov eax, edx

	pop rbx

exit:
	ret
cpu_sse ENDP


cpu_sse2 PROC

	call cpu_id_supported
	cmp eax, 0
	je exit

	push rbx

	mov eax, 1
	cpuid
	shr edx, 26
	and edx, 1
	mov eax, edx

	pop rbx

exit:
	ret
cpu_sse2 ENDP


cpu_sse3 PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx

	mov eax, 1
	cpuid
	and ecx, 1
	mov eax, ecx

	pop rbx

exit:
	ret
cpu_sse3 ENDP


cpu_ssse3 PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx

	mov eax, 1
	cpuid
	shr ecx, 9
	and ecx, 1
	mov eax, ecx

	pop rbx

exit:
	ret
cpu_ssse3 ENDP


cpu_sse41 PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx

	mov eax, 1
	cpuid
	shr ecx, 19
	and ecx, 1
	mov eax, ecx

	pop rbx

exit:
	ret
cpu_sse41 ENDP


cpu_sse42 PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx

	mov eax, 1
	cpuid
	shr ecx, 20
	and ecx, 1
	mov eax, ecx

	pop rbx

exit:
	ret
cpu_sse42 ENDP


cpu_logical_processor_count PROC

	call cpu_id_supported
	cmp eax, 0
	je exit

	call cpu_hyperthreading
	cmp eax, 0
	je exit

	push rbx

	mov eax, 1
	cpuid
	and ebx, 00FF0000h
	mov eax, ebx
	shr eax, 16

	pop rbx

exit:
	ret
cpu_logical_processor_count ENDP


cpu_hyperthreading PROC

	call cpu_id_supported
	cmp eax, 0
	je exit
	
	push rbx
	
	mov eax, 1
	cpuid
	shr edx, 28
	and edx, 1
	mov eax, edx

	pop rbx

exit:
	ret
cpu_hyperthreading ENDP


_TEXT	ENDS
END

The header file:


#ifndef CPUIDLIB64_H

#define CPUIDLIB64_H

extern "C" int cpu_id_supported(); // returns true if CPUID is supported
extern "C" int cpu_processor_features_edx(); // returns 0 if not supported, otherwise, returns edx
extern "C" int cpu_processor_features_ecx(); // returns 0 if not supported, otherwise, returns ecx
extern "C" int cpu_processor_features_ebx(); // returns 0 if not supported, otherwise, returns ebx
extern "C" int cpu_processor_features_eax(); // returns 0 if not supported, otherwise, returns eax
extern "C" long long cpu_brand_part0(); // returns 8 byte string if brand is supported, or 0 if not supported
extern "C" long long cpu_brand_part1(); // returns 8 byte string if brand is supported, or 0 if not supported
extern "C" long long cpu_brand_part2(); // returns 8 byte string if brand is supported, or 0 if not supported
extern "C" long long cpu_brand_part3(); // returns 8 byte string if brand is supported, or 0 if not supported
extern "C" long long cpu_brand_part4(); // returns 8 byte string if brand is supported, or 0 if not supported
extern "C" long long cpu_brand_part5(); // returns 8 byte string if brand is supported, or 0 if not supported
extern "C" int cpu_avx(); // returns true if AVX is supported
extern "C" int cpu_avx2(); // returns true if AVX2 is supported
extern "C" int cpu_mmx(); // returns true if MMX is supported
extern "C" int cpu_sse(); // returns true if SSE is supported
extern "C" int cpu_sse2(); // returns true if SSE2 is supported
extern "C" int cpu_sse3(); // returns true if SSE3 is supported
extern "C" int cpu_ssse3(); // returns true if SSSE3 is supported
extern "C" int cpu_sse41(); // returns true if SSE41 is supported
extern "C" int cpu_sse42(); // returns true if SSE42 is supported
extern "C" int cpu_logical_processor_count(); // returns the number of logical processors
extern "C" int cpu_hyperthreading(); // returns true if HT is a feature

#endif

The driver code:


#include <iostream>
#include "CPUIDLIB64.h"
using namespace std;

int main()
{
	if (cpu_id_supported())
	{
		cout << "CPUID = yes" << endl;
		cout << "AVX = " << (cpu_avx() ? "yes" : "no") << endl;
		cout << "AVX2 = " << (cpu_avx2() ? "yes" : "no") << endl;
		cout << "MMX = " << (cpu_mmx() ? "yes" : "no") << endl;
		cout << "SSE = " << (cpu_sse() ? "yes" : "no") << endl;
		cout << "SSE2 = " << (cpu_sse2() ? "yes" : "no") << endl;
		cout << "SSE3 = " << (cpu_sse3() ? "yes" : "no") << endl;
		cout << "SSSE3 = " << (cpu_ssse3() ? "yes" : "no") << endl;
		cout << "SSE41 = " << (cpu_sse41() ? "yes" : "no") << endl;
		cout << "SSE42 = " << (cpu_sse42() ? "yes" : "no") << endl;
		cout << "HT = " << (cpu_hyperthreading() ? "yes" : "no") << endl;
		cout << "ThreadCount = " << cpu_logical_processor_count() << endl;

		// retrieve the processor brand
		union {
			char brand[48 + 1];
			long long buffer[6];
		};
		brand[48] = 0;
		buffer[0] = cpu_brand_part0();
		buffer[1] = cpu_brand_part1();
		buffer[2] = cpu_brand_part2();
		buffer[3] = cpu_brand_part3();
		buffer[4] = cpu_brand_part4();
		buffer[5] = cpu_brand_part5();
		cout << "Brand = " << brand << endl;
		cout << endl << "Ctrl+C to quit" << endl;
	}
	else
	{
		cout << "CPUID = no" << endl;
	}
	cin.get();
	return 0;
}

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE