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
36uint32_t m88100_mp_atomic_begin(__cpu_simple_lock_t *, uint *);
37void	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
48const 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
71int 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
82void	dae_print_one(u_int, u_int, u_int, u_int);
83void	dae_process(struct trapframe *, u_int, u_int, u_int, u_int);
84
85void
86dae_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
98void
99dae_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
151void
152data_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
169void
170dae_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
312void
313m88100_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
337void
338m88100_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
348uint32_t
349m88100_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
360void
361m88100_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