xref: /plan9-contrib/sys/src/cmd/aux/realemu/main.c (revision ccaec48a6a7d481d90233fb80c88e608b0a02604)
1*ccaec48aSDavid du Colombier #include <u.h>
2*ccaec48aSDavid du Colombier #include <libc.h>
3*ccaec48aSDavid du Colombier #include "dat.h"
4*ccaec48aSDavid du Colombier #include "fns.h"
5*ccaec48aSDavid du Colombier 
6*ccaec48aSDavid du Colombier /* for fs */
7*ccaec48aSDavid du Colombier #include <auth.h>
8*ccaec48aSDavid du Colombier #include <fcall.h>
9*ccaec48aSDavid du Colombier #include <thread.h>
10*ccaec48aSDavid du Colombier #include <9p.h>
11*ccaec48aSDavid du Colombier 
12*ccaec48aSDavid du Colombier #include "/386/include/ureg.h"
13*ccaec48aSDavid du Colombier 
14*ccaec48aSDavid du Colombier enum {
15*ccaec48aSDavid du Colombier 	MEMSIZE = 0x100000,
16*ccaec48aSDavid du Colombier 
17*ccaec48aSDavid du Colombier 	RMBUF = 0x9000,
18*ccaec48aSDavid du Colombier 	RMCODE = 0x8000,
19*ccaec48aSDavid du Colombier 
20*ccaec48aSDavid du Colombier 	PITHZ = 1193182,
21*ccaec48aSDavid du Colombier 	PITNS = 1000000000/PITHZ,
22*ccaec48aSDavid du Colombier };
23*ccaec48aSDavid du Colombier 
24*ccaec48aSDavid du Colombier static Cpu cpu;
25*ccaec48aSDavid du Colombier static uchar memory[MEMSIZE+4];
26*ccaec48aSDavid du Colombier static uchar pageregtmp[0x10];
27*ccaec48aSDavid du Colombier static int portfd[5];
28*ccaec48aSDavid du Colombier static int realmemfd;
29*ccaec48aSDavid du Colombier static int cputrace;
30*ccaec48aSDavid du Colombier static int porttrace;
31*ccaec48aSDavid du Colombier static Pit pit[3];
32*ccaec48aSDavid du Colombier static uchar rtcaddr;
33*ccaec48aSDavid du Colombier 
34*ccaec48aSDavid du Colombier static vlong pitclock;
35*ccaec48aSDavid du Colombier 
36*ccaec48aSDavid du Colombier static void
startclock(void)37*ccaec48aSDavid du Colombier startclock(void)
38*ccaec48aSDavid du Colombier {
39*ccaec48aSDavid du Colombier 	pitclock = nsec();
40*ccaec48aSDavid du Colombier }
41*ccaec48aSDavid du Colombier 
42*ccaec48aSDavid du Colombier static void
runclock(void)43*ccaec48aSDavid du Colombier runclock(void)
44*ccaec48aSDavid du Colombier {
45*ccaec48aSDavid du Colombier 	vlong now, dt;
46*ccaec48aSDavid du Colombier 
47*ccaec48aSDavid du Colombier 	now = nsec();
48*ccaec48aSDavid du Colombier 	dt = now - pitclock;
49*ccaec48aSDavid du Colombier 	if(dt >= PITNS){
50*ccaec48aSDavid du Colombier 		clockpit(pit, dt/PITNS);
51*ccaec48aSDavid du Colombier 		pitclock = now;
52*ccaec48aSDavid du Colombier 	}
53*ccaec48aSDavid du Colombier }
54*ccaec48aSDavid du Colombier 
55*ccaec48aSDavid du Colombier static ulong
gw1(uchar * p)56*ccaec48aSDavid du Colombier gw1(uchar *p)
57*ccaec48aSDavid du Colombier {
58*ccaec48aSDavid du Colombier 	return p[0];
59*ccaec48aSDavid du Colombier }
60*ccaec48aSDavid du Colombier static ulong
gw2(uchar * p)61*ccaec48aSDavid du Colombier gw2(uchar *p)
62*ccaec48aSDavid du Colombier {
63*ccaec48aSDavid du Colombier 	return (ulong)p[0] | (ulong)p[1]<<8;
64*ccaec48aSDavid du Colombier }
65*ccaec48aSDavid du Colombier static ulong
gw4(uchar * p)66*ccaec48aSDavid du Colombier gw4(uchar *p)
67*ccaec48aSDavid du Colombier {
68*ccaec48aSDavid du Colombier 	return (ulong)p[0] | (ulong)p[1]<<8 | (ulong)p[2]<<16 | (ulong)p[3]<<24;
69*ccaec48aSDavid du Colombier }
70*ccaec48aSDavid du Colombier static ulong (*gw[5])(uchar *p) = {
71*ccaec48aSDavid du Colombier 	[1] gw1,
72*ccaec48aSDavid du Colombier 	[2] gw2,
73*ccaec48aSDavid du Colombier 	[4] gw4,
74*ccaec48aSDavid du Colombier };
75*ccaec48aSDavid du Colombier 
76*ccaec48aSDavid du Colombier static void
pw1(uchar * p,ulong w)77*ccaec48aSDavid du Colombier pw1(uchar *p, ulong w)
78*ccaec48aSDavid du Colombier {
79*ccaec48aSDavid du Colombier 	p[0] = w & 0xFF;
80*ccaec48aSDavid du Colombier }
81*ccaec48aSDavid du Colombier static void
pw2(uchar * p,ulong w)82*ccaec48aSDavid du Colombier pw2(uchar *p, ulong w)
83*ccaec48aSDavid du Colombier {
84*ccaec48aSDavid du Colombier 	p[0] = w & 0xFF;
85*ccaec48aSDavid du Colombier 	p[1] = (w>>8) & 0xFF;
86*ccaec48aSDavid du Colombier }
87*ccaec48aSDavid du Colombier static void
pw4(uchar * p,ulong w)88*ccaec48aSDavid du Colombier pw4(uchar *p, ulong w)
89*ccaec48aSDavid du Colombier {
90*ccaec48aSDavid du Colombier 	p[0] = w & 0xFF;
91*ccaec48aSDavid du Colombier 	p[1] = (w>>8) & 0xFF;
92*ccaec48aSDavid du Colombier 	p[2] = (w>>16) & 0xFF;
93*ccaec48aSDavid du Colombier 	p[3] = (w>>24) & 0xFF;
94*ccaec48aSDavid du Colombier }
95*ccaec48aSDavid du Colombier static void (*pw[5])(uchar *p, ulong w) = {
96*ccaec48aSDavid du Colombier 	[1] pw1,
97*ccaec48aSDavid du Colombier 	[2] pw2,
98*ccaec48aSDavid du Colombier 	[4] pw4,
99*ccaec48aSDavid du Colombier };
100*ccaec48aSDavid du Colombier 
101*ccaec48aSDavid du Colombier static ulong
rbad(void *,ulong off,int)102*ccaec48aSDavid du Colombier rbad(void *, ulong off, int)
103*ccaec48aSDavid du Colombier {
104*ccaec48aSDavid du Colombier 	fprint(2, "bad mem read %.5lux\n", off);
105*ccaec48aSDavid du Colombier 	trap(&cpu, EMEM);
106*ccaec48aSDavid du Colombier 
107*ccaec48aSDavid du Colombier 	/* not reached */
108*ccaec48aSDavid du Colombier 	return 0;
109*ccaec48aSDavid du Colombier }
110*ccaec48aSDavid du Colombier 
111*ccaec48aSDavid du Colombier static void
wbad(void *,ulong off,ulong,int)112*ccaec48aSDavid du Colombier wbad(void *, ulong off, ulong, int)
113*ccaec48aSDavid du Colombier {
114*ccaec48aSDavid du Colombier 	fprint(2, "bad mem write %.5lux\n", off);
115*ccaec48aSDavid du Colombier 	trap(&cpu, EMEM);
116*ccaec48aSDavid du Colombier }
117*ccaec48aSDavid du Colombier 
118*ccaec48aSDavid du Colombier static ulong
rmem(void *,ulong off,int len)119*ccaec48aSDavid du Colombier rmem(void *, ulong off, int len)
120*ccaec48aSDavid du Colombier {
121*ccaec48aSDavid du Colombier 	return gw[len](memory + off);
122*ccaec48aSDavid du Colombier }
123*ccaec48aSDavid du Colombier 
124*ccaec48aSDavid du Colombier static void
wmem(void *,ulong off,ulong w,int len)125*ccaec48aSDavid du Colombier wmem(void *, ulong off, ulong w, int len)
126*ccaec48aSDavid du Colombier {
127*ccaec48aSDavid du Colombier 	pw[len](memory + off, w);
128*ccaec48aSDavid du Colombier }
129*ccaec48aSDavid du Colombier 
130*ccaec48aSDavid du Colombier static ulong
rrealmem(void *,ulong off,int len)131*ccaec48aSDavid du Colombier rrealmem(void *, ulong off, int len)
132*ccaec48aSDavid du Colombier {
133*ccaec48aSDavid du Colombier 	uchar data[4];
134*ccaec48aSDavid du Colombier 
135*ccaec48aSDavid du Colombier 	if(pread(realmemfd, data, len, off) != len){
136*ccaec48aSDavid du Colombier 		fprint(2, "bad real mem read %.5lux: %r\n", off);
137*ccaec48aSDavid du Colombier 		trap(&cpu, EMEM);
138*ccaec48aSDavid du Colombier 	}
139*ccaec48aSDavid du Colombier 	return gw[len](data);
140*ccaec48aSDavid du Colombier }
141*ccaec48aSDavid du Colombier 
142*ccaec48aSDavid du Colombier static void
wrealmem(void *,ulong off,ulong w,int len)143*ccaec48aSDavid du Colombier wrealmem(void *, ulong off, ulong w, int len)
144*ccaec48aSDavid du Colombier {
145*ccaec48aSDavid du Colombier 	uchar data[4];
146*ccaec48aSDavid du Colombier 
147*ccaec48aSDavid du Colombier 	pw[len](data, w);
148*ccaec48aSDavid du Colombier 	if(pwrite(realmemfd, data, len, off) != len){
149*ccaec48aSDavid du Colombier 		fprint(2, "bad real mem write %.5lux: %r\n", off);
150*ccaec48aSDavid du Colombier 		trap(&cpu, EMEM);
151*ccaec48aSDavid du Colombier 	}
152*ccaec48aSDavid du Colombier }
153*ccaec48aSDavid du Colombier 
154*ccaec48aSDavid du Colombier 
155*ccaec48aSDavid du Colombier static ulong
rport(void *,ulong p,int len)156*ccaec48aSDavid du Colombier rport(void *, ulong p, int len)
157*ccaec48aSDavid du Colombier {
158*ccaec48aSDavid du Colombier 	uchar data[4];
159*ccaec48aSDavid du Colombier 	ulong w;
160*ccaec48aSDavid du Colombier 
161*ccaec48aSDavid du Colombier 	switch(p){
162*ccaec48aSDavid du Colombier 	case 0x20:	/* PIC 1 */
163*ccaec48aSDavid du Colombier 	case 0x21:
164*ccaec48aSDavid du Colombier 		w = 0;
165*ccaec48aSDavid du Colombier 		break;
166*ccaec48aSDavid du Colombier 	case 0x40:
167*ccaec48aSDavid du Colombier 	case 0x41:
168*ccaec48aSDavid du Colombier 	case 0x42:
169*ccaec48aSDavid du Colombier 	case 0x43:
170*ccaec48aSDavid du Colombier 		runclock();
171*ccaec48aSDavid du Colombier 		w = rpit(pit, p - 0x40);
172*ccaec48aSDavid du Colombier 		break;
173*ccaec48aSDavid du Colombier 	case 0x60:	/* keyboard data output buffer */
174*ccaec48aSDavid du Colombier 		w = 0;
175*ccaec48aSDavid du Colombier 		break;
176*ccaec48aSDavid du Colombier 	case 0x61:	/* keyboard controller port b */
177*ccaec48aSDavid du Colombier 		runclock();
178*ccaec48aSDavid du Colombier 		w = pit[2].out<<5 | pit[2].gate;
179*ccaec48aSDavid du Colombier 		break;
180*ccaec48aSDavid du Colombier 	case 0x62:	/* PPI (XT only) */
181*ccaec48aSDavid du Colombier 		runclock();
182*ccaec48aSDavid du Colombier 		w = pit[2].out<<5;
183*ccaec48aSDavid du Colombier 		break;
184*ccaec48aSDavid du Colombier 	case 0x63:	/* PPI (XT only) read dip switches */
185*ccaec48aSDavid du Colombier 		w = 0;
186*ccaec48aSDavid du Colombier 		break;
187*ccaec48aSDavid du Colombier 	case 0x65:	/* A20 gate */
188*ccaec48aSDavid du Colombier 		w = 1 << 2;
189*ccaec48aSDavid du Colombier 		break;
190*ccaec48aSDavid du Colombier 	case 0x70:	/* RTC addr */
191*ccaec48aSDavid du Colombier 		w = rtcaddr;
192*ccaec48aSDavid du Colombier 		break;
193*ccaec48aSDavid du Colombier 	case 0x71:	/* RTC data */
194*ccaec48aSDavid du Colombier 		w = 0xFF;
195*ccaec48aSDavid du Colombier 		break;
196*ccaec48aSDavid du Colombier 	case 0x80:	/* extra dma registers (temp) */
197*ccaec48aSDavid du Colombier 	case 0x84:
198*ccaec48aSDavid du Colombier 	case 0x85:
199*ccaec48aSDavid du Colombier 	case 0x86:
200*ccaec48aSDavid du Colombier 	case 0x88:
201*ccaec48aSDavid du Colombier 	case 0x8c:
202*ccaec48aSDavid du Colombier 	case 0x8d:
203*ccaec48aSDavid du Colombier 	case 0x8e:
204*ccaec48aSDavid du Colombier 		w = pageregtmp[p-0x80];
205*ccaec48aSDavid du Colombier 		break;
206*ccaec48aSDavid du Colombier 	case 0x92:	/* A20 gate (system control port a) */
207*ccaec48aSDavid du Colombier 		w = 1 << 1;
208*ccaec48aSDavid du Colombier 		break;
209*ccaec48aSDavid du Colombier 	case 0xa0:	/* PIC 2 */
210*ccaec48aSDavid du Colombier 	case 0xa1:
211*ccaec48aSDavid du Colombier 		w = 0;
212*ccaec48aSDavid du Colombier 		break;
213*ccaec48aSDavid du Colombier 	default:
214*ccaec48aSDavid du Colombier 		if(pread(portfd[len], data, len, p) != len){
215*ccaec48aSDavid du Colombier 			fprint(2, "bad %d bit port read %.4lux: %r\n", len*8, p);
216*ccaec48aSDavid du Colombier 			trap(&cpu, EIO);
217*ccaec48aSDavid du Colombier 		}
218*ccaec48aSDavid du Colombier 		w = gw[len](data);
219*ccaec48aSDavid du Colombier 	}
220*ccaec48aSDavid du Colombier 	if(porttrace)
221*ccaec48aSDavid du Colombier 		fprint(2, "rport %.4lux %.*lux\n", p, len<<1, w);
222*ccaec48aSDavid du Colombier 	return w;
223*ccaec48aSDavid du Colombier }
224*ccaec48aSDavid du Colombier 
225*ccaec48aSDavid du Colombier static void
wport(void *,ulong p,ulong w,int len)226*ccaec48aSDavid du Colombier wport(void *, ulong p, ulong w, int len)
227*ccaec48aSDavid du Colombier {
228*ccaec48aSDavid du Colombier 	uchar data[4];
229*ccaec48aSDavid du Colombier 
230*ccaec48aSDavid du Colombier 	if(porttrace)
231*ccaec48aSDavid du Colombier 		fprint(2, "wport %.4lux %.*lux\n", p, len<<1, w);
232*ccaec48aSDavid du Colombier 
233*ccaec48aSDavid du Colombier 	switch(p){
234*ccaec48aSDavid du Colombier 	case 0x20:	/* PIC 1 */
235*ccaec48aSDavid du Colombier 	case 0x21:
236*ccaec48aSDavid du Colombier 		break;
237*ccaec48aSDavid du Colombier 	case 0x40:
238*ccaec48aSDavid du Colombier 	case 0x41:
239*ccaec48aSDavid du Colombier 	case 0x42:
240*ccaec48aSDavid du Colombier 	case 0x43:
241*ccaec48aSDavid du Colombier 		runclock();
242*ccaec48aSDavid du Colombier 		wpit(pit, p - 0x40, w);
243*ccaec48aSDavid du Colombier 		break;
244*ccaec48aSDavid du Colombier 	case 0x60:	/* keyboard controller data port */
245*ccaec48aSDavid du Colombier 		break;
246*ccaec48aSDavid du Colombier 	case 0x61:	/* keyboard controller port B */
247*ccaec48aSDavid du Colombier 		setgate(&pit[2], w & 1);
248*ccaec48aSDavid du Colombier 		break;
249*ccaec48aSDavid du Colombier 	case 0x62:	/* PPI (XT only) */
250*ccaec48aSDavid du Colombier 	case 0x63:
251*ccaec48aSDavid du Colombier 	case 0x64:	/* KB controller input buffer (ISA, EISA) */
252*ccaec48aSDavid du Colombier 	case 0x65:	/* A20 gate (bit 2) */
253*ccaec48aSDavid du Colombier 		break;
254*ccaec48aSDavid du Colombier 	case 0x70:	/* RTC addr */
255*ccaec48aSDavid du Colombier 		rtcaddr = w & 0xFF;
256*ccaec48aSDavid du Colombier 		break;
257*ccaec48aSDavid du Colombier 	case 0x71:	/* RTC data */
258*ccaec48aSDavid du Colombier 		break;
259*ccaec48aSDavid du Colombier 	case 0x80:
260*ccaec48aSDavid du Colombier 	case 0x84:
261*ccaec48aSDavid du Colombier 	case 0x85:
262*ccaec48aSDavid du Colombier 	case 0x86:
263*ccaec48aSDavid du Colombier 	case 0x88:
264*ccaec48aSDavid du Colombier 	case 0x8c:
265*ccaec48aSDavid du Colombier 	case 0x8d:
266*ccaec48aSDavid du Colombier 	case 0x8e:
267*ccaec48aSDavid du Colombier 		pageregtmp[p-0x80] = w & 0xFF;
268*ccaec48aSDavid du Colombier 		break;
269*ccaec48aSDavid du Colombier 	case 0x92:	/* system control port a */
270*ccaec48aSDavid du Colombier 	case 0x94:	/* system port enable setup register */
271*ccaec48aSDavid du Colombier 	case 0x96:
272*ccaec48aSDavid du Colombier 		break;
273*ccaec48aSDavid du Colombier 	case 0xA0:	/* PIC 2 */
274*ccaec48aSDavid du Colombier 	case 0xA1:
275*ccaec48aSDavid du Colombier 		break;
276*ccaec48aSDavid du Colombier 
277*ccaec48aSDavid du Colombier 	default:
278*ccaec48aSDavid du Colombier 		pw[len](data, w);
279*ccaec48aSDavid du Colombier 		if(pwrite(portfd[len], data, len, p) != len){
280*ccaec48aSDavid du Colombier 			fprint(2, "bad %d bit port write %.4lux: %r\n", len*8, p);
281*ccaec48aSDavid du Colombier 			trap(&cpu, EIO);
282*ccaec48aSDavid du Colombier 		}
283*ccaec48aSDavid du Colombier 	}
284*ccaec48aSDavid du Colombier }
285*ccaec48aSDavid du Colombier 
286*ccaec48aSDavid du Colombier static Bus memio[] = {
287*ccaec48aSDavid du Colombier 	/* 0 */ memory, rmem, wmem,	/* RAM: IVT, BIOS data area */
288*ccaec48aSDavid du Colombier 	/* 1 */ memory,	rmem, wmem,	/* custom */
289*ccaec48aSDavid du Colombier 	/* 2 */ nil,	rbad, wbad,
290*ccaec48aSDavid du Colombier 	/* 3 */ nil,	rbad, wbad,
291*ccaec48aSDavid du Colombier 	/* 4 */ nil,	rbad, wbad,
292*ccaec48aSDavid du Colombier 	/* 5 */ nil,	rbad, wbad,
293*ccaec48aSDavid du Colombier 	/* 6 */ nil,	rbad, wbad,
294*ccaec48aSDavid du Colombier 	/* 7 */ nil,	rbad, wbad,
295*ccaec48aSDavid du Colombier 	/* 8 */ nil,	rbad, wbad,
296*ccaec48aSDavid du Colombier 	/* 9 */ memory,	rmem, wmem,	/* RAM: extended BIOS data area */
297*ccaec48aSDavid du Colombier 	/* A */ nil,	rrealmem, wrealmem,	/* RAM: VGA framebuffer */
298*ccaec48aSDavid du Colombier 	/* B */ nil,	rrealmem, wrealmem,	/* RAM: VGA framebuffer */
299*ccaec48aSDavid du Colombier 	/* C */ memory,	rmem, wmem,	/* ROM: VGA BIOS */
300*ccaec48aSDavid du Colombier 	/* D */ nil,	rbad, wbad,
301*ccaec48aSDavid du Colombier 	/* E */ memory,	rmem, wmem,	/* ROM: BIOS */
302*ccaec48aSDavid du Colombier 	/* F */ memory,	rmem, wbad,	/* ROM: BIOS */
303*ccaec48aSDavid du Colombier };
304*ccaec48aSDavid du Colombier 
305*ccaec48aSDavid du Colombier static Bus portio = {
306*ccaec48aSDavid du Colombier 	nil, rport, wport,
307*ccaec48aSDavid du Colombier };
308*ccaec48aSDavid du Colombier 
309*ccaec48aSDavid du Colombier static void
cpuinit(void)310*ccaec48aSDavid du Colombier cpuinit(void)
311*ccaec48aSDavid du Colombier {
312*ccaec48aSDavid du Colombier 	int i;
313*ccaec48aSDavid du Colombier 
314*ccaec48aSDavid du Colombier 	fmtinstall('I', instfmt);
315*ccaec48aSDavid du Colombier 	fmtinstall('J', flagfmt);
316*ccaec48aSDavid du Colombier 	fmtinstall('C', cpufmt);
317*ccaec48aSDavid du Colombier 
318*ccaec48aSDavid du Colombier 	if((portfd[1] = open("#P/iob", ORDWR)) < 0)
319*ccaec48aSDavid du Colombier 		sysfatal("open iob: %r");
320*ccaec48aSDavid du Colombier 	if((portfd[2] = open("#P/iow", ORDWR)) < 0)
321*ccaec48aSDavid du Colombier 		sysfatal("open iow: %r");
322*ccaec48aSDavid du Colombier 	if((portfd[4] = open("#P/iol", ORDWR)) < 0)
323*ccaec48aSDavid du Colombier 		sysfatal("open iol: %r");
324*ccaec48aSDavid du Colombier 
325*ccaec48aSDavid du Colombier 	if((realmemfd = open("#P/realmodemem", ORDWR)) < 0)
326*ccaec48aSDavid du Colombier 		sysfatal("open realmodemem: %r");
327*ccaec48aSDavid du Colombier 
328*ccaec48aSDavid du Colombier 	for(i=0; i<nelem(memio); i++){
329*ccaec48aSDavid du Colombier 		ulong off;
330*ccaec48aSDavid du Colombier 
331*ccaec48aSDavid du Colombier 		if(memio[i].r != rmem)
332*ccaec48aSDavid du Colombier 			continue;
333*ccaec48aSDavid du Colombier 
334*ccaec48aSDavid du Colombier 		off = (ulong)i << 16;
335*ccaec48aSDavid du Colombier 		seek(realmemfd, off, 0);
336*ccaec48aSDavid du Colombier 		if(readn(realmemfd, memory + off, 0x10000) != 0x10000)
337*ccaec48aSDavid du Colombier 			sysfatal("read real mem %lux: %r\n", off);
338*ccaec48aSDavid du Colombier 	}
339*ccaec48aSDavid du Colombier 
340*ccaec48aSDavid du Colombier 	cpu.ic = 0;
341*ccaec48aSDavid du Colombier 	cpu.mem = memio;
342*ccaec48aSDavid du Colombier 	cpu.port = &portio;
343*ccaec48aSDavid du Colombier 	cpu.alen = cpu.olen = cpu.slen = 2;
344*ccaec48aSDavid du Colombier }
345*ccaec48aSDavid du Colombier 
346*ccaec48aSDavid du Colombier static char Ebusy[] = "device is busy";
347*ccaec48aSDavid du Colombier static char Eintr[] = "interrupted";
348*ccaec48aSDavid du Colombier static char Eperm[] = "permission denied";
349*ccaec48aSDavid du Colombier static char Eio[] = "i/o error";
350*ccaec48aSDavid du Colombier static char Emem[] = "bad memory access";
351*ccaec48aSDavid du Colombier static char Enonexist[] = "file does not exist";
352*ccaec48aSDavid du Colombier static char Ebadspec[] = "bad attach specifier";
353*ccaec48aSDavid du Colombier static char Ewalk[] = "walk in non directory";
354*ccaec48aSDavid du Colombier static char Ebadureg[] = "write a Ureg";
355*ccaec48aSDavid du Colombier static char Ebadoff[] = "invalid offset";
356*ccaec48aSDavid du Colombier static char Ebadtrap[] = "bad trap";
357*ccaec48aSDavid du Colombier 
358*ccaec48aSDavid du Colombier static char *trapstr[] = {
359*ccaec48aSDavid du Colombier 	[EDIV0] "division by zero",
360*ccaec48aSDavid du Colombier 	[EDEBUG] "debug exception",
361*ccaec48aSDavid du Colombier 	[ENMI] "not maskable interrupt",
362*ccaec48aSDavid du Colombier 	[EBRK] "breakpoint",
363*ccaec48aSDavid du Colombier 	[EINTO] "into overflow",
364*ccaec48aSDavid du Colombier 	[EBOUND] "bounds check",
365*ccaec48aSDavid du Colombier 	[EBADOP] "bad opcode",
366*ccaec48aSDavid du Colombier 	[ENOFPU] "no fpu installed",
367*ccaec48aSDavid du Colombier 	[EDBLF] "double fault",
368*ccaec48aSDavid du Colombier 	[EFPUSEG] "fpu segment overflow",
369*ccaec48aSDavid du Colombier 	[EBADTSS] "invalid task state segment",
370*ccaec48aSDavid du Colombier 	[ENP] "segment not present",
371*ccaec48aSDavid du Colombier 	[ESTACK] "stack fault",
372*ccaec48aSDavid du Colombier 	[EGPF] "general protection fault",
373*ccaec48aSDavid du Colombier 	[EPF] "page fault",
374*ccaec48aSDavid du Colombier };
375*ccaec48aSDavid du Colombier 
376*ccaec48aSDavid du Colombier static int flushed(void *);
377*ccaec48aSDavid du Colombier 
378*ccaec48aSDavid du Colombier #define GETUREG(x)	gw[sizeof(u->x)]((uchar*)&u->x)
379*ccaec48aSDavid du Colombier #define PUTUREG(x,y)	pw[sizeof(u->x)]((uchar*)&u->x,y)
380*ccaec48aSDavid du Colombier 
381*ccaec48aSDavid du Colombier static char*
realmode(Cpu * cpu,struct Ureg * u,void * r)382*ccaec48aSDavid du Colombier realmode(Cpu *cpu, struct Ureg *u, void *r)
383*ccaec48aSDavid du Colombier {
384*ccaec48aSDavid du Colombier 	char *err;
385*ccaec48aSDavid du Colombier 	int i;
386*ccaec48aSDavid du Colombier 
387*ccaec48aSDavid du Colombier 	cpu->reg[RDI] = GETUREG(di);
388*ccaec48aSDavid du Colombier 	cpu->reg[RSI] = GETUREG(si);
389*ccaec48aSDavid du Colombier 	cpu->reg[RBP] = GETUREG(bp);
390*ccaec48aSDavid du Colombier 	cpu->reg[RBX] = GETUREG(bx);
391*ccaec48aSDavid du Colombier 	cpu->reg[RDX] = GETUREG(dx);
392*ccaec48aSDavid du Colombier 	cpu->reg[RCX] = GETUREG(cx);
393*ccaec48aSDavid du Colombier 	cpu->reg[RAX] = GETUREG(ax);
394*ccaec48aSDavid du Colombier 
395*ccaec48aSDavid du Colombier 	cpu->reg[RGS] = GETUREG(gs);
396*ccaec48aSDavid du Colombier 	cpu->reg[RFS] = GETUREG(fs);
397*ccaec48aSDavid du Colombier 	cpu->reg[RES] = GETUREG(es);
398*ccaec48aSDavid du Colombier 	cpu->reg[RDS] = GETUREG(ds);
399*ccaec48aSDavid du Colombier 
400*ccaec48aSDavid du Colombier 	cpu->reg[RFL] = GETUREG(flags);
401*ccaec48aSDavid du Colombier 
402*ccaec48aSDavid du Colombier 	if(i = GETUREG(trap)){
403*ccaec48aSDavid du Colombier 		cpu->reg[RSS] = 0x0000;
404*ccaec48aSDavid du Colombier 		cpu->reg[RSP] = 0x7C00;
405*ccaec48aSDavid du Colombier 		cpu->reg[RCS] = (RMCODE>>4)&0xF000;
406*ccaec48aSDavid du Colombier 		cpu->reg[RIP] = RMCODE & 0xFFFF;
407*ccaec48aSDavid du Colombier 		memory[RMCODE] = 0xf4;	/* HLT instruction */
408*ccaec48aSDavid du Colombier 		if(intr(cpu, i) < 0)
409*ccaec48aSDavid du Colombier 			return Ebadtrap;
410*ccaec48aSDavid du Colombier 	} else {
411*ccaec48aSDavid du Colombier 		cpu->reg[RSS] = GETUREG(ss);
412*ccaec48aSDavid du Colombier 		cpu->reg[RSP] = GETUREG(sp);
413*ccaec48aSDavid du Colombier 		cpu->reg[RCS] = GETUREG(cs);
414*ccaec48aSDavid du Colombier 		cpu->reg[RIP] = GETUREG(pc);
415*ccaec48aSDavid du Colombier 	}
416*ccaec48aSDavid du Colombier 
417*ccaec48aSDavid du Colombier 	startclock();
418*ccaec48aSDavid du Colombier 	for(;;){
419*ccaec48aSDavid du Colombier 		if(cputrace)
420*ccaec48aSDavid du Colombier 			fprint(2, "%C\n", cpu);
421*ccaec48aSDavid du Colombier 		switch(i = xec(cpu, (porttrace | cputrace) ? 1 : 100000)){
422*ccaec48aSDavid du Colombier 		case -1:
423*ccaec48aSDavid du Colombier 			if(flushed(r)){
424*ccaec48aSDavid du Colombier 				err = Eintr;
425*ccaec48aSDavid du Colombier 				break;
426*ccaec48aSDavid du Colombier 			}
427*ccaec48aSDavid du Colombier 			runclock();
428*ccaec48aSDavid du Colombier 			continue;
429*ccaec48aSDavid du Colombier 
430*ccaec48aSDavid du Colombier 		/* normal interrupts */
431*ccaec48aSDavid du Colombier 		default:
432*ccaec48aSDavid du Colombier 			if(intr(cpu, i) < 0){
433*ccaec48aSDavid du Colombier 				err = Ebadtrap;
434*ccaec48aSDavid du Colombier 				break;
435*ccaec48aSDavid du Colombier 			}
436*ccaec48aSDavid du Colombier 			continue;
437*ccaec48aSDavid du Colombier 
438*ccaec48aSDavid du Colombier 		/* pseudo-interrupts */
439*ccaec48aSDavid du Colombier 		case EHALT:
440*ccaec48aSDavid du Colombier 			err = nil;
441*ccaec48aSDavid du Colombier 			break;
442*ccaec48aSDavid du Colombier 		case EIO:
443*ccaec48aSDavid du Colombier 			err = Eio;
444*ccaec48aSDavid du Colombier 			break;
445*ccaec48aSDavid du Colombier 		case EMEM:
446*ccaec48aSDavid du Colombier 			err = Emem;
447*ccaec48aSDavid du Colombier 			break;
448*ccaec48aSDavid du Colombier 
449*ccaec48aSDavid du Colombier 		/* processor traps */
450*ccaec48aSDavid du Colombier 		case EDIV0:
451*ccaec48aSDavid du Colombier 		case EDEBUG:
452*ccaec48aSDavid du Colombier 		case ENMI:
453*ccaec48aSDavid du Colombier 		case EBRK:
454*ccaec48aSDavid du Colombier 		case EINTO:
455*ccaec48aSDavid du Colombier 		case EBOUND:
456*ccaec48aSDavid du Colombier 		case EBADOP:
457*ccaec48aSDavid du Colombier 		case ENOFPU:
458*ccaec48aSDavid du Colombier 		case EDBLF:
459*ccaec48aSDavid du Colombier 		case EFPUSEG:
460*ccaec48aSDavid du Colombier 		case EBADTSS:
461*ccaec48aSDavid du Colombier 		case ENP:
462*ccaec48aSDavid du Colombier 		case ESTACK:
463*ccaec48aSDavid du Colombier 		case EGPF:
464*ccaec48aSDavid du Colombier 		case EPF:
465*ccaec48aSDavid du Colombier 			PUTUREG(trap, i);
466*ccaec48aSDavid du Colombier 			err = trapstr[i];
467*ccaec48aSDavid du Colombier 			break;
468*ccaec48aSDavid du Colombier 		}
469*ccaec48aSDavid du Colombier 
470*ccaec48aSDavid du Colombier 		break;
471*ccaec48aSDavid du Colombier 	}
472*ccaec48aSDavid du Colombier 
473*ccaec48aSDavid du Colombier 	if(err)
474*ccaec48aSDavid du Colombier 		fprint(2, "%s\n%C\n", err, cpu);
475*ccaec48aSDavid du Colombier 
476*ccaec48aSDavid du Colombier 	PUTUREG(di, cpu->reg[RDI]);
477*ccaec48aSDavid du Colombier 	PUTUREG(si, cpu->reg[RSI]);
478*ccaec48aSDavid du Colombier 	PUTUREG(bp, cpu->reg[RBP]);
479*ccaec48aSDavid du Colombier 	PUTUREG(bx, cpu->reg[RBX]);
480*ccaec48aSDavid du Colombier 	PUTUREG(dx, cpu->reg[RDX]);
481*ccaec48aSDavid du Colombier 	PUTUREG(cx, cpu->reg[RCX]);
482*ccaec48aSDavid du Colombier 	PUTUREG(ax, cpu->reg[RAX]);
483*ccaec48aSDavid du Colombier 
484*ccaec48aSDavid du Colombier 	PUTUREG(gs, cpu->reg[RGS]);
485*ccaec48aSDavid du Colombier 	PUTUREG(fs, cpu->reg[RFS]);
486*ccaec48aSDavid du Colombier 	PUTUREG(es, cpu->reg[RES]);
487*ccaec48aSDavid du Colombier 	PUTUREG(ds, cpu->reg[RDS]);
488*ccaec48aSDavid du Colombier 
489*ccaec48aSDavid du Colombier 	PUTUREG(flags, cpu->reg[RFL]);
490*ccaec48aSDavid du Colombier 
491*ccaec48aSDavid du Colombier 	PUTUREG(pc, cpu->reg[RIP]);
492*ccaec48aSDavid du Colombier 	PUTUREG(cs, cpu->reg[RCS]);
493*ccaec48aSDavid du Colombier 	PUTUREG(sp, cpu->reg[RSP]);
494*ccaec48aSDavid du Colombier 	PUTUREG(ss, cpu->reg[RSS]);
495*ccaec48aSDavid du Colombier 
496*ccaec48aSDavid du Colombier 	return err;
497*ccaec48aSDavid du Colombier }
498*ccaec48aSDavid du Colombier 
499*ccaec48aSDavid du Colombier enum {
500*ccaec48aSDavid du Colombier 	Qroot,
501*ccaec48aSDavid du Colombier 	Qcall,
502*ccaec48aSDavid du Colombier 	Qmem,
503*ccaec48aSDavid du Colombier 	Nqid,
504*ccaec48aSDavid du Colombier };
505*ccaec48aSDavid du Colombier 
506*ccaec48aSDavid du Colombier static struct Qtab {
507*ccaec48aSDavid du Colombier 	char *name;
508*ccaec48aSDavid du Colombier 	int mode;
509*ccaec48aSDavid du Colombier 	int type;
510*ccaec48aSDavid du Colombier 	int length;
511*ccaec48aSDavid du Colombier } qtab[Nqid] = {
512*ccaec48aSDavid du Colombier 	"/",
513*ccaec48aSDavid du Colombier 		DMDIR|0555,
514*ccaec48aSDavid du Colombier 		QTDIR,
515*ccaec48aSDavid du Colombier 		0,
516*ccaec48aSDavid du Colombier 
517*ccaec48aSDavid du Colombier 	"realmode",
518*ccaec48aSDavid du Colombier 		0666,
519*ccaec48aSDavid du Colombier 		0,
520*ccaec48aSDavid du Colombier 		0,
521*ccaec48aSDavid du Colombier 
522*ccaec48aSDavid du Colombier 	"realmodemem",
523*ccaec48aSDavid du Colombier 		0666,
524*ccaec48aSDavid du Colombier 		0,
525*ccaec48aSDavid du Colombier 		MEMSIZE,
526*ccaec48aSDavid du Colombier };
527*ccaec48aSDavid du Colombier 
528*ccaec48aSDavid du Colombier static int
fillstat(ulong qid,Dir * d)529*ccaec48aSDavid du Colombier fillstat(ulong qid, Dir *d)
530*ccaec48aSDavid du Colombier {
531*ccaec48aSDavid du Colombier 	struct Qtab *t;
532*ccaec48aSDavid du Colombier 
533*ccaec48aSDavid du Colombier 	memset(d, 0, sizeof(Dir));
534*ccaec48aSDavid du Colombier 	d->uid = "realemu";
535*ccaec48aSDavid du Colombier 	d->gid = "realemu";
536*ccaec48aSDavid du Colombier 	d->muid = "";
537*ccaec48aSDavid du Colombier 	d->qid = (Qid){qid, 0, 0};
538*ccaec48aSDavid du Colombier 	d->atime = time(0);
539*ccaec48aSDavid du Colombier 	t = qtab + qid;
540*ccaec48aSDavid du Colombier 	d->name = t->name;
541*ccaec48aSDavid du Colombier 	d->qid.type = t->type;
542*ccaec48aSDavid du Colombier 	d->mode = t->mode;
543*ccaec48aSDavid du Colombier 	d->length = t->length;
544*ccaec48aSDavid du Colombier 	return 1;
545*ccaec48aSDavid du Colombier }
546*ccaec48aSDavid du Colombier 
547*ccaec48aSDavid du Colombier static void
fsattach(Req * r)548*ccaec48aSDavid du Colombier fsattach(Req *r)
549*ccaec48aSDavid du Colombier {
550*ccaec48aSDavid du Colombier 	char *spec;
551*ccaec48aSDavid du Colombier 
552*ccaec48aSDavid du Colombier 	spec = r->ifcall.aname;
553*ccaec48aSDavid du Colombier 	if(spec && spec[0]){
554*ccaec48aSDavid du Colombier 		respond(r, Ebadspec);
555*ccaec48aSDavid du Colombier 		return;
556*ccaec48aSDavid du Colombier 	}
557*ccaec48aSDavid du Colombier 	r->fid->qid = (Qid){Qroot, 0, QTDIR};
558*ccaec48aSDavid du Colombier 	r->ofcall.qid = r->fid->qid;
559*ccaec48aSDavid du Colombier 	respond(r, nil);
560*ccaec48aSDavid du Colombier }
561*ccaec48aSDavid du Colombier 
562*ccaec48aSDavid du Colombier static void
fsstat(Req * r)563*ccaec48aSDavid du Colombier fsstat(Req *r)
564*ccaec48aSDavid du Colombier {
565*ccaec48aSDavid du Colombier 	fillstat((ulong)r->fid->qid.path, &r->d);
566*ccaec48aSDavid du Colombier 	r->d.name = estrdup9p(r->d.name);
567*ccaec48aSDavid du Colombier 	r->d.uid = estrdup9p(r->d.uid);
568*ccaec48aSDavid du Colombier 	r->d.gid = estrdup9p(r->d.gid);
569*ccaec48aSDavid du Colombier 	r->d.muid = estrdup9p(r->d.muid);
570*ccaec48aSDavid du Colombier 	respond(r, nil);
571*ccaec48aSDavid du Colombier }
572*ccaec48aSDavid du Colombier 
573*ccaec48aSDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)574*ccaec48aSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
575*ccaec48aSDavid du Colombier {
576*ccaec48aSDavid du Colombier 	int i;
577*ccaec48aSDavid du Colombier 	ulong path;
578*ccaec48aSDavid du Colombier 
579*ccaec48aSDavid du Colombier 	path = fid->qid.path;
580*ccaec48aSDavid du Colombier 	switch(path){
581*ccaec48aSDavid du Colombier 	case Qroot:
582*ccaec48aSDavid du Colombier 		if (strcmp(name, "..") == 0) {
583*ccaec48aSDavid du Colombier 			*qid = (Qid){Qroot, 0, QTDIR};
584*ccaec48aSDavid du Colombier 			fid->qid = *qid;
585*ccaec48aSDavid du Colombier 			return nil;
586*ccaec48aSDavid du Colombier 		}
587*ccaec48aSDavid du Colombier 		for(i = fid->qid.path; i<Nqid; i++){
588*ccaec48aSDavid du Colombier 			if(strcmp(name, qtab[i].name) != 0)
589*ccaec48aSDavid du Colombier 				continue;
590*ccaec48aSDavid du Colombier 			*qid = (Qid){i, 0, 0};
591*ccaec48aSDavid du Colombier 			fid->qid = *qid;
592*ccaec48aSDavid du Colombier 			return nil;
593*ccaec48aSDavid du Colombier 		}
594*ccaec48aSDavid du Colombier 		return Enonexist;
595*ccaec48aSDavid du Colombier 
596*ccaec48aSDavid du Colombier 	default:
597*ccaec48aSDavid du Colombier 		return Ewalk;
598*ccaec48aSDavid du Colombier 	}
599*ccaec48aSDavid du Colombier }
600*ccaec48aSDavid du Colombier 
601*ccaec48aSDavid du Colombier static void
fsopen(Req * r)602*ccaec48aSDavid du Colombier fsopen(Req *r)
603*ccaec48aSDavid du Colombier {
604*ccaec48aSDavid du Colombier 	static int need[4] = { 4, 2, 6, 1 };
605*ccaec48aSDavid du Colombier 	struct Qtab *t;
606*ccaec48aSDavid du Colombier 	int n;
607*ccaec48aSDavid du Colombier 
608*ccaec48aSDavid du Colombier 	t = qtab + r->fid->qid.path;
609*ccaec48aSDavid du Colombier 	n = need[r->ifcall.mode & 3];
610*ccaec48aSDavid du Colombier 	if((n & t->mode) != n)
611*ccaec48aSDavid du Colombier 		respond(r, Eperm);
612*ccaec48aSDavid du Colombier 	else
613*ccaec48aSDavid du Colombier 		respond(r, nil);
614*ccaec48aSDavid du Colombier }
615*ccaec48aSDavid du Colombier 
616*ccaec48aSDavid du Colombier static int
readtopdir(Fid *,uchar * buf,long off,int cnt,int blen)617*ccaec48aSDavid du Colombier readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
618*ccaec48aSDavid du Colombier {
619*ccaec48aSDavid du Colombier 	int i, m, n;
620*ccaec48aSDavid du Colombier 	long pos;
621*ccaec48aSDavid du Colombier 	Dir d;
622*ccaec48aSDavid du Colombier 
623*ccaec48aSDavid du Colombier 	n = 0;
624*ccaec48aSDavid du Colombier 	pos = 0;
625*ccaec48aSDavid du Colombier 	for (i = 1; i < Nqid; i++){
626*ccaec48aSDavid du Colombier 		fillstat(i, &d);
627*ccaec48aSDavid du Colombier 		m = convD2M(&d, &buf[n], blen-n);
628*ccaec48aSDavid du Colombier 		if(off <= pos){
629*ccaec48aSDavid du Colombier 			if(m <= BIT16SZ || m > cnt)
630*ccaec48aSDavid du Colombier 				break;
631*ccaec48aSDavid du Colombier 			n += m;
632*ccaec48aSDavid du Colombier 			cnt -= m;
633*ccaec48aSDavid du Colombier 		}
634*ccaec48aSDavid du Colombier 		pos += m;
635*ccaec48aSDavid du Colombier 	}
636*ccaec48aSDavid du Colombier 	return n;
637*ccaec48aSDavid du Colombier }
638*ccaec48aSDavid du Colombier 
639*ccaec48aSDavid du Colombier static Channel *reqchan;
640*ccaec48aSDavid du Colombier 
641*ccaec48aSDavid du Colombier static void
cpuproc(void *)642*ccaec48aSDavid du Colombier cpuproc(void *)
643*ccaec48aSDavid du Colombier {
644*ccaec48aSDavid du Colombier 	static struct Ureg rmu;
645*ccaec48aSDavid du Colombier 	ulong path;
646*ccaec48aSDavid du Colombier 	vlong o;
647*ccaec48aSDavid du Colombier 	ulong n;
648*ccaec48aSDavid du Colombier 	char *p;
649*ccaec48aSDavid du Colombier 	Req *r;
650*ccaec48aSDavid du Colombier 
651*ccaec48aSDavid du Colombier 	threadsetname("cpuproc");
652*ccaec48aSDavid du Colombier 
653*ccaec48aSDavid du Colombier 	while(r = recvp(reqchan)){
654*ccaec48aSDavid du Colombier 		if(flushed(r)){
655*ccaec48aSDavid du Colombier 			respond(r, Eintr);
656*ccaec48aSDavid du Colombier 			continue;
657*ccaec48aSDavid du Colombier 		}
658*ccaec48aSDavid du Colombier 
659*ccaec48aSDavid du Colombier 		path = r->fid->qid.path;
660*ccaec48aSDavid du Colombier 
661*ccaec48aSDavid du Colombier 		p = r->ifcall.data;
662*ccaec48aSDavid du Colombier 		n = r->ifcall.count;
663*ccaec48aSDavid du Colombier 		o = r->ifcall.offset;
664*ccaec48aSDavid du Colombier 
665*ccaec48aSDavid du Colombier 		switch(((int)r->ifcall.type<<8)|path){
666*ccaec48aSDavid du Colombier 		case (Tread<<8) | Qmem:
667*ccaec48aSDavid du Colombier 			readbuf(r, memory, MEMSIZE);
668*ccaec48aSDavid du Colombier 			respond(r, nil);
669*ccaec48aSDavid du Colombier 			break;
670*ccaec48aSDavid du Colombier 
671*ccaec48aSDavid du Colombier 		case (Tread<<8) | Qcall:
672*ccaec48aSDavid du Colombier 			readbuf(r, &rmu, sizeof rmu);
673*ccaec48aSDavid du Colombier 			respond(r, nil);
674*ccaec48aSDavid du Colombier 			break;
675*ccaec48aSDavid du Colombier 
676*ccaec48aSDavid du Colombier 		case (Twrite<<8) | Qmem:
677*ccaec48aSDavid du Colombier 			if(o < 0 || o >= MEMSIZE || o+n > MEMSIZE){
678*ccaec48aSDavid du Colombier 				respond(r, Ebadoff);
679*ccaec48aSDavid du Colombier 				break;
680*ccaec48aSDavid du Colombier 			}
681*ccaec48aSDavid du Colombier 			memmove(memory + o, p, n);
682*ccaec48aSDavid du Colombier 			r->ofcall.count = n;
683*ccaec48aSDavid du Colombier 			respond(r, nil);
684*ccaec48aSDavid du Colombier 			break;
685*ccaec48aSDavid du Colombier 
686*ccaec48aSDavid du Colombier 		case (Twrite<<8) | Qcall:
687*ccaec48aSDavid du Colombier 			if(n != sizeof rmu){
688*ccaec48aSDavid du Colombier 				respond(r, Ebadureg);
689*ccaec48aSDavid du Colombier 				break;
690*ccaec48aSDavid du Colombier 			}
691*ccaec48aSDavid du Colombier 			memmove(&rmu, p, n);
692*ccaec48aSDavid du Colombier 			if(p = realmode(&cpu, &rmu, r)){
693*ccaec48aSDavid du Colombier 				respond(r, p);
694*ccaec48aSDavid du Colombier 				break;
695*ccaec48aSDavid du Colombier 			}
696*ccaec48aSDavid du Colombier 			r->ofcall.count = n;
697*ccaec48aSDavid du Colombier 			respond(r, nil);
698*ccaec48aSDavid du Colombier 			break;
699*ccaec48aSDavid du Colombier 		}
700*ccaec48aSDavid du Colombier 	}
701*ccaec48aSDavid du Colombier }
702*ccaec48aSDavid du Colombier 
703*ccaec48aSDavid du Colombier static Channel *flushchan;
704*ccaec48aSDavid du Colombier 
705*ccaec48aSDavid du Colombier static int
flushed(void * r)706*ccaec48aSDavid du Colombier flushed(void *r)
707*ccaec48aSDavid du Colombier {
708*ccaec48aSDavid du Colombier 	return nbrecvp(flushchan) == r;
709*ccaec48aSDavid du Colombier }
710*ccaec48aSDavid du Colombier 
711*ccaec48aSDavid du Colombier static void
fsflush(Req * r)712*ccaec48aSDavid du Colombier fsflush(Req *r)
713*ccaec48aSDavid du Colombier {
714*ccaec48aSDavid du Colombier 	nbsendp(flushchan, r->oldreq);
715*ccaec48aSDavid du Colombier 	respond(r, nil);
716*ccaec48aSDavid du Colombier }
717*ccaec48aSDavid du Colombier 
718*ccaec48aSDavid du Colombier static void
dispatch(Req * r)719*ccaec48aSDavid du Colombier dispatch(Req *r)
720*ccaec48aSDavid du Colombier {
721*ccaec48aSDavid du Colombier 	if(!nbsendp(reqchan, r))
722*ccaec48aSDavid du Colombier 		respond(r, Ebusy);
723*ccaec48aSDavid du Colombier }
724*ccaec48aSDavid du Colombier 
725*ccaec48aSDavid du Colombier static void
fsread(Req * r)726*ccaec48aSDavid du Colombier fsread(Req *r)
727*ccaec48aSDavid du Colombier {
728*ccaec48aSDavid du Colombier 	switch((ulong)r->fid->qid.path){
729*ccaec48aSDavid du Colombier 	case Qroot:
730*ccaec48aSDavid du Colombier 		r->ofcall.count = readtopdir(r->fid, (void*)r->ofcall.data, r->ifcall.offset,
731*ccaec48aSDavid du Colombier 			r->ifcall.count, r->ifcall.count);
732*ccaec48aSDavid du Colombier 		respond(r, nil);
733*ccaec48aSDavid du Colombier 		break;
734*ccaec48aSDavid du Colombier 	default:
735*ccaec48aSDavid du Colombier 		dispatch(r);
736*ccaec48aSDavid du Colombier 	}
737*ccaec48aSDavid du Colombier }
738*ccaec48aSDavid du Colombier 
739*ccaec48aSDavid du Colombier static void
fsend(Srv *)740*ccaec48aSDavid du Colombier fsend(Srv*)
741*ccaec48aSDavid du Colombier {
742*ccaec48aSDavid du Colombier 	threadexitsall(nil);
743*ccaec48aSDavid du Colombier }
744*ccaec48aSDavid du Colombier 
745*ccaec48aSDavid du Colombier static Srv fs = {
746*ccaec48aSDavid du Colombier 	.attach=		fsattach,
747*ccaec48aSDavid du Colombier 	.walk1=			fswalk1,
748*ccaec48aSDavid du Colombier 	.open=			fsopen,
749*ccaec48aSDavid du Colombier 	.read=			fsread,
750*ccaec48aSDavid du Colombier 	.write=			dispatch,
751*ccaec48aSDavid du Colombier 	.stat=			fsstat,
752*ccaec48aSDavid du Colombier 	.flush=			fsflush,
753*ccaec48aSDavid du Colombier 	.end=			fsend,
754*ccaec48aSDavid du Colombier };
755*ccaec48aSDavid du Colombier 
756*ccaec48aSDavid du Colombier static void
usage(void)757*ccaec48aSDavid du Colombier usage(void)
758*ccaec48aSDavid du Colombier {
759*ccaec48aSDavid du Colombier 	fprint(2, "usgae:\t%s [-Dpt] [-s srvname] [-m mountpoint]\n", argv0);
760*ccaec48aSDavid du Colombier 	exits("usage");
761*ccaec48aSDavid du Colombier }
762*ccaec48aSDavid du Colombier 
763*ccaec48aSDavid du Colombier void
threadmain(int argc,char * argv[])764*ccaec48aSDavid du Colombier threadmain(int argc, char *argv[])
765*ccaec48aSDavid du Colombier {
766*ccaec48aSDavid du Colombier 	char *mnt = "/dev";
767*ccaec48aSDavid du Colombier 	char *srv = nil;
768*ccaec48aSDavid du Colombier 
769*ccaec48aSDavid du Colombier 	ARGBEGIN{
770*ccaec48aSDavid du Colombier 	case 'D':
771*ccaec48aSDavid du Colombier 		chatty9p++;
772*ccaec48aSDavid du Colombier 		break;
773*ccaec48aSDavid du Colombier 	case 'p':
774*ccaec48aSDavid du Colombier 		porttrace = 1;
775*ccaec48aSDavid du Colombier 		break;
776*ccaec48aSDavid du Colombier 	case 't':
777*ccaec48aSDavid du Colombier 		cputrace = 1;
778*ccaec48aSDavid du Colombier 		break;
779*ccaec48aSDavid du Colombier 	case 's':
780*ccaec48aSDavid du Colombier 		srv = EARGF(usage());
781*ccaec48aSDavid du Colombier 		mnt = nil;
782*ccaec48aSDavid du Colombier 		break;
783*ccaec48aSDavid du Colombier 	case 'm':
784*ccaec48aSDavid du Colombier 		mnt = EARGF(usage());
785*ccaec48aSDavid du Colombier 		break;
786*ccaec48aSDavid du Colombier 	default:
787*ccaec48aSDavid du Colombier 		usage();
788*ccaec48aSDavid du Colombier 	}ARGEND
789*ccaec48aSDavid du Colombier 
790*ccaec48aSDavid du Colombier 	cpuinit();
791*ccaec48aSDavid du Colombier 
792*ccaec48aSDavid du Colombier 	reqchan = chancreate(sizeof(Req*), 8);
793*ccaec48aSDavid du Colombier 	flushchan = chancreate(sizeof(Req*), 8);
794*ccaec48aSDavid du Colombier 	procrfork(cpuproc, nil, 16*1024, RFNAMEG|RFNOTEG);
795*ccaec48aSDavid du Colombier 	threadpostmountsrv(&fs, srv, mnt, MBEFORE);
796*ccaec48aSDavid du Colombier }
797