xref: /haiku/src/system/kernel/arch/x86/arch_system_info.cpp (revision 2710b4f5d4251c5cf88c82b0114ea99b0ef46d22)
1bd185b41SIngo Weinhold /*
2bd185b41SIngo Weinhold  * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3bd185b41SIngo Weinhold  * Distributed under the terms of the MIT License.
4bd185b41SIngo Weinhold  */
5bd185b41SIngo Weinhold 
6bd185b41SIngo Weinhold 
7bd185b41SIngo Weinhold #include <arch/system_info.h>
8bd185b41SIngo Weinhold 
9bd185b41SIngo Weinhold #include <string.h>
10bd185b41SIngo Weinhold 
11bd185b41SIngo Weinhold #include <KernelExport.h>
12bd185b41SIngo Weinhold #include <OS.h>
13bd185b41SIngo Weinhold 
14bd185b41SIngo Weinhold #include <boot/kernel_args.h>
15bd185b41SIngo Weinhold #include <cpu.h>
16bd185b41SIngo Weinhold #include <kernel.h>
17bd185b41SIngo Weinhold #include <smp.h>
18bd185b41SIngo Weinhold 
19bd185b41SIngo Weinhold 
201bc7045fSPawel Dziepak enum cpu_vendor sCPUVendor;
211bc7045fSPawel Dziepak uint32 sCPUModel;
221bc7045fSPawel Dziepak int64 sCPUClockSpeed;
23bd185b41SIngo Weinhold 
24bd185b41SIngo Weinhold 
25bd185b41SIngo Weinhold static bool
get_cpuid_for(cpuid_info * info,uint32 currentCPU,uint32 eaxRegister,uint32 forCPU)26bd185b41SIngo Weinhold get_cpuid_for(cpuid_info *info, uint32 currentCPU, uint32 eaxRegister,
27bd185b41SIngo Weinhold 	uint32 forCPU)
28bd185b41SIngo Weinhold {
29bd185b41SIngo Weinhold 	if (currentCPU != forCPU)
30bd185b41SIngo Weinhold 		return false;
31bd185b41SIngo Weinhold 
324110b730SPawel Dziepak 	get_current_cpuid(info, eaxRegister, 0);
33bd185b41SIngo Weinhold 	return true;
34bd185b41SIngo Weinhold }
35bd185b41SIngo Weinhold 
36bd185b41SIngo Weinhold 
37bd185b41SIngo Weinhold status_t
get_cpuid(cpuid_info * info,uint32 eaxRegister,uint32 forCPU)38bd185b41SIngo Weinhold get_cpuid(cpuid_info *info, uint32 eaxRegister, uint32 forCPU)
39bd185b41SIngo Weinhold {
40bd185b41SIngo Weinhold 	uint32 numCPUs = (uint32)smp_get_num_cpus();
41bd185b41SIngo Weinhold 	cpu_status state;
42bd185b41SIngo Weinhold 
43bd185b41SIngo Weinhold 	if (forCPU >= numCPUs)
44bd185b41SIngo Weinhold 		return B_BAD_VALUE;
45bd185b41SIngo Weinhold 
46bd185b41SIngo Weinhold 	// prevent us from being rescheduled
47bd185b41SIngo Weinhold 	state = disable_interrupts();
48bd185b41SIngo Weinhold 
49bd185b41SIngo Weinhold 	// ToDo: as long as we only run on pentium-class systems, we can assume
50bd185b41SIngo Weinhold 	//	that the CPU supports cpuid.
51bd185b41SIngo Weinhold 
52bd185b41SIngo Weinhold 	if (!get_cpuid_for(info, smp_get_current_cpu(), eaxRegister, forCPU)) {
5311d3892dSAlex Smith 		smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (addr_t)info,
54bd185b41SIngo Weinhold 			eaxRegister, forCPU, (void *)get_cpuid_for, SMP_MSG_FLAG_SYNC);
55bd185b41SIngo Weinhold 	}
56bd185b41SIngo Weinhold 
57bd185b41SIngo Weinhold 	restore_interrupts(state);
58bd185b41SIngo Weinhold 	return B_OK;
59bd185b41SIngo Weinhold }
60bd185b41SIngo Weinhold 
61bd185b41SIngo Weinhold 
62bd185b41SIngo Weinhold status_t
arch_system_info_init(struct kernel_args * args)63bd185b41SIngo Weinhold arch_system_info_init(struct kernel_args *args)
64bd185b41SIngo Weinhold {
651bc7045fSPawel Dziepak 	// So far we don't have to care about heterogeneous x86 platforms.
66bd185b41SIngo Weinhold 	cpu_ent* cpu = get_cpu_struct();
67bd185b41SIngo Weinhold 
68bd185b41SIngo Weinhold 	switch (cpu->arch.vendor) {
69bd185b41SIngo Weinhold 		case VENDOR_AMD:
701bc7045fSPawel Dziepak 			sCPUVendor = B_CPU_VENDOR_AMD;
71bd185b41SIngo Weinhold 			break;
72bd185b41SIngo Weinhold 		case VENDOR_CENTAUR:
731bc7045fSPawel Dziepak 			sCPUVendor = B_CPU_VENDOR_VIA;
74bd185b41SIngo Weinhold 			break;
751bc7045fSPawel Dziepak 		case VENDOR_CYRIX:
761bc7045fSPawel Dziepak 			sCPUVendor = B_CPU_VENDOR_CYRIX;
77bd185b41SIngo Weinhold 			break;
781bc7045fSPawel Dziepak 		case VENDOR_INTEL:
791bc7045fSPawel Dziepak 			sCPUVendor = B_CPU_VENDOR_INTEL;
80bd185b41SIngo Weinhold 			break;
81bd185b41SIngo Weinhold 		case VENDOR_NSC:
821bc7045fSPawel Dziepak 			sCPUVendor = B_CPU_VENDOR_NATIONAL_SEMICONDUCTOR;
831bc7045fSPawel Dziepak 			break;
841bc7045fSPawel Dziepak 		case VENDOR_RISE:
851bc7045fSPawel Dziepak 			sCPUVendor = B_CPU_VENDOR_RISE;
861bc7045fSPawel Dziepak 			break;
871bc7045fSPawel Dziepak 		case VENDOR_TRANSMETA:
881bc7045fSPawel Dziepak 			sCPUVendor = B_CPU_VENDOR_TRANSMETA;
89bd185b41SIngo Weinhold 			break;
90357b9d3cSJérôme Duval 		case VENDOR_HYGON:
91357b9d3cSJérôme Duval 			sCPUVendor = B_CPU_VENDOR_HYGON;
92357b9d3cSJérôme Duval 			break;
93bd185b41SIngo Weinhold 		default:
941bc7045fSPawel Dziepak 			sCPUVendor = B_CPU_VENDOR_UNKNOWN;
951bc7045fSPawel Dziepak 			break;
96bd185b41SIngo Weinhold 	}
97bd185b41SIngo Weinhold 
981bc7045fSPawel Dziepak 	sCPUModel = (cpu->arch.extended_family << 20)
991bc7045fSPawel Dziepak 		| (cpu->arch.extended_model << 16) | (cpu->arch.type << 12)
100bd185b41SIngo Weinhold 		| (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping;
101bd185b41SIngo Weinhold 
1021bc7045fSPawel Dziepak 	sCPUClockSpeed = args->arch_args.cpu_clock_speed;
103*2e69f2b0SJérôme Duval 	if (cpu->arch.vendor == VENDOR_INTEL) {
104*2e69f2b0SJérôme Duval 		cpuid_info cpuid;
105*2e69f2b0SJérôme Duval 		get_current_cpuid(&cpuid, 0, 0);
106*2e69f2b0SJérôme Duval 		uint32 maxBasicLeaf = cpuid.eax_0.max_eax;
107*2e69f2b0SJérôme Duval 		if (maxBasicLeaf >= 0x16) {
108*2e69f2b0SJérôme Duval 			get_current_cpuid(&cpuid, 0x16, 0);
109*2e69f2b0SJérôme Duval 			if (cpuid.regs.eax != 0) {
110*2e69f2b0SJérôme Duval 				sCPUClockSpeed = cpuid.regs.eax * 1000000LL;
111*2e69f2b0SJérôme Duval 				dprintf("found clock speed with CPUID.16h\n");
112*2e69f2b0SJérôme Duval 			}
113*2e69f2b0SJérôme Duval 		}
114*2e69f2b0SJérôme Duval 	}
115bd185b41SIngo Weinhold 	return B_OK;
116bd185b41SIngo Weinhold }
117bd185b41SIngo Weinhold 
118bd185b41SIngo Weinhold 
1191bc7045fSPawel Dziepak void
arch_fill_topology_node(cpu_topology_node_info * node,int32 cpu)1201bc7045fSPawel Dziepak arch_fill_topology_node(cpu_topology_node_info* node, int32 cpu)
1211bc7045fSPawel Dziepak {
1221bc7045fSPawel Dziepak 	switch (node->type) {
1231bc7045fSPawel Dziepak 		case B_TOPOLOGY_ROOT:
1245ffbe7d7SAugustin Cavalier #if __i386__
1251bc7045fSPawel Dziepak 			node->data.root.platform = B_CPU_x86;
1261bc7045fSPawel Dziepak #elif __x86_64__
1271bc7045fSPawel Dziepak 			node->data.root.platform = B_CPU_x86_64;
1281bc7045fSPawel Dziepak #else
1291bc7045fSPawel Dziepak 			node->data.root.platform = B_CPU_UNKNOWN;
1301bc7045fSPawel Dziepak #endif
1311bc7045fSPawel Dziepak 			break;
1321bc7045fSPawel Dziepak 
1331bc7045fSPawel Dziepak 		case B_TOPOLOGY_PACKAGE:
1341bc7045fSPawel Dziepak 			node->data.package.vendor = sCPUVendor;
1351bc7045fSPawel Dziepak 			node->data.package.cache_line_size = CACHE_LINE_SIZE;
1361bc7045fSPawel Dziepak 			break;
1371bc7045fSPawel Dziepak 
1381bc7045fSPawel Dziepak 		case B_TOPOLOGY_CORE:
1391bc7045fSPawel Dziepak 			node->data.core.model = sCPUModel;
1401bc7045fSPawel Dziepak 			node->data.core.default_frequency = sCPUClockSpeed;
1411bc7045fSPawel Dziepak 			break;
1421bc7045fSPawel Dziepak 
1431bc7045fSPawel Dziepak 		default:
1441bc7045fSPawel Dziepak 			break;
1451bc7045fSPawel Dziepak 	}
1461bc7045fSPawel Dziepak }
1471bc7045fSPawel Dziepak 
1481bc7045fSPawel Dziepak 
14922fdfc44SJérôme Duval static void
get_frequency_for(void * _frequency,int cpu)1504106e3f1SJérôme Duval get_frequency_for(void *_frequency, int cpu)
15122fdfc44SJérôme Duval {
15222fdfc44SJérôme Duval 	uint64 *frequency = (uint64*)_frequency;
15322fdfc44SJérôme Duval 
1544106e3f1SJérôme Duval 	bigtime_t timestamp = gCPU[cpu].arch.perf_timestamp;
1554106e3f1SJérôme Duval 	bigtime_t timestamp2 = system_time();
1564106e3f1SJérôme Duval 	if (timestamp2 - timestamp < 100) {
1574106e3f1SJérôme Duval 		*frequency = gCPU[cpu].arch.frequency;
1584106e3f1SJérôme Duval 		return;
1594106e3f1SJérôme Duval 	}
16022fdfc44SJérôme Duval 
1614106e3f1SJérôme Duval 	uint64 mperf = gCPU[cpu].arch.mperf_prev;
1624106e3f1SJérôme Duval 	uint64 aperf = gCPU[cpu].arch.aperf_prev;
16322fdfc44SJérôme Duval 	uint64 mperf2 = x86_read_msr(IA32_MSR_MPERF);
16422fdfc44SJérôme Duval 	uint64 aperf2 = x86_read_msr(IA32_MSR_APERF);
16522fdfc44SJérôme Duval 
16622fdfc44SJérôme Duval 	if (mperf2 == mperf)
16722fdfc44SJérôme Duval 		*frequency = 0;
1684106e3f1SJérôme Duval 	else {
16922fdfc44SJérôme Duval 		*frequency = (aperf2 - aperf) * sCPUClockSpeed / (mperf2 - mperf);
1704106e3f1SJérôme Duval 		gCPU[cpu].arch.mperf_prev = mperf2;
1714106e3f1SJérôme Duval 		gCPU[cpu].arch.aperf_prev = aperf2;
1724106e3f1SJérôme Duval 		gCPU[cpu].arch.perf_timestamp = timestamp2;
1734106e3f1SJérôme Duval 		gCPU[cpu].arch.frequency = *frequency;
1744106e3f1SJérôme Duval 	}
17522fdfc44SJérôme Duval }
17622fdfc44SJérôme Duval 
17722fdfc44SJérôme Duval 
17822fdfc44SJérôme Duval status_t
arch_get_frequency(uint64 * frequency,int32 cpu)17922fdfc44SJérôme Duval arch_get_frequency(uint64 *frequency, int32 cpu)
18022fdfc44SJérôme Duval {
18122fdfc44SJérôme Duval 	if (x86_check_feature(IA32_FEATURE_APERFMPERF, FEATURE_6_ECX))
18222fdfc44SJérôme Duval 		call_single_cpu_sync(cpu, get_frequency_for, frequency);
18322fdfc44SJérôme Duval 	else
18422fdfc44SJérôme Duval 		*frequency = sCPUClockSpeed;
18522fdfc44SJérôme Duval 
18622fdfc44SJérôme Duval 	return B_OK;
18722fdfc44SJérôme Duval }
18822fdfc44SJérôme Duval 
18922fdfc44SJérôme Duval 
190bd185b41SIngo Weinhold //	#pragma mark -
191bd185b41SIngo Weinhold 
192bd185b41SIngo Weinhold 
193bd185b41SIngo Weinhold status_t
_user_get_cpuid(cpuid_info * userInfo,uint32 eaxRegister,uint32 cpuNum)194bd185b41SIngo Weinhold _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum)
195bd185b41SIngo Weinhold {
196bd185b41SIngo Weinhold 	cpuid_info info;
197bd185b41SIngo Weinhold 	status_t status;
198bd185b41SIngo Weinhold 
199bd185b41SIngo Weinhold 	if (!IS_USER_ADDRESS(userInfo))
200bd185b41SIngo Weinhold 		return B_BAD_ADDRESS;
201bd185b41SIngo Weinhold 
202bd185b41SIngo Weinhold 	status = get_cpuid(&info, eaxRegister, cpuNum);
203bd185b41SIngo Weinhold 
204bd185b41SIngo Weinhold 	if (status == B_OK
205bd185b41SIngo Weinhold 		&& user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK)
206bd185b41SIngo Weinhold 		return B_BAD_ADDRESS;
207bd185b41SIngo Weinhold 
208bd185b41SIngo Weinhold 	return status;
209bd185b41SIngo Weinhold }
2101bc7045fSPawel Dziepak 
211