xref: /haiku/src/system/kernel/arch/x86/arch_system_info.cpp (revision 4106e3f1466fb5e49230cca1a33de549809da7a5)
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
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
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
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;
103bd185b41SIngo Weinhold 	return B_OK;
104bd185b41SIngo Weinhold }
105bd185b41SIngo Weinhold 
106bd185b41SIngo Weinhold 
1071bc7045fSPawel Dziepak void
1081bc7045fSPawel Dziepak arch_fill_topology_node(cpu_topology_node_info* node, int32 cpu)
1091bc7045fSPawel Dziepak {
1101bc7045fSPawel Dziepak 	switch (node->type) {
1111bc7045fSPawel Dziepak 		case B_TOPOLOGY_ROOT:
1125ffbe7d7SAugustin Cavalier #if __i386__
1131bc7045fSPawel Dziepak 			node->data.root.platform = B_CPU_x86;
1141bc7045fSPawel Dziepak #elif __x86_64__
1151bc7045fSPawel Dziepak 			node->data.root.platform = B_CPU_x86_64;
1161bc7045fSPawel Dziepak #else
1171bc7045fSPawel Dziepak 			node->data.root.platform = B_CPU_UNKNOWN;
1181bc7045fSPawel Dziepak #endif
1191bc7045fSPawel Dziepak 			break;
1201bc7045fSPawel Dziepak 
1211bc7045fSPawel Dziepak 		case B_TOPOLOGY_PACKAGE:
1221bc7045fSPawel Dziepak 			node->data.package.vendor = sCPUVendor;
1231bc7045fSPawel Dziepak 			node->data.package.cache_line_size = CACHE_LINE_SIZE;
1241bc7045fSPawel Dziepak 			break;
1251bc7045fSPawel Dziepak 
1261bc7045fSPawel Dziepak 		case B_TOPOLOGY_CORE:
1271bc7045fSPawel Dziepak 			node->data.core.model = sCPUModel;
1281bc7045fSPawel Dziepak 			node->data.core.default_frequency = sCPUClockSpeed;
1291bc7045fSPawel Dziepak 			break;
1301bc7045fSPawel Dziepak 
1311bc7045fSPawel Dziepak 		default:
1321bc7045fSPawel Dziepak 			break;
1331bc7045fSPawel Dziepak 	}
1341bc7045fSPawel Dziepak }
1351bc7045fSPawel Dziepak 
1361bc7045fSPawel Dziepak 
13722fdfc44SJérôme Duval static void
138*4106e3f1SJérôme Duval get_frequency_for(void *_frequency, int cpu)
13922fdfc44SJérôme Duval {
14022fdfc44SJérôme Duval 	uint64 *frequency = (uint64*)_frequency;
14122fdfc44SJérôme Duval 
142*4106e3f1SJérôme Duval 	bigtime_t timestamp = gCPU[cpu].arch.perf_timestamp;
143*4106e3f1SJérôme Duval 	bigtime_t timestamp2 = system_time();
144*4106e3f1SJérôme Duval 	if (timestamp2 - timestamp < 100) {
145*4106e3f1SJérôme Duval 		*frequency = gCPU[cpu].arch.frequency;
146*4106e3f1SJérôme Duval 		return;
147*4106e3f1SJérôme Duval 	}
14822fdfc44SJérôme Duval 
149*4106e3f1SJérôme Duval 	uint64 mperf = gCPU[cpu].arch.mperf_prev;
150*4106e3f1SJérôme Duval 	uint64 aperf = gCPU[cpu].arch.aperf_prev;
15122fdfc44SJérôme Duval 	uint64 mperf2 = x86_read_msr(IA32_MSR_MPERF);
15222fdfc44SJérôme Duval 	uint64 aperf2 = x86_read_msr(IA32_MSR_APERF);
15322fdfc44SJérôme Duval 
15422fdfc44SJérôme Duval 	if (mperf2 == mperf)
15522fdfc44SJérôme Duval 		*frequency = 0;
156*4106e3f1SJérôme Duval 	else {
15722fdfc44SJérôme Duval 		*frequency = (aperf2 - aperf) * sCPUClockSpeed / (mperf2 - mperf);
158*4106e3f1SJérôme Duval 		gCPU[cpu].arch.mperf_prev = mperf2;
159*4106e3f1SJérôme Duval 		gCPU[cpu].arch.aperf_prev = aperf2;
160*4106e3f1SJérôme Duval 		gCPU[cpu].arch.perf_timestamp = timestamp2;
161*4106e3f1SJérôme Duval 		gCPU[cpu].arch.frequency = *frequency;
162*4106e3f1SJérôme Duval 	}
16322fdfc44SJérôme Duval }
16422fdfc44SJérôme Duval 
16522fdfc44SJérôme Duval 
16622fdfc44SJérôme Duval status_t
16722fdfc44SJérôme Duval arch_get_frequency(uint64 *frequency, int32 cpu)
16822fdfc44SJérôme Duval {
16922fdfc44SJérôme Duval 	if (x86_check_feature(IA32_FEATURE_APERFMPERF, FEATURE_6_ECX))
17022fdfc44SJérôme Duval 		call_single_cpu_sync(cpu, get_frequency_for, frequency);
17122fdfc44SJérôme Duval 	else
17222fdfc44SJérôme Duval 		*frequency = sCPUClockSpeed;
17322fdfc44SJérôme Duval 
17422fdfc44SJérôme Duval 	return B_OK;
17522fdfc44SJérôme Duval }
17622fdfc44SJérôme Duval 
17722fdfc44SJérôme Duval 
178bd185b41SIngo Weinhold //	#pragma mark -
179bd185b41SIngo Weinhold 
180bd185b41SIngo Weinhold 
181bd185b41SIngo Weinhold status_t
182bd185b41SIngo Weinhold _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum)
183bd185b41SIngo Weinhold {
184bd185b41SIngo Weinhold 	cpuid_info info;
185bd185b41SIngo Weinhold 	status_t status;
186bd185b41SIngo Weinhold 
187bd185b41SIngo Weinhold 	if (!IS_USER_ADDRESS(userInfo))
188bd185b41SIngo Weinhold 		return B_BAD_ADDRESS;
189bd185b41SIngo Weinhold 
190bd185b41SIngo Weinhold 	status = get_cpuid(&info, eaxRegister, cpuNum);
191bd185b41SIngo Weinhold 
192bd185b41SIngo Weinhold 	if (status == B_OK
193bd185b41SIngo Weinhold 		&& user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK)
194bd185b41SIngo Weinhold 		return B_BAD_ADDRESS;
195bd185b41SIngo Weinhold 
196bd185b41SIngo Weinhold 	return status;
197bd185b41SIngo Weinhold }
1981bc7045fSPawel Dziepak 
199