1 | /*␊ |
2 | * Copyright 2008 Islam Ahmed Zaid. All rights reserved. <azismed@gmail.com>␊ |
3 | * AsereBLN: 2009: cleanup and bugfix␊ |
4 | */␊ |
5 | ␊ |
6 | #ifndef __LIBSAIO_CPU_H␊ |
7 | #define __LIBSAIO_CPU_H␊ |
8 | ␊ |
9 | #include "platform.h"␊ |
10 | ␊ |
11 | extern void scan_cpu(PlatformInfo_t *);␊ |
12 | ␊ |
13 | #define CPU_STRING_UNKNOWN␉␉"Unknown CPU Type"␊ |
14 | ␊ |
15 | //definitions from Apple XNU␊ |
16 | ␊ |
17 | /* CPU defines */␊ |
18 | #define bit(n)␉␉␉␉(1ULL << (n))␊ |
19 | #define bitmask(h,l)␉␉␉((bit(h) | (bit(h)-1)) & ~(bit(l)-1))␊ |
20 | #define bitfield(x,h,l)␉␉␉(((x) & bitmask(h,l)) >> l)␊ |
21 | #define hbit(n)␉␉␉␉(1ULL << ((n)+32))␊ |
22 | #define min(a,b)␉␉␉((a) < (b) ? (a) : (b))␊ |
23 | #define quad32(hi,lo)␉␉␉((((uint32_t)(hi)) << 16) | (((uint32_t)(lo)) & 0xFFFF))␊ |
24 | #define quad64(hi,lo)␉␉␉((((uint64_t)(hi)) << 32) | (((uint64_t)(lo)) & 0xFFFFFFFFUL))␊ |
25 | ␊ |
26 | /*␊ |
27 | * The CPUID_FEATURE_XXX values define 64-bit values␊ |
28 | * returned in %ecx:%edx to a CPUID request with %eax of 1: ␊ |
29 | */␊ |
30 | #define CPUID_FEATURE_FPU␉␉bit(0) /* Floating point unit on-chip */␊ |
31 | #define CPUID_FEATURE_VME␉␉bit(1) /* Virtual Mode Extension */␊ |
32 | #define CPUID_FEATURE_DE␉␉bit(2) /* Debugging Extension */␊ |
33 | #define CPUID_FEATURE_PSE␉␉bit(3) /* Page Size Extension */␊ |
34 | #define CPUID_FEATURE_TSC␉␉bit(4) /* Time Stamp Counter */␊ |
35 | #define CPUID_FEATURE_MSR␉␉bit(5) /* Model Specific Registers */␊ |
36 | #define CPUID_FEATURE_PAE␉␉bit(6) /* Physical Address Extension */␊ |
37 | #define CPUID_FEATURE_MCE␉␉bit(7) /* Machine Check Exception */␊ |
38 | #define CPUID_FEATURE_CX8␉␉bit(8) /* CMPXCHG8B */␊ |
39 | #define CPUID_FEATURE_APIC␉␉bit(9) /* On-chip APIC */␊ |
40 | #define CPUID_FEATURE_SEP␉␉bit(11) /* Fast System Call */␊ |
41 | #define CPUID_FEATURE_MTRR␉␉bit(12) /* Memory Type Range Register */␊ |
42 | #define CPUID_FEATURE_PGE␉␉bit(13) /* Page Global Enable */␊ |
43 | #define CPUID_FEATURE_MCA␉␉bit(14) /* Machine Check Architecture */␊ |
44 | #define CPUID_FEATURE_CMOV␉␉bit(15) /* Conditional Move Instruction */␊ |
45 | #define CPUID_FEATURE_PAT␉␉bit(16) /* Page Attribute Table */␊ |
46 | #define CPUID_FEATURE_PSE36␉␉bit(17) /* 36-bit Page Size Extension */␊ |
47 | #define CPUID_FEATURE_PSN␉␉bit(18) /* Processor Serial Number */␊ |
48 | #define CPUID_FEATURE_CLFSH␉␉bit(19) /* CLFLUSH Instruction supported */␊ |
49 | #define CPUID_FEATURE_DS␉␉bit(21) /* Debug Store */␊ |
50 | #define CPUID_FEATURE_ACPI␉␉bit(22) /* Thermal monitor and Clock Ctrl */␊ |
51 | #define CPUID_FEATURE_MMX␉␉bit(23) /* MMX supported */␊ |
52 | #define CPUID_FEATURE_FXSR␉␉bit(24) /* Fast floating pt save/restore */␊ |
53 | #define CPUID_FEATURE_SSE␉␉bit(25) /* Streaming SIMD extensions */␊ |
54 | #define CPUID_FEATURE_SSE2␉␉bit(26) /* Streaming SIMD extensions 2 */␊ |
55 | #define CPUID_FEATURE_SS␉␉bit(27) /* Self-Snoop */␊ |
56 | #define CPUID_FEATURE_HTT␉␉bit(28) /* Hyper-Threading Technology */␊ |
57 | #define CPUID_FEATURE_TM␉␉bit(29) /* Thermal Monitor (TM1) */␊ |
58 | #define CPUID_FEATURE_PBE␉␉bit(31) /* Pend Break Enable */␊ |
59 | ␊ |
60 | #define CPUID_FEATURE_SSE3␉␉hbit(0) /* Streaming SIMD extensions 3 */␊ |
61 | #define CPUID_FEATURE_PCLMULQDQ␉␉hbit(1) /* PCLMULQDQ Instruction */␊ |
62 | #define CPUID_FEATURE_DTES64␉␉hbit(2) /* 64-bit DS layout */␊ |
63 | #define CPUID_FEATURE_MONITOR␉␉hbit(3) /* Monitor/mwait */␊ |
64 | #define CPUID_FEATURE_DSCPL␉␉hbit(4) /* Debug Store CPL */␊ |
65 | #define CPUID_FEATURE_VMX␉␉hbit(5) /* VMX */␊ |
66 | #define CPUID_FEATURE_SMX␉␉hbit(6) /* SMX */␊ |
67 | #define CPUID_FEATURE_EST␉␉hbit(7) /* Enhanced SpeedsTep (GV3) */␊ |
68 | #define CPUID_FEATURE_TM2␉␉hbit(8) /* Thermal Monitor 2 */␊ |
69 | #define CPUID_FEATURE_SSSE3␉␉hbit(9) /* Supplemental SSE3 instructions */␊ |
70 | #define CPUID_FEATURE_CID␉␉hbit(10) /* L1 Context ID */␊ |
71 | #define CPUID_FEATURE_SEGLIM64␉␉hbit(11) /* 64-bit segment limit checking */␊ |
72 | #define CPUID_FEATURE_FMA␉␉hbit(12) /* Fused-Multiply-Add support */␊ |
73 | #define CPUID_FEATURE_CX16␉␉hbit(13) /* CmpXchg16b instruction */␊ |
74 | #define CPUID_FEATURE_xTPR␉␉hbit(14) /* Send Task PRiority msgs */␊ |
75 | #define CPUID_FEATURE_PDCM␉␉hbit(15) /* Perf/Debug Capability MSR */␊ |
76 | ␊ |
77 | #define CPUID_FEATURE_PCID␉␉hbit(17) /* ASID-PCID support */␊ |
78 | #define CPUID_FEATURE_DCA␉␉hbit(18) /* Direct Cache Access */␊ |
79 | #define CPUID_FEATURE_SSE4_1␉␉hbit(19) /* Streaming SIMD extensions 4.1 */␊ |
80 | #define CPUID_FEATURE_SSE4_2␉␉hbit(20) /* Streaming SIMD extensions 4.2 */␊ |
81 | #define CPUID_FEATURE_x2APIC␉␉hbit(21) /* Extended APIC Mode */␊ |
82 | #define CPUID_FEATURE_MOVBE␉␉hbit(22) /* MOVBE instruction */␊ |
83 | #define CPUID_FEATURE_POPCNT␉␉hbit(23) /* POPCNT instruction */␊ |
84 | #define CPUID_FEATURE_TSCTMR␉␉hbit(24) /* TSC deadline timer */␊ |
85 | #define CPUID_FEATURE_AES␉␉hbit(25) /* AES instructions */␊ |
86 | #define CPUID_FEATURE_XSAVE␉␉hbit(26) /* XSAVE instructions */␊ |
87 | #define CPUID_FEATURE_OSXSAVE␉␉hbit(27) /* XGETBV/XSETBV instructions */␊ |
88 | #define CPUID_FEATURE_AVX1_0␉␉hbit(28) /* AVX 1.0 instructions */␊ |
89 | #define CPUID_FEATURE_F16C␉␉hbit(29) /* Float16 convert instructions */␊ |
90 | #define CPUID_FEATURE_RDRAND␉␉hbit(30) /* RDRAND instruction */␊ |
91 | #define CPUID_FEATURE_VMM␉␉hbit(31) /* VMM (Hypervisor) present */␊ |
92 | ␊ |
93 | /*␊ |
94 | * Leaf 7, subleaf 0 additional features.␊ |
95 | * Bits returned in %ebx to a CPUID request with {%eax,%ecx} of (0x7,0x0}:␊ |
96 | */␊ |
97 | #define CPUID_LEAF7_FEATURE_RDWRFSGS␉bit(0)␉/* FS/GS base read/write */␊ |
98 | #define CPUID_LEAF7_FEATURE_TSCOFF␉bit(1)␉/* TSC thread offset */␊ |
99 | #define CPUID_LEAF7_FEATURE_BMI1␉bit(3)␉/* Bit Manipulation Instrs, set 1 */␊ |
100 | #define CPUID_LEAF7_FEATURE_HLE␉␉bit(4)␉/* Hardware Lock Elision*/␊ |
101 | #define CPUID_LEAF7_FEATURE_AVX2␉bit(5)␉/* AVX2 Instructions */␊ |
102 | #define CPUID_LEAF7_FEATURE_SMEP␉bit(7)␉/* Supervisor Mode Execute Protect */␊ |
103 | #define CPUID_LEAF7_FEATURE_BMI2␉bit(8)␉/* Bit Manipulation Instrs, set 2 */␊ |
104 | #define CPUID_LEAF7_FEATURE_ENFSTRG␉bit(9)␉/* ENhanced Fast STRinG copy */␊ |
105 | #define CPUID_LEAF7_FEATURE_INVPCID␉bit(10)␉/* INVPCID intruction, TDB */␊ |
106 | #define CPUID_LEAF7_FEATURE_RTM␉␉bit(11)␉/* TBD */␊ |
107 | ␊ |
108 | /*␊ |
109 | * The CPUID_EXTFEATURE_XXX values define 64-bit values␊ |
110 | * returned in %ecx:%edx to a CPUID request with %eax of 0x80000001: ␊ |
111 | */␊ |
112 | #define CPUID_EXTFEATURE_SYSCALL␉bit(11)␉/* SYSCALL/sysret */␊ |
113 | #define CPUID_EXTFEATURE_XD␉␉bit(20)␉/* eXecute Disable */␊ |
114 | ␊ |
115 | #define CPUID_EXTFEATURE_1GBPAGE␉bit(26)␉/* 1GB pages support */␊ |
116 | #define CPUID_EXTFEATURE_RDTSCP␉␉bit(27)␉/* RDTSCP */␊ |
117 | #define CPUID_EXTFEATURE_EM64T␉␉bit(29)␉/* Extended Mem 64 Technology */␊ |
118 | ␊ |
119 | ␊ |
120 | ␊ |
121 | #define CPUID_EXTFEATURE_LAHF␉␉hbit(0)␉/* LAFH/SAHF instructions */␊ |
122 | ␊ |
123 | /*␊ |
124 | * The CPUID_EXTFEATURE_XXX values define 64-bit values␊ |
125 | * returned in %ecx:%edx to a CPUID request with %eax of 0x80000007: ␊ |
126 | */␊ |
127 | #define CPUID_EXTFEATURE_TSCI␉␉bit(8)␉/* TSC Invariant */␊ |
128 | ␊ |
129 | #define␉CPUID_CACHE_SIZE␉␉16␉/* Number of descriptor values */␊ |
130 | ␊ |
131 | #define CPUID_MWAIT_EXTENSION␉␉bit(0)␉/* enumeration of WMAIT extensions */␊ |
132 | #define CPUID_MWAIT_BREAK␉␉bit(1)␉/* interrupts are break events␉ */␊ |
133 | ␊ |
134 | //-- processor type -> p_type:␊ |
135 | #define PT_OEM␉␉␉␉0x00␉// Intel Original OEM Processor;␊ |
136 | #define PT_OD␉␉␉␉0x01 ␉// Intel Over Drive Processor;␊ |
137 | #define PT_DUAL␉␉␉␉0x02␉// Intel Dual Processor;␊ |
138 | #define PT_RES␉␉␉␉0x03␉// Intel Reserved;␊ |
139 | ␊ |
140 | /* Known MSR registers */␊ |
141 | #define MSR_IA32_PLATFORM_ID␉␉0x0017␊ |
142 | #define IA32_APIC_BASE␉␉␉0x001B /* used also for AMD */␊ |
143 | #define MSR_CORE_THREAD_COUNT␉␉0x0035␉/* limited use - not for Penryn or older */␊ |
144 | #define IA32_TSC_ADJUST␉␉␉0x003B␊ |
145 | #define MSR_IA32_BIOS_SIGN_ID␉␉0x008B␉/* microcode version */␊ |
146 | #define MSR_FSB_FREQ␉␉␉0x00CD␉/* limited use - not for i7 */␊ |
147 | #define␉MSR_PLATFORM_INFO␉␉0x00CE␉/* limited use - MinRatio for i7 but Max for Yonah␉*/␊ |
148 | /* turbo for penryn */␊ |
149 | #define MSR_PKG_CST_CONFIG_CONTROL␉0x00E2␉␉// sandy and ivy␊ |
150 | #define MSR_PMG_IO_CAPTURE_BASE␉␉0x00E4␊ |
151 | #define IA32_MPERF␉␉␉0x00E7␉␉// TSC in C0 only␊ |
152 | #define IA32_APERF␉␉␉0x00E8␉␉// actual clocks in C0␊ |
153 | #define MSR_IA32_EXT_CONFIG␉␉0x00EE␉␉// limited use - not for i7␊ |
154 | #define MSR_FLEX_RATIO␉␉␉0x0194␉␉// limited use - not for Penryn or older␊ |
155 | ␉␉␉␉␉␉//see no value on most CPUs␊ |
156 | #define␉MSR_IA32_PERF_STATUS␉␉0x0198␊ |
157 | #define MSR_IA32_PERF_CONTROL␉␉0x0199␊ |
158 | #define MSR_IA32_CLOCK_MODULATION␉0x019A␊ |
159 | #define MSR_THERMAL_STATUS␉␉0x019C␊ |
160 | #define MSR_IA32_MISC_ENABLE␉␉0x01A0␊ |
161 | #define MSR_THERMAL_TARGET␉␉0x01A2␉␉// TjMax limited use - not for Penryn or older␊ |
162 | #define MSR_MISC_PWR_MGMT␉␉0x01AA␊ |
163 | #define MSR_TURBO_RATIO_LIMIT␉␉0x01AD␉␉// limited use - not for Penryn or older␊ |
164 | ␊ |
165 | #define IA32_ENERGY_PERF_BIAS␉␉0x01B0␊ |
166 | #define MSR_PACKAGE_THERM_STATUS␉0x01B1␊ |
167 | #define IA32_PLATFORM_DCA_CAP␉␉0x01F8␊ |
168 | #define MSR_POWER_CTL␉␉␉0x01FC␉␉// MSR 000001FC 0000-0000-0004-005F␊ |
169 | ␊ |
170 | // Sandy Bridge & JakeTown specific 'Running Average Power Limit' MSR's.␊ |
171 | #define MSR_RAPL_POWER_UNIT␉␉0x606␉␉// R/O␊ |
172 | //MSR 00000606 0000-0000-000A-1003␊ |
173 | #define MSR_PKGC3_IRTL␉␉␉0x60A␉␉// RW time limit to go C3␊ |
174 | // bit 15 = 1 -- the value valid for C-state PM␊ |
175 | #define MSR_PKGC6_IRTL␉␉␉0x60B␉␉// RW time limit to go C6␊ |
176 | //MSR 0000060B 0000-0000-0000-8854␊ |
177 | //Valid + 010=1024ns + 0x54=84mks␊ |
178 | #define MSR_PKGC7_IRTL␉␉␉0x60C␉␉// RW time limit to go C7␊ |
179 | //MSR 0000060C 0000-0000-0000-8854␊ |
180 | #define MSR_PKG_C2_RESIDENCY␉␉0x60D␉␉// same as TSC but in C2 only␊ |
181 | ␊ |
182 | #define MSR_PKG_RAPL_POWER_LIMIT␉0x610␉␉//MSR 00000610 0000-A580-0000-8960␊ |
183 | #define MSR_PKG_ENERGY_STATUS␉␉0x611␉␉//MSR 00000611 0000-0000-3212-A857␊ |
184 | #define MSR_PKG_POWER_INFO␉␉0x614␉␉//MSR 00000614 0000-0000-01E0-02F8␊ |
185 | ␊ |
186 | // Sandy Bridge IA (Core) domain MSR's.␊ |
187 | #define MSR_PP0_POWER_LIMIT␉␉0x638␊ |
188 | #define MSR_PP0_ENERGY_STATUS␉␉0x639␊ |
189 | #define MSR_PP0_POLICY␉␉␉0x63A␊ |
190 | #define MSR_PP0_PERF_STATUS␉␉0x63B␊ |
191 | ␊ |
192 | // Sandy Bridge Uncore (IGPU) domain MSR's (Not on JakeTown).␊ |
193 | #define MSR_PP1_POWER_LIMIT␉␉0x640␊ |
194 | #define MSR_PP1_ENERGY_STATUS␉ ␉0x641␊ |
195 | //MSR 00000641 0000-0000-0000-0000␊ |
196 | #define MSR_PP1_POLICY␉␉␉0x642␊ |
197 | ␊ |
198 | // JakeTown only Memory MSR's.␊ |
199 | #define MSR_PKG_PERF_STATUS␉␉0x613 ␊ |
200 | #define MSR_DRAM_POWER_LIMIT␉ ␉0x618␊ |
201 | #define MSR_DRAM_ENERGY_STATUS␉␉0x619␊ |
202 | #define MSR_DRAM_PERF_STATUS␉␉0x61B␊ |
203 | #define MSR_DRAM_POWER_INFO␉␉0x61C␊ |
204 | ␊ |
205 | //IVY_BRIDGE␊ |
206 | #define MSR_CONFIG_TDP_NOMINAL␉␉0x648␊ |
207 | #define MSR_CONFIG_TDP_LEVEL1␉␉0x649␊ |
208 | #define MSR_CONFIG_TDP_LEVEL2␉␉0x64A␊ |
209 | #define MSR_CONFIG_TDP_CONTROL␉␉0x64B␉␉// write once to lock␊ |
210 | #define MSR_TURBO_ACTIVATION_RATIO␉0x64C␊ |
211 | ␊ |
212 | //AMD␊ |
213 | #define K8_FIDVID_STATUS␉␉0xC0010042␊ |
214 | #define K10_COFVID_LIMIT␉␉0xC0010061␉// max enabled p-state (msr >> 4) & 7␊ |
215 | #define K10_COFVID_CONTROL␉␉0xC0010062␉// switch to p-state␊ |
216 | #define K10_PSTATE_STATUS␉␉0xC0010064␊ |
217 | #define K10_COFVID_STATUS␉␉0xC0010071␉// current p-state (msr >> 16) & 7␊ |
218 | ␊ |
219 | #define MSR_AMD_MPERF␉␉␉0x000000E7␊ |
220 | #define MSR_AMD_APERF␉␉␉0x000000E8␊ |
221 | ␊ |
222 | #define DEFAULT_FSB␉␉␉100000 /* for now, hardcoding 100MHz for old CPUs */␊ |
223 | ␊ |
224 | // DFE: This constant comes from older xnu:␊ |
225 | #define CLKNUM␉␉␉␉1193182␉␉/* formerly 1193167 */␊ |
226 | ␊ |
227 | // DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM␊ |
228 | #define CALIBRATE_TIME_MSEC␉30␉␉/* 30 msecs */␊ |
229 | #define CALIBRATE_LATCH␉␉((CLKNUM * CALIBRATE_TIME_MSEC + 1000/2)/1000)␊ |
230 | ␊ |
231 | static inline uint64_t rdtsc64(void)␊ |
232 | {␊ |
233 | ␉uint64_t ret;␊ |
234 | ␉__asm__ volatile("rdtsc" : "=A" (ret));␊ |
235 | ␉return ret;␊ |
236 | }␊ |
237 | ␊ |
238 | static inline uint64_t rdmsr64(uint32_t msr)␊ |
239 | {␊ |
240 | uint64_t ret;␊ |
241 | __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));␊ |
242 | return ret;␊ |
243 | }␊ |
244 | ␊ |
245 | static inline void wrmsr64(uint32_t msr, uint64_t val)␊ |
246 | {␊ |
247 | ␉__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));␊ |
248 | }␊ |
249 | ␊ |
250 | static inline void intel_waitforsts(void) {␊ |
251 | ␉uint32_t inline_timeout = 100000;␊ |
252 | ␉while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }␊ |
253 | }␊ |
254 | ␊ |
255 | /* From Apple's cpuid.h */␊ |
256 | typedef enum { eax, ebx, ecx, edx } cpuid_register_t;␊ |
257 | ␊ |
258 | static inline void cpuid(uint32_t *data)␊ |
259 | {␊ |
260 | ␉asm(␊ |
261 | ␉␉"cpuid" : "=a" (data[eax]),␊ |
262 | ␉␉"=b" (data[ebx]),␊ |
263 | ␉␉"=c" (data[ecx]),␊ |
264 | ␉␉"=d" (data[edx]) : "a" (data[eax]),␊ |
265 | ␉␉"b" (data[ebx]),␊ |
266 | ␉␉"c" (data[ecx]),␊ |
267 | ␉␉"d" (data[edx]));␊ |
268 | }␊ |
269 | ␊ |
270 | static inline void do_cpuid(uint32_t selector, uint32_t *data)␊ |
271 | {␊ |
272 | ␉asm(␊ |
273 | ␉␉"cpuid" : "=a" (data[eax]),␊ |
274 | ␉␉"=b" (data[ebx]),␊ |
275 | ␉␉"=c" (data[ecx]),␊ |
276 | ␉␉"=d" (data[edx]) : "a"(selector),␊ |
277 | ␉␉"b" (0),␊ |
278 | ␉␉"c" (0),␊ |
279 | ␉␉"d" (0));␊ |
280 | }␊ |
281 | ␊ |
282 | static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)␊ |
283 | {␊ |
284 | ␉asm volatile (␊ |
285 | ␉␉"cpuid" : "=a" (data[eax]),␊ |
286 | ␉␉"=b" (data[ebx]),␊ |
287 | ␉␉"=c" (data[ecx]),␊ |
288 | ␉␉"=d" (data[edx]) : "a" (selector),␊ |
289 | ␉␉"b" (0),␊ |
290 | ␉␉"c" (selector2),␊ |
291 | ␉␉"d" (0));␊ |
292 | }␊ |
293 | ␊ |
294 | // DFE: enable_PIT2 and disable_PIT2 come from older xnu␊ |
295 | ␊ |
296 | /*␊ |
297 | * Enable or disable timer 2.␊ |
298 | * Port 0x61 controls timer 2:␊ |
299 | * bit 0 gates the clock,␊ |
300 | * bit 1 gates output to speaker.␊ |
301 | */␊ |
302 | static inline void enable_PIT2(void)␊ |
303 | {␊ |
304 | /* Enable gate, disable speaker */␊ |
305 | __asm__ volatile(␊ |
306 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
307 | ␉␉␉␉␉ " and $0xFC,%%al \n\t" /* & ~0x03 */␊ |
308 | ␉␉␉␉␉ " or $1,%%al \n\t"␊ |
309 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
310 | ␉␉␉␉␉ : : : "%al" );␊ |
311 | }␊ |
312 | ␊ |
313 | static inline void disable_PIT2(void)␊ |
314 | {␊ |
315 | /* Disable gate and output to speaker */␊ |
316 | __asm__ volatile(␊ |
317 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
318 | ␉␉␉␉␉ " and $0xFC,%%al \n\t"␉/* & ~0x03 */␊ |
319 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
320 | ␉␉␉␉␉ : : : "%al" );␊ |
321 | }␊ |
322 | ␊ |
323 | // DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are␊ |
324 | // roughly based on Linux code␊ |
325 | ␊ |
326 | /* Set the 8254 channel 2 to mode 0 with the specified value.␊ |
327 | In mode 0, the counter will initially set its gate low when the␊ |
328 | timer expires. For this to be useful, you ought to set it high␊ |
329 | before calling this function. The enable_PIT2 function does this.␊ |
330 | */␊ |
331 | static inline void set_PIT2_mode0(uint16_t value)␊ |
332 | {␊ |
333 | __asm__ volatile(␊ |
334 | ␉␉␉␉␉ " movb $0xB0,%%al \n\t"␊ |
335 | ␉␉␉␉␉ " outb␉%%al,$0x43␉\n\t"␊ |
336 | ␉␉␉␉␉ " movb␉%%dl,%%al␉\n\t"␊ |
337 | ␉␉␉␉␉ " outb␉%%al,$0x42␉\n\t"␊ |
338 | ␉␉␉␉␉ " movb␉%%dh,%%al␉\n\t"␊ |
339 | ␉␉␉␉␉ " outb␉%%al,$0x42"␊ |
340 | ␉␉␉␉␉ : : "d"(value) /*: no clobber */ );␊ |
341 | }␊ |
342 | ␊ |
343 | /* Returns the number of times the loop ran before the PIT2 signaled */␊ |
344 | static inline unsigned long poll_PIT2_gate(void)␊ |
345 | {␊ |
346 | unsigned long count = 0;␊ |
347 | unsigned char nmi_sc_val;␊ |
348 | do {␊ |
349 | ++count;␊ |
350 | __asm__ volatile(␊ |
351 | ␉␉␉␉␉␉ "inb␉$0x61,%0"␊ |
352 | ␉␉␉␉␉␉ : "=a"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);␊ |
353 | } while( (nmi_sc_val & 0x20) == 0);␊ |
354 | return count;␊ |
355 | }␊ |
356 | ␊ |
357 | inline static void␊ |
358 | set_PIT2(int value)␊ |
359 | {␊ |
360 | /*␊ |
361 | * First, tell the clock we are going to write 16 bits to the counter␊ |
362 | * and enable one-shot mode (command 0xB8 to port 0x43)␊ |
363 | * Then write the two bytes into the PIT2 clock register (port 0x42).␊ |
364 | * Loop until the value is "realized" in the clock,␊ |
365 | * this happens on the next tick.␊ |
366 | */␊ |
367 | asm volatile(␊ |
368 | " movb $0xB8,%%al \n\t"␊ |
369 | " outb %%al,$0x43 \n\t"␊ |
370 | " movb %%dl,%%al \n\t"␊ |
371 | " outb %%al,$0x42 \n\t"␊ |
372 | " movb %%dh,%%al \n\t"␊ |
373 | " outb %%al,$0x42 \n"␊ |
374 | "1: inb $0x42,%%al \n\t" ␊ |
375 | " inb $0x42,%%al \n\t"␊ |
376 | " cmp %%al,%%dh \n\t"␊ |
377 | " jne 1b"␊ |
378 | : : "d"(value) : "%al");␊ |
379 | }␊ |
380 | ␊ |
381 | ␊ |
382 | inline static uint64_t␊ |
383 | get_PIT2(unsigned int *value)␊ |
384 | {␊ |
385 | register uint64_t result;␊ |
386 | /*␊ |
387 | * This routine first latches the time (command 0x80 to port 0x43),␊ |
388 | * then gets the time stamp so we know how long the read will take later.␊ |
389 | * Read (from port 0x42) and return the current value of the timer.␊ |
390 | */␊ |
391 | #ifdef __i386__␊ |
392 | asm volatile(␊ |
393 | " xorl %%ecx,%%ecx \n\t"␊ |
394 | " movb $0x80,%%al \n\t"␊ |
395 | " outb %%al,$0x43 \n\t"␊ |
396 | " rdtsc \n\t"␊ |
397 | " pushl %%eax \n\t"␊ |
398 | " inb $0x42,%%al \n\t"␊ |
399 | " movb %%al,%%cl \n\t"␊ |
400 | " inb $0x42,%%al \n\t"␊ |
401 | " movb %%al,%%ch \n\t"␊ |
402 | " popl %%eax "␊ |
403 | : "=A"(result), "=c"(*value));␊ |
404 | #else /* __x86_64__ */␊ |
405 | asm volatile(␊ |
406 | ␉␉" xorq %%rcx,%%rcx \n\t"␊ |
407 | ␉␉" movb $0x80,%%al \n\t"␊ |
408 | ␉␉" outb %%al,$0x43 \n\t"␊ |
409 | ␉␉" rdtsc \n\t"␊ |
410 | ␉␉" pushq %%rax \n\t"␊ |
411 | ␉␉" inb $0x42,%%al \n\t"␊ |
412 | ␉␉" movb %%al,%%cl \n\t"␊ |
413 | ␉␉" inb $0x42,%%al \n\t"␊ |
414 | ␉␉" movb %%al,%%ch \n\t"␊ |
415 | ␉␉" popq %%rax "␊ |
416 | ␉␉: "=A"(result), "=c"(*value));␊ |
417 | #endif␊ |
418 | ␊ |
419 | return result;␊ |
420 | }␊ |
421 | ␊ |
422 | #endif /* !__LIBSAIO_CPU_H */␊ |
423 | |