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
8 #include "mp.h"
9
10 #define cpuserver 1
11
12 _MP_ *_mp_;
13
14 static _MP_*
mpscan(uchar * addr,int len)15 mpscan(uchar *addr, int len)
16 {
17 uchar *e, *p, sum;
18 int i;
19
20 e = addr+len;
21 for(p = addr; p < e; p += sizeof(_MP_)){
22 if(memcmp(p, "_MP_", 4))
23 continue;
24 sum = 0;
25 for(i = 0; i < sizeof(_MP_); i++)
26 sum += p[i];
27 if(sum == 0)
28 return (_MP_*)p;
29 }
30 return 0;
31 }
32
33 static _MP_*
mpsearch(void)34 mpsearch(void)
35 {
36 uchar *bda;
37 ulong p;
38 _MP_ *mp;
39
40 /*
41 * Search for the MP Floating Pointer Structure:
42 * 1) in the first KB of the EBDA;
43 * 2) in the last KB of system base memory;
44 * 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
45 */
46 bda = KADDR(0x400);
47 if((p = (bda[0x0F]<<8)|bda[0x0E])){
48 if(mp = mpscan(KADDR(p), 1024))
49 return mp;
50 }
51 else{
52 p = ((bda[0x14]<<8)|bda[0x13])*1024;
53 if(mp = mpscan(KADDR(p-1024), 1024))
54 return mp;
55 }
56 return mpscan(KADDR(0xF0000), 0x10000);
57 }
58
59 static int identify(void);
60
61 PCArch archmp = {
62 .id= "_MP_",
63 .ident= identify,
64 .reset= mpshutdown,
65 .intrinit= mpinit,
66 .intrenable= mpintrenable,
67 .fastclock= i8253read,
68 .timerset= lapictimerset,
69 };
70
71 static int
identify(void)72 identify(void)
73 {
74 PCMP *pcmp;
75 uchar *p, sum;
76 ulong length;
77
78 if(getconf("*nomp"))
79 return 1;
80
81 /*
82 * Search for an MP configuration table. For now,
83 * don't accept the default configurations (physaddr == 0).
84 * Check for correct signature, calculate the checksum and,
85 * if correct, check the version.
86 * To do: check extended table checksum.
87 */
88 if((_mp_ = mpsearch()) == 0 || _mp_->physaddr == 0)
89 return 1;
90
91 pcmp = KADDR(_mp_->physaddr);
92 if(memcmp(pcmp, "PCMP", 4))
93 return 1;
94
95 length = pcmp->length;
96 sum = 0;
97 for(p = (uchar*)pcmp; length; length--)
98 sum += *p++;
99
100 if(sum || (pcmp->version != 1 && pcmp->version != 4))
101 return 1;
102
103 if(cpuserver && m->havetsc)
104 archmp.fastclock = tscticks;
105 return 0;
106 }
107
108 Lock mpsynclock;
109
110 void
syncclock(void)111 syncclock(void)
112 {
113 uvlong x;
114
115 if(arch->fastclock != tscticks)
116 return;
117
118 if(m->machno == 0){
119 wrmsr(0x10, 0);
120 m->tscticks = 0;
121 } else {
122 x = MACHP(0)->tscticks;
123 while(x == MACHP(0)->tscticks)
124 ;
125 wrmsr(0x10, MACHP(0)->tscticks);
126 cycles(&m->tscticks);
127 }
128 }
129
130 uvlong
tscticks(uvlong * hz)131 tscticks(uvlong *hz)
132 {
133 if(hz != nil)
134 *hz = m->cpuhz;
135
136 cycles(&m->tscticks); /* Uses the rdtsc instruction */
137 return m->tscticks;
138 }
139