2 Copyright © 2010-2017, The AROS Development Team. All rights reserved.
8 #include <aros/config.h>
9 #include <aros/debug.h>
10 #include <proto/exec.h>
11 #include <resources/processor.h>
13 #include "processor_arch_intern.h"
16 * This code can't work on hosted because rdmsr instruction requires supervisor privilege.
17 * Hosted ports could have host-specific version of this code which would utilize host OS services.
19 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
21 #define MSR_IA32_MPERF 0xE7
22 #define MSR_IA32_APERF 0xE8
23 #define MSR_P4_EBC_FREQUENCY_ID 0x2C
24 #define MSR_CORE_FSB_FREQ 0xCD
25 #define MSR_CORE_EBL_CR_POWERON 0x2A
26 #define MSR_NAHALEM_PLATFORM_INFO 0xCE
27 #define MSR_K10_PSTATE_P0 0xC0010064
28 #define MSR_K8_FIDVID_STATUS 0xC0010042
30 #define FSB_100 100000000ULL
31 #define FSB_133 133330000ULL
32 #define FSB_166 166670000ULL
33 #define FSB_200 200000000ULL
34 #define FSB_266 266670000ULL
35 #define FSB_333 333330000ULL
36 #define FSB_400 400000000ULL
38 static VOID
ReadIntelMaxFrequencyInformation(struct X86ProcessorInformation
* info
)
42 D(bug("[processor.x86] :%s()\n", __func__
));
46 /* Procedure for Pentium 4 family (NetBurst) */
47 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM4
) && (info
->Model
>= 2))
53 /* This procedure calculates the maximum frequency */
55 rdmsr(MSR_P4_EBC_FREQUENCY_ID
, &eax
, &edx
);
57 /*Intel 64 and IA-32 Architectures
58 Software Developer's Manual
59 Volume 3B:System Programming Guide, Part 2
61 switch((eax
>> 16) & 0x07)
69 case(1): fsb
= FSB_133
; break;
70 case(2): fsb
= FSB_200
; break;
71 case(3): fsb
= FSB_166
; break;
72 case(4): fsb
= FSB_333
; break;
73 default: fsb
= 0; break;
76 /* Getting multiplier at reset time */
79 info
->MaxCPUFrequency
= fsb
* mult
;
80 info
->MaxFSBFrequency
= fsb
* 4;
83 /* Procedure for Pentium M (part of Pentium Pro) family */
84 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM_PRO
) &&
86 (info
->Model
== 0x09) || /* Pentium M */
87 (info
->Model
== 0x0D) /* Pentium M */
94 /*Intel 64 and IA-32 Architectures
95 Software Developer's Manual
96 Volume 3B:System Programming Guide, Part 2
99 rdmsr(MSR_CORE_EBL_CR_POWERON
, &eax
, &edx
);
101 mult
= (eax
>> 22) & 0x1F;
103 info
->MaxCPUFrequency
= FSB_100
* mult
;
104 info
->MaxFSBFrequency
= FSB_100
* 4;
107 /* Procedure for Core (part of Pentium Pro) family (ATOM, Core, Core Duo) */
108 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM_PRO
) &&
110 (info
->Model
== 0x0E) || /* Core Duo */
111 (info
->Model
== 0x0F) || /* Core 2 Duo */
112 (info
->Model
== 0x16) || /* Core Celeron */
113 (info
->Model
== 0x17) || /* Core 2 Extreme */
114 (info
->Model
== 0x1C) /* ATOM */
122 /* This procedure calculates the maximum frequency */
124 rdmsr(MSR_CORE_FSB_FREQ
, &eax
, &edx
);
126 /*Intel 64 and IA-32 Architectures
127 Software Developer's Manual
128 Volume 3B:System Programming Guide, Part 2
132 case(5): fsb
= FSB_100
; break;
133 case(1): fsb
= FSB_133
; break;
134 case(3): fsb
= FSB_166
; break;
135 case(2): fsb
= FSB_200
; break;
136 case(0): fsb
= FSB_266
; break;
137 case(4): fsb
= FSB_333
; break;
138 case(6): fsb
= FSB_400
; break;
139 default: fsb
= 0; break;
142 rdmsr(MSR_CORE_EBL_CR_POWERON
, &eax
, &edx
);
143 /* Getting multiplier at reset time */
144 mult
= (eax
>> 22) & 0x1F;
146 info
->MaxCPUFrequency
= fsb
* mult
;
147 info
->MaxFSBFrequency
= fsb
* 4;
150 /* Procedure for Nahalem (part of Pentium Pro) family (i7, i5, i3) */
151 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM_PRO
) &&
153 (info
->Model
== 0x1A) || /* Core i7 */
154 (info
->Model
== 0x1E) || /* ? */
155 (info
->Model
== 0x1F) || /* ? */
156 (info
->Model
== 0x2E) /* ? */
162 /* This procedure calculates the maximum frequency */
163 mult
= rdmsri(MSR_NAHALEM_PLATFORM_INFO
);
165 /*Intel 64 and IA-32 Architectures
166 Software Developer's Manual
167 Volume 3B:System Programming Guide, Part 2
169 mult
= (mult
>> 8) & 0xFF;
171 info
->MaxCPUFrequency
= FSB_133
* mult
;
172 /* Note: FSB is not a valid concept with iX (Nahalem) processors */
173 info
->MaxFSBFrequency
= 0;
176 /* Procedure for SandyBridge and newer (part of Pentium Pro) family (i7, i5, i3) */
177 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM_PRO
) &&
179 (info
->Model
== 0x2A) || /* SandyBridge */
180 (info
->Model
== 0x2D) || /* SandyBridge */
181 (info
->Model
== 0x3A) || /* IvyBridge */
182 (info
->Model
== 0x3C) || /* Haswell */
183 (info
->Model
== 0x45) || /* Haswell */
184 (info
->Model
== 0x46) || /* Haswell */
185 (info
->Model
== 0x3F) /* Haswell-E */
186 /* More to come... */
192 /* This procedure calculates the maximum frequency */
193 mult
= rdmsri(MSR_NAHALEM_PLATFORM_INFO
);
195 /*Intel 64 and IA-32 Architectures
196 Software Developer's Manual
197 Volume 3B:System Programming Guide, Part 2
199 mult
= (mult
>> 8) & 0xFF;
201 info
->MaxCPUFrequency
= FSB_100
* mult
;
202 /* Note: FSB is not a valid concept with iX (Nahalem) processors */
203 info
->MaxFSBFrequency
= 0;
209 static VOID
ReadAMDMaxFrequencyInformation(struct X86ProcessorInformation
* info
)
213 D(bug("[processor.x86] :%s()\n", __func__
));
217 if (info
->Family
== CPUFAMILY_AMD_K10
)
220 ULONG cpufid
= 0, cpudid
= 0;
222 /* AMD Family 10h Processor BKDG, page 425 */
223 rdmsr(MSR_K10_PSTATE_P0
, &eax
, &edx
);
226 cpudid
= (eax
>> 6) & 0x07;
228 info
->MaxCPUFrequency
= FSB_100
* (cpufid
+ 0x10) / (1 << cpudid
);
229 /* Note: FSB is not a valid concept with K10 processors */
230 info
->MaxFSBFrequency
= 0;
233 if ((info
->Family
== CPUFAMILY_AMD_K9
)
234 || (info
->Family
== CPUFAMILY_AMD_K8
))
236 ULONG eax
, ebx
, ecx
, edx
;
240 /* BIOS and Kernel Developer's Guide for the AMD AthlonTM 64 and
241 AMD OpteronTM Processors, page 382 */
243 /* Check for power management features */
244 if (info
->CPUIDHighestExtendedFunction
< 0x80000007)
251 /* Check avalability of FID */
252 if ((edx
& 0x02) == 0)
258 /* It should be safe to read MSR_K8_FIDVID_STATUS */
259 rdmsr(MSR_K8_FIDVID_STATUS
, &eax
, &edx
);
261 cpufid
= (eax
>> 16) & 0x3F;
263 /* Note: K8 has only even multipliers, but they match K9 ones */
264 info
->MaxCPUFrequency
= FSB_200
* (4 * 2 + cpufid
) / 2;
266 /* Note: FSB is not a valid concept with K8, K9 processors */
267 info
->MaxFSBFrequency
= 0;
274 #endif /* AROS_FLAVOUR_STANDALONE */
276 VOID
ReadMaxFrequencyInformation(struct X86ProcessorInformation
* info
)
278 D(bug("[processor.x86] :%s()\n", __func__
));
280 info
->MaxCPUFrequency
= 0;
281 info
->MaxFSBFrequency
= 0;
283 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
288 ReadIntelMaxFrequencyInformation(info
);
291 ReadAMDMaxFrequencyInformation(info
);
300 /* Currently the only method of calculating CPU Frequency is based on
301 using performance counter. Other methods might include reading power state
302 and checking with ACPI power tables or hardcoded power tables */
304 UQUAD
GetCurrentProcessorFrequency(struct X86ProcessorInformation
* info
)
306 UQUAD retFreq
= info
->MaxCPUFrequency
;
308 D(bug("[processor.x86] :%s()\n", __func__
));
310 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
313 Check if APERF/MPERF is available
314 Notes: K10, K9 - rdmsr can be used to read current PState/cpufid/cpudid
316 if (info
->APERFMPERF
)
320 UQUAD startaperf
, endaperf
, diffaperf
= 0;
321 UQUAD startmperf
, endmperf
, diffmperf
= 0;
326 for(i
= 0; i
< 10; i
++)
328 rdmsr(MSR_IA32_MPERF
, &eax
, &edx
);
329 startmperf
= (UQUAD
)edx
<< 32 | eax
;
330 rdmsr(MSR_IA32_APERF
, &eax
, &edx
);
331 startaperf
= (UQUAD
)edx
<< 32 | eax
;
333 rdmsr(MSR_IA32_MPERF
, &eax
, &edx
);
334 endmperf
= (UQUAD
)edx
<< 32 | eax
;
335 rdmsr(MSR_IA32_APERF
, &eax
, &edx
);
336 endaperf
= (UQUAD
)edx
<< 32 | eax
;
338 if ((startmperf
> endmperf
) || (startaperf
> endaperf
))
339 continue; /* Overflow error. Skip */
341 diffmperf
+= endmperf
- startmperf
;
342 diffaperf
+= endaperf
- startaperf
;
347 D(bug("[processor.x86] %s: max: %x, diffa: %x, diffm %x\n", __func__
, info
->MaxCPUFrequency
, diffaperf
, diffmperf
));
349 if (info
->MaxCPUFrequency
== 0)
350 ReadMaxFrequencyInformation(info
);
352 /* Use ratio between MPERF and APERF */
354 retFreq
= info
->MaxCPUFrequency
* diffaperf
/ diffmperf
;
356 retFreq
= info
->MaxCPUFrequency
;