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