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