xref: /haiku/src/system/kernel/arch/x86/arch_system_info.cpp (revision 4110b730dbee59f5515a0bf9997b6cd167965080)
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 
20bd185b41SIngo Weinhold uint32 sCpuType;
21bd185b41SIngo Weinhold int32 sCpuRevision;
22bd185b41SIngo Weinhold 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 
32*4110b730SPawel 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_get_system_info(system_info *info, size_t size)
64bd185b41SIngo Weinhold {
65bd185b41SIngo Weinhold 	info->cpu_type = (cpu_types)sCpuType;
66bd185b41SIngo Weinhold 	info->cpu_revision = sCpuRevision;
67bd185b41SIngo Weinhold 
68bd185b41SIngo Weinhold 	// - various cpu_info
69bd185b41SIngo Weinhold 	info->cpu_clock_speed = sCpuClockSpeed;
70bd185b41SIngo Weinhold 	// - bus_clock_speed
719a5503d0SAlex Smith #ifdef __x86_64__
729a5503d0SAlex Smith 	info->platform_type = B_64_BIT_PC_PLATFORM;
739a5503d0SAlex Smith #else
74bd185b41SIngo Weinhold 	info->platform_type = B_AT_CLONE_PLATFORM;
759a5503d0SAlex Smith #endif
76bd185b41SIngo Weinhold 
77bd185b41SIngo Weinhold 	// ToDo: clock speeds could be retrieved via SMBIOS/DMI
78bd185b41SIngo Weinhold 	return B_OK;
79bd185b41SIngo Weinhold }
80bd185b41SIngo Weinhold 
81bd185b41SIngo Weinhold 
82bd185b41SIngo Weinhold status_t
83bd185b41SIngo Weinhold arch_system_info_init(struct kernel_args *args)
84bd185b41SIngo Weinhold {
85bd185b41SIngo Weinhold 	// This is what you get if the CPU vendor is not recognized
86bd185b41SIngo Weinhold 	// or the CPU does not support cpuid with eax == 1.
87bd185b41SIngo Weinhold 	uint32 base;
88bd185b41SIngo Weinhold 	uint32 model = 0;
89bd185b41SIngo Weinhold 	cpu_ent *cpu = get_cpu_struct();
90bd185b41SIngo Weinhold 
91bd185b41SIngo Weinhold 	switch (cpu->arch.vendor) {
92bd185b41SIngo Weinhold 		case VENDOR_INTEL:
93bd185b41SIngo Weinhold 			base = B_CPU_INTEL_x86;
94bd185b41SIngo Weinhold 			break;
95bd185b41SIngo Weinhold 		case VENDOR_AMD:
96bd185b41SIngo Weinhold 			base = B_CPU_AMD_x86;
97bd185b41SIngo Weinhold 			break;
98bd185b41SIngo Weinhold 		case VENDOR_CYRIX:
99bd185b41SIngo Weinhold 			base = B_CPU_CYRIX_x86;
100bd185b41SIngo Weinhold 			break;
101bd185b41SIngo Weinhold 		case VENDOR_UMC:
102bd185b41SIngo Weinhold 			base = B_CPU_INTEL_x86; // XXX
103bd185b41SIngo Weinhold 			break;
104bd185b41SIngo Weinhold 		case VENDOR_NEXGEN:
105bd185b41SIngo Weinhold 			base = B_CPU_INTEL_x86; // XXX
106bd185b41SIngo Weinhold 			break;
107bd185b41SIngo Weinhold 		case VENDOR_CENTAUR:
108bd185b41SIngo Weinhold 			base = B_CPU_VIA_IDT_x86;
109bd185b41SIngo Weinhold 			break;
110bd185b41SIngo Weinhold 		case VENDOR_RISE:
111bd185b41SIngo Weinhold 			base = B_CPU_RISE_x86;
112bd185b41SIngo Weinhold 			break;
113bd185b41SIngo Weinhold 		case VENDOR_TRANSMETA:
114bd185b41SIngo Weinhold 			base = B_CPU_TRANSMETA_x86;
115bd185b41SIngo Weinhold 			break;
116bd185b41SIngo Weinhold 		case VENDOR_NSC:
117bd185b41SIngo Weinhold 			base = B_CPU_NATIONAL_x86;
118bd185b41SIngo Weinhold 			break;
119bd185b41SIngo Weinhold 		default:
120bd185b41SIngo Weinhold 			base = B_CPU_x86;
121bd185b41SIngo Weinhold 	}
122bd185b41SIngo Weinhold 
123bd185b41SIngo Weinhold 	if (base != B_CPU_x86) {
124548b1a49SAlexander von Gluck IV 		if (base == B_CPU_INTEL_x86
125548b1a49SAlexander von Gluck IV 			|| (base == B_CPU_AMD_x86 && cpu->arch.family == 0xF)) {
126bd185b41SIngo Weinhold 			model = (cpu->arch.extended_family << 20)
127bd185b41SIngo Weinhold 				+ (cpu->arch.extended_model << 16)
128bd185b41SIngo Weinhold 				+ (cpu->arch.family << 4) + cpu->arch.model;
129bd185b41SIngo Weinhold 		} else {
130548b1a49SAlexander von Gluck IV 			model = (cpu->arch.family << 4)
131548b1a49SAlexander von Gluck IV 				+ cpu->arch.model;
132548b1a49SAlexander von Gluck IV 			// Isn't much useful extended family and model information
133548b1a49SAlexander von Gluck IV 			// yet on other processors.
134bd185b41SIngo Weinhold 		}
135bd185b41SIngo Weinhold 	}
136bd185b41SIngo Weinhold 
137bd185b41SIngo Weinhold 	sCpuRevision = (cpu->arch.extended_family << 18)
138bd185b41SIngo Weinhold 		| (cpu->arch.extended_model << 14) | (cpu->arch.type << 12)
139bd185b41SIngo Weinhold 		| (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping;
140bd185b41SIngo Weinhold 
141bd185b41SIngo Weinhold 	sCpuType = base + model;
142bd185b41SIngo Weinhold 	sCpuClockSpeed = args->arch_args.cpu_clock_speed;
143bd185b41SIngo Weinhold 	return B_OK;
144bd185b41SIngo Weinhold }
145bd185b41SIngo Weinhold 
146bd185b41SIngo Weinhold 
147bd185b41SIngo Weinhold //	#pragma mark -
148bd185b41SIngo Weinhold 
149bd185b41SIngo Weinhold 
150bd185b41SIngo Weinhold status_t
151bd185b41SIngo Weinhold _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum)
152bd185b41SIngo Weinhold {
153bd185b41SIngo Weinhold 	cpuid_info info;
154bd185b41SIngo Weinhold 	status_t status;
155bd185b41SIngo Weinhold 
156bd185b41SIngo Weinhold 	if (!IS_USER_ADDRESS(userInfo))
157bd185b41SIngo Weinhold 		return B_BAD_ADDRESS;
158bd185b41SIngo Weinhold 
159bd185b41SIngo Weinhold 	status = get_cpuid(&info, eaxRegister, cpuNum);
160bd185b41SIngo Weinhold 
161bd185b41SIngo Weinhold 	if (status == B_OK
162bd185b41SIngo Weinhold 		&& user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK)
163bd185b41SIngo Weinhold 		return B_BAD_ADDRESS;
164bd185b41SIngo Weinhold 
165bd185b41SIngo Weinhold 	return status;
166bd185b41SIngo Weinhold }
167