darwin-xnu/osfmk/ppc/db_interface.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/*
  23 * @OSF_COPYRIGHT@
  24 */
  25
  26#include <platforms.h>
  27#include <time_stamp.h>
  28#include <mach_mp_debug.h>
  29#include <mach_ldebug.h>
  30#include <db_machine_commands.h>
  31
  32#include <kern/spl.h>
  33#include <kern/cpu_number.h>
  34#include <kern/kern_types.h>
  35#include <kern/misc_protos.h>
  36#include <vm/pmap.h>
  37
  38#include <ppc/mem.h>
  39#include <ppc/db_machdep.h>
  40#include <ppc/trap.h>
  41#include <ppc/setjmp.h>
  42#include <ppc/pmap.h>
  43#include <ppc/misc_protos.h>
  44#include <ppc/cpu_internal.h>
  45#include <ppc/exception.h>
  46#include <ppc/db_machdep.h>
  47#include <ppc/mappings.h>
  48#include <ppc/Firmware.h>
  49
  50#include <mach/vm_param.h>
  51#include <mach/machine/vm_types.h>
  52#include <vm/vm_map.h>
  53#include <kern/thread.h>
  54#include <kern/task.h>
  55#include <kern/debug.h>
  56#include <pexpert/pexpert.h>
  57#include <IOKit/IOPlatformExpert.h>
  58
  59#include <ddb/db_command.h>
  60#include <ddb/db_task_thread.h>
  61#include <ddb/db_run.h>
  62#include <ddb/db_trap.h>
  63#include <ddb/db_output.h>
  64#include <ddb/db_access.h>
  65#include <ddb/db_sym.h>
  66#include <ddb/db_break.h>
  67#include <ddb/db_watch.h>
  68
  69struct   savearea *ppc_last_saved_statep;
  70struct   savearea ppc_nested_saved_state;
  71unsigned ppc_last_kdb_sp;
  72
  73extern int debugger_cpu;                                /* Current cpu running debugger */
  74
  75int             db_all_set_up = 0;
  76
  77
  78#if !MACH_KDP
  79void kdp_register_send_receive(void);
  80#endif
  81
  82/*
  83 *      Enter KDB through a keyboard trap.
  84 *      We show the registers as of the keyboard interrupt
  85 *      instead of those at its call to KDB.
  86 */
  87struct int_regs {
  88        /* XXX more registers ? */
  89        struct ppc_interrupt_state *is;
  90};
  91
  92extern char *   trap_type[];
  93extern int      TRAP_TYPES;
  94
  95/*
  96 * Code used to synchronize kdb among all cpus, one active at a time, switch
  97 * from on to another using kdb_on! #cpu or cpu #cpu
  98 */
  99
 100decl_simple_lock_data(, kdb_lock)       /* kdb lock                     */
 101
 102#define db_simple_lock_init(l, e)       hw_lock_init(&((l)->interlock))
 103#define db_simple_lock_try(l)           hw_lock_try(&((l)->interlock))
 104#define db_simple_unlock(l)             hw_lock_unlock(&((l)->interlock))
 105
 106extern volatile unsigned int    cpus_holding_bkpts;     /* counter for number of cpus holding
 107                                                   breakpoints (ie: cpus that did not
 108                                                   insert back breakpoints) */
 109extern boolean_t        db_breakpoints_inserted;
 110
 111/* Forward */
 112
 113extern void     kdbprinttrap(
 114                        int                     type,
 115                        int                     code,
 116                        int                     *pc,
 117                        int                     sp);
 118extern void     db_write_bytes_user_space(
 119                        vm_offset_t             addr,
 120                        int                     size,
 121                        char                    *data,
 122                        task_t                  task);
 123extern int      db_search_null(
 124                        task_t                  task,
 125                        unsigned                *svaddr,
 126                        unsigned                evaddr,
 127                        unsigned                *skaddr,
 128                        int                     flag);
 129extern int      kdb_enter(int);
 130extern void     kdb_leave(void);
 131extern void     lock_kdb(void);
 132extern void     unlock_kdb(void);
 133
 134#if DB_MACHINE_COMMANDS
 135struct db_command       ppc_db_commands[] = {
 136        { "lt",         db_low_trace,   CS_MORE|CS_SET_DOT,     0 },
 137        { (char *)0,    0,              0,                      0 }
 138};
 139#endif /* DB_MACHINE_COMMANDS */
 140
 141#if !MACH_KDP
 142void kdp_register_send_receive(void) {}
 143#endif
 144
 145extern jmp_buf_t *db_recover;
 146
 147/*
 148 *  kdb_trap - field a TRACE or BPT trap
 149 */
 150void
 151kdb_trap(
 152        int                     type,
 153        struct savearea *regs)
 154{
 155        boolean_t       trap_from_user;
 156        int                     previous_console_device;
 157        int                     code=0;
 158
 159        previous_console_device=switch_to_serial_console();
 160
 161        switch (type) {
 162            case T_TRACE:       /* single_step */
 163            case T_PROGRAM:     /* breakpoint */
 164#if 0
 165            case T_WATCHPOINT:  /* watchpoint */
 166#endif
 167            case -1:    /* keyboard interrupt */
 168                break;
 169
 170            default:
 171                if (db_recover) {
 172                    ppc_nested_saved_state = *regs;
 173                    db_printf("Caught ");
 174                    if (type > TRAP_TYPES)
 175                        db_printf("type %d", type);
 176                    else
 177                        db_printf("%s", trap_type[type]);
 178                    db_printf(" trap, pc = %llx\n",
 179                              regs->save_srr0);
 180                    db_error("");
 181                    /*NOTREACHED*/
 182                }
 183                kdbprinttrap(type, code, (int *)&regs->save_srr0, regs->save_r1);
 184        }
 185
 186        getPerProc()->db_saved_state = regs;
 187
 188        ppc_last_saved_statep = regs;
 189        ppc_last_kdb_sp = (unsigned) &type;
 190
 191        if (!IS_USER_TRAP(regs)) {
 192                bzero((char *)&ddb_regs, sizeof (ddb_regs));
 193                ddb_regs = *regs;
 194                trap_from_user = FALSE; 
 195
 196        }
 197        else {
 198                ddb_regs = *regs;
 199                trap_from_user = TRUE;
 200        }
 201
 202        db_task_trap(type, code, trap_from_user);
 203
 204        *regs = ddb_regs;
 205
 206        if ((type == T_PROGRAM) &&
 207            (db_get_task_value(regs->save_srr0,
 208                               BKPT_SIZE,
 209                               FALSE,
 210                               db_target_space(current_thread(),
 211                                               trap_from_user))
 212                              == BKPT_INST))
 213            regs->save_srr0 += BKPT_SIZE;
 214
 215kdb_exit:
 216        getPerProc()->db_saved_state = 0;
 217        switch_to_old_console(previous_console_device);
 218
 219}
 220
 221
 222/*
 223 * Print trap reason.
 224 */
 225
 226void
 227kdbprinttrap(
 228        int     type,
 229        int     code,
 230        int     *pc,
 231        int     sp)
 232{
 233        printf("kernel: ");
 234        if (type > TRAP_TYPES)
 235            db_printf("type %d", type);
 236        else
 237            db_printf("%s", trap_type[type]);
 238        db_printf(" trap, code=%x pc@%x = %x sp=%x\n",
 239                  code, pc, *(int *)pc, sp);
 240        db_run_mode = STEP_CONTINUE;
 241}
 242
 243/*
 244 *
 245 */
 246addr64_t db_vtophys(
 247        pmap_t pmap,
 248        vm_offset_t va)
 249{
 250        ppnum_t pp;
 251        addr64_t pa;
 252
 253        pp = pmap_find_phys(pmap, (addr64_t)va);
 254
 255        if (pp == 0) return(0);                                 /* Couldn't find it */
 256        
 257        pa = ((addr64_t)pp << 12) | (addr64_t)(va & 0xFFF);     /* Get physical address */
 258
 259        return(pa);
 260}
 261
 262/*
 263 * Read bytes from task address space for debugger.
 264 */
 265void
 266db_read_bytes(
 267        vm_offset_t     addr,
 268        int             size,
 269        char            *data,
 270        task_t          task)
 271{
 272        int             n,max;
 273        addr64_t        phys_dst;
 274        addr64_t        phys_src;
 275        pmap_t  pmap;
 276        
 277        while (size > 0) {
 278                if (task != NULL)
 279                        pmap = task->map->pmap;
 280                else
 281                        pmap = kernel_pmap;
 282
 283                phys_src = db_vtophys(pmap, (vm_offset_t)addr);  
 284                if (phys_src == 0) {
 285                        db_printf("\nno memory is assigned to src address %08x\n",
 286                                  addr);
 287                        db_error(0);
 288                        /* NOTREACHED */
 289                }
 290
 291                phys_dst = db_vtophys(kernel_pmap, (vm_offset_t)data); 
 292                if (phys_dst == 0) {
 293                        db_printf("\nno memory is assigned to dst address %08x\n",
 294                                  data);
 295                        db_error(0);
 296                        /* NOTREACHED */
 297                }
 298                
 299                /* don't over-run any page boundaries - check src range */
 300                max = round_page_64(phys_src + 1) - phys_src;
 301                if (max > size)
 302                        max = size;
 303                /* Check destination won't run over boundary either */
 304                n = round_page_64(phys_dst + 1) - phys_dst;
 305                
 306                if (n < max) max = n;
 307                size -= max;
 308                addr += max;
 309                phys_copy(phys_src, phys_dst, max);
 310
 311                /* resync I+D caches */
 312                sync_cache64(phys_dst, max);
 313
 314                phys_src += max;
 315                phys_dst += max;
 316        }
 317}
 318
 319/*
 320 * Write bytes to task address space for debugger.
 321 */
 322void
 323db_write_bytes(
 324        vm_offset_t     addr,
 325        int             size,
 326        char            *data,
 327        task_t          task)
 328{
 329        int             n,max;
 330        addr64_t        phys_dst;
 331        addr64_t        phys_src;
 332        pmap_t  pmap;
 333        
 334        while (size > 0) {
 335
 336                phys_src = db_vtophys(kernel_pmap, (vm_offset_t)data); 
 337                if (phys_src == 0) {
 338                        db_printf("\nno memory is assigned to src address %08x\n",
 339                                  data);
 340                        db_error(0);
 341                        /* NOTREACHED */
 342                }
 343                
 344                /* space stays as kernel space unless in another task */
 345                if (task == NULL) pmap = kernel_pmap;
 346                else pmap = task->map->pmap;
 347
 348                phys_dst = db_vtophys(pmap, (vm_offset_t)addr);  
 349                if (phys_dst == 0) {
 350                        db_printf("\nno memory is assigned to dst address %08x\n",
 351                                  addr);
 352                        db_error(0);
 353                        /* NOTREACHED */
 354                }
 355
 356                /* don't over-run any page boundaries - check src range */
 357                max = round_page_64(phys_src + 1) - phys_src;
 358                if (max > size)
 359                        max = size;
 360                /* Check destination won't run over boundary either */
 361                n = round_page_64(phys_dst + 1) - phys_dst;
 362                if (n < max)
 363                        max = n;
 364                size -= max;
 365                addr += max;
 366                phys_copy(phys_src, phys_dst, max);
 367
 368                /* resync I+D caches */
 369                sync_cache64(phys_dst, max);
 370
 371                phys_src += max;
 372                phys_dst += max;
 373        }
 374}
 375        
 376boolean_t
 377db_check_access(
 378        vm_offset_t     addr,
 379        int             size,
 380        task_t          task)
 381{
 382        register int    n;
 383        unsigned int    kern_addr;
 384
 385        if (task == kernel_task || task == TASK_NULL) {
 386            if (kernel_task == TASK_NULL)  return(TRUE);
 387            task = kernel_task;
 388        } else if (task == TASK_NULL) {
 389            if (current_thread() == THR_ACT_NULL) return(FALSE);
 390            task = current_thread()->task;
 391        }
 392
 393        while (size > 0) {
 394                if(!pmap_find_phys(task->map->pmap, (addr64_t)addr)) return (FALSE);    /* Fail if page not mapped */
 395            n = trunc_page_32(addr+PPC_PGBYTES) - addr;
 396            if (n > size)
 397                n = size;
 398            size -= n;
 399            addr += n;
 400        }
 401        return(TRUE);
 402}
 403
 404boolean_t
 405db_phys_eq(
 406        task_t          task1,
 407        vm_offset_t     addr1,
 408        task_t          task2,
 409        vm_offset_t     addr2)
 410{
 411        addr64_t        physa, physb;
 412
 413        if ((addr1 & (PPC_PGBYTES-1)) != (addr2 & (PPC_PGBYTES-1)))     /* Is byte displacement the same? */
 414                return FALSE;
 415
 416        if (task1 == TASK_NULL) {                                               /* See if there is a task active */
 417                if (current_thread() == THR_ACT_NULL)           /* See if there is a current task */
 418                        return FALSE;
 419                task1 = current_thread()->task;                         /* If so, use that one */
 420        }
 421        
 422        if(!(physa = db_vtophys(task1->map->pmap, (vm_offset_t)trunc_page_32(addr1)))) return FALSE;    /* Get real address of the first */
 423        if(!(physb = db_vtophys(task2->map->pmap, (vm_offset_t)trunc_page_32(addr2)))) return FALSE;    /* Get real address of the second */
 424        
 425        return (physa == physb);                                                /* Check if they are equal, then return... */
 426}
 427
 428#define DB_USER_STACK_ADDR              (0xc0000000)
 429#define DB_NAME_SEARCH_LIMIT            (DB_USER_STACK_ADDR-(PPC_PGBYTES*3))
 430
 431boolean_t       db_phys_cmp(
 432                                vm_offset_t a1, 
 433                                vm_offset_t a2, 
 434                                vm_size_t s1) {
 435
 436        db_printf("db_phys_cmp: not implemented\n");
 437        return 0;
 438}
 439
 440
 441int
 442db_search_null(
 443        task_t          task,
 444        unsigned        *svaddr,
 445        unsigned        evaddr,
 446        unsigned        *skaddr,
 447        int             flag)
 448{
 449        register unsigned vaddr;
 450        register unsigned *kaddr;
 451
 452        db_printf("db_search_null: not implemented\n");
 453
 454        return(-1);
 455}
 456
 457unsigned char *getProcName(struct proc *proc);
 458
 459void
 460db_task_name(
 461        task_t          task)
 462{
 463        register unsigned char *p;
 464        register int n;
 465        unsigned int vaddr, kaddr;
 466        unsigned char tname[33];
 467        int i;
 468
 469        p = 0;
 470        tname[0] = 0;
 471        
 472        if(task->bsd_info) p = getProcName((struct proc *)(task->bsd_info));    /* Point to task name */
 473        
 474        if(p) {
 475                for(i = 0; i < 32; i++) {                       /* Move no more than 32 bytes */
 476                        tname[i] = p[i];
 477                        if(p[i] == 0) break;
 478                }
 479                tname[i] = 0;
 480                db_printf("%s", tname);
 481        }
 482        else db_printf("no name");
 483}
 484
 485void
 486db_machdep_init(void) {
 487#define KDB_READY       0x1
 488        extern int     kdb_flag;  
 489
 490        kdb_flag |= KDB_READY;
 491}
 492
 493
 494#ifdef  __STDC__
 495#define KDB_SAVE(type, name) extern type name; type name##_save = name
 496#define KDB_RESTORE(name) name = name##_save
 497#else   /* __STDC__ */
 498#define KDB_SAVE(type, name) extern type name; type name/**/_save = name
 499#define KDB_RESTORE(name) name = name/**/_save
 500#endif  /* __STDC__ */
 501
 502#define KDB_SAVE_CTXT() \
 503        KDB_SAVE(int, db_run_mode); \
 504        KDB_SAVE(boolean_t, db_sstep_print); \
 505        KDB_SAVE(int, db_loop_count); \
 506        KDB_SAVE(int, db_call_depth); \
 507        KDB_SAVE(int, db_inst_count); \
 508        KDB_SAVE(int, db_last_inst_count); \
 509        KDB_SAVE(int, db_load_count); \
 510        KDB_SAVE(int, db_store_count); \
 511        KDB_SAVE(boolean_t, db_cmd_loop_done); \
 512        KDB_SAVE(jmp_buf_t *, db_recover); \
 513        KDB_SAVE(db_addr_t, db_dot); \
 514        KDB_SAVE(db_addr_t, db_last_addr); \
 515        KDB_SAVE(db_addr_t, db_prev); \
 516        KDB_SAVE(db_addr_t, db_next); \
 517        KDB_SAVE(db_regs_t, ddb_regs); 
 518
 519#define KDB_RESTORE_CTXT() \
 520        KDB_RESTORE(db_run_mode); \
 521        KDB_RESTORE(db_sstep_print); \
 522        KDB_RESTORE(db_loop_count); \
 523        KDB_RESTORE(db_call_depth); \
 524        KDB_RESTORE(db_inst_count); \
 525        KDB_RESTORE(db_last_inst_count); \
 526        KDB_RESTORE(db_load_count); \
 527        KDB_RESTORE(db_store_count); \
 528        KDB_RESTORE(db_cmd_loop_done); \
 529        KDB_RESTORE(db_recover); \
 530        KDB_RESTORE(db_dot); \
 531        KDB_RESTORE(db_last_addr); \
 532        KDB_RESTORE(db_prev); \
 533        KDB_RESTORE(db_next); \
 534        KDB_RESTORE(ddb_regs); 
 535
 536/*
 537 * switch to another cpu
 538 */
 539void
 540kdb_on(
 541        int             cpu)
 542{
 543        KDB_SAVE_CTXT();
 544        if (cpu < 0 || cpu >= real_ncpus || !PerProcTable[cpu].ppe_vaddr->debugger_active)
 545                return;
 546        db_set_breakpoints();
 547        db_set_watchpoints();
 548        debugger_cpu = cpu;
 549        unlock_debugger();
 550        lock_debugger();
 551        db_clear_breakpoints();
 552        db_clear_watchpoints();
 553        KDB_RESTORE_CTXT();
 554        if (debugger_cpu == -1)  {/* someone continued */
 555                debugger_cpu = cpu_number();
 556                db_continue_cmd(0, 0, 0, "");
 557        }
 558}
 559
 560/*
 561 * system reboot
 562 */
 563
 564extern int (*PE_halt_restart)(unsigned int type);
 565
 566void db_reboot(
 567        db_expr_t       addr,
 568        boolean_t       have_addr,
 569        db_expr_t       count,
 570        char            *modif)
 571{
 572        boolean_t       reboot = TRUE;
 573        char            *cp, c;
 574        
 575        cp = modif;
 576        while ((c = *cp++) != 0) {
 577                if (c == 'r')   /* reboot */
 578                        reboot = TRUE;
 579                if (c == 'h')   /* halt */
 580                        reboot = FALSE;
 581        }
 582        if(!reboot) halt_all_cpus(FALSE);       /* If no reboot, try to be clean about it */
 583
 584        if (PE_halt_restart) return (*PE_halt_restart)(kPERestartCPU);
 585        db_printf("Sorry, system can't reboot automatically yet...  You need to do it by hand...\n");
 586
 587}
 588
 589/*
 590 * Switch to gdb
 591 */
 592void
 593db_to_gdb(
 594        void)
 595{
 596        extern unsigned int switch_debugger;
 597
 598        switch_debugger=1;
 599}
 600
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.