Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * Remote debugging file system
3
 */
4
 
5
#include <u.h>
6
#include <libc.h>
7
#include <auth.h>
8
#include <fcall.h>
9
#include <bio.h>
10
#include <thread.h>
11
#include <9p.h>
12
 
13
int dbg = 0;
14
#define DBG	if(dbg)fprint
15
 
16
enum {
17
	NHASH = 4096,
18
	Readlen = 4,
19
	Pagequantum = 1024,
20
};
21
 
22
/* caching memory pages: a lot of space to avoid serial communications */
23
Lock pglock;
24
typedef struct	Page	Page;
25
struct Page {	/* cached memory contents */
26
	Page *link;
27
	ulong len;
28
	ulong addr;
29
	int count;
30
	uchar val[Readlen];
31
};
32
 
33
Page *pgtab[NHASH];
34
 
35
Page *freelist;
36
 
37
/* called with pglock locked */
38
Page*
39
newpg(void)
40
{
41
	int i;
42
	Page *p, *q;
43
 
44
	if(freelist == nil){
45
		p = malloc(sizeof(Page)*Pagequantum);
46
		if(p == nil)
47
			sysfatal("out of memory");
48
 
49
		for(i=0, q=p; i<Pagequantum-1; i++, q++)
50
			q->link = q+1;
51
		q->link = nil;
52
 
53
		freelist = p;
54
	}
55
	p = freelist;
56
	freelist = freelist->link;
57
	return p;
58
}
59
 
60
#define PHIINV 0.61803398874989484820
61
uint
62
ahash(ulong addr)
63
{
64
	return (uint)floor(NHASH*fmod(addr*PHIINV, 1.0));
65
}
66
 
67
int
68
lookup(ulong addr, uchar *val, ulong count)
69
{
70
	Page *p;
71
 
72
	lock(&pglock);
73
	for(p=pgtab[ahash(addr)]; p; p=p->link){
74
		if(p->addr == addr && p->count == count){
75
			memmove(val, p->val, count);
76
			unlock(&pglock);
77
			return 1;
78
		}
79
	}
80
	unlock(&pglock);
81
	return 0;
82
}
83
 
84
void
85
insert(ulong addr, uchar *val, int count)
86
{
87
	Page *p;
88
	uint h;
89
 
90
	lock(&pglock);
91
	p = newpg();
92
	p->addr = addr;
93
	p->count = count;
94
	memmove(p->val, val, count);
95
	h = ahash(addr);
96
	p->link = pgtab[h];
97
	p->len = pgtab[h] ? pgtab[h]->len+1 : 1;
98
	pgtab[h] = p;
99
	unlock(&pglock);
100
}
101
 
102
void
103
flushcache(void)
104
{
105
	int i;
106
	Page *p;
107
 
108
	lock(&pglock);
109
	for(i=0; i<NHASH; i++){
110
		if(p=pgtab[i]){
111
			for(;p->link; p=p->link)
112
				;
113
			p->link = freelist;
114
			freelist = p;
115
		}
116
		pgtab[i] = nil;
117
	}
118
	unlock(&pglock);
119
}
120
 
121
enum
122
{
123
	Xctl	= 1,
124
	Xfpregs,
125
	Xkregs,
126
	Xmem,
127
	Xproc,
128
	Xregs,
129
	Xtext,
130
	Xstatus,
131
 
132
};
133
 
134
int	textfd;
135
int	rfd;
136
Biobuf	rfb;
137
char*	portname = "/dev/eia0";
138
char*	textfile = "/386/9pc";
139
char*	procname = "1";
140
char*	srvname;
141
Channel* rchan;
142
 
143
void
144
usage(void)
145
{
146
	fprint(2, "usage: rdbfs [-p procnum] [-s srvname] [-t textfile] [serialport]\n");
147
	exits("usage");
148
}
149
 
150
void
151
noalarm(void*, char *msg)
152
{
153
	if(strstr(msg, "alarm"))
154
		noted(NCONT);
155
	noted(NDFLT);
156
}
157
 
158
/*
159
 * 	send and receive responses on the serial line
160
 */
161
void
162
eiaread(void*)
163
{
164
	Req *r;
165
	char *p;
166
	uchar *data;
167
	char err[ERRMAX];
168
	char buf[1000];
169
	int i, tries;
170
 
171
	notify(noalarm);
172
	while(r = recvp(rchan)){
173
		DBG(2, "got %F: here goes...", &r->ifcall);
174
		if(r->ifcall.count > Readlen)
175
			r->ifcall.count = Readlen;
176
		r->ofcall.count = r->ifcall.count;
177
		if(r->type == Tread && lookup(r->ifcall.offset, (uchar*)r->ofcall.data, r->ofcall.count)){
178
			respond(r, nil);
179
			continue;
180
		}
181
		for(tries=0; tries<5; tries++){
182
			if(r->type == Twrite){
183
				DBG(2, "w%.8lux %.8lux...", (ulong)r->ifcall.offset, *(ulong*)r->ifcall.data);
184
				fprint(rfd, "w%.8lux %.8lux\n", (ulong)r->ifcall.offset, *(ulong*)r->ifcall.data);
185
			}else if(r->type == Tread){
186
				DBG(2, "r%.8lux...", (ulong)r->ifcall.offset);
187
				fprint(rfd, "r%.8lux\n", (ulong)r->ifcall.offset);
188
			}else{
189
				respond(r, "oops");
190
				break;
191
			}
192
			for(;;){
193
				werrstr("");
194
				alarm(500);
195
				p=Brdline(&rfb, '\n');
196
				alarm(0);
197
				if(p == nil){
198
					rerrstr(err, sizeof err);
199
					DBG(2, "error %s\n", err);
200
					if(strstr(err, "alarm") || strstr(err, "interrupted"))
201
						break;
202
					if(Blinelen(&rfb) == 0) // true eof
203
						sysfatal("eof on serial line?");
204
					Bread(&rfb, buf, Blinelen(&rfb)<sizeof buf ? Blinelen(&rfb) : sizeof buf);
205
					continue;
206
				}
207
				p[Blinelen(&rfb)-1] = 0;
208
				if(p[0] == '\r')
209
					p++;
210
				DBG(2, "serial %s\n", p);
211
				if(p[0] == 'R'){
212
					if(strtoul(p+1, 0, 16) == (ulong)r->ifcall.offset){
213
						/* we know that data can handle Readlen bytes */
214
						data = (uchar*)r->ofcall.data;
215
						for(i=0; i<r->ifcall.count; i++)
216
							data[i] = strtol(p+1+8+1+3*i, 0, 16);
217
						insert(r->ifcall.offset, data, r->ifcall.count);
218
						respond(r, nil);
219
						goto Break2;
220
					}else
221
						DBG(2, "%.8lux ≠ %.8lux\n", strtoul(p+1, 0, 16), (ulong)r->ifcall.offset);
222
				}else if(p[0] == 'W'){
223
					respond(r, nil);
224
					goto Break2;
225
				}else{
226
					DBG(2, "unknown message\n");
227
				}
228
			}
229
		}
230
	Break2:;
231
	}
232
}
233
 
234
void
235
attachremote(char* name)
236
{
237
	int fd;
238
	char buf[128];
239
 
240
	print("attach %s\n", name);
241
	rfd = open(name, ORDWR);
242
	if(rfd < 0)
243
		sysfatal("can't open remote %s", name);
244
 
245
	sprint(buf, "%sctl", name);
246
	fd = open(buf, OWRITE);
247
	if(fd < 0)
248
		sysfatal("can't set baud rate on %s", buf);
249
	write(fd, "B9600", 6);
250
	close(fd);
251
	Binit(&rfb, rfd, OREAD);
252
}
253
 
254
void
255
fsopen(Req *r)
256
{
257
	char buf[ERRMAX];
258
 
259
	switch((uintptr)r->fid->file->aux){
260
	case Xtext:
261
		close(textfd);
262
		textfd = open(textfile, OREAD);
263
		if(textfd < 0) {
264
			snprint(buf, sizeof buf, "text: %r");
265
			respond(r, buf);
266
			return;
267
		}
268
		break;
269
	}		
270
	respond(r, nil);
271
}
272
 
273
void
274
fsread(Req *r)
275
{
276
	int i, n;
277
	char buf[512];
278
 
279
	switch((uintptr)r->fid->file->aux) {
280
	case Xfpregs:
281
	case Xproc:
282
	case Xregs:
283
		respond(r, "Egreg");
284
		break;
285
	case Xkregs:
286
	case Xmem:
287
		if(sendp(rchan, r) != 1){
288
			snprint(buf, sizeof buf, "rdbfs sendp: %r");
289
			respond(r, buf);
290
			return;
291
		}
292
		break;
293
	case Xtext:
294
		n = pread(textfd, r->ofcall.data, r->ifcall.count, r->ifcall.offset);
295
		if(n < 0) {
296
			rerrstr(buf, sizeof buf);
297
			respond(r, buf);
298
			break;
299
		}
300
		r->ofcall.count = n;
301
		respond(r, nil);
302
		break;
303
	case Xstatus:
304
		n = sprint(buf, "%-28s%-28s%-28s", "remote", "system", "New");
305
		for(i = 0; i < 9; i++)
306
			n += sprint(buf+n, "%-12d", 0);
307
		readstr(r, buf);
308
		respond(r, nil);
309
		break;
310
	default:
311
		respond(r, "unknown read");
312
	}
313
}
314
 
315
void
316
fswrite(Req *r)
317
{
318
	char buf[ERRMAX];
319
 
320
	switch((uintptr)r->fid->file->aux) {
321
	case Xctl:
322
		if(strncmp(r->ifcall.data, "kill", 4) == 0 ||
323
		   strncmp(r->ifcall.data, "exit", 4) == 0) {
324
			respond(r, nil);
325
			postnote(PNGROUP, getpid(), "umount");
326
			exits(nil);
327
		}else if(strncmp(r->ifcall.data, "refresh", 7) == 0){
328
			flushcache();
329
			respond(r, nil);
330
		}else if(strncmp(r->ifcall.data, "hashstats", 9) == 0){
331
			int i;
332
			lock(&pglock);
333
			for(i=0; i<NHASH; i++)
334
				if(pgtab[i])
335
					print("%lud ", pgtab[i]->len);
336
			print("\n");
337
			unlock(&pglock);
338
			respond(r, nil);
339
		}else
340
			respond(r, "permission denied");
341
		break;
342
	case Xkregs:
343
	case Xmem:
344
		if(sendp(rchan, r) != 1) {
345
			snprint(buf, sizeof buf, "rdbfs sendp: %r");
346
			respond(r, buf);
347
			return;
348
		}
349
		break;
350
	default:
351
		respond(r, "Egreg");
352
		break;
353
	}
354
}
355
 
356
struct {
357
	char *s;
358
	int id;
359
	int mode;
360
} tab[] = {
361
	"ctl",		Xctl,		0222,
362
	"fpregs",	Xfpregs,	0666,
363
	"kregs",	Xkregs,		0666,
364
	"mem",		Xmem,		0666,
365
	"proc",		Xproc,		0444,
366
	"regs",		Xregs,		0666,
367
	"text",		Xtext,		0444,
368
	"status",	Xstatus,	0444,
369
};
370
 
371
void
372
killall(Srv*)
373
{
374
	postnote(PNGROUP, getpid(), "kill");
375
}
376
 
377
Srv fs = {
378
.open=	fsopen,
379
.read=	fsread,
380
.write=	fswrite,
381
.end=	killall,
382
};
383
 
384
void
385
threadmain(int argc, char **argv)
386
{
387
	int i, p[2];
388
	File *dir;
389
 
390
	rfork(RFNOTEG);
391
	ARGBEGIN{
392
	case 'D':
393
		chatty9p++;
394
		break;
395
	case 'd':
396
		dbg = 1;
397
		break;
398
	case 'p':
399
		procname = EARGF(usage());
400
		break;
401
	case 's':
402
		srvname = EARGF(usage());
403
		break;
404
	case 't':
405
		textfile = EARGF(usage());
406
		break;
407
	default:
408
		usage();
409
	}ARGEND;
410
 
411
	switch(argc){
412
	case 0:
413
		break;
414
	case 1:
415
		portname = argv[0];
416
		break;
417
	default:
418
		usage();
419
	}
420
 
421
	rchan = chancreate(sizeof(Req*), 10);
422
	attachremote(portname);
423
	if(pipe(p) < 0)
424
		sysfatal("pipe: %r");
425
 
426
	fmtinstall('F', fcallfmt);
427
	proccreate(eiaread, nil, 8192);
428
 
429
	fs.tree = alloctree("rdbfs", "rdbfs", DMDIR|0555, nil);
430
	dir = createfile(fs.tree->root, procname, "rdbfs", DMDIR|0555, 0);
431
	for(i=0; i<nelem(tab); i++)
432
		closefile(createfile(dir, tab[i].s, "rdbfs", tab[i].mode, (void*)tab[i].id));
433
	closefile(dir);
434
	threadpostmountsrv(&fs, srvname, "/proc", MBEFORE);
435
	exits(0);
436
}
437