Chameleon

Chameleon Svn Source Tree

Root/branches/Chimera/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 "libsaio.h"
10
11extern void scan_cpu(PlatformInfo_t *);
12
13#define bit(n)(1ULL << (n))
14#define bitmask(h,l)((bit(h)|(bit(h)-1)) & ~(bit(l)-1))
15#define bitfield(x,h,l)(((x) & bitmask(h,l)) >> l)
16
17#define CPU_STRING_UNKNOWN"Unknown CPU Type"
18
19#define MSR_CORE_THREAD_COUNT0x35// Undocumented. Nehalem and newer only
20#define MSR_FLEX_RATIO 0x194// Undocumented.
21#define MSR_IA32_EXT_CONFIG 0xEE// Undocumented. Core Solo and Core Duo only
22#define MSR_PKG_CST_CONFIG_CTL0xE2
23#defineMSR_IA32_PERF_STATUS0x198
24#define MSR_IA32_PERF_CONTROL0x199
25#define MSR_IA32_PLATFORM_ID0x17
26#defineMSR_PLATFORM_INFO 0xCE
27#define MSR_TURBO_RATIO_LIMIT0x1AD
28
29#define K8_FIDVID_STATUS 0xC0010042
30#define K10_COFVID_STATUS 0xC0010071
31
32#define MSR_AMD_MPERF 0x000000E7
33#define MSR_AMD_APERF 0x000000E8
34
35#define DEFAULT_FSB100000 /* for now, hardcoding 100MHz for old CPUs */
36
37// DFE: This constant comes from older xnu:
38#define CLKNUM1193182/* formerly 1193167 */
39
40// DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM
41#define CALIBRATE_TIME_MSEC30/* 30 msecs */
42#define CALIBRATE_LATCH((CLKNUM * CALIBRATE_TIME_MSEC + 1000/2)/1000)
43
44static inline uint64_t rdtsc64(void)
45{
46uint64_t ret;
47__asm__ volatile("rdtsc" : "=A" (ret));
48return ret;
49}
50
51static inline uint64_t rdmsr64(uint32_t msr)
52{
53 uint64_t ret;
54 __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));
55 return ret;
56}
57
58static inline void wrmsr64(uint32_t msr, uint64_t val)
59{
60__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));
61}
62
63static inline void intel_waitforsts(void) {
64uint32_t inline_timeout = 100000;
65while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }
66}
67
68static inline void do_cpuid(uint32_t selector, uint32_t *data)
69{
70asm volatile ("cpuid"
71 : "=a" (data[0]),
72 "=b" (data[1]),
73 "=c" (data[2]),
74 "=d" (data[3])
75 : "a" (selector));
76}
77
78static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)
79{
80asm volatile ("cpuid"
81 : "=a" (data[0]),
82 "=b" (data[1]),
83 "=c" (data[2]),
84 "=d" (data[3])
85 : "a" (selector), "c" (selector2));
86}
87
88// DFE: enable_PIT2 and disable_PIT2 come from older xnu
89
90/*
91 * Enable or disable timer 2.
92 * Port 0x61 controls timer 2:
93 * bit 0 gates the clock,
94 * bit 1 gates output to speaker.
95 */
96static inline void enable_PIT2(void)
97{
98 /* Enable gate, disable speaker */
99 __asm__ volatile(
100 " inb $0x61,%%al \n\t"
101 " and $0xFC,%%al \n\t" /* & ~0x03 */
102 " or $1,%%al \n\t"
103 " outb %%al,$0x61 \n\t"
104 : : : "%al" );
105}
106
107static inline void disable_PIT2(void)
108{
109 /* Disable gate and output to speaker */
110 __asm__ volatile(
111 " inb $0x61,%%al \n\t"
112 " and $0xFC,%%al \n\t"/* & ~0x03 */
113 " outb %%al,$0x61 \n\t"
114 : : : "%al" );
115}
116
117// DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are
118// roughly based on Linux code
119
120/* Set the 8254 channel 2 to mode 0 with the specified value.
121 In mode 0, the counter will initially set its gate low when the
122 timer expires. For this to be useful, you ought to set it high
123 before calling this function. The enable_PIT2 function does this.
124 */
125static inline void set_PIT2_mode0(uint16_t value)
126{
127 __asm__ volatile(
128 " movb $0xB0,%%al \n\t"
129 " outb%%al,$0x43\n\t"
130 " movb%%dl,%%al\n\t"
131 " outb%%al,$0x42\n\t"
132 " movb%%dh,%%al\n\t"
133 " outb%%al,$0x42"
134 : : "d"(value) /*: no clobber */ );
135}
136
137/* Returns the number of times the loop ran before the PIT2 signaled */
138static inline unsigned long poll_PIT2_gate(void)
139{
140 unsigned long count = 0;
141 unsigned char nmi_sc_val;
142 do {
143 ++count;
144 __asm__ volatile(
145 "inb$0x61,%0"
146 : "=q"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);
147 } while( (nmi_sc_val & 0x20) == 0);
148 return count;
149}
150
151
152inline static void
153set_PIT2(int value)
154{
155/*
156 * First, tell the clock we are going to write 16 bits to the counter
157 * and enable one-shot mode (command 0xB8 to port 0x43)
158 * Then write the two bytes into the PIT2 clock register (port 0x42).
159 * Loop until the value is "realized" in the clock,
160 * this happens on the next tick.
161 */
162 asm volatile(
163 " movb $0xB8,%%al \n\t"
164 " outb %%al,$0x43 \n\t"
165 " movb %%dl,%%al \n\t"
166 " outb %%al,$0x42 \n\t"
167 " movb %%dh,%%al \n\t"
168 " outb %%al,$0x42 \n"
169"1: inb $0x42,%%al \n\t"
170 " inb $0x42,%%al \n\t"
171 " cmp %%al,%%dh \n\t"
172 " jne 1b"
173 : : "d"(value) : "%al");
174}
175
176
177inline static uint64_t
178get_PIT2(unsigned int *value)
179{
180 register uint64_t result;
181/*
182 * This routine first latches the time (command 0x80 to port 0x43),
183 * then gets the time stamp so we know how long the read will take later.
184 * Read (from port 0x42) and return the current value of the timer.
185 */
186#ifdef __i386__
187 asm volatile(
188 " xorl %%ecx,%%ecx \n\t"
189 " movb $0x80,%%al \n\t"
190 " outb %%al,$0x43 \n\t"
191 " rdtsc \n\t"
192 " pushl %%eax \n\t"
193 " inb $0x42,%%al \n\t"
194 " movb %%al,%%cl \n\t"
195 " inb $0x42,%%al \n\t"
196 " movb %%al,%%ch \n\t"
197 " popl %%eax "
198 : "=A"(result), "=c"(*value));
199#else /* __x86_64__ */
200 asm volatile(
201" xorq %%rcx,%%rcx \n\t"
202" movb $0x80,%%al \n\t"
203" outb %%al,$0x43 \n\t"
204" rdtsc \n\t"
205" pushq %%rax \n\t"
206" inb $0x42,%%al \n\t"
207" movb %%al,%%cl \n\t"
208" inb $0x42,%%al \n\t"
209" movb %%al,%%ch \n\t"
210" popq %%rax "
211: "=A"(result), "=c"(*value));
212#endif
213
214 return result;
215}
216
217#endif /* !__LIBSAIO_CPU_H */
218

Archive Download this file

Revision: 2225