cpuid.cc

来自「Murphy 大俠 GPL 的 C++/x86 RTOS, 支持 MMU, 用戶」· CC 代码 · 共 366 行

CC
366
字号
/* 
 * Copyright (c) 1996 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 * All rights reserved.
 *
 * Permission to use, copy, modify and distribute this software is hereby
 * granted provided that (1) source code retains these copyright, permission,
 * and disclaimer notices, and (2) redistributions including binaries
 * reproduce the notices in supporting documentation, and (3) all advertising
 * materials mentioning features or use of this software display the following
 * acknowledgement: ``This product includes software developed by the
 * Computer Systems Laboratory at the University of Utah.''
 *
 * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
 * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
 * improvements that they make and grant CSL redistribution rights.
 */
/*
 * CPU identification code for x86 processors.
 */


#include <stdarg.h>
#include "proc_reg.h"
#include "cpuid.h"
#include "LibC/stdio/stdio.h"
#include "LibC/string/string.h"

static void get_cache_config(struct cpu_info *id)
{
	unsigned ci[4];
	unsigned cicount = 0;
	unsigned ccidx = 0;

	do
	{
		unsigned i;

		cicount++;
		asm volatile("
			cpuid
		" : "=a" (ci[0]), 
		    "=b" (ci[1]),
		    "=c" (ci[2]),
		    "=d" (ci[3])
		  : "a" (2));

		for (i = 0; i < 4; i++)
		{
			unsigned reg = ci[i];
			if ((reg & (1 << 31)) == 0)
			{
				/* The low BYTE of EAX isn't a descriptor.  */
				if (i == 0)
					reg >>= 8;
				while (reg != 0)
				{
					if ((reg & 0xff) &&
					    (ccidx < sizeof(id->cache_config)))
					{
						id->cache_config[ccidx++] =
							reg & 0xff;
					}
					reg >>= 8;
				}
			}
		}
	}
	while (cicount < (ci[0] & 0xff));
}

void cpuid(cpu_info *out_id)
{
	int orig_eflags = get_eflags();

	memset(out_id, 0, sizeof(*out_id));

	/* Check for a dumb old 386 by trying to toggle the AC flag.  */
	set_eflags(orig_eflags ^ EFL_AC);
	if ((get_eflags() ^ orig_eflags) & EFL_AC)
	{
		/* It's a 486 or better.  Now try toggling the ID flag.  */
		set_eflags(orig_eflags ^ EFL_ID);
		if ((get_eflags() ^ orig_eflags) & EFL_ID)
		{
			int highest_val;

			/*
			 * CPUID is supported, so use it.
			 * First get the vendor ID string.
			 */
			asm volatile("
				cpuid
			" : "=a" (highest_val),
			    "=b" (*((int*)(out_id->vendor_id+0))),
			    "=d" (*((int*)(out_id->vendor_id+4))),
			    "=c" (*((int*)(out_id->vendor_id+8)))
			  : "a" (0));

			/* Now the feature information.  */
			if (highest_val >= 1)
			{
				asm volatile("
					cpuid
				" : "=a" (*((int*)out_id)),
				    "=d" (out_id->feature_flags)
				  : "a" (1)
				  : "ebx", "ecx");
			}

			/* Cache and TLB information.  */
			if (highest_val >= 2)
				get_cache_config(out_id);
		}
		else
		{
			/* No CPUID support - it's an older 486.  */
			out_id->family = CPU_FAMILY_486;

			/* XXX detect FPU */
		}
	}
	else
	{
		out_id->family = CPU_FAMILY_386;

		/* XXX detect FPU */
	}

	set_eflags(orig_eflags);
}


// -----------------------------------------------------------------------
// cpu_info_format

void cpu_info_format(
	struct cpu_info *id,
	void (*formatter)(void *data, const char *fmt, ...),
	void *data)
{
	const static char *cputype[4] = {"0 (Original OEM processor)",
				   "1 (OverDrive processor)",
				   "2 (Dual processor)",
				   "3"};
	const static char *features[] = {
		"On-chip FPU",
		"Virtual 8086 mode enhancement",
		"I/O breakpoints",
		"4MB page size extensions",
		"Time stamp counter",
		"Model-specific registers",
		"36-bit physical address extension",
		"Machine check exception",
		"CMPXCHG8B instruction",
		"On-chip local APIC",
		0,
		0,
		"Memory type range registers",
		"Global bit in page table entries",
		"Machine check architecture",
		"CMOVcc instruction"};

	const char *company = "";
	const char *modelname = "";
	char fam[4];
	const char *family = fam;
	char vendorname[13];
	unsigned i;

	/*
	 * First try to guess a descriptive processor name
	 * based on the vendor ID, family, and model information.
	 * Much of this information comes from the x86 info file
	 * compiled by Christian Ludloff, ludloff@anet-dfw.com,
	 * http://webusers.anet-dfw.com/~ludloff.
	 */

	/* Default family string: #86 */
	fam[0] = '0' + id->family;
	fam[1] = '8';
	fam[2] = '6';
	fam[3] = 0;

	/* Check for specific vendors and models */
	if (memcmp(id->vendor_id, "GenuineIntel", 12) == 0)
	{
		static const char *m486[] =
			{"DX", "DX50", "SX", "DX/2", "SL",
			 "SX/2", "", "DX/2-WB", "DX/4", "DX/4-WB"};
		static const char *mp5[] =
			{" 60/66",
			 " 60/66",
			 " 75/90/100/120/133",
			 " P24T",
			 " OverDrive for Pentium-3.3v",
			 " OverDrive for iDX4",
			 " OverDrive for Pentium-5v"};
		static const char *mp6[] =
			{"", "", "", "", "OverDrive"};

		company = "Intel ";
		switch (id->family)
		{
		case 4:
			if (id->model < sizeof(m486)/sizeof(m486[0]))
				modelname = m486[id->model];
			break;
		case 5:
			family = "Pentium";
			if (id->model < sizeof(mp5)/sizeof(mp5[0]))
				modelname = mp5[id->model];
			break;
		case 6:
			family = "Pentium Pro";
			if (id->model < sizeof(mp6)/sizeof(mp6[0]))
				modelname = mp6[id->model];
			break;
		}
	}
	else if (memcmp(id->vendor_id, "UMC UMC UMC ", 12) == 0)
	{
		static const char *u486[] = {"", " U5D", " U5S"};

		company = "UMC ";
		switch (id->family)
		{
		case 4:
			if (id->model < sizeof(u486)/sizeof(u486[0]))
				modelname = u486[id->model];
			break;
		}
	}
	else if (memcmp(id->vendor_id, "AuthenticAMD", 12) == 0)
	{
		static const char *a486[] =
			{"", "", "", "DX2", "", "", "", "DX2WB",
			 "DX4", "DX4WB", "", "", "", "", "X5WT", "X5WB"};
		static const char *ak5[] = {" SSA5", " 5k86"};

		company = "AMD ";
		switch (id->family)
		{
		case 4:
			if (id->model < sizeof(a486)/sizeof(a486[0]))
				modelname = a486[id->model];
			break;
		case 5:
			family = "K5";
			if (id->model < sizeof(ak5)/sizeof(ak5[0]))
				modelname = ak5[id->model];
			break;
		}
	}
	else if (memcmp(id->vendor_id, "CyrixInstead", 12) == 0)
	{
		company = "Cyrix ";
		switch (id->family)
		{
		case 4:
			family = "5x86";
			break;
		case 5:
			family = "6x86";
			break;
		}
	}
	else if (memcmp(id->vendor_id, "NexGenDriven", 12) == 0)
	{
		company = "NexGen ";
		switch (id->family)
		{
		case 5:
			family = "Nx586";
			break;
		}
	}
	formatter(data, "Processor: %s%s%s\n", company, family, modelname);

	/*
	 * Now print the specific information
	 * exactly as provided by the processor.
	 */
	memcpy(vendorname, id->vendor_id, 12);
	vendorname[12] = 0;
	formatter(data, "Vendor ID: %s\n", vendorname);
	formatter(data, "Family: %c86\n", '0' + id->family);
	formatter(data, "Model: %d\n", id->model);
	formatter(data, "Stepping: %c\n", 'A' + id->stepping);
	formatter(data, "Type: %s\n", cputype[id->type]);

	/* Now the feature flags.  */
	for (i = 0; i < sizeof(features)/sizeof(features[0]); i++)
	{
		if (features[i])
			formatter(data, "%s: %s\n", features[i],
				  id->feature_flags & (1 << i) ? "yes" : "no");
	}


	/* Now the cache configuration information, if any.  */
	for (i = 0; i < sizeof(id->cache_config)/sizeof(id->cache_config[0]); i++)
	{
		char sbuf[40];
		const char *s = 0;

		switch (id->cache_config[i])
		{
		case 0: 
			break;
		case 0x01: s = "Instruction TLB: 4K-BYTE pages, "
				"4-way set associative, 64 entries"; break;
		case 0x02: s = "Instruction TLB: 4M-BYTE pages, "
				"4-way set associative, 4 entries"; break;
		case 0x03: s = "Data TLB: 4K-BYTE pages, "
				"4-way set associative, 64 entries"; break;
		case 0x04: s = "Data TLB: 4M-BYTE pages, "
				"4-way set associative, 8 entries"; break;
		case 0x06: s = "Instruction cache: 8K BYTEs, "
				"4-way set associative, 32 BYTE line size";
				break;
		case 0x0a: s = "Data cache: 8K BYTEs, "
				"2-way set associative, 32 BYTE line size";
				break;
		case 0x41: s = "Unified cache: 128K BYTEs, "
				"4-way set associative, 32 BYTE line size";
				break;
		case 0x42: s = "Unified cache: 256K BYTEs, "
				"4-way set associative, 32 BYTE line size";
				break;
		case 0x43: s = "Unified cache: 512K BYTEs, "
				"4-way set associative, 32 BYTE line size";
				break;
		default:
			sprintf(sbuf, "(unknown cache/TLB descriptor 0x%02x)",
				id->cache_config[i]);
			s = sbuf;
			break;
		}
		if (s)
			formatter(data, "%s\n", s);
	}
}


// ------------------------------------------------------------------------
// cpu_info_dump

static void formatter(void *data, const char *fmt, ...)
{
	va_list vl;

	va_start(vl, fmt);
	vprintf(fmt, vl);
	va_end(vl);
}

void cpu_info_dump(struct cpu_info *id)
{
	cpu_info_format(id, formatter, 0);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?