xref: /openbsd/sys/arch/m88k/m88k/m88100_machdep.c (revision 19c1239e)
1 /*	$OpenBSD: m88100_machdep.c,v 1.12 2014/05/31 11:19:06 miod Exp $	*/
2 /*
3  * Mach Operating System
4  * Copyright (c) 1993-1991 Carnegie Mellon University
5  * Copyright (c) 1991 OMRON Corporation
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
16  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 
32 #include <machine/asm_macro.h>
33 #include <m88k/m88100.h>
34 
35 #ifdef MULTIPROCESSOR
36 uint32_t m88100_mp_atomic_begin(__cpu_simple_lock_t *, uint *);
37 void	m88100_mp_atomic_end(uint32_t, __cpu_simple_lock_t *, uint);
38 #endif
39 
40 /*
41  *  Data Access Emulation for M88100 exceptions
42  */
43 
44 #define DMT_BYTE	1
45 #define DMT_HALF	2
46 #define DMT_WORD	4
47 
48 const struct {
49 	unsigned char    offset;
50 	unsigned char    size;
51 } dmt_en_info[16] = {
52 	{0, 0},
53 	{3, DMT_BYTE},
54 	{2, DMT_BYTE},
55 	{2, DMT_HALF},
56 	{1, DMT_BYTE},
57 	{0, 0},
58 	{0, 0},
59 	{0, 0},
60 	{0, DMT_BYTE},
61 	{0, 0},
62 	{0, 0},
63 	{0, 0},
64 	{0, DMT_HALF},
65 	{0, 0},
66 	{0, 0},
67 	{0, DMT_WORD}
68 };
69 
70 #ifdef DATA_DEBUG
71 int data_access_emulation_debug = 0;
72 #define DAE_DEBUG(stuff) \
73 	do { \
74 		if (data_access_emulation_debug != 0) { \
75 			stuff; \
76 		} \
77 	} while (0)
78 #else
79 #define DAE_DEBUG(stuff)
80 #endif
81 
82 void	dae_print_one(u_int, u_int, u_int, u_int);
83 void	dae_process(struct trapframe *, u_int, u_int, u_int, u_int);
84 
85 void
dae_print(u_int * f)86 dae_print(u_int *f)
87 {
88 	struct trapframe *eframe = (void *)f;
89 
90 	if (!ISSET(eframe->tf_dmt0, DMT_VALID))
91 		return;
92 
93 	dae_print_one(0, eframe->tf_dma0, eframe->tf_dmd0, eframe->tf_dmt0);
94 	dae_print_one(1, eframe->tf_dma1, eframe->tf_dmd1, eframe->tf_dmt1);
95 	dae_print_one(2, eframe->tf_dma2, eframe->tf_dmd2, eframe->tf_dmt2);
96 }
97 
98 void
dae_print_one(u_int x,u_int dmax,u_int dmdx,u_int dmtx)99 dae_print_one(u_int x, u_int dmax, u_int dmdx, u_int dmtx)
100 {
101 	u_int enbits;
102 	const char *width, *usr, *xmem;
103 
104 	if (!ISSET(dmtx, DMT_VALID))
105 		return;
106 
107 	enbits = DMT_ENBITS(dmtx);
108 	dmax += dmt_en_info[enbits].offset;
109 
110 	if (dmtx & DMT_DOUB1)
111 		width = ".d";
112 	else {
113 		switch (dmt_en_info[enbits].size) {
114 		case DMT_BYTE:
115 			if (dmtx & DMT_SIGNED)
116 				width = ".b";
117 			else
118 				width = ".bu";
119 			break;
120 		case DMT_HALF:
121 			if (dmtx & DMT_SIGNED)
122 				width = ".h";
123 			else
124 				width = ".hu";
125 			break;
126 		case DMT_WORD:
127 			width = "";
128 			break;
129 		default:
130 			width = ".???";
131 			break;
132 		}
133 	}
134 	if (dmtx & DMT_DAS)
135 		usr = "";
136 	else
137 		usr = ".usr";
138 	if (dmtx & DMT_LOCKBAR)
139 		xmem = "(xmem)";
140 	else
141 		xmem = "";
142 
143 	if (ISSET(dmtx, DMT_WRITE))
144 		printf("[DMT%d=%x: %sst%s%s %08x to %08x]\n",
145 		    x, dmtx, xmem, width, usr, dmdx, dmax);
146 	else
147 		printf("[DMT%d=%x: %sld%s%s r%d <- %x]\n",
148 		    x, dmtx, xmem, width, usr, DMT_DREGBITS(dmtx), dmax);
149 }
150 
151 void
data_access_emulation(u_int * f)152 data_access_emulation(u_int *f)
153 {
154 	struct trapframe *eframe = (void *)f;
155 
156 	if (!ISSET(eframe->tf_dmt0, DMT_VALID))
157 		return;
158 
159 	dae_process(eframe, 0,
160 	    eframe->tf_dma0, eframe->tf_dmd0, eframe->tf_dmt0);
161 	dae_process(eframe, 1,
162 	    eframe->tf_dma1, eframe->tf_dmd1, eframe->tf_dmt1);
163 	dae_process(eframe, 2,
164 	    eframe->tf_dma2, eframe->tf_dmd2, eframe->tf_dmt2);
165 
166 	eframe->tf_dmt0 = 0;
167 }
168 
169 void
dae_process(struct trapframe * eframe,u_int x,u_int dmax,u_int dmdx,u_int dmtx)170 dae_process(struct trapframe *eframe, u_int x,
171     u_int dmax, u_int dmdx, u_int dmtx)
172 {
173 	u_int v, reg, enbits;
174 
175 	if (!ISSET(dmtx, DMT_VALID))
176 		return;
177 
178 	DAE_DEBUG(dae_print_one(x, dmax, dmdx, dmtx));
179 
180 	enbits = DMT_ENBITS(dmtx);
181 	dmax += dmt_en_info[enbits].offset;
182 	reg = DMT_DREGBITS(dmtx);
183 
184 	if (!ISSET(dmtx, DMT_LOCKBAR)) {
185 		/* the fault is not during an XMEM */
186 
187 		if (x == 2 && ISSET(dmtx, DMT_DOUB1)) {
188 			/* pipeline 2 (earliest stage) for a double */
189 
190 			if (ISSET(dmtx, DMT_WRITE)) {
191 				/*
192 				 * STORE DOUBLE WILL BE REINITIATED BY rte
193 				 */
194 			} else {
195 				/* EMULATE ld.d INSTRUCTION */
196 				v = do_load_word(dmax, dmtx & DMT_DAS);
197 				if (reg != 0)
198 					eframe->tf_r[reg] = v;
199 				v = do_load_word(dmax ^ 4, dmtx & DMT_DAS);
200 				if (reg != 31)
201 					eframe->tf_r[reg + 1] = v;
202 			}
203 		} else {
204 			/* not pipeline #2 with a double */
205 			if (dmtx & DMT_WRITE) {
206 				switch (dmt_en_info[enbits].size) {
207 				case DMT_BYTE:
208 				DAE_DEBUG(
209 					printf("[byte %x -> %08x(%c)]\n",
210 					    dmdx & 0xff, dmax,
211 					    ISSET(dmtx, DMT_DAS) ? 's' : 'u')
212 				);
213 					do_store_byte(dmax, dmdx,
214 					    dmtx & DMT_DAS);
215 					break;
216 				case DMT_HALF:
217 				DAE_DEBUG(
218 					printf("[half %x -> %08x(%c)]\n",
219 					    dmdx & 0xffff, dmax,
220 					    ISSET(dmtx, DMT_DAS) ? 's' : 'u')
221 				);
222 					do_store_half(dmax, dmdx,
223 					    dmtx & DMT_DAS);
224 					break;
225 				case DMT_WORD:
226 				DAE_DEBUG(
227 					printf("[word %x -> %08x(%c)]\n",
228 					    dmdx, dmax,
229 					    ISSET(dmtx, DMT_DAS) ? 's' : 'u')
230 				);
231 					do_store_word(dmax, dmdx,
232 					    dmtx & DMT_DAS);
233 					break;
234 				}
235 			} else {
236 				/* else it's a read */
237 				switch (dmt_en_info[enbits].size) {
238 				case DMT_BYTE:
239 					v = do_load_byte(dmax, dmtx & DMT_DAS);
240 					if (!ISSET(dmtx, DMT_SIGNED))
241 						v &= 0x000000ff;
242 					break;
243 				case DMT_HALF:
244 					v = do_load_half(dmax, dmtx & DMT_DAS);
245 					if (!ISSET(dmtx, DMT_SIGNED))
246 						v &= 0x0000ffff;
247 					break;
248 				case DMT_WORD:
249 					v = do_load_word(dmax, dmtx & DMT_DAS);
250 					break;
251 				}
252 				DAE_DEBUG(
253 					if (reg == 0)
254 						printf("[no write to r0 done]\n");
255 					else
256 						printf("[r%d <- %08x]\n", reg, v);
257 				);
258 				if (reg != 0)
259 					eframe->tf_r[reg] = v;
260 			}
261 		}
262 	} else {
263 		/* if lockbar is set... it's part of an XMEM */
264 		/*
265 		 * According to Motorola's "General Information",
266 		 * the DMT_DOUB1 bit is never set in this case, as it
267 		 * should be.
268 		 * If lockbar is set (as it is if we're here) and if
269 		 * the write is not set, then it's the same as if DOUB1
270 		 * was set...
271 		 */
272 		if (!ISSET(dmtx, DMT_WRITE)) {
273 			if (x < 2) {
274 				/* RERUN xmem WITH DMD(x+1) */
275 				dmdx =
276 				    x == 0 ? eframe->tf_dmd1 : eframe->tf_dmd2;
277 			} else {
278 				/* RERUN xmem WITH DMD2 */
279 			}
280 
281 			if (dmt_en_info[enbits].size == DMT_WORD) {
282 				v = do_xmem_word(dmax, dmdx, dmtx & DMT_DAS);
283 			} else {
284 				v = do_xmem_byte(dmax, dmdx, dmtx & DMT_DAS);
285 			}
286 			DAE_DEBUG(
287 				if (reg == 0)
288 					printf("[no write to r0 done]\n");
289 				else
290 					printf("[r%d <- %08x]\n", reg, v);
291 			);
292 			if (reg != 0)
293 				eframe->tf_r[reg] = v;
294 		} else {
295 			if (x == 0) {
296 				if (reg != 0)
297 					eframe->tf_r[reg] = dmdx;
298 				m88100_rewind_insn(&(eframe->tf_regs));
299 				/* xmem RERUN ON rte */
300 				eframe->tf_dmt0 = 0;
301 				return;
302 			}
303 		}
304 	}
305 }
306 
307 /*
308  * Routines to patch the kernel code on 88100 systems not affected by
309  * the xxx.usr bug.
310  */
311 
312 void
m88100_apply_patches()313 m88100_apply_patches()
314 {
315 #ifdef ERRATA__XXX_USR
316 	if (((get_cpu_pid() & PID_VN) >> VN_SHIFT) > 10) {
317 		/*
318 		 * Patch DAE helpers.
319 		 *	    before		    after
320 		 *	branch			branch
321 		 *	NOP			jmp.n r1
322 		 *	xxx.usr			xxx.usr
323 		 *	NOP; NOP; NOP
324 		 *	jmp r1
325 		 */
326 		((u_int32_t *)(do_load_word))[1] = 0xf400c401;
327 		((u_int32_t *)(do_load_half))[1] = 0xf400c401;
328 		((u_int32_t *)(do_load_byte))[1] = 0xf400c401;
329 		((u_int32_t *)(do_store_word))[1] = 0xf400c401;
330 		((u_int32_t *)(do_store_half))[1] = 0xf400c401;
331 		((u_int32_t *)(do_store_byte))[1] = 0xf400c401;
332 	}
333 #endif
334 }
335 
336 #ifdef MULTIPROCESSOR
337 void
m88100_smp_setup(struct cpu_info * ci)338 m88100_smp_setup(struct cpu_info *ci)
339 {
340 	/*
341 	 * Setup function pointers for mplock operation.
342 	 */
343 
344 	ci->ci_mp_atomic_begin = m88100_mp_atomic_begin;
345 	ci->ci_mp_atomic_end = m88100_mp_atomic_end;
346 }
347 
348 uint32_t
m88100_mp_atomic_begin(__cpu_simple_lock_t * lock,uint * csr)349 m88100_mp_atomic_begin(__cpu_simple_lock_t *lock, uint *csr)
350 {
351 	uint32_t psr;
352 
353 	psr = get_psr();
354 	set_psr(psr | PSR_IND);
355 	__cpu_simple_lock(lock);
356 
357 	return psr;
358 }
359 
360 void
m88100_mp_atomic_end(uint32_t psr,__cpu_simple_lock_t * lock,uint csr)361 m88100_mp_atomic_end(uint32_t psr, __cpu_simple_lock_t *lock, uint csr)
362 {
363 	__cpu_simple_unlock(lock);
364 	set_psr(psr);
365 }
366 #endif
367