xref: /inferno-os/os/pc/archmp.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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