Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /*-------------------------------------------------------------------------- |
| 2 | -- |
| 3 | -- Identity : Linux50 Debug Funcions |
| 4 | -- |
| 5 | -- File : arch/sh64/lib/dbg.C |
| 6 | -- |
| 7 | -- Copyright 2000, 2001 STMicroelectronics Limited. |
| 8 | -- Copyright 2004 Richard Curnow (evt_debug etc) |
| 9 | -- |
| 10 | --------------------------------------------------------------------------*/ |
| 11 | #include <linux/config.h> |
| 12 | #include <linux/types.h> |
| 13 | #include <linux/kernel.h> |
| 14 | #include <linux/sched.h> |
| 15 | #include <linux/mm.h> |
| 16 | #include <asm/mmu_context.h> |
| 17 | |
| 18 | typedef u64 regType_t; |
| 19 | |
| 20 | static regType_t getConfigReg(u64 id) |
| 21 | { |
| 22 | register u64 reg __asm__("r2"); |
| 23 | asm volatile ("getcfg %1, 0, %0":"=r" (reg):"r"(id)); |
| 24 | return (reg); |
| 25 | } |
| 26 | |
| 27 | /* ======================================================================= */ |
| 28 | |
| 29 | static char *szTab[] = { "4k", "64k", "1M", "512M" }; |
| 30 | static char *protTab[] = { "----", |
| 31 | "---R", |
| 32 | "--X-", |
| 33 | "--XR", |
| 34 | "-W--", |
| 35 | "-W-R", |
| 36 | "-WX-", |
| 37 | "-WXR", |
| 38 | "U---", |
| 39 | "U--R", |
| 40 | "U-X-", |
| 41 | "U-XR", |
| 42 | "UW--", |
| 43 | "UW-R", |
| 44 | "UWX-", |
| 45 | "UWXR" |
| 46 | }; |
| 47 | #define ITLB_BASE 0x00000000 |
| 48 | #define DTLB_BASE 0x00800000 |
| 49 | #define MAX_TLBs 64 |
| 50 | /* PTE High */ |
| 51 | #define GET_VALID(pte) ((pte) & 0x1) |
| 52 | #define GET_SHARED(pte) ((pte) & 0x2) |
| 53 | #define GET_ASID(pte) ((pte >> 2) & 0x0ff) |
| 54 | #define GET_EPN(pte) ((pte) & 0xfffff000) |
| 55 | |
| 56 | /* PTE Low */ |
| 57 | #define GET_CBEHAVIOR(pte) ((pte) & 0x3) |
| 58 | #define GET_PAGE_SIZE(pte) szTab[((pte >> 3) & 0x3)] |
| 59 | #define GET_PROTECTION(pte) protTab[((pte >> 6) & 0xf)] |
| 60 | #define GET_PPN(pte) ((pte) & 0xfffff000) |
| 61 | |
| 62 | #define PAGE_1K_MASK 0x00000000 |
| 63 | #define PAGE_4K_MASK 0x00000010 |
| 64 | #define PAGE_64K_MASK 0x00000080 |
| 65 | #define MMU_PAGESIZE_MASK (PAGE_64K_MASK | PAGE_4K_MASK) |
| 66 | #define PAGE_1MB_MASK MMU_PAGESIZE_MASK |
| 67 | #define PAGE_1K (1024) |
| 68 | #define PAGE_4K (1024 * 4) |
| 69 | #define PAGE_64K (1024 * 64) |
| 70 | #define PAGE_1MB (1024 * 1024) |
| 71 | |
| 72 | #define HOW_TO_READ_TLB_CONTENT \ |
| 73 | "[ ID] PPN EPN ASID Share CB P.Size PROT.\n" |
| 74 | |
| 75 | void print_single_tlb(unsigned long tlb, int single_print) |
| 76 | { |
| 77 | regType_t pteH; |
| 78 | regType_t pteL; |
| 79 | unsigned int valid, shared, asid, epn, cb, ppn; |
| 80 | char *pSize; |
| 81 | char *pProt; |
| 82 | |
| 83 | /* |
| 84 | ** in case of single print <single_print> is true, this implies: |
| 85 | ** 1) print the TLB in any case also if NOT VALID |
| 86 | ** 2) print out the header |
| 87 | */ |
| 88 | |
| 89 | pteH = getConfigReg(tlb); |
| 90 | valid = GET_VALID(pteH); |
| 91 | if (single_print) |
| 92 | printk(HOW_TO_READ_TLB_CONTENT); |
| 93 | else if (!valid) |
| 94 | return; |
| 95 | |
| 96 | pteL = getConfigReg(tlb + 1); |
| 97 | |
| 98 | shared = GET_SHARED(pteH); |
| 99 | asid = GET_ASID(pteH); |
| 100 | epn = GET_EPN(pteH); |
| 101 | cb = GET_CBEHAVIOR(pteL); |
| 102 | pSize = GET_PAGE_SIZE(pteL); |
| 103 | pProt = GET_PROTECTION(pteL); |
| 104 | ppn = GET_PPN(pteL); |
| 105 | printk("[%c%2ld] 0x%08x 0x%08x %03d %02x %02x %4s %s\n", |
| 106 | ((valid) ? ' ' : 'u'), ((tlb & 0x0ffff) / TLB_STEP), |
| 107 | ppn, epn, asid, shared, cb, pSize, pProt); |
| 108 | } |
| 109 | |
| 110 | void print_dtlb(void) |
| 111 | { |
| 112 | int count; |
| 113 | unsigned long tlb; |
| 114 | |
| 115 | printk(" ================= SH-5 D-TLBs Status ===================\n"); |
| 116 | printk(HOW_TO_READ_TLB_CONTENT); |
| 117 | tlb = DTLB_BASE; |
| 118 | for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP) |
| 119 | print_single_tlb(tlb, 0); |
| 120 | printk |
| 121 | (" =============================================================\n"); |
| 122 | } |
| 123 | |
| 124 | void print_itlb(void) |
| 125 | { |
| 126 | int count; |
| 127 | unsigned long tlb; |
| 128 | |
| 129 | printk(" ================= SH-5 I-TLBs Status ===================\n"); |
| 130 | printk(HOW_TO_READ_TLB_CONTENT); |
| 131 | tlb = ITLB_BASE; |
| 132 | for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP) |
| 133 | print_single_tlb(tlb, 0); |
| 134 | printk |
| 135 | (" =============================================================\n"); |
| 136 | } |
| 137 | |
| 138 | /* ======================================================================= */ |
| 139 | |
| 140 | #ifdef CONFIG_POOR_MANS_STRACE |
| 141 | |
| 142 | #include "syscalltab.h" |
| 143 | |
| 144 | struct ring_node { |
| 145 | int evt; |
| 146 | int ret_addr; |
| 147 | int event; |
| 148 | int tra; |
| 149 | int pid; |
| 150 | unsigned long sp; |
| 151 | unsigned long pc; |
| 152 | }; |
| 153 | |
| 154 | static struct ring_node event_ring[16]; |
| 155 | static int event_ptr = 0; |
| 156 | |
| 157 | struct stored_syscall_data { |
| 158 | int pid; |
| 159 | int syscall_number; |
| 160 | }; |
| 161 | |
| 162 | #define N_STORED_SYSCALLS 16 |
| 163 | |
| 164 | static struct stored_syscall_data stored_syscalls[N_STORED_SYSCALLS]; |
| 165 | static int syscall_next=0; |
| 166 | static int syscall_next_print=0; |
| 167 | |
| 168 | void evt_debug(int evt, int ret_addr, int event, int tra, struct pt_regs *regs) |
| 169 | { |
| 170 | int syscallno = tra & 0xff; |
| 171 | unsigned long sp; |
| 172 | unsigned long stack_bottom; |
| 173 | int pid; |
| 174 | struct ring_node *rr; |
| 175 | |
| 176 | pid = current->pid; |
| 177 | stack_bottom = (unsigned long) current->thread_info; |
| 178 | asm volatile("ori r15, 0, %0" : "=r" (sp)); |
| 179 | rr = event_ring + event_ptr; |
| 180 | rr->evt = evt; |
| 181 | rr->ret_addr = ret_addr; |
| 182 | rr->event = event; |
| 183 | rr->tra = tra; |
| 184 | rr->pid = pid; |
| 185 | rr->sp = sp; |
| 186 | rr->pc = regs->pc; |
| 187 | |
| 188 | if (sp < stack_bottom + 3092) { |
| 189 | printk("evt_debug : stack underflow report\n"); |
| 190 | int i, j; |
| 191 | for (j=0, i = event_ptr; j<16; j++) { |
| 192 | rr = event_ring + i; |
| 193 | printk("evt=%08x event=%08x tra=%08x pid=%5d sp=%08lx pc=%08lx\n", |
| 194 | rr->evt, rr->event, rr->tra, rr->pid, rr->sp, rr->pc); |
| 195 | i--; |
| 196 | i &= 15; |
| 197 | } |
| 198 | panic("STACK UNDERFLOW\n"); |
| 199 | } |
| 200 | |
| 201 | event_ptr = (event_ptr + 1) & 15; |
| 202 | |
| 203 | if ((event == 2) && (evt == 0x160)) { |
| 204 | if (syscallno < NUM_SYSCALL_INFO_ENTRIES) { |
| 205 | /* Store the syscall information to print later. We |
| 206 | * can't print this now - currently we're running with |
| 207 | * SR.BL=1, so we can't take a tlbmiss (which could occur |
| 208 | * in the console drivers under printk). |
| 209 | * |
| 210 | * Just overwrite old entries on ring overflow - this |
| 211 | * is only for last-hope debugging. */ |
| 212 | stored_syscalls[syscall_next].pid = current->pid; |
| 213 | stored_syscalls[syscall_next].syscall_number = syscallno; |
| 214 | syscall_next++; |
| 215 | syscall_next &= (N_STORED_SYSCALLS - 1); |
| 216 | } |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | static void drain_syscalls(void) { |
| 221 | while (syscall_next_print != syscall_next) { |
| 222 | printk("Task %d: %s()\n", |
| 223 | stored_syscalls[syscall_next_print].pid, |
| 224 | syscall_info_table[stored_syscalls[syscall_next_print].syscall_number].name); |
| 225 | syscall_next_print++; |
| 226 | syscall_next_print &= (N_STORED_SYSCALLS - 1); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | void evt_debug2(unsigned int ret) |
| 231 | { |
| 232 | drain_syscalls(); |
| 233 | printk("Task %d: syscall returns %08x\n", current->pid, ret); |
| 234 | } |
| 235 | |
| 236 | void evt_debug_ret_from_irq(struct pt_regs *regs) |
| 237 | { |
| 238 | int pid; |
| 239 | struct ring_node *rr; |
| 240 | |
| 241 | pid = current->pid; |
| 242 | rr = event_ring + event_ptr; |
| 243 | rr->evt = 0xffff; |
| 244 | rr->ret_addr = 0; |
| 245 | rr->event = 0; |
| 246 | rr->tra = 0; |
| 247 | rr->pid = pid; |
| 248 | rr->pc = regs->pc; |
| 249 | event_ptr = (event_ptr + 1) & 15; |
| 250 | } |
| 251 | |
| 252 | void evt_debug_ret_from_exc(struct pt_regs *regs) |
| 253 | { |
| 254 | int pid; |
| 255 | struct ring_node *rr; |
| 256 | |
| 257 | pid = current->pid; |
| 258 | rr = event_ring + event_ptr; |
| 259 | rr->evt = 0xfffe; |
| 260 | rr->ret_addr = 0; |
| 261 | rr->event = 0; |
| 262 | rr->tra = 0; |
| 263 | rr->pid = pid; |
| 264 | rr->pc = regs->pc; |
| 265 | event_ptr = (event_ptr + 1) & 15; |
| 266 | } |
| 267 | |
| 268 | #endif /* CONFIG_POOR_MANS_STRACE */ |
| 269 | |
| 270 | /* ======================================================================= */ |
| 271 | |
| 272 | void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs) |
| 273 | { |
| 274 | |
| 275 | unsigned long long ah, al, bh, bl, ch, cl; |
| 276 | |
| 277 | printk("\n"); |
| 278 | printk("EXCEPTION - %s: task %d; Linux trap # %d; signal = %d\n", |
| 279 | ((from) ? from : "???"), current->pid, trapnr, signr); |
| 280 | |
| 281 | asm volatile ("getcon " __EXPEVT ", %0":"=r"(ah)); |
| 282 | asm volatile ("getcon " __EXPEVT ", %0":"=r"(al)); |
| 283 | ah = (ah) >> 32; |
| 284 | al = (al) & 0xffffffff; |
| 285 | asm volatile ("getcon " __KCR1 ", %0":"=r"(bh)); |
| 286 | asm volatile ("getcon " __KCR1 ", %0":"=r"(bl)); |
| 287 | bh = (bh) >> 32; |
| 288 | bl = (bl) & 0xffffffff; |
| 289 | asm volatile ("getcon " __INTEVT ", %0":"=r"(ch)); |
| 290 | asm volatile ("getcon " __INTEVT ", %0":"=r"(cl)); |
| 291 | ch = (ch) >> 32; |
| 292 | cl = (cl) & 0xffffffff; |
| 293 | printk("EXPE: %08Lx%08Lx KCR1: %08Lx%08Lx INTE: %08Lx%08Lx\n", |
| 294 | ah, al, bh, bl, ch, cl); |
| 295 | |
| 296 | asm volatile ("getcon " __PEXPEVT ", %0":"=r"(ah)); |
| 297 | asm volatile ("getcon " __PEXPEVT ", %0":"=r"(al)); |
| 298 | ah = (ah) >> 32; |
| 299 | al = (al) & 0xffffffff; |
| 300 | asm volatile ("getcon " __PSPC ", %0":"=r"(bh)); |
| 301 | asm volatile ("getcon " __PSPC ", %0":"=r"(bl)); |
| 302 | bh = (bh) >> 32; |
| 303 | bl = (bl) & 0xffffffff; |
| 304 | asm volatile ("getcon " __PSSR ", %0":"=r"(ch)); |
| 305 | asm volatile ("getcon " __PSSR ", %0":"=r"(cl)); |
| 306 | ch = (ch) >> 32; |
| 307 | cl = (cl) & 0xffffffff; |
| 308 | printk("PEXP: %08Lx%08Lx PSPC: %08Lx%08Lx PSSR: %08Lx%08Lx\n", |
| 309 | ah, al, bh, bl, ch, cl); |
| 310 | |
| 311 | ah = (regs->pc) >> 32; |
| 312 | al = (regs->pc) & 0xffffffff; |
| 313 | bh = (regs->regs[18]) >> 32; |
| 314 | bl = (regs->regs[18]) & 0xffffffff; |
| 315 | ch = (regs->regs[15]) >> 32; |
| 316 | cl = (regs->regs[15]) & 0xffffffff; |
| 317 | printk("PC : %08Lx%08Lx LINK: %08Lx%08Lx SP : %08Lx%08Lx\n", |
| 318 | ah, al, bh, bl, ch, cl); |
| 319 | |
| 320 | ah = (regs->sr) >> 32; |
| 321 | al = (regs->sr) & 0xffffffff; |
| 322 | asm volatile ("getcon " __TEA ", %0":"=r"(bh)); |
| 323 | asm volatile ("getcon " __TEA ", %0":"=r"(bl)); |
| 324 | bh = (bh) >> 32; |
| 325 | bl = (bl) & 0xffffffff; |
| 326 | asm volatile ("getcon " __KCR0 ", %0":"=r"(ch)); |
| 327 | asm volatile ("getcon " __KCR0 ", %0":"=r"(cl)); |
| 328 | ch = (ch) >> 32; |
| 329 | cl = (cl) & 0xffffffff; |
| 330 | printk("SR : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n", |
| 331 | ah, al, bh, bl, ch, cl); |
| 332 | |
| 333 | ah = (regs->regs[0]) >> 32; |
| 334 | al = (regs->regs[0]) & 0xffffffff; |
| 335 | bh = (regs->regs[1]) >> 32; |
| 336 | bl = (regs->regs[1]) & 0xffffffff; |
| 337 | ch = (regs->regs[2]) >> 32; |
| 338 | cl = (regs->regs[2]) & 0xffffffff; |
| 339 | printk("R0 : %08Lx%08Lx R1 : %08Lx%08Lx R2 : %08Lx%08Lx\n", |
| 340 | ah, al, bh, bl, ch, cl); |
| 341 | |
| 342 | ah = (regs->regs[3]) >> 32; |
| 343 | al = (regs->regs[3]) & 0xffffffff; |
| 344 | bh = (regs->regs[4]) >> 32; |
| 345 | bl = (regs->regs[4]) & 0xffffffff; |
| 346 | ch = (regs->regs[5]) >> 32; |
| 347 | cl = (regs->regs[5]) & 0xffffffff; |
| 348 | printk("R3 : %08Lx%08Lx R4 : %08Lx%08Lx R5 : %08Lx%08Lx\n", |
| 349 | ah, al, bh, bl, ch, cl); |
| 350 | |
| 351 | ah = (regs->regs[6]) >> 32; |
| 352 | al = (regs->regs[6]) & 0xffffffff; |
| 353 | bh = (regs->regs[7]) >> 32; |
| 354 | bl = (regs->regs[7]) & 0xffffffff; |
| 355 | ch = (regs->regs[8]) >> 32; |
| 356 | cl = (regs->regs[8]) & 0xffffffff; |
| 357 | printk("R6 : %08Lx%08Lx R7 : %08Lx%08Lx R8 : %08Lx%08Lx\n", |
| 358 | ah, al, bh, bl, ch, cl); |
| 359 | |
| 360 | ah = (regs->regs[9]) >> 32; |
| 361 | al = (regs->regs[9]) & 0xffffffff; |
| 362 | bh = (regs->regs[10]) >> 32; |
| 363 | bl = (regs->regs[10]) & 0xffffffff; |
| 364 | ch = (regs->regs[11]) >> 32; |
| 365 | cl = (regs->regs[11]) & 0xffffffff; |
| 366 | printk("R9 : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n", |
| 367 | ah, al, bh, bl, ch, cl); |
| 368 | printk("....\n"); |
| 369 | |
| 370 | ah = (regs->tregs[0]) >> 32; |
| 371 | al = (regs->tregs[0]) & 0xffffffff; |
| 372 | bh = (regs->tregs[1]) >> 32; |
| 373 | bl = (regs->tregs[1]) & 0xffffffff; |
| 374 | ch = (regs->tregs[2]) >> 32; |
| 375 | cl = (regs->tregs[2]) & 0xffffffff; |
| 376 | printk("T0 : %08Lx%08Lx T1 : %08Lx%08Lx T2 : %08Lx%08Lx\n", |
| 377 | ah, al, bh, bl, ch, cl); |
| 378 | printk("....\n"); |
| 379 | |
| 380 | print_dtlb(); |
| 381 | print_itlb(); |
| 382 | } |
| 383 | |
| 384 | /* ======================================================================= */ |
| 385 | |
| 386 | /* |
| 387 | ** Depending on <base> scan the MMU, Data or Instrction side |
| 388 | ** looking for a valid mapping matching Eaddr & asid. |
| 389 | ** Return -1 if not found or the TLB id entry otherwise. |
| 390 | ** Note: it works only for 4k pages! |
| 391 | */ |
| 392 | static unsigned long |
| 393 | lookup_mmu_side(unsigned long base, unsigned long Eaddr, unsigned long asid) |
| 394 | { |
| 395 | regType_t pteH; |
| 396 | unsigned long epn; |
| 397 | int count; |
| 398 | |
| 399 | epn = Eaddr & 0xfffff000; |
| 400 | |
| 401 | for (count = 0; count < MAX_TLBs; count++, base += TLB_STEP) { |
| 402 | pteH = getConfigReg(base); |
| 403 | if (GET_VALID(pteH)) |
| 404 | if ((unsigned long) GET_EPN(pteH) == epn) |
| 405 | if ((unsigned long) GET_ASID(pteH) == asid) |
| 406 | break; |
| 407 | } |
| 408 | return ((unsigned long) ((count < MAX_TLBs) ? base : -1)); |
| 409 | } |
| 410 | |
| 411 | unsigned long lookup_dtlb(unsigned long Eaddr) |
| 412 | { |
| 413 | unsigned long asid = get_asid(); |
| 414 | return (lookup_mmu_side((u64) DTLB_BASE, Eaddr, asid)); |
| 415 | } |
| 416 | |
| 417 | unsigned long lookup_itlb(unsigned long Eaddr) |
| 418 | { |
| 419 | unsigned long asid = get_asid(); |
| 420 | return (lookup_mmu_side((u64) ITLB_BASE, Eaddr, asid)); |
| 421 | } |
| 422 | |
| 423 | void print_page(struct page *page) |
| 424 | { |
| 425 | printk(" page[%p] -> index 0x%lx, count 0x%x, flags 0x%lx\n", |
| 426 | page, page->index, page_count(page), page->flags); |
| 427 | printk(" address_space = %p, pages =%ld\n", page->mapping, |
| 428 | page->mapping->nrpages); |
| 429 | |
| 430 | } |