112657Skvn/*	$OpenBSD: db_machdep.c,v 1.2 1998/09/15 10:50:13 pefo Exp $ */
212657Skvn
312657Skvn/*-
412657Skvn * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
512657Skvn *
612657Skvn * Redistribution and use in source and binary forms, with or without
712657Skvn * modification, are permitted provided that the following conditions
812657Skvn * are met:
912657Skvn * 1. Redistributions of source code must retain the above copyright
1012657Skvn *    notice, this list of conditions and the following disclaimer.
1112657Skvn * 2. Redistributions in binary form must reproduce the above copyright
1212657Skvn *    notice, this list of conditions and the following disclaimer in the
1312657Skvn *    documentation and/or other materials provided with the distribution.
1412657Skvn * 3. All advertising materials mentioning features or use of this software
1512657Skvn *    must display the following acknowledgement:
1612657Skvn *	This product includes software developed under OpenBSD by
1712657Skvn *	Per Fogelstrom, Opsycon AB, Sweden.
1812657Skvn * 4. The name of the author may not be used to endorse or promote products
1912657Skvn *    derived from this software without specific prior written permission.
2012657Skvn *
2112657Skvn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
2212657Skvn * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2312657Skvn * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2412657Skvn * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2512657Skvn * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2612657Skvn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2712657Skvn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2813264Siveresov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2912657Skvn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3012657Skvn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3113482Siveresov * SUCH DAMAGE.
3213482Siveresov *
3313482Siveresov *	JNPR: db_interface.c,v 1.6.2.1 2007/08/29 12:24:49 girish
3413482Siveresov */
3513482Siveresov
3612657Skvn#include <sys/cdefs.h>
3712657Skvn__FBSDID("$FreeBSD: stable/11/sys/mips/mips/db_interface.c 327195 2017-12-26 10:07:17Z kib $");
3813264Siveresov
3913264Siveresov#include <sys/types.h>
4013264Siveresov#include <sys/param.h>
4113264Siveresov#include <sys/systm.h>
4212657Skvn#include <sys/cons.h>
4313482Siveresov#include <sys/lock.h>
4412657Skvn#include <vm/vm.h>
4512657Skvn#include <vm/vm_object.h>
4612657Skvn#include <vm/vm_page.h>
4712657Skvn#include <vm/pmap.h>
4812657Skvn#include <vm/vm_map.h>
4912657Skvn#include <sys/user.h>
5012657Skvn#include <sys/proc.h>
5112657Skvn#include <sys/reboot.h>
5212657Skvn
5312657Skvn#include <machine/cache.h>
5412657Skvn#include <machine/db_machdep.h>
5512657Skvn#include <machine/mips_opcode.h>
5612657Skvn#include <machine/vmparam.h>
5712657Skvn#include <machine/md_var.h>
5812657Skvn#include <machine/setjmp.h>
5912657Skvn
6012657Skvn#include <ddb/ddb.h>
6112657Skvn#include <ddb/db_sym.h>
6212657Skvn#include <ddb/db_access.h>
6312657Skvn#include <ddb/db_output.h>
6412657Skvn#include <ddb/db_variables.h>
6512657Skvn#include <sys/kdb.h>
6612657Skvn
6712657Skvnstatic db_varfcn_t db_frame;
6812657Skvn
6912657Skvn#define	DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
7012657Skvnstruct db_variable db_regs[] = {
7112657Skvn	{ "at",  DB_OFFSET(ast),	db_frame },
7212657Skvn	{ "v0",  DB_OFFSET(v0),		db_frame },
7313264Siveresov	{ "v1",  DB_OFFSET(v1),		db_frame },
7412657Skvn	{ "a0",  DB_OFFSET(a0),		db_frame },
7512657Skvn	{ "a1",  DB_OFFSET(a1),		db_frame },
7612657Skvn	{ "a2",  DB_OFFSET(a2),		db_frame },
7712657Skvn	{ "a3",  DB_OFFSET(a3),		db_frame },
7812657Skvn#if defined(__mips_n32) || defined(__mips_n64)
7912657Skvn	{ "a4",  DB_OFFSET(a4),		db_frame },
8012657Skvn	{ "a5",  DB_OFFSET(a5),		db_frame },
8112657Skvn	{ "a6",  DB_OFFSET(a6),		db_frame },
8212657Skvn	{ "a7",  DB_OFFSET(a7),		db_frame },
8312657Skvn	{ "t0",  DB_OFFSET(t0),		db_frame },
8413264Siveresov	{ "t1",  DB_OFFSET(t1),		db_frame },
8512657Skvn	{ "t2",  DB_OFFSET(t2),		db_frame },
8612657Skvn	{ "t3",  DB_OFFSET(t3),		db_frame },
8713264Siveresov#else
8812657Skvn	{ "t0",  DB_OFFSET(t0),		db_frame },
8912657Skvn	{ "t1",  DB_OFFSET(t1),		db_frame },
9013264Siveresov	{ "t2",  DB_OFFSET(t2),		db_frame },
9112657Skvn	{ "t3",  DB_OFFSET(t3),		db_frame },
9212657Skvn	{ "t4",  DB_OFFSET(t4),		db_frame },
9312657Skvn	{ "t5",  DB_OFFSET(t5),		db_frame },
9412657Skvn	{ "t6",  DB_OFFSET(t6),		db_frame },
9512657Skvn	{ "t7",  DB_OFFSET(t7),		db_frame },
9612657Skvn#endif
9712657Skvn	{ "s0",  DB_OFFSET(s0),		db_frame },
9813264Siveresov	{ "s1",  DB_OFFSET(s1),		db_frame },
9912657Skvn	{ "s2",  DB_OFFSET(s2),		db_frame },
10012657Skvn	{ "s3",  DB_OFFSET(s3),		db_frame },
10112657Skvn	{ "s4",  DB_OFFSET(s4),		db_frame },
10212657Skvn	{ "s5",  DB_OFFSET(s5),		db_frame },
10312657Skvn	{ "s6",  DB_OFFSET(s6),		db_frame },
10412657Skvn	{ "s7",  DB_OFFSET(s7),		db_frame },
10512657Skvn	{ "t8",  DB_OFFSET(t8),		db_frame },
10612657Skvn	{ "t9",  DB_OFFSET(t9),		db_frame },
10712657Skvn	{ "k0",  DB_OFFSET(k0),		db_frame },
10812657Skvn	{ "k1",  DB_OFFSET(k1),		db_frame },
10912657Skvn	{ "gp",  DB_OFFSET(gp),		db_frame },
11012657Skvn	{ "sp",  DB_OFFSET(sp),		db_frame },
11112657Skvn	{ "s8",  DB_OFFSET(s8),		db_frame },
11213264Siveresov	{ "ra",  DB_OFFSET(ra),		db_frame },
11312657Skvn	{ "sr",  DB_OFFSET(sr),		db_frame },
11413482Siveresov	{ "lo",  DB_OFFSET(mullo),	db_frame },
11513482Siveresov	{ "hi",  DB_OFFSET(mulhi),	db_frame },
11612657Skvn	{ "bad", DB_OFFSET(badvaddr),	db_frame },
11713482Siveresov	{ "cs",  DB_OFFSET(cause),	db_frame },
11813482Siveresov	{ "pc",  DB_OFFSET(pc),		db_frame },
11913482Siveresov};
12012657Skvnstruct db_variable *db_eregs = db_regs + nitems(db_regs);
12112657Skvn
12212657Skvnint (*do_db_log_stack_trace_cmd)(char *);
12313482Siveresov
12412657Skvnstatic int
12512657Skvndb_frame(struct db_variable *vp, db_expr_t *valuep, int op)
12612657Skvn{
12712657Skvn	register_t *reg;
12812657Skvn
12912657Skvn	if (kdb_frame == NULL)
13012657Skvn		return (0);
13112657Skvn
13212657Skvn	reg = (register_t *)((uintptr_t)kdb_frame + (size_t)(intptr_t)vp->valuep);
13312657Skvn	if (op == DB_VAR_GET)
13412657Skvn		*valuep = *reg;
13512657Skvn	else
13612657Skvn		*reg = *valuep;
13712657Skvn	return (1);
13812657Skvn}
13912657Skvn
14012657Skvnint
14112657Skvndb_read_bytes(vm_offset_t addr, size_t size, char *data)
14212657Skvn{
14312657Skvn	jmp_buf jb;
14412657Skvn	void *prev_jb;
14513482Siveresov	int ret;
14612657Skvn
14712657Skvn	prev_jb = kdb_jmpbuf(jb);
14812657Skvn	ret = setjmp(jb);
14912657Skvn	if (ret == 0) {
15012657Skvn		/*
15112657Skvn		 * 'addr' could be a memory-mapped I/O address.  Try to
15212657Skvn		 * do atomic load/store in unit of size requested.
15312657Skvn		 * size == 8 is only atomic on 64bit or n32 kernel.
15412657Skvn		 */
15512657Skvn		if ((size == 2 || size == 4 || size == 8) &&
15612657Skvn		    ((addr & (size -1)) == 0) &&
15712657Skvn		    (((vm_offset_t)data & (size -1)) == 0)) {
15812657Skvn			switch (size) {
15912657Skvn			case 2:
16012657Skvn				*(uint16_t *)data = *(uint16_t *)addr;
16113482Siveresov				break;
16213482Siveresov			case 4:
16313482Siveresov				*(uint32_t *)data = *(uint32_t *)addr;
16413482Siveresov				break;
16512657Skvn			case 8:
16612657Skvn				*(uint64_t *)data = *(uint64_t *)addr;
16712657Skvn				break;
16812657Skvn			}
16912657Skvn		} else {
17012657Skvn			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		 * size == 8 is only atomic on 64bit or n32 kernel.
197		 */
198		if ((size == 2 || size == 4 || size == 8) &&
199		    ((addr & (size -1)) == 0) &&
200		    (((vm_offset_t)data & (size -1)) == 0)) {
201			switch (size) {
202			case 2:
203				*(uint16_t *)addr = *(uint16_t *)data;
204				break;
205			case 4:
206				*(uint32_t *)addr = *(uint32_t *)data;
207				break;
208			case 8:
209				*(uint64_t *)addr = *(uint64_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