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
96static inline uint64_t rdtsc64(void)
97{
98uint64_t ret;
99__asm__ volatile("rdtsc" : "=A" (ret));
100return ret;
101}
102
103static inline uint64_t rdmsr64(uint32_t msr)
104{
105 uint64_t ret;
106 __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));
107 return ret;
108}
109
110static inline void wrmsr64(uint32_t msr, uint64_t val)
111{
112__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));
113}
114
115static inline void intel_waitforsts(void) {
116uint32_t inline_timeout = 100000;
117while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }
118}
119
120/* From Apple's cpuid.h */
121typedef enum { eax, ebx, ecx, edx } cpuid_register_t;
122
123static inline void cpuid(uint32_t *data)
124{
125asm(
126"cpuid" : "=a" (data[eax]),
127"=b" (data[ebx]),
128"=c" (data[ecx]),
129"=d" (data[edx]) : "a" (data[eax]),
130"b" (data[ebx]),
131"c" (data[ecx]),
132"d" (data[edx]));
133}
134
135static inline void do_cpuid(uint32_t selector, uint32_t *data)
136{
137asm(
138"cpuid" : "=a" (data[eax]),
139"=b" (data[ebx]),
140"=c" (data[ecx]),
141"=d" (data[edx]) : "a"(selector),
142"b" (0),
143"c" (0),
144"d" (0));
145}
146
147static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)
148{
149asm volatile (
150"cpuid" : "=a" (data[eax]),
151"=b" (data[ebx]),
152"=c" (data[ecx]),
153"=d" (data[edx]) : "a" (selector),
154"b" (0),
155"c" (selector2),
156"d" (0));
157}
158
159// DFE: enable_PIT2 and disable_PIT2 come from older xnu
160
161/*
162 * Enable or disable timer 2.
163 * Port 0x61 controls timer 2:
164 * bit 0 gates the clock,
165 * bit 1 gates output to speaker.
166 */
167static inline void enable_PIT2(void)
168{
169 /* Enable gate, disable speaker */
170 __asm__ volatile(
171 " inb $0x61,%%al \n\t"
172 " and $0xFC,%%al \n\t" /* & ~0x03 */
173 " or $1,%%al \n\t"
174 " outb %%al,$0x61 \n\t"
175 : : : "%al" );
176}
177
178static inline void disable_PIT2(void)
179{
180 /* Disable gate and output to speaker */
181 __asm__ volatile(
182 " inb $0x61,%%al \n\t"
183 " and $0xFC,%%al \n\t"/* & ~0x03 */
184 " outb %%al,$0x61 \n\t"
185 : : : "%al" );
186}
187
188// DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are
189// roughly based on Linux code
190
191/* Set the 8254 channel 2 to mode 0 with the specified value.
192 In mode 0, the counter will initially set its gate low when the
193 timer expires. For this to be useful, you ought to set it high
194 before calling this function. The enable_PIT2 function does this.
195 */
196static inline void set_PIT2_mode0(uint16_t value)
197{
198 __asm__ volatile(
199 " movb $0xB0,%%al \n\t"
200 " outb%%al,$0x43\n\t"
201 " movb%%dl,%%al\n\t"
202 " outb%%al,$0x42\n\t"
203 " movb%%dh,%%al\n\t"
204 " outb%%al,$0x42"
205 : : "d"(value) /*: no clobber */ );
206}
207
208/* Returns the number of times the loop ran before the PIT2 signaled */
209static inline unsigned long poll_PIT2_gate(void)
210{
211 unsigned long count = 0;
212 unsigned char nmi_sc_val;
213 do {
214 ++count;
215 __asm__ volatile(
216 "inb$0x61,%0"
217 : "=a"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);
218 } while( (nmi_sc_val & 0x20) == 0);
219 return count;
220}
221
222inline static void
223set_PIT2(int value)
224{
225/*
226 * First, tell the clock we are going to write 16 bits to the counter
227 * and enable one-shot mode (command 0xB8 to port 0x43)
228 * Then write the two bytes into the PIT2 clock register (port 0x42).
229 * Loop until the value is "realized" in the clock,
230 * this happens on the next tick.
231 */
232 asm volatile(
233 " movb $0xB8,%%al \n\t"
234 " outb %%al,$0x43 \n\t"
235 " movb %%dl,%%al \n\t"
236 " outb %%al,$0x42 \n\t"
237 " movb %%dh,%%al \n\t"
238 " outb %%al,$0x42 \n"
239"1: inb $0x42,%%al \n\t"
240 " inb $0x42,%%al \n\t"
241 " cmp %%al,%%dh \n\t"
242 " jne 1b"
243 : : "d"(value) : "%al");
244}
245
246
247inline static uint64_t
248get_PIT2(unsigned int *value)
249{
250 register uint64_t result;
251/*
252 * This routine first latches the time (command 0x80 to port 0x43),
253 * then gets the time stamp so we know how long the read will take later.
254 * Read (from port 0x42) and return the current value of the timer.
255 */
256#ifdef __i386__
257 asm volatile(
258 " xorl %%ecx,%%ecx \n\t"
259 " movb $0x80,%%al \n\t"
260 " outb %%al,$0x43 \n\t"
261 " rdtsc \n\t"
262 " pushl %%eax \n\t"
263 " inb $0x42,%%al \n\t"
264 " movb %%al,%%cl \n\t"
265 " inb $0x42,%%al \n\t"
266 " movb %%al,%%ch \n\t"
267 " popl %%eax "
268 : "=A"(result), "=c"(*value));
269#else /* __x86_64__ */
270 asm volatile(
271" xorq %%rcx,%%rcx \n\t"
272" movb $0x80,%%al \n\t"
273" outb %%al,$0x43 \n\t"
274" rdtsc \n\t"
275" pushq %%rax \n\t"
276" inb $0x42,%%al \n\t"
277" movb %%al,%%cl \n\t"
278" inb $0x42,%%al \n\t"
279" movb %%al,%%ch \n\t"
280" popq %%rax "
281: "=A"(result), "=c"(*value));
282#endif
283
284 return result;
285}
286
287#endif /* !__LIBSAIO_CPU_H */
288

Archive Download this file

Revision: 2679