Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"ureg.h"
7
#include	"../port/error.h"
8
#include	"io.h"
9
 
10
enum {
11
	Debug = 0,
12
};
13
 
14
typedef struct Fault Fault;
15
struct Fault {
16
	uintptr	va;
17
	ulong	pid;
18
	uintptr	pc;
19
	int	cnt;
20
	char	*prog;
21
	int	code;
22
};
23
 
24
extern char *excname[];
25
 
26
static Fault lflt, maxflt;
27
 
28
/*
29
 * Ask if the instruction at EPC could have cause this badvaddr
30
 */
31
int
32
tstbadvaddr(Ureg *ur)
33
{
34
	int rn;
35
	ulong iw, off, ea;
36
 
37
	iw = ur->pc;
38
	if(ur->cause & BD)
39
		iw += 4;
40
 
41
	if(seg(up, iw, 0) == 0)
42
		return 0;
43
 
44
	iw = *(ulong*)iw;
45
 
46
/*	print("iw: %#lux\n", iw);	/**/
47
 
48
	switch((iw>>26) & 0x3f) {
49
	default:
50
		return 1;
51
	case 0x20:	/* LB */
52
	case 0x24:	/* LBU */
53
			/* LD */
54
	case 0x35:
55
	case 0x36:
56
	case 0x37:	/* LDCz */
57
	case 0x1A:	/* LDL */
58
	case 0x1B:	/* LDR */
59
	case 0x21:	/* LH */
60
	case 0x25:	/* LHU */
61
	case 0x30:	/* LL */
62
	case 0x34:	/* LLD */
63
	case 0x23:	/* LW */
64
	case 0x31:
65
	case 0x32:	/* LWCz possible 0x33 */
66
	case 0x27:	/* LWU */
67
	case 0x22:	/* LWL */
68
	case 0x26:	/* LWR */
69
		break;
70
 
71
	case 0x28:	/* SB */
72
	case 0x38:	/* SC */
73
	case 0x3C:	/* SCD */
74
	case 0x3D:
75
	case 0x3E:
76
	case 0x3F:	/* SDCz */
77
	case 0x2C:	/* SDL */
78
	case 0x2D:	/* SDR */
79
	case 0x29:	/* SH */
80
	case 0x2B:	/* SW */
81
	case 0x39:
82
	case 0x3A:	/* SWCz */
83
	case 0x2A:	/* SWL */
84
	case 0x2E:	/* SWR */
85
		break;
86
	}
87
 
88
	off = iw & 0xffff;
89
	if(off & 0x8000)
90
		off |= ~0xffff;
91
 
92
	rn = (iw>>21) & 0x1f;
93
	ea = *reg(ur, rn);
94
	if(rn == 0)
95
		ea = 0;
96
	ea += off;
97
 
98
	/* print("ea %#lux %#lux(R%d) bv %#lux pc %#lux\n", ea, off, rn, ur->badvaddr, ur->pc); /**/
99
 
100
	if(ur->badvaddr == ea)
101
		return 0;
102
 
103
	return 1;
104
}
105
 
106
/*
107
 * we think we get consecutive page faults from unlucky combinations of
108
 * scheduling and stlb hashes, and they only happen with 16K pages.
109
 * however, we also get page faults while servicing the exact same fault.
110
 * more than 5 consecutive faults is unusual, now that we have a better
111
 * hash function.
112
 *
113
 * this can be helpful during mmu and cache debugging.
114
 */
115
static int
116
ckfaultstuck(Ureg *ur, int read, int code)
117
{
118
	uintptr pc, va;
119
 
120
	va = ur->badvaddr;
121
	pc = ur->pc;
122
	if (va != lflt.va || up->pid != lflt.pid || pc != lflt.pc ||
123
	    code != lflt.code) {
124
		/* at least one address or cause is different from last time */
125
		lflt.cnt = 1;
126
		lflt.va = va;
127
		lflt.pid = up->pid;
128
		lflt.pc = pc;
129
		lflt.code = code;
130
		return 0;
131
	}
132
	++lflt.cnt;
133
	if (lflt.cnt >= 1000)	/* fixfault() isn't fixing underlying cause? */
134
		panic("fault: %d consecutive faults for va %#p", lflt.cnt, va);
135
	if (lflt.cnt > maxflt.cnt) {
136
		maxflt.cnt = lflt.cnt;
137
		maxflt.va = va;
138
		maxflt.pid = up->pid;
139
		maxflt.pc = pc;
140
		kstrdup(&maxflt.prog, up->text);
141
	}
142
 
143
	/* we're servicing that fault now! */
144
	/* adjust the threshold and program name to suit */
145
	if (lflt.cnt < 5 || strncmp(up->text, "8l", 2) != 0)
146
		return 0;
147
	iprint("%d consecutive faults for va %#p at pc %#p in %s "
148
		"pid %ld\n", lflt.cnt, lflt.va, pc, up->text, lflt.pid);
149
	iprint("\t%s: %s%s r31 %#lux tlbvirt %#lux\n",
150
		excname[code], va == pc? "[instruction] ": "",
151
		(read? "read": "write"), ur->r31, tlbvirt());
152
	return 0;
153
}
154
 
155
char *
156
faultsprint(char *p, char *ep)
157
{
158
	if (Debug)
159
		p = seprint(p, ep,
160
			"max consecutive faults %d for va %#p in %s\n",
161
			maxflt.cnt, maxflt.va, maxflt.prog);
162
	return p;
163
}
164
 
165
/*
166
 *  find out fault address and type of access.
167
 *  Call common fault handler.
168
 */
169
void
170
faultmips(Ureg *ur, int user, int code)
171
{
172
	int read;
173
	ulong addr;
174
	char *p, buf[ERRMAX];
175
	static int infault, printed;
176
 
177
	if (0 && infault && !printed) {
178
		printed = 1;
179
		print("fault: recursive fault (%d deep) pc %#p va %#p\n",
180
			infault+1, ur->pc, ur->badvaddr);
181
	}
182
	infault++;
183
	if(waserror()){
184
		infault--;
185
		nexterror();
186
	}
187
 
188
	addr = ur->badvaddr;
189
	addr &= ~(BY2PG-1);
190
 
191
	read = !(code==CTLBM || code==CTLBS);
192
 
193
/*	print("fault: %s code %d va %#p pc %#p r31 %#lux tlbvirt %#lux\n",
194
		up->text, code, ur->badvaddr, ur->pc, ur->r31, tlbvirt());/**/
195
 
196
	if (Debug && ckfaultstuck(ur, read, code) || fault(addr, read) == 0){
197
		infault--;
198
		poperror();
199
		return;
200
	}
201
 
202
	infault--;
203
	poperror();
204
 
205
	if(tstbadvaddr(ur)) {
206
		print("fault: spurious badvaddr %#lux in %s at pc %#lux\n",
207
			ur->badvaddr, up->text, ur->pc);/**/
208
		return;
209
	}
210
 
211
	if(user) {
212
		p = "store";
213
		if(read)
214
			p = "load";
215
		snprint(buf, sizeof buf, "sys: trap: fault %s addr=%#lux r31=%#lux",
216
			p, ur->badvaddr, ur->r31);
217
		postnote(up, 1, buf, NDebug);
218
		return;
219
	}
220
 
221
	print("kernel %s vaddr=%#lux\n", excname[code], ur->badvaddr);
222
	print("st=%#lux pc=%#lux r31=%#lux sp=%#lux\n",
223
		ur->status, ur->pc, ur->r31, ur->sp);
224
	dumpregs(ur);
225
	panic("fault");
226
}
227
 
228
/*
229
 * called in syscallfmt.c, sysfile.c, sysproc.c
230
 */
231
void
232
validalign(uintptr addr, unsigned align)
233
{
234
	/*
235
	 * Plan 9 is a 32-bit O/S, and the hardware it runs on
236
	 * does not usually have instructions which move 64-bit
237
	 * quantities directly, synthesizing the operations
238
	 * with 32-bit move instructions. Therefore, the compiler
239
	 * (and hardware) usually only enforce 32-bit alignment,
240
	 * if at all.
241
	 *
242
	 * Take this out if the architecture warrants it.
243
	 */
244
	if(align == sizeof(vlong))
245
		align = sizeof(long);
246
 
247
	/*
248
	 * Check align is a power of 2, then addr alignment.
249
	 */
250
	if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
251
		return;
252
	postnote(up, 1, "sys: odd address", NDebug);
253
	error(Ebadarg);
254
	/*NOTREACHED*/
255
}