|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "io.h"
7: #include "ureg.h"
8:
9: /*
10: * 8253 timer
11: */
12: enum
13: {
14: T0cntr= 0x40, /* counter ports */
15: T1cntr= 0x41, /* ... */
16: T2cntr= 0x42, /* ... */
17: Tmode= 0x43, /* mode port */
18:
19: /* commands */
20: Latch0= 0x00, /* latch counter 0's value */
21: Load0= 0x30, /* load counter 0 with 2 bytes */
22:
23: /* modes */
24: Square= 0x36, /* perioic square wave */
25: Trigger= 0x30, /* interrupt on terminal count */
26:
27: Freq= 1193182, /* Real clock frequency */
28: };
29:
30: static int cpufreq = 66000000;
31: static int cpumhz = 66;
32: static int loopconst = 100;
33: static int cpuidax, cpuiddx;
34:
35: static void
36: clock(Ureg *ur, void *arg)
37: {
38: Proc *p;
39: int nrun = 0;
40:
41: USED(arg);
42:
43: m->ticks++;
44:
45: checkalarms();
46: uartclock();
47: hardclock();
48:
49: /*
50: * process time accounting
51: */
52: p = m->proc;
53: if(p){
54: nrun = 1;
55: p->pc = ur->pc;
56: if (p->state==Running)
57: p->time[p->insyscall]++;
58: }
59: nrun = (nrdy+nrun)*1000;
60: MACHP(0)->load = (MACHP(0)->load*19+nrun)/20;
61:
62: if(u && p && p->state==Running){
63: /*
64: * preemption
65: */
66: if(anyready()){
67: if(p->hasspin)
68: p->hasspin = 0;
69: else
70: sched();
71: }
72: if((ur->cs&0xffff) == UESEL){
73: spllo(); /* in case we fault */
74: (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1); /* profiling clock */
75: splhi();
76: }
77: }
78:
79: /* last because it goes spllo() */
80: mouseclock();
81: }
82:
83: #define STEPPING(x) ((x)&0xf)
84: #define MODEL(x) (((x)>>4)&0xf)
85: #define FAMILY(x) (((x)>>8)&0xf)
86:
87: enum
88: {
89: /* flags */
90: CpuidFPU = 0x001, /* on-chip floating point unit */
91: CpuidMCE = 0x080, /* machine check exception */
92: CpuidCX8 = 0x100, /* CMPXCHG8B instruction */
93: };
94:
95: typedef struct
96: {
97: int family;
98: int model;
99: int aalcycles;
100: char *name;
101: } X86type;
102:
103: X86type x86type[] =
104: {
105: /* from the cpuid instruction */
106: { 4, 0, 22, "Intel486DX", },
107: { 4, 1, 22, "Intel486DX", },
108: { 4, 2, 22, "Intel486SX", },
109: { 4, 3, 22, "Intel486DX2", },
110: { 4, 4, 22, "Intel486DX2", },
111: { 4, 5, 22, "Intel486SL", },
112: { 4, 8, 22, "IntelDX4", },
113: { 5, 1, 23, "Pentium510", },
114: { 5, 2, 23, "Pentium735", },
115:
116: /* family defaults */
117: { 3, -1, 32, "Intel386", },
118: { 4, -1, 22, "Intel486", },
119: { 5, -1, 23, "Pentium", },
120:
121: /* total default */
122: { -1, -1, 23, "unknown", },
123: };
124:
125: static X86type *cputype;
126:
127: /*
128: * delay for l milliseconds more or less. delayloop is set by
129: * clockinit() to match the actual CPU speed.
130: */
131: void
132: delay(int l)
133: {
134: l *= loopconst;
135: if(l <= 0)
136: l = 1;
137: aamloop(l);
138: }
139:
140: /*
141: * microsecond delay
142: */
143: void
144: microdelay(int l)
145: {
146: l *= loopconst;
147: l /= 1000;
148: if(l <= 0)
149: l = 1;
150: aamloop(l);
151: }
152:
153: void
154: printcpufreq(void)
155: {
156: print("CPU is a %d MHz %s (cpuid: ax %lux dx %lux)\n",
157: cpumhz, cputype->name, cpuidax, cpuiddx);
158: }
159:
160: int
161: x86(void)
162: {
163: return cputype->family;
164: }
165:
166: void
167: clockinit(void)
168: {
169: int x, y; /* change in counter */
170: int family, model, loops, incr;
171: X86type *t;
172:
173: /*
174: * set vector for clock interrupts
175: */
176: setvec(Clockvec, clock, 0);
177:
178: /*
179: * figure out what we are
180: */
181: x86cpuid(&cpuidax, &cpuiddx);
182: family = FAMILY(cpuidax);
183: model = MODEL(cpuidax);
184: for(t = x86type; t->name; t++)
185: if((t->family == family && t->model == model)
186: || (t->family == family && t->model == -1)
187: || (t->family == -1))
188: break;
189: cputype = t;
190:
191: /*
192: * set clock for 1/HZ seconds
193: */
194: outb(Tmode, Load0|Square);
195: outb(T0cntr, (Freq/HZ)); /* low byte */
196: outb(T0cntr, (Freq/HZ)>>8); /* high byte */
197:
198: /* find biggest loop that doesn't wrap */
199: incr = 16000000/(t->aalcycles*HZ*2);
200: x = 2000;
201: for(loops = incr; loops < 64*1024; loops += incr) {
202:
203: /*
204: * measure time for the loop
205: *
206: * MOVL loops,CX
207: * aaml1: AAM
208: * LOOP aaml1
209: *
210: * the time for the loop should be independent of external
211: * cache and memory system since it fits in the execution
212: * prefetch buffer.
213: *
214: */
215: outb(Tmode, Latch0);
216: x = inb(T0cntr);
217: x |= inb(T0cntr)<<8;
218: aamloop(loops);
219: outb(Tmode, Latch0);
220: y = inb(T0cntr);
221: y |= inb(T0cntr)<<8;
222: x -= y;
223:
224: if(x < 0)
225: x += Freq/HZ;
226:
227: if(x > Freq/(3*HZ))
228: break;
229: }
230:
231: /*
232: * counter goes at twice the frequency, once per transition,
233: * i.e., twice per square wave
234: */
235: x >>= 1;
236:
237: /*
238: * figure out clock frequency and a loop multiplier for delay().
239: */
240: cpufreq = loops*((t->aalcycles*Freq)/x);
241: loopconst = (cpufreq/1000)/t->aalcycles; /* AAM+LOOP's for 1 ms */
242:
243: /*
244: * add in possible .2% error and convert to MHz
245: */
246: cpumhz = (cpufreq + cpufreq/500)/1000000;
247: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.