xref: /haiku/src/system/kernel/arch/x86/arch_system_info.cpp (revision 204dee708a999d5a71d0cb9497650ee7cef85d0a)
1 /*
2  * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <arch/system_info.h>
8 
9 #include <string.h>
10 
11 #include <KernelExport.h>
12 #include <OS.h>
13 
14 #include <boot/kernel_args.h>
15 #include <cpu.h>
16 #include <kernel.h>
17 #include <smp.h>
18 
19 
20 uint32 sCpuType;
21 int32 sCpuRevision;
22 int64 sCpuClockSpeed;
23 
24 
25 static bool
26 get_cpuid_for(cpuid_info *info, uint32 currentCPU, uint32 eaxRegister,
27 	uint32 forCPU)
28 {
29 	if (currentCPU != forCPU)
30 		return false;
31 
32 	get_current_cpuid(info, eaxRegister);
33 	return true;
34 }
35 
36 
37 status_t
38 get_cpuid(cpuid_info *info, uint32 eaxRegister, uint32 forCPU)
39 {
40 	uint32 numCPUs = (uint32)smp_get_num_cpus();
41 	cpu_status state;
42 
43 	if (forCPU >= numCPUs)
44 		return B_BAD_VALUE;
45 
46 	// prevent us from being rescheduled
47 	state = disable_interrupts();
48 
49 	// ToDo: as long as we only run on pentium-class systems, we can assume
50 	//	that the CPU supports cpuid.
51 
52 	if (!get_cpuid_for(info, smp_get_current_cpu(), eaxRegister, forCPU)) {
53 		smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (addr_t)info,
54 			eaxRegister, forCPU, (void *)get_cpuid_for, SMP_MSG_FLAG_SYNC);
55 	}
56 
57 	restore_interrupts(state);
58 	return B_OK;
59 }
60 
61 
62 status_t
63 arch_get_system_info(system_info *info, size_t size)
64 {
65 	info->cpu_type = (cpu_types)sCpuType;
66 	info->cpu_revision = sCpuRevision;
67 
68 	// - various cpu_info
69 	info->cpu_clock_speed = sCpuClockSpeed;
70 	// - bus_clock_speed
71 #ifdef __x86_64__
72 	info->platform_type = B_64_BIT_PC_PLATFORM;
73 #else
74 	info->platform_type = B_AT_CLONE_PLATFORM;
75 #endif
76 
77 	// ToDo: clock speeds could be retrieved via SMBIOS/DMI
78 	return B_OK;
79 }
80 
81 
82 status_t
83 arch_system_info_init(struct kernel_args *args)
84 {
85 	// This is what you get if the CPU vendor is not recognized
86 	// or the CPU does not support cpuid with eax == 1.
87 	uint32 base;
88 	uint32 model = 0;
89 	cpu_ent *cpu = get_cpu_struct();
90 
91 	switch (cpu->arch.vendor) {
92 		case VENDOR_INTEL:
93 			base = B_CPU_INTEL_x86;
94 			break;
95 		case VENDOR_AMD:
96 			base = B_CPU_AMD_x86;
97 			break;
98 		case VENDOR_CYRIX:
99 			base = B_CPU_CYRIX_x86;
100 			break;
101 		case VENDOR_UMC:
102 			base = B_CPU_INTEL_x86; // XXX
103 			break;
104 		case VENDOR_NEXGEN:
105 			base = B_CPU_INTEL_x86; // XXX
106 			break;
107 		case VENDOR_CENTAUR:
108 			base = B_CPU_VIA_IDT_x86;
109 			break;
110 		case VENDOR_RISE:
111 			base = B_CPU_RISE_x86;
112 			break;
113 		case VENDOR_TRANSMETA:
114 			base = B_CPU_TRANSMETA_x86;
115 			break;
116 		case VENDOR_NSC:
117 			base = B_CPU_NATIONAL_x86;
118 			break;
119 		default:
120 			base = B_CPU_x86;
121 	}
122 
123 	if (base != B_CPU_x86) {
124 		if (base == B_CPU_INTEL_x86
125 			|| (base == B_CPU_AMD_x86 && cpu->arch.family == 0xF)) {
126 			model = (cpu->arch.extended_family << 20)
127 				+ (cpu->arch.extended_model << 16)
128 				+ (cpu->arch.family << 4) + cpu->arch.model;
129 		} else {
130 			model = (cpu->arch.family << 4)
131 				+ cpu->arch.model;
132 			// Isn't much useful extended family and model information
133 			// yet on other processors.
134 		}
135 	}
136 
137 	sCpuRevision = (cpu->arch.extended_family << 18)
138 		| (cpu->arch.extended_model << 14) | (cpu->arch.type << 12)
139 		| (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping;
140 
141 	sCpuType = base + model;
142 	sCpuClockSpeed = args->arch_args.cpu_clock_speed;
143 	return B_OK;
144 }
145 
146 
147 //	#pragma mark -
148 
149 
150 status_t
151 _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum)
152 {
153 	cpuid_info info;
154 	status_t status;
155 
156 	if (!IS_USER_ADDRESS(userInfo))
157 		return B_BAD_ADDRESS;
158 
159 	status = get_cpuid(&info, eaxRegister, cpuNum);
160 
161 	if (status == B_OK
162 		&& user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK)
163 		return B_BAD_ADDRESS;
164 
165 	return status;
166 }
167