Root/
Source at commit HEAD created 5 years 6 days ago. By ifabio, Few update to kernelPatcher (Credits to CrazyBirdy) | |
---|---|
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 | struct clock_frequency_info_t␊ |
14 | {␊ |
15 | ␉unsigned long bus_clock_rate_hz;␊ |
16 | ␉unsigned long cpu_clock_rate_hz;␊ |
17 | ␉unsigned long dec_clock_rate_hz;␊ |
18 | ␉unsigned long bus_clock_rate_num;␊ |
19 | ␉unsigned long bus_clock_rate_den;␊ |
20 | ␉unsigned long bus_to_cpu_rate_num;␊ |
21 | ␉unsigned long bus_to_cpu_rate_den;␊ |
22 | ␉unsigned long bus_to_dec_rate_num;␊ |
23 | ␉unsigned long bus_to_dec_rate_den;␊ |
24 | ␉unsigned long timebase_frequency_hz;␊ |
25 | ␉unsigned long timebase_frequency_num;␊ |
26 | ␉unsigned long timebase_frequency_den;␊ |
27 | ␉unsigned long long bus_frequency_hz;␊ |
28 | ␉unsigned long long bus_frequency_min_hz;␊ |
29 | ␉unsigned long long bus_frequency_max_hz;␊ |
30 | ␉unsigned long long cpu_frequency_hz;␊ |
31 | ␉unsigned long long cpu_frequency_min_hz;␊ |
32 | ␉unsigned long long cpu_frequency_max_hz;␊ |
33 | ␉unsigned long long prf_frequency_hz;␊ |
34 | ␉unsigned long long prf_frequency_min_hz;␊ |
35 | ␉unsigned long long prf_frequency_max_hz;␊ |
36 | ␉unsigned long long mem_frequency_hz;␊ |
37 | ␉unsigned long long mem_frequency_min_hz;␊ |
38 | ␉unsigned long long mem_frequency_max_hz;␊ |
39 | ␉unsigned long long fix_frequency_hz;␊ |
40 | };␊ |
41 | ␊ |
42 | typedef struct clock_frequency_info_t clock_frequency_info_t;␊ |
43 | ␊ |
44 | extern clock_frequency_info_t gPEClockFrequencyInfo;␊ |
45 | ␊ |
46 | ␊ |
47 | struct mach_timebase_info␊ |
48 | {␊ |
49 | ␉uint32_t␉numer;␊ |
50 | ␉uint32_t␉denom;␊ |
51 | };␊ |
52 | ␊ |
53 | struct hslock␊ |
54 | {␊ |
55 | ␉int␉␉lock_data;␊ |
56 | };␊ |
57 | typedef struct hslock hw_lock_data_t, *hw_lock_t;␊ |
58 | ␊ |
59 | #define hw_lock_addr(hwl)␉(&((hwl).lock_data))␊ |
60 | ␊ |
61 | typedef struct uslock_debug␊ |
62 | {␊ |
63 | ␉void␉␉*lock_pc;␉/* pc where lock operation began */␊ |
64 | ␉void␉␉*lock_thread;␉/* thread that acquired lock */␊ |
65 | ␉unsigned long␉duration[2];␊ |
66 | ␉unsigned short␉state;␊ |
67 | ␉unsigned char␉lock_cpu;␊ |
68 | ␉void␉␉*unlock_thread;␉/* last thread to release lock */␊ |
69 | ␉unsigned char␉unlock_cpu;␊ |
70 | ␉void␉␉*unlock_pc;␉/* pc where lock operation ended */␊ |
71 | } uslock_debug;␊ |
72 | ␊ |
73 | typedef struct slock␊ |
74 | {␊ |
75 | ␉hw_lock_data_t␉interlock;␉/* must be first... see lock.c */␊ |
76 | ␉unsigned short␉lock_type;␉/* must be second... see lock.c */␊ |
77 | #define USLOCK_TAG␉0x5353␊ |
78 | ␉uslock_debug␉debug;␊ |
79 | } usimple_lock_data_t, *usimple_lock_t;␊ |
80 | ␊ |
81 | #if !defined(decl_simple_lock_data)␊ |
82 | typedef usimple_lock_data_t␉*simple_lock_t;␊ |
83 | typedef usimple_lock_data_t␉simple_lock_data_t;␊ |
84 | ␊ |
85 | #define␉decl_simple_lock_data(class,name) \␊ |
86 | class␉simple_lock_data_t␉name;␊ |
87 | #endif␉/* !defined(decl_simple_lock_data) */␊ |
88 | ␊ |
89 | typedef struct mach_timebase_info␉*mach_timebase_info_t;␊ |
90 | typedef struct mach_timebase_info␉mach_timebase_info_data_t;␊ |
91 | ␊ |
92 | // DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM␊ |
93 | #define CALIBRATE_TIME_MSEC␉30␉␉/* 30 msecs */␊ |
94 | #define CALIBRATE_LATCH␉␉((CLKNUM * CALIBRATE_TIME_MSEC + 1000/2)/1000)␊ |
95 | ␊ |
96 | #define MSR_AMD_INT_PENDING_CMP_HALT 0xC0010055␊ |
97 | #define AMD_ACTONCMPHALT_SHIFT 27␊ |
98 | #define AMD_ACTONCMPHALT_MASK 3␊ |
99 | ␊ |
100 | /*␊ |
101 | * Control register 0␊ |
102 | */␊ |
103 | ␊ |
104 | typedef struct _cr0 {␊ |
105 | unsigned int␉pe␉:1,␊ |
106 | ␉␉␉mp␉:1,␊ |
107 | ␉␉␉em␉:1,␊ |
108 | ␉␉␉ts␉:1,␊ |
109 | ␉␉␉␉:1,␊ |
110 | ␉␉␉ne␉:1,␊ |
111 | ␉␉␉␉:10,␊ |
112 | ␉␉␉wp␉:1,␊ |
113 | ␉␉␉␉:1,␊ |
114 | ␉␉␉am␉:1,␊ |
115 | ␉␉␉␉:10,␊ |
116 | ␉␉␉nw␉:1,␊ |
117 | ␉␉␉cd␉:1,␊ |
118 | ␉␉␉pg␉:1;␊ |
119 | } cr0_t;␊ |
120 | ␊ |
121 | /*␊ |
122 | * Debugging register 6␊ |
123 | */␊ |
124 | ␊ |
125 | typedef struct _dr6 {␊ |
126 | unsigned int␉b0␉:1,␊ |
127 | ␉␉␉b1␉:1,␊ |
128 | ␉␉␉b2␉:1,␊ |
129 | ␉␉␉b3␉:1,␊ |
130 | ␉␉␉␉:9,␊ |
131 | ␉␉␉bd␉:1,␊ |
132 | ␉␉␉bs␉:1,␊ |
133 | ␉␉␉bt␉:1,␊ |
134 | ␉␉␉␉:16;␊ |
135 | } dr6_t;␊ |
136 | ␊ |
137 | static inline uint64_t rdtsc64(void)␊ |
138 | {␊ |
139 | ␉uint64_t ret;␊ |
140 | ␉__asm__ volatile("rdtsc" : "=A" (ret));␊ |
141 | ␉return ret;␊ |
142 | }␊ |
143 | ␊ |
144 | static inline uint64_t rdmsr64(uint32_t msr)␊ |
145 | {␊ |
146 | uint64_t ret;␊ |
147 | __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));␊ |
148 | return ret;␊ |
149 | }␊ |
150 | ␊ |
151 | static inline void wrmsr64(uint32_t msr, uint64_t val)␊ |
152 | {␊ |
153 | ␉__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));␊ |
154 | }␊ |
155 | ␊ |
156 | static inline void intel_waitforsts(void) {␊ |
157 | ␉uint32_t inline_timeout = 100000;␊ |
158 | ␉while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }␊ |
159 | }␊ |
160 | ␊ |
161 | /* From Apple's cpuid.h */␊ |
162 | typedef enum { eax, ebx, ecx, edx } cpuid_register_t;␊ |
163 | ␊ |
164 | static inline void cpuid(uint32_t *data)␊ |
165 | {␊ |
166 | ␉asm(␊ |
167 | ␉␉"cpuid" : "=a" (data[eax]),␊ |
168 | ␉␉"=b" (data[ebx]),␊ |
169 | ␉␉"=c" (data[ecx]),␊ |
170 | ␉␉"=d" (data[edx]) : "a" (data[eax]),␊ |
171 | ␉␉"b" (data[ebx]),␊ |
172 | ␉␉"c" (data[ecx]),␊ |
173 | ␉␉"d" (data[edx]));␊ |
174 | }␊ |
175 | ␊ |
176 | static inline void do_cpuid(uint32_t selector, uint32_t *data)␊ |
177 | {␊ |
178 | ␉asm(␊ |
179 | ␉␉"cpuid" : "=a" (data[eax]),␊ |
180 | ␉␉"=b" (data[ebx]),␊ |
181 | ␉␉"=c" (data[ecx]),␊ |
182 | ␉␉"=d" (data[edx]) : "a"(selector),␊ |
183 | ␉␉"b" (0),␊ |
184 | ␉␉"c" (0),␊ |
185 | ␉␉"d" (0));␊ |
186 | }␊ |
187 | ␊ |
188 | static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)␊ |
189 | {␊ |
190 | ␉asm volatile (␊ |
191 | ␉␉"cpuid" : "=a" (data[eax]),␊ |
192 | ␉␉"=b" (data[ebx]),␊ |
193 | ␉␉"=c" (data[ecx]),␊ |
194 | ␉␉"=d" (data[edx]) : "a" (selector),␊ |
195 | ␉␉"b" (0),␊ |
196 | ␉␉"c" (selector2),␊ |
197 | ␉␉"d" (0));␊ |
198 | }␊ |
199 | ␊ |
200 | // DFE: enable_PIT2 and disable_PIT2 come from older xnu␊ |
201 | ␊ |
202 | /*␊ |
203 | * Enable or disable timer 2.␊ |
204 | * Port 0x61 controls timer 2:␊ |
205 | * bit 0 gates the clock,␊ |
206 | * bit 1 gates output to speaker.␊ |
207 | */␊ |
208 | static inline void enable_PIT2(void)␊ |
209 | {␊ |
210 | /* Enable gate, disable speaker */␊ |
211 | __asm__ volatile(␊ |
212 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
213 | ␉␉␉␉␉ " and $0xFC,%%al \n\t" /* & ~0x03 */␊ |
214 | ␉␉␉␉␉ " or $1,%%al \n\t"␊ |
215 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
216 | ␉␉␉␉␉ : : : "%al" );␊ |
217 | }␊ |
218 | ␊ |
219 | static inline void disable_PIT2(void)␊ |
220 | {␊ |
221 | /* Disable gate and output to speaker */␊ |
222 | __asm__ volatile(␊ |
223 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
224 | ␉␉␉␉␉ " and $0xFC,%%al \n\t"␉/* & ~0x03 */␊ |
225 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
226 | ␉␉␉␉␉ : : : "%al" );␊ |
227 | }␊ |
228 | ␊ |
229 | // DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are␊ |
230 | // roughly based on Linux code␊ |
231 | ␊ |
232 | /* Set the 8254 channel 2 to mode 0 with the specified value.␊ |
233 | In mode 0, the counter will initially set its gate low when the␊ |
234 | timer expires. For this to be useful, you ought to set it high␊ |
235 | before calling this function. The enable_PIT2 function does this.␊ |
236 | */␊ |
237 | static inline void set_PIT2_mode0(uint16_t value)␊ |
238 | {␊ |
239 | __asm__ volatile(␊ |
240 | ␉␉␉␉␉ " movb $0xB0,%%al \n\t"␊ |
241 | ␉␉␉␉␉ " outb␉%%al,$0x43␉\n\t"␊ |
242 | ␉␉␉␉␉ " movb␉%%dl,%%al␉\n\t"␊ |
243 | ␉␉␉␉␉ " outb␉%%al,$0x42␉\n\t"␊ |
244 | ␉␉␉␉␉ " movb␉%%dh,%%al␉\n\t"␊ |
245 | ␉␉␉␉␉ " outb␉%%al,$0x42"␊ |
246 | ␉␉␉␉␉ : : "d"(value) /*: no clobber */ );␊ |
247 | }␊ |
248 | ␊ |
249 | /* Returns the number of times the loop ran before the PIT2 signaled */␊ |
250 | static inline unsigned long poll_PIT2_gate(void)␊ |
251 | {␊ |
252 | unsigned long count = 0;␊ |
253 | unsigned char nmi_sc_val;␊ |
254 | do {␊ |
255 | ++count;␊ |
256 | __asm__ volatile(␊ |
257 | ␉␉␉␉␉␉ "inb␉$0x61,%0"␊ |
258 | ␉␉␉␉␉␉ : "=a"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);␊ |
259 | } while( (nmi_sc_val & 0x20) == 0);␊ |
260 | return count;␊ |
261 | }␊ |
262 | ␊ |
263 | inline static void␊ |
264 | set_PIT2(int value)␊ |
265 | {␊ |
266 | /*␊ |
267 | * First, tell the clock we are going to write 16 bits to the counter␊ |
268 | * and enable one-shot mode (command 0xB8 to port 0x43)␊ |
269 | * Then write the two bytes into the PIT2 clock register (port 0x42).␊ |
270 | * Loop until the value is "realized" in the clock,␊ |
271 | * this happens on the next tick.␊ |
272 | */␊ |
273 | asm volatile(␊ |
274 | " movb $0xB8,%%al \n\t"␊ |
275 | " outb %%al,$0x43 \n\t"␊ |
276 | " movb %%dl,%%al \n\t"␊ |
277 | " outb %%al,$0x42 \n\t"␊ |
278 | " movb %%dh,%%al \n\t"␊ |
279 | " outb %%al,$0x42 \n"␊ |
280 | "1: inb $0x42,%%al \n\t" ␊ |
281 | " inb $0x42,%%al \n\t"␊ |
282 | " cmp %%al,%%dh \n\t"␊ |
283 | " jne 1b"␊ |
284 | : : "d"(value) : "%al");␊ |
285 | }␊ |
286 | ␊ |
287 | inline static uint64_t␊ |
288 | get_PIT2(unsigned int *value)␊ |
289 | {␊ |
290 | register uint64_t result;␊ |
291 | /*␊ |
292 | * This routine first latches the time (command 0x80 to port 0x43),␊ |
293 | * then gets the time stamp so we know how long the read will take later.␊ |
294 | * Read (from port 0x42) and return the current value of the timer.␊ |
295 | */␊ |
296 | #ifdef __i386__␊ |
297 | asm volatile(␊ |
298 | " xorl %%ecx,%%ecx \n\t"␊ |
299 | " movb $0x80,%%al \n\t"␊ |
300 | " outb %%al,$0x43 \n\t"␊ |
301 | " rdtsc \n\t"␊ |
302 | " pushl %%eax \n\t"␊ |
303 | " inb $0x42,%%al \n\t"␊ |
304 | " movb %%al,%%cl \n\t"␊ |
305 | " inb $0x42,%%al \n\t"␊ |
306 | " movb %%al,%%ch \n\t"␊ |
307 | " popl %%eax "␊ |
308 | : "=A"(result), "=c"(*value));␊ |
309 | #else /* __x86_64__ */␊ |
310 | asm volatile(␊ |
311 | ␉␉" xorq %%rcx,%%rcx \n\t"␊ |
312 | ␉␉" movb $0x80,%%al \n\t"␊ |
313 | ␉␉" outb %%al,$0x43 \n\t"␊ |
314 | ␉␉" rdtsc \n\t"␊ |
315 | ␉␉" pushq %%rax \n\t"␊ |
316 | ␉␉" inb $0x42,%%al \n\t"␊ |
317 | ␉␉" movb %%al,%%cl \n\t"␊ |
318 | ␉␉" inb $0x42,%%al \n\t"␊ |
319 | ␉␉" movb %%al,%%ch \n\t"␊ |
320 | ␉␉" popq %%rax "␊ |
321 | ␉␉: "=A"(result), "=c"(*value));␊ |
322 | #endif␊ |
323 | ␊ |
324 | return result;␊ |
325 | }␊ |
326 | ␊ |
327 | /*␊ |
328 | * Timing Functions␊ |
329 | */␊ |
330 | ␊ |
331 | /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */␊ |
332 | static inline void CpuPause(void)␊ |
333 | {␊ |
334 | ␉__asm__ volatile ("rep; nop");␊ |
335 | }␊ |
336 | ␊ |
337 | static inline uint32_t DivU64x32(uint64_t dividend, uint32_t divisor)␊ |
338 | {␊ |
339 | ␉__asm__ volatile ("divl %1" : "+A"(dividend) : "r"(divisor));␊ |
340 | ␉return (uint32_t) dividend;␊ |
341 | }␊ |
342 | ␊ |
343 | static inline uint64_t MultU32x32(uint32_t multiplicand, uint32_t multiplier)␊ |
344 | {␊ |
345 | ␉uint64_t result;␊ |
346 | ␉__asm__ volatile ("mull %2" : "=A"(result) : "a"(multiplicand), "r"(multiplier));␊ |
347 | ␉return result;␊ |
348 | }␊ |
349 | ␊ |
350 | #endif /* !__LIBSAIO_CPU_H */␊ |
351 |