Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/libsaio/cpu.h

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
11extern void scan_cpu(PlatformInfo_t *);
12
13struct clock_frequency_info_t
14{
15unsigned long bus_clock_rate_hz;
16unsigned long cpu_clock_rate_hz;
17unsigned long dec_clock_rate_hz;
18unsigned long bus_clock_rate_num;
19unsigned long bus_clock_rate_den;
20unsigned long bus_to_cpu_rate_num;
21unsigned long bus_to_cpu_rate_den;
22unsigned long bus_to_dec_rate_num;
23unsigned long bus_to_dec_rate_den;
24unsigned long timebase_frequency_hz;
25unsigned long timebase_frequency_num;
26unsigned long timebase_frequency_den;
27unsigned long long bus_frequency_hz;
28unsigned long long bus_frequency_min_hz;
29unsigned long long bus_frequency_max_hz;
30unsigned long long cpu_frequency_hz;
31unsigned long long cpu_frequency_min_hz;
32unsigned long long cpu_frequency_max_hz;
33unsigned long long prf_frequency_hz;
34unsigned long long prf_frequency_min_hz;
35unsigned long long prf_frequency_max_hz;
36unsigned long long mem_frequency_hz;
37unsigned long long mem_frequency_min_hz;
38unsigned long long mem_frequency_max_hz;
39unsigned long long fix_frequency_hz;
40};
41
42typedef struct clock_frequency_info_t clock_frequency_info_t;
43
44extern clock_frequency_info_t gPEClockFrequencyInfo;
45
46
47struct mach_timebase_info
48{
49uint32_tnumer;
50uint32_tdenom;
51};
52
53struct hslock
54{
55intlock_data;
56};
57typedef struct hslock hw_lock_data_t, *hw_lock_t;
58
59#define hw_lock_addr(hwl)(&((hwl).lock_data))
60
61typedef struct uslock_debug
62{
63void*lock_pc;/* pc where lock operation began */
64void*lock_thread;/* thread that acquired lock */
65unsigned longduration[2];
66unsigned shortstate;
67unsigned charlock_cpu;
68void*unlock_thread;/* last thread to release lock */
69unsigned charunlock_cpu;
70void*unlock_pc;/* pc where lock operation ended */
71} uslock_debug;
72
73typedef struct slock
74{
75hw_lock_data_tinterlock;/* must be first... see lock.c */
76unsigned shortlock_type;/* must be second... see lock.c */
77#define USLOCK_TAG0x5353
78uslock_debugdebug;
79} usimple_lock_data_t, *usimple_lock_t;
80
81#if !defined(decl_simple_lock_data)
82typedef usimple_lock_data_t*simple_lock_t;
83typedef usimple_lock_data_tsimple_lock_data_t;
84
85#definedecl_simple_lock_data(class,name) \
86classsimple_lock_data_tname;
87#endif/* !defined(decl_simple_lock_data) */
88
89typedef struct mach_timebase_info*mach_timebase_info_t;
90typedef struct mach_timebase_infomach_timebase_info_data_t;
91
92// DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM
93#define CALIBRATE_TIME_MSEC30/* 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
104typedef struct _cr0 {
105 unsigned intpe:1,
106 mp:1,
107em:1,
108ts:1,
109:1,
110ne:1,
111:10,
112wp:1,
113:1,
114am:1,
115:10,
116nw:1,
117cd:1,
118pg:1;
119} cr0_t;
120
121/*
122 * Debugging register 6
123 */
124
125typedef struct _dr6 {
126 unsigned intb0:1,
127 b1:1,
128b2:1,
129b3:1,
130:9,
131bd:1,
132bs:1,
133bt:1,
134:16;
135} dr6_t;
136
137static inline uint64_t rdtsc64(void)
138{
139uint64_t ret;
140__asm__ volatile("rdtsc" : "=A" (ret));
141return ret;
142}
143
144static 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
151static inline void wrmsr64(uint32_t msr, uint64_t val)
152{
153__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));
154}
155
156static inline void intel_waitforsts(void) {
157uint32_t inline_timeout = 100000;
158while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }
159}
160
161/* From Apple's cpuid.h */
162typedef enum { eax, ebx, ecx, edx } cpuid_register_t;
163
164static inline void cpuid(uint32_t *data)
165{
166asm(
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
176static inline void do_cpuid(uint32_t selector, uint32_t *data)
177{
178asm(
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
188static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)
189{
190asm 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 */
208static 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
219static 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 */
237static 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 */
250static 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
263inline static void
264set_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
287inline static uint64_t
288get_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. */
332static inline void CpuPause(void)
333{
334__asm__ volatile ("rep; nop");
335}
336
337static inline uint32_t DivU64x32(uint64_t dividend, uint32_t divisor)
338{
339__asm__ volatile ("divl %1" : "+A"(dividend) : "r"(divisor));
340return (uint32_t) dividend;
341}
342
343static inline uint64_t MultU32x32(uint32_t multiplicand, uint32_t multiplier)
344{
345uint64_t result;
346__asm__ volatile ("mull %2" : "=A"(result) : "a"(multiplicand), "r"(multiplier));
347return result;
348}
349
350#endif /* !__LIBSAIO_CPU_H */
351

Archive Download this file

Revision: 2803