1 /* $NetBSD: kgdb_machdep.c,v 1.26 2024/09/08 10:02:49 andvar Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Allen Briggs for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: kgdb_machdep.c,v 1.26 2024/09/08 10:02:49 andvar Exp $"); 40 41 #ifdef _KERNEL_OPT 42 #include "opt_ppcarch.h" 43 #endif 44 45 /* 46 * Machine-dependent functions for remote KGDB. 47 */ 48 49 #include <sys/param.h> 50 #include <sys/kgdb.h> 51 #include <sys/systm.h> 52 53 #include <uvm/uvm_extern.h> 54 55 #include <machine/reg.h> 56 #include <machine/trap.h> 57 #include <machine/pmap.h> 58 #include <machine/psl.h> 59 60 #include <powerpc/spr.h> 61 #if defined (PPC_OEA) || defined (PPC_OEA601) || defined (PPC_OEA64_BRIDGE) 62 #include <powerpc/oea/spr.h> 63 #include <powerpc/oea/bat.h> 64 65 #elif defined (PPC_OEA64) 66 #include <powerpc/oea/spr.h> 67 68 #elif defined (PPC_IBM4XX) 69 #include <powerpc/booke/spr.h> 70 71 #elif defined (PPC_BOOKE) 72 #include <powerpc/booke/spr.h> 73 74 #else 75 #error unknown architecture 76 #endif 77 78 /* 79 * Determine if the memory at va..(va+len) is valid. 80 */ 81 int 82 kgdb_acc(vaddr_t va, size_t len) 83 { 84 vaddr_t last_va; 85 paddr_t pa; 86 u_int msr; 87 #if defined (PPC_OEA) || defined (PPC_OEA601) || defined (PPC_OEA64_BRIDGE) 88 u_int batu; 89 #ifdef PPC_OEA601 90 u_int batl; 91 #endif 92 #endif 93 94 /* If translation is off, everything is fair game */ 95 __asm volatile ("mfmsr %0" : "=r"(msr)); 96 if ((msr & PSL_DR) == 0) { 97 return 1; 98 } 99 100 #if defined (PPC_OEA) || defined (PPC_OEA601) || defined (PPC_OEA64_BRIDGE) 101 /* Now check battable registers */ 102 #ifdef PPC_OEA601 103 if ((mfpvr() >> 16) == MPC601) { 104 __asm volatile ("mfibatl %0,0" : "=r"(batl)); 105 __asm volatile ("mfibatu %0,0" : "=r"(batu)); 106 if (BAT601_VALID_P(batl) && 107 BAT601_VA_MATCH_P(batu,batl,va)) 108 return 1; 109 __asm volatile ("mfibatl %0,1" : "=r"(batl)); 110 __asm volatile ("mfibatu %0,1" : "=r"(batu)); 111 if (BAT601_VALID_P(batl) && 112 BAT601_VA_MATCH_P(batu,batl,va)) 113 return 1; 114 __asm volatile ("mfibatl %0,2" : "=r"(batl)); 115 __asm volatile ("mfibatu %0,2" : "=r"(batu)); 116 if (BAT601_VALID_P(batl) && 117 BAT601_VA_MATCH_P(batu,batl,va)) 118 return 1; 119 __asm volatile ("mfibatl %0,3" : "=r"(batl)); 120 __asm volatile ("mfibatu %0,3" : "=r"(batu)); 121 if (BAT601_VALID_P(batl) && 122 BAT601_VA_MATCH_P(batu,batl,va)) 123 return 1; 124 } else { 125 #endif /* PPC_OEA601 */ 126 __asm volatile ("mfdbatu %0,0" : "=r"(batu)); 127 if (BAT_VALID_P(batu,msr) && 128 BAT_VA_MATCH_P(batu,va) && 129 (batu & BAT_PP) != BAT_PP_NONE) { 130 return 1; 131 } 132 __asm volatile ("mfdbatu %0,1" : "=r"(batu)); 133 if (BAT_VALID_P(batu,msr) && 134 BAT_VA_MATCH_P(batu,va) && 135 (batu & BAT_PP) != BAT_PP_NONE) { 136 return 1; 137 } 138 __asm volatile ("mfdbatu %0,2" : "=r"(batu)); 139 if (BAT_VALID_P(batu,msr) && 140 BAT_VA_MATCH_P(batu,va) && 141 (batu & BAT_PP) != BAT_PP_NONE) { 142 return 1; 143 } 144 __asm volatile ("mfdbatu %0,3" : "=r"(batu)); 145 if (BAT_VALID_P(batu,msr) && 146 BAT_VA_MATCH_P(batu,va) && 147 (batu & BAT_PP) != BAT_PP_NONE) { 148 return 1; 149 #ifdef PPC_OEA601 150 } 151 #endif 152 } 153 #endif /* PPC_OEA || PPC_OEA601 || PPC_OEA64_BRIDGE */ 154 155 #if defined(PPC_IBM4XX) 156 /* Is it (supposed to be) TLB-reserved mapping? */ 157 if (va < VM_MIN_KERNEL_ADDRESS || va > VM_MAX_KERNEL_ADDRESS) 158 return (1); 159 #endif 160 161 last_va = va + len; 162 va &= ~PGOFSET; 163 last_va &= ~PGOFSET; 164 165 do { 166 /* 167 * I think this should be able to handle 168 * non-pmap_kernel() va's, too. 169 */ 170 if (!pmap_extract(pmap_kernel(), va, &pa)) 171 return 0; 172 va += PAGE_SIZE; 173 } while (va <= last_va); 174 175 return (1); 176 } 177 178 /* 179 * Translate a trap number into a unix compatible signal value. 180 * (gdb only understands unix signal numbers). Some of these are bogus 181 * and should be reviewed. 182 */ 183 int 184 kgdb_signal(int type) 185 { 186 switch (type) { 187 #if defined (PPC_IBM4XX) || defined (PPC_BOOKE) 188 case EXC_PIT: /* 40x - Programmable interval timer */ 189 case EXC_FIT: /* 40x - Fixed interval timer */ 190 return SIGALRM; 191 192 case EXC_CII: /* 40x - Critical input interrupt */ 193 case EXC_WDOG: /* 40x - Watchdog timer */ 194 case EXC_DEBUG: /* 40x - Debug trap */ 195 return SIGTRAP; 196 197 case EXC_DTMISS: /* 40x - Instruction TLB miss */ 198 case EXC_ITMISS: /* 40x - Data TLB miss */ 199 return SIGSEGV; 200 #endif 201 202 #if defined (PPC_OEA) || defined (PPC_OEA601) || defined (PPC_OEA64_BRIDGE) 203 case EXC_PERF: /* 604/750/7400 - Performance monitoring */ 204 case EXC_BPT: /* 604/750/7400 - Instruction breakpoint */ 205 case EXC_SMI: /* 604/750/7400 - System management interrupt */ 206 case EXC_THRM: /* 750/7400 - Thermal management interrupt */ 207 return SIGTRAP; 208 209 case EXC_IMISS: /* 603 - Instruction translation miss */ 210 case EXC_DLMISS: /* 603 - Data load translation miss */ 211 case EXC_DSMISS: /* 603 - Data store translation miss */ 212 return SIGSEGV; 213 214 case EXC_RST: /* All but IBM 4xx - Reset */ 215 return SIGURG; 216 217 case EXC_VEC: /* 7400 - Altivec unavailable */ 218 case EXC_VECAST: /* 7400 - Altivec assist */ 219 return SIGFPE; 220 #endif 221 222 case EXC_DECR: /* Decrementer interrupt */ 223 return SIGALRM; 224 225 case EXC_EXI: /* External interrupt */ 226 return SIGINT; 227 228 case EXC_PGM: /* Program interrupt */ 229 case EXC_ALI: /* Alignment */ 230 return SIGILL; 231 232 case T_BREAKPOINT: 233 case EXC_MCHK: /* Machine check */ 234 case EXC_TRC: /* Trace */ 235 return SIGTRAP; 236 237 case EXC_ISI: /* Instruction storage interrupt */ 238 case EXC_DSI: /* Data storage interrupt */ 239 return SIGSEGV; 240 241 case EXC_FPU: /* Floating point unavailable */ 242 case EXC_FPA: /* Floating-point assist */ 243 return SIGFPE; 244 245 case EXC_SC: /* System call */ 246 return SIGURG; 247 248 case EXC_RSVD: /* Reserved */ 249 case EXC_AST: /* Floating point unavailable */ 250 default: 251 return SIGEMT; 252 } 253 } 254 255 /* 256 * Translate the values stored in the kernel regs struct to the format 257 * understood by gdb. 258 */ 259 void 260 kgdb_getregs(db_regs_t *regs, kgdb_reg_t *gdb_regs) 261 { 262 memcpy(gdb_regs, regs, 32 * sizeof(unsigned long)); 263 gdb_regs[KGDB_PPC_PC_REG] = regs->iar; 264 gdb_regs[KGDB_PPC_MSR_REG] = regs->msr; 265 gdb_regs[KGDB_PPC_CR_REG] = regs->cr; 266 gdb_regs[KGDB_PPC_LR_REG] = regs->lr; 267 gdb_regs[KGDB_PPC_CTR_REG] = regs->ctr; 268 gdb_regs[KGDB_PPC_XER_REG] = regs->xer; 269 } 270 271 /* 272 * Reverse the above. 273 */ 274 void 275 kgdb_setregs(db_regs_t *regs, kgdb_reg_t *gdb_regs) 276 { 277 regs->xer = gdb_regs[KGDB_PPC_XER_REG]; 278 regs->ctr = gdb_regs[KGDB_PPC_CTR_REG]; 279 regs->lr = gdb_regs[KGDB_PPC_LR_REG]; 280 regs->cr = gdb_regs[KGDB_PPC_CR_REG]; 281 regs->msr = gdb_regs[KGDB_PPC_MSR_REG]; 282 regs->iar = gdb_regs[KGDB_PPC_PC_REG]; 283 memcpy(regs, gdb_regs, 32 * sizeof(unsigned long)); 284 } 285 286 /* 287 * Trap into kgdb to wait for debugger to connect, 288 * noting on the console why nothing else is going on. 289 */ 290 void 291 kgdb_connect(int verbose) 292 { 293 if (kgdb_dev == NODEV) 294 return; 295 296 if (verbose) 297 printf("kgdb waiting..."); 298 299 __asm volatile(BKPT_ASM); 300 301 if (verbose && kgdb_active) { 302 printf("kgdb connected.\n"); 303 } 304 305 kgdb_debug_panic = 1; 306 } 307 308 /* 309 * Decide what to do on panic. 310 * (This is called by panic, like Debugger()) 311 */ 312 void 313 kgdb_panic(void) 314 { 315 if (kgdb_dev != NODEV && kgdb_debug_panic) { 316 printf("entering kgdb\n"); 317 kgdb_connect(kgdb_active == 0); 318 } 319 } 320