CPUID命令

x86アーキテクチャではCPUの情報を読み取るにはCPUID命令を使用します。
この命令はeaxレジスタに値をセット後、CPUID命令を実行すると、eax, ebx, edx, ecxレジスタに出力結果がセットされます。

最新のIntelプロセッサでは入力のeaxレジスタには0x00から0x0aまで、拡張命令で0x80000000から0x80000008まで値をとります。
詳しくは "CPUID - CPU Identification" in Chapter 2, "Instruction set Reference, A-M", in the Intel 64 and IA-32 Architectures Software Developer's Manual 2A

例として、eaxレジスタに0をセットし、CPUIDを実行した場合は次の様になる。

#include <stdio.h>
#include <stdint.h>

#define VENDER_ID_LENGTH 12

struct cpuid_struct {
	uint32_t basic_info;
	char vender_id[VENDER_ID_LENGTH];
	/* etc */
} cpuid_info;

struct registers {
	uint32_t eax, ebx, edx, ecx;
};

void cpuid(uint32_t cmd, struct registers *regs)
{
	asm volatile("cpuid"
		     : "=a" (regs->eax),
		       "=b" (regs->ebx),
		       "=d" (regs->edx),
		       "=c" (regs->ecx)
		     : "a" (cmd));
}

int main(void)
{
	int i;
	struct registers regs;
	cpuid(0, &regs);

	cpuid_info.vender_id[0]	 = regs.eax;	
	cpuid_info.vender_id[0]	 = regs.ebx;
	cpuid_info.vender_id[1]	 = regs.ebx >> 8;
	cpuid_info.vender_id[2]	 = regs.ebx >> 16;
	cpuid_info.vender_id[3]	 = regs.ebx >> 24;
	cpuid_info.vender_id[4]	 = regs.edx;
	cpuid_info.vender_id[5]	 = regs.edx >> 8;
	cpuid_info.vender_id[6]	 = regs.edx >> 16;
	cpuid_info.vender_id[7]	 = regs.edx >> 24;
	cpuid_info.vender_id[8]	 = regs.ecx;
	cpuid_info.vender_id[9]	 = regs.ecx >> 8;
	cpuid_info.vender_id[10] = regs.ecx >> 16;
	cpuid_info.vender_id[11] = regs.ecx >> 24;

	for (i = 0; i < VENDER_ID_LENGTH; i++)
		printf("%c", cpuid_info.vender_id[i]);
	putchar('\n');

	return 0;
}
/* $ gcc cpuid.c && ./a.out
 * GenuineIntel
 */