Chameleon

Chameleon Svn Source Tree

Root/trunk/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
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#defineMSR_IA32_PERF_STATUS0x00000198
20#define MSR_IA32_PERF_CONTROL0x199
21#define MSR_IA32_EXT_CONFIG0x00EE
22#define MSR_FLEX_RATIO0x194
23#define MSR_TURBO_RATIO_LIMIT0x1AD
24#defineMSR_PLATFORM_INFO0xCE
25#define MSR_CORE_THREAD_COUNT0x35// Undocumented
26#define MSR_IA32_PLATFORM_ID0x17
27
28#define K8_FIDVID_STATUS0xC0010042
29#define K10_COFVID_STATUS0xC0010071
30
31#define MSR_AMD_MPERF 0x000000E7
32#define MSR_AMD_APERF 0x000000E8
33
34#define DEFAULT_FSB100000 /* for now, hardcoding 100MHz for old CPUs */
35
36// DFE: This constant comes from older xnu:
37#define CLKNUM1193182/* formerly 1193167 */
38
39// DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM
40#define CALIBRATE_TIME_MSEC30/* 30 msecs */
41#define CALIBRATE_LATCH((CLKNUM * CALIBRATE_TIME_MSEC + 1000/2)/1000)
42
43// CPUID Values
44
45#define CPUID_MODEL_PRESCOTT3 // 0x03 Celeron D, Pentium 4 (90nm)
46#define CPUID_MODEL_NOCONA4 // 0x04 Xeon Nocona, Irwindale (90nm)
47#define CPUID_MODEL_PRESLER6 // 0x06 Pentium 4, Pentium D (65nm)
48#define CPUID_MODEL_PENTIUM_M9 // 0x09
49#define CPUID_MODEL_DOTHAN13 // 0x0D Dothan
50#define CPUID_MODEL_YONAH14 // 0x0E Intel Mobile Core Solo, Duo
51#define CPUID_MODEL_MEROM15 // 0x0F Intel Mobile Core 2 Solo, Duo, Xeon 30xx, Xeon 51xx, Xeon X53xx, Xeon E53xx, Xeon X32xx
52#define CPUID_MODEL_CONROE15 // 0x0F
53#define CPUID_MODEL_CELERON22 // 0x16
54#define CPUID_MODEL_PENRYN23 // 0x17 Intel Core 2 Solo, Duo, Quad, Extreme, Xeon X54xx, Xeon X33xx
55#define CPUID_MODEL_WOLFDALE23 // 0x17
56#define CPUID_MODEL_NEHALEM26 // 0x1A Intel Core i7, Xeon W35xx, Xeon X55xx, Xeon E55xx LGA1366 (45nm)
57#define CPUID_MODEL_ATOM28 // 0x1C Intel Atom (45nm) Pineview, Silverthorne
58#define CPUID_MODEL_XEON_MP29 // 0x1D MP 7400
59#define CPUID_MODEL_FIELDS30 // 0x1E Intel Core i5, i7, Xeon X34xx LGA1156 (45nm),(Clarksfiled, Lynnfield, Jasper Forest)
60#define CPUID_MODEL_DALES31 // 0x1F Havendale, Auburndale
61#define CPUID_MODEL_DALES_32NM37 // 0x25 Intel Core i3, i5 LGA1156 (32nm), (Arrandale, Clarksdale)
62#define CPUID_MODEL_ATOM_SAN38 // 0x26
63#define CPUID_MODEL_LINCROFT39 // 0x27 Intel Atom (45nm) Z6xx (single core)
64#define CPUID_MODEL_SANDYBRIDGE42 // 0x2A Intel Core i3, i5, i7 LGA1155 (32nm)
65#define CPUID_MODEL_WESTMERE44 // 0x2C Intel Core i7, Xeon X56xx, Xeon E56xx, Xeon W36xx LGA1366 (32nm) 6 Core
66#define CPUID_MODEL_JAKETOWN 45 // 0x2D Intel Xeon E5 LGA2011 (32nm), SandyBridge-E, SandyBridge-EN, SandyBridge-EP
67#define CPUID_MODEL_NEHALEM_EX46 // 0x2E Intel Xeon X75xx, Xeon X65xx, Xeon E75xx, Xeon E65x
68#define CPUID_MODEL_WESTMERE_EX47 // 0x2F Intel Xeon E7
69#define CPUID_MODEL_ATOM_200054 // 0x36 Intel Atom (32nm) Cedarview
70#define CPUID_MODEL_IVYBRIDGE58 // 0x3A Intel Core i5, i7 LGA1155 (22nm)
71#define CPUID_MODEL_HASWELL60 // 0x3C Desktop version
72#define CPUID_MODEL_IVYBRIDGE_XEON62 // 0x3E
73#define CPUID_MODEL_HASWELL_MB63 // 0x3F Mobile/Laptop version
74//#define CPUID_MODEL_HASWELL_H?? // 0x??
75#define CPUID_MODEL_HASWELL_ULT69 // 0x45
76#define CPUID_MODEL_HASWELL_ULX70 // 0x46
77
78/* HASWELL-DT HASWELL-MB HASWELL-H HASWELL-ULT HASWELL ULX*/
79
80static inline uint64_t rdtsc64(void)
81{
82uint64_t ret;
83__asm__ volatile("rdtsc" : "=A" (ret));
84return ret;
85}
86
87static inline uint64_t rdmsr64(uint32_t msr)
88{
89 uint64_t ret;
90 __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));
91 return ret;
92}
93
94static inline void wrmsr64(uint32_t msr, uint64_t val)
95{
96__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));
97}
98
99static inline void intel_waitforsts(void) {
100uint32_t inline_timeout = 100000;
101while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }
102}
103
104static inline void do_cpuid(uint32_t selector, uint32_t *data)
105{
106asm volatile ("cpuid"
107 : "=a" (data[0]),
108 "=b" (data[1]),
109 "=c" (data[2]),
110 "=d" (data[3])
111 : "a" (selector));
112}
113
114static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)
115{
116asm volatile ("cpuid"
117 : "=a" (data[0]),
118 "=b" (data[1]),
119 "=c" (data[2]),
120 "=d" (data[3])
121 : "a" (selector), "c" (selector2));
122}
123
124// DFE: enable_PIT2 and disable_PIT2 come from older xnu
125
126/*
127 * Enable or disable timer 2.
128 * Port 0x61 controls timer 2:
129 * bit 0 gates the clock,
130 * bit 1 gates output to speaker.
131 */
132static inline void enable_PIT2(void)
133{
134 /* Enable gate, disable speaker */
135 __asm__ volatile(
136 " inb $0x61,%%al \n\t"
137 " and $0xFC,%%al \n\t" /* & ~0x03 */
138 " or $1,%%al \n\t"
139 " outb %%al,$0x61 \n\t"
140 : : : "%al" );
141}
142
143static inline void disable_PIT2(void)
144{
145 /* Disable gate and output to speaker */
146 __asm__ volatile(
147 " inb $0x61,%%al \n\t"
148 " and $0xFC,%%al \n\t"/* & ~0x03 */
149 " outb %%al,$0x61 \n\t"
150 : : : "%al" );
151}
152
153// DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are
154// roughly based on Linux code
155
156/* Set the 8254 channel 2 to mode 0 with the specified value.
157 In mode 0, the counter will initially set its gate low when the
158 timer expires. For this to be useful, you ought to set it high
159 before calling this function. The enable_PIT2 function does this.
160 */
161static inline void set_PIT2_mode0(uint16_t value)
162{
163 __asm__ volatile(
164 " movb $0xB0,%%al \n\t"
165 " outb%%al,$0x43\n\t"
166 " movb%%dl,%%al\n\t"
167 " outb%%al,$0x42\n\t"
168 " movb%%dh,%%al\n\t"
169 " outb%%al,$0x42"
170 : : "d"(value) /*: no clobber */ );
171}
172
173/* Returns the number of times the loop ran before the PIT2 signaled */
174static inline unsigned long poll_PIT2_gate(void)
175{
176 unsigned long count = 0;
177 unsigned char nmi_sc_val;
178 do {
179 ++count;
180 __asm__ volatile(
181 "inb$0x61,%0"
182 : "=a"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);
183 } while( (nmi_sc_val & 0x20) == 0);
184 return count;
185}
186
187inline static void
188set_PIT2(int value)
189{
190/*
191 * First, tell the clock we are going to write 16 bits to the counter
192 * and enable one-shot mode (command 0xB8 to port 0x43)
193 * Then write the two bytes into the PIT2 clock register (port 0x42).
194 * Loop until the value is "realized" in the clock,
195 * this happens on the next tick.
196 */
197 asm volatile(
198 " movb $0xB8,%%al \n\t"
199 " outb %%al,$0x43 \n\t"
200 " movb %%dl,%%al \n\t"
201 " outb %%al,$0x42 \n\t"
202 " movb %%dh,%%al \n\t"
203 " outb %%al,$0x42 \n"
204"1: inb $0x42,%%al \n\t"
205 " inb $0x42,%%al \n\t"
206 " cmp %%al,%%dh \n\t"
207 " jne 1b"
208 : : "d"(value) : "%al");
209}
210
211
212inline static uint64_t
213get_PIT2(unsigned int *value)
214{
215 register uint64_t result;
216/*
217 * This routine first latches the time (command 0x80 to port 0x43),
218 * then gets the time stamp so we know how long the read will take later.
219 * Read (from port 0x42) and return the current value of the timer.
220 */
221#ifdef __i386__
222 asm volatile(
223 " xorl %%ecx,%%ecx \n\t"
224 " movb $0x80,%%al \n\t"
225 " outb %%al,$0x43 \n\t"
226 " rdtsc \n\t"
227 " pushl %%eax \n\t"
228 " inb $0x42,%%al \n\t"
229 " movb %%al,%%cl \n\t"
230 " inb $0x42,%%al \n\t"
231 " movb %%al,%%ch \n\t"
232 " popl %%eax "
233 : "=A"(result), "=c"(*value));
234#else /* __x86_64__ */
235 asm volatile(
236" xorq %%rcx,%%rcx \n\t"
237" movb $0x80,%%al \n\t"
238" outb %%al,$0x43 \n\t"
239" rdtsc \n\t"
240" pushq %%rax \n\t"
241" inb $0x42,%%al \n\t"
242" movb %%al,%%cl \n\t"
243" inb $0x42,%%al \n\t"
244" movb %%al,%%ch \n\t"
245" popq %%rax "
246: "=A"(result), "=c"(*value));
247#endif
248
249 return result;
250}
251
252#endif /* !__LIBSAIO_CPU_H */
253

Archive Download this file

Revision: 2266