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: releng/10.3/sys/mips/mips/db_interface.c 250138 2013-05-01 06:57:46Z imp $"); 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