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

Archive Download this file

Revision: 2385