xref: /openbsd/sys/arch/luna88k/stand/boot/fault.c (revision 264ca280)
1 /*	$OpenBSD: fault.c,v 1.2 2014/03/29 18:09:29 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 2013 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Standalone code to recover from faults. Allows for hardware detection.
21  */
22 
23 #include <sys/param.h>
24 
25 #include <machine/asm.h>
26 #include <machine/asm_macro.h>
27 #include <machine/psl.h>
28 
29 typedef struct label_t {
30         long val[19];
31 } label_t;
32 
33 extern int setjmp(label_t *);
34 extern void longjmp(label_t *);
35 
36 static label_t badaddr_jmpbuf;
37 static uint32_t badaddr_psr;
38 
39 static uint32_t prom_vbr;
40 static uint32_t vector_page[512 * 2] __attribute__ ((__aligned__(0x1000)));
41 
42 static __inline__ uint32_t
43 get_vbr()
44 {
45 	uint32_t vbr;
46 	__asm__ volatile ("ldcr %0, %%cr7" : "=r"(vbr));
47 	return vbr;
48 }
49 
50 static __inline__ void
51 set_vbr(uint32_t vbr)
52 {
53 	__asm__ volatile ("stcr %0, %%cr7" :: "r"(vbr));
54 }
55 
56 /*
57  * This is an horribly crude logic to recover from data access exceptions
58  * by longjmp'ing back to badaddr(). We should theoretically at least use
59  * an `rte' somewhere to unfreeze the scoreboard. But since we restore a
60  * PSR with interrupts disabled, this turns out to be safe.
61  */
62 static void
63 libsa_fault_handler(void)
64 {
65 	set_psr(badaddr_psr | PSR_IND);	/* undo SFRZ */
66 	flush_pipeline();
67 
68 	longjmp(&badaddr_jmpbuf);
69 	/* NOTREACHED */
70 }
71 
72 static __inline__ uint32_t
73 br(uint32_t delta)
74 {
75 	return 0xc0000000 | (((int32_t)delta >> 2) & 0x03ffffff);
76 }
77 
78 static void
79 libsa_fault_init()
80 {
81 	int vec;
82 	uint32_t *insn;
83 	uint32_t br_insn;
84 
85 	prom_vbr = get_vbr();
86 
87 	insn = vector_page;
88 	br_insn = br(prom_vbr - (uint32_t)&vector_page - 4);
89 	for (vec = 512; vec != 0; vec--) {
90 		*insn++ = 0xf4005800;	/* nop */
91 		*insn++ = br_insn;	/* br into prom vbr page */
92 	}
93 
94 	/* override data access exception */
95 	vector_page[3 * 2 + 1] =
96 	    br((uint32_t)&libsa_fault_handler -
97 	       (uint32_t)&vector_page[3 * 2 + 1]);
98 }
99 
100 int
101 badaddr(void *addr, int len)
102 {
103 	int rc;
104 
105 	if (vector_page[0] == 0)
106 		libsa_fault_init();
107 
108 	badaddr_psr = get_psr();
109 	set_psr(badaddr_psr | PSR_IND);
110 
111 	set_vbr((uint32_t)&vector_page);
112 
113 	if (setjmp(&badaddr_jmpbuf) == 0) {
114 		switch (len) {
115 		case 1:
116 			(void)*(volatile uint8_t *)addr;
117 			rc = 0;
118 			break;
119 		case 2:
120 			if ((uint32_t)addr & 1)
121 				rc = 1;
122 			else {
123 				(void)*(volatile uint16_t *)addr;
124 				rc = 0;
125 			}
126 			break;
127 		case 4:
128 			if ((uint32_t)addr & 3)
129 				rc = 1;
130 			else {
131 				(void)*(volatile uint32_t *)addr;
132 				rc = 0;
133 			}
134 			break;
135 		default:
136 			rc = 1;
137 			break;
138 		}
139 	} else {
140 		rc = 1;
141 	}
142 
143 	set_vbr(prom_vbr);
144 	flush_pipeline();
145 	set_psr(badaddr_psr);
146 
147 	return rc;
148 }
149