1/*	$OpenBSD: db_machdep.c,v 1.2 1998/09/15 10:50:13 pefo Exp $ */
2
3/*-
4 * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed under OpenBSD by
17 *	Per Fogelstrom, Opsycon AB, Sweden.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	JNPR: db_interface.c,v 1.6.2.1 2007/08/29 12:24:49 girish
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD$");
38
39#include <sys/types.h>
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/cons.h>
43#include <sys/lock.h>
44#include <vm/vm.h>
45#include <vm/vm_object.h>
46#include <vm/vm_page.h>
47#include <vm/pmap.h>
48#include <vm/vm_map.h>
49#include <sys/user.h>
50#include <sys/proc.h>
51#include <sys/reboot.h>
52
53#include <machine/cache.h>
54#include <machine/db_machdep.h>
55#include <machine/mips_opcode.h>
56#include <machine/vmparam.h>
57#include <machine/md_var.h>
58#include <machine/setjmp.h>
59
60#include <ddb/ddb.h>
61#include <ddb/db_sym.h>
62#include <ddb/db_access.h>
63#include <ddb/db_output.h>
64#include <ddb/db_variables.h>
65#include <sys/kdb.h>
66
67static db_varfcn_t db_frame;
68
69#define	DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
70struct db_variable db_regs[] = {
71	{ "at",  DB_OFFSET(ast),	db_frame },
72	{ "v0",  DB_OFFSET(v0),		db_frame },
73	{ "v1",  DB_OFFSET(v1),		db_frame },
74	{ "a0",  DB_OFFSET(a0),		db_frame },
75	{ "a1",  DB_OFFSET(a1),		db_frame },
76	{ "a2",  DB_OFFSET(a2),		db_frame },
77	{ "a3",  DB_OFFSET(a3),		db_frame },
78#if defined(__mips_n32) || defined(__mips_n64)
79	{ "a4",  DB_OFFSET(a4),		db_frame },
80	{ "a5",  DB_OFFSET(a5),		db_frame },
81	{ "a6",  DB_OFFSET(a6),		db_frame },
82	{ "a7",  DB_OFFSET(a7),		db_frame },
83	{ "t0",  DB_OFFSET(t0),		db_frame },
84	{ "t1",  DB_OFFSET(t1),		db_frame },
85	{ "t2",  DB_OFFSET(t2),		db_frame },
86	{ "t3",  DB_OFFSET(t3),		db_frame },
87#else
88	{ "t0",  DB_OFFSET(t0),		db_frame },
89	{ "t1",  DB_OFFSET(t1),		db_frame },
90	{ "t2",  DB_OFFSET(t2),		db_frame },
91	{ "t3",  DB_OFFSET(t3),		db_frame },
92	{ "t4",  DB_OFFSET(t4),		db_frame },
93	{ "t5",  DB_OFFSET(t5),		db_frame },
94	{ "t6",  DB_OFFSET(t6),		db_frame },
95	{ "t7",  DB_OFFSET(t7),		db_frame },
96#endif
97	{ "s0",  DB_OFFSET(s0),		db_frame },
98	{ "s1",  DB_OFFSET(s1),		db_frame },
99	{ "s2",  DB_OFFSET(s2),		db_frame },
100	{ "s3",  DB_OFFSET(s3),		db_frame },
101	{ "s4",  DB_OFFSET(s4),		db_frame },
102	{ "s5",  DB_OFFSET(s5),		db_frame },
103	{ "s6",  DB_OFFSET(s6),		db_frame },
104	{ "s7",  DB_OFFSET(s7),		db_frame },
105	{ "t8",  DB_OFFSET(t8),		db_frame },
106	{ "t9",  DB_OFFSET(t9),		db_frame },
107	{ "k0",  DB_OFFSET(k0),		db_frame },
108	{ "k1",  DB_OFFSET(k1),		db_frame },
109	{ "gp",  DB_OFFSET(gp),		db_frame },
110	{ "sp",  DB_OFFSET(sp),		db_frame },
111	{ "s8",  DB_OFFSET(s8),		db_frame },
112	{ "ra",  DB_OFFSET(ra),		db_frame },
113	{ "sr",  DB_OFFSET(sr),		db_frame },
114	{ "lo",  DB_OFFSET(mullo),	db_frame },
115	{ "hi",  DB_OFFSET(mulhi),	db_frame },
116	{ "bad", DB_OFFSET(badvaddr),	db_frame },
117	{ "cs",  DB_OFFSET(cause),	db_frame },
118	{ "pc",  DB_OFFSET(pc),		db_frame },
119};
120struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
121
122int (*do_db_log_stack_trace_cmd)(char *);
123
124static int
125db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
126{
127	register_t *reg;
128
129	if (kdb_frame == NULL)
130		return (0);
131
132	reg = (register_t *)((uintptr_t)kdb_frame + (size_t)(intptr_t)vp->valuep);
133	if (op == DB_VAR_GET)
134		*valuep = *reg;
135	else
136		*reg = *valuep;
137	return (1);
138}
139
140int
141db_read_bytes(vm_offset_t addr, size_t size, char *data)
142{
143	jmp_buf jb;
144	void *prev_jb;
145	int ret;
146
147	prev_jb = kdb_jmpbuf(jb);
148	ret = setjmp(jb);
149	if (ret == 0) {
150		/*
151		 * 'addr' could be a memory-mapped I/O address.  Try to
152		 * do atomic load/store in unit of size requested.
153		 */
154		if ((size == 2 || size == 4 || size == 8) &&
155		    ((addr & (size -1)) == 0) &&
156		    (((vm_offset_t)data & (size -1)) == 0)) {
157			switch (size) {
158			case 2:
159				*(uint16_t *)data = *(uint16_t *)addr;
160				break;
161			case 4:
162				*(uint32_t *)data = *(uint32_t *)addr;
163				break;
164			case 8:
165				atomic_load_64((volatile u_int64_t *)addr,
166				    (u_int64_t *)data);
167			break;
168			}
169		} else {
170			char *src;
171
172			src = (char *)addr;
173			while (size-- > 0)
174				*data++ = *src++;
175		}
176	}
177
178	(void)kdb_jmpbuf(prev_jb);
179	return (ret);
180}
181
182int
183db_write_bytes(vm_offset_t addr, size_t size, char *data)
184{
185	int ret;
186	jmp_buf jb;
187	void *prev_jb;
188
189	prev_jb = kdb_jmpbuf(jb);
190	ret = setjmp(jb);
191
192	if (ret == 0) {
193		/*
194		 * 'addr' could be a memory-mapped I/O address.  Try to
195		 * do atomic load/store in unit of size requested.
196		 */
197		if ((size == 2 || size == 4 || size == 8) &&
198		    ((addr & (size -1)) == 0) &&
199		    (((vm_offset_t)data & (size -1)) == 0)) {
200			switch (size) {
201			case 2:
202				*(uint16_t *)addr = *(uint16_t *)data;
203				break;
204			case 4:
205				*(uint32_t *)addr = *(uint32_t *)data;
206				break;
207			case 8:
208				atomic_store_64((volatile u_int64_t *)addr,
209				    (u_int64_t *)data);
210			break;
211			}
212		} else {
213			char *dst;
214			size_t len = size;
215
216			dst = (char *)addr;
217			while (len-- > 0)
218				*dst++ = *data++;
219		}
220
221		mips_icache_sync_range((db_addr_t) addr, size);
222		mips_dcache_wbinv_range((db_addr_t) addr, size);
223	}
224	(void)kdb_jmpbuf(prev_jb);
225	return (ret);
226}
227
228/*
229 *	To do a single step ddb needs to know the next address
230 *	that we will get to. It means that we need to find out
231 *	both the address for a branch taken and for not taken, NOT! :-)
232 *	MipsEmulateBranch will do the job to find out _exactly_ which
233 *	address we will end up at so the 'dual bp' method is not
234 *	requiered.
235 */
236db_addr_t
237next_instr_address(db_addr_t pc, boolean_t bd)
238{
239	db_addr_t next;
240
241	next = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, 0, 0);
242	return (next);
243}
244
245
246/*
247 *	Decode instruction and figure out type.
248 */
249int
250db_inst_type(int ins)
251{
252	InstFmt inst;
253	int	ityp = 0;
254
255	inst.word = ins;
256	switch ((int)inst.JType.op) {
257	case OP_SPECIAL:
258		switch ((int)inst.RType.func) {
259		case OP_JR:
260			ityp = IT_BRANCH;
261			break;
262		case OP_JALR:
263		case OP_SYSCALL:
264			ityp = IT_CALL;
265			break;
266		}
267		break;
268
269	case OP_BCOND:
270		switch ((int)inst.IType.rt) {
271		case OP_BLTZ:
272		case OP_BLTZL:
273		case OP_BGEZ:
274		case OP_BGEZL:
275			ityp = IT_BRANCH;
276			break;
277
278		case OP_BLTZAL:
279		case OP_BLTZALL:
280		case OP_BGEZAL:
281		case OP_BGEZALL:
282			ityp = IT_CALL;
283			break;
284		}
285		break;
286
287	case OP_JAL:
288		ityp = IT_CALL;
289		break;
290
291	case OP_J:
292	case OP_BEQ:
293	case OP_BEQL:
294	case OP_BNE:
295	case OP_BNEL:
296	case OP_BLEZ:
297	case OP_BLEZL:
298	case OP_BGTZ:
299	case OP_BGTZL:
300		ityp = IT_BRANCH;
301		break;
302
303	case OP_COP1:
304		switch (inst.RType.rs) {
305		case OP_BCx:
306		case OP_BCy:
307			ityp = IT_BRANCH;
308			break;
309		}
310		break;
311
312	case OP_LB:
313	case OP_LH:
314	case OP_LW:
315	case OP_LD:
316	case OP_LBU:
317	case OP_LHU:
318	case OP_LWU:
319	case OP_LWC1:
320		ityp = IT_LOAD;
321		break;
322
323	case OP_SB:
324	case OP_SH:
325	case OP_SW:
326	case OP_SD:
327	case OP_SWC1:
328		ityp = IT_STORE;
329		break;
330	}
331	return (ityp);
332}
333
334/*
335 * Return the next pc if the given branch is taken.
336 * MachEmulateBranch() runs analysis for branch delay slot.
337 */
338db_addr_t
339branch_taken(int inst, db_addr_t pc)
340{
341	db_addr_t ra;
342	register_t fpucsr;
343
344	/* TBD: when is fsr set */
345	fpucsr = (curthread) ? curthread->td_pcb->pcb_regs.fsr : 0;
346	ra = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, fpucsr, 0);
347	return (ra);
348}
349