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
tstbadvaddr(Ureg * ur)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
ckfaultstuck(Ureg * ur,int read,int code)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 *
faultsprint(char * p,char * ep)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
faultmips(Ureg * ur,int user,int code)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
validalign(uintptr addr,unsigned align)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 }
256