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