/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * The debugger/PROM interface layer - debugger activation */ #include #include #include #include #include #include #include #include #include #include kaif_cpusave_t kaif_cb_save; static const char kaif_defer_word_tmpl[] = /* 1 */ ": kmdb_callback " /* * Don't hand control to the debugger if we're coming from OBP's text. */ /* 2 */ " %%pc f000.0000 ffff.ffff between if exit then " /* * Save registers */ /* 3 */ " %%pc h# %x x! " /* 4 */ " %%npc h# %x x! " /* 5 */ " %%g1 h# %x x! " /* 6 */ " %%g2 h# %x x! " /* 7 */ " %%g3 h# %x x! " /* 8 */ " %%g4 h# %x x! " /* 9 */ " %%g5 h# %x x! " /* 10 */ " %%g6 h# %x x! " /* 11 */ " %%g7 h# %x x! " /* 12 */ " 1 %%tstate h# %x x! " /* 13 */ " 1 %%tt h# %x x! " /* 14 */ " %%tba h# %x x! " /* 15 */ " h# %x set-pc " /* 16 */ " go " /* 17 */ "; "; /* * Format the Forth word which tells the prom how to save state for * giving control to us. */ static char * kaif_format_word(void) { static char prom_str[550]; kreg_t *kregs = kaif_cb_save.krs_gregs.kregs; int len; len = mdb_snprintf(prom_str, sizeof (prom_str), kaif_defer_word_tmpl, &kregs[KREG_PC], /* 3 */ &kregs[KREG_NPC], /* 4 */ &kregs[KREG_G1], /* 5 */ &kregs[KREG_G2], /* 6 */ &kregs[KREG_G3], /* 7 */ &kregs[KREG_G4], /* 8 */ &kregs[KREG_G5], /* 9 */ &kregs[KREG_G6], /* 10 */ &kregs[KREG_G7], /* 11 */ &kaif_cb_save.krs_tstate, /* 12 */ &kregs[KREG_TT], /* 13 */ &kregs[KREG_TBA], /* 14 */ kaif_trap_obp); /* 15 */ ASSERT(len <= sizeof (prom_str)); return (prom_str); } static void kaif_prom_install(void) { kmdb_prom_interpret(kaif_format_word()); kmdb_prom_interpret(" ['] kmdb_callback init-debugger-hook "); } void kaif_prom_rearm(void) { kmdb_prom_interpret(" ['] kmdb_callback is debugger-hook "); } /*ARGSUSED*/ static void kaif_cpu_init(cpu_t *cp) { kaif_wapt_set_regs(); } /*ARGSUSED*/ static void kaif_install_generic(caddr_t tgt, caddr_t arg) { bcopy((caddr_t)kaif_hdlr_generic, tgt, 32); } #ifdef sun4v /*ARGSUSED*/ static void kaif_install_goto_tt64(caddr_t tgt, caddr_t arg) { /* LINTED - pointer alignment */ uint32_t *hdlr = (uint32_t *)tgt; uint32_t disp = (T_FAST_INSTR_MMU_MISS - T_INSTR_MMU_MISS) * 0x20; *hdlr++ = 0x10480000 | (disp >> 2); /* ba,pt (to tt64) */ *hdlr++ = 0x01000000; /* nop */ } /*ARGSUSED*/ static void kaif_install_goto_tt68(caddr_t tgt, caddr_t arg) { /* LINTED - pointer alignment */ uint32_t *hdlr = (uint32_t *)tgt; uint32_t disp = (T_FAST_DATA_MMU_MISS - T_DATA_MMU_MISS) * 0x20; *hdlr++ = 0x10480000 | (disp >> 2); /* ba,pt (to tt68) */ *hdlr++ = 0x01000000; /* nop */ } #endif /* sun4v */ static void kaif_install_dmmumiss(caddr_t tgt, caddr_t vatotte) { uint32_t *patch; bcopy((caddr_t)kaif_hdlr_dmiss, tgt, 128); /* LINTED - pointer alignment */ patch = (uint32_t *)(tgt + ((uintptr_t)&kaif_hdlr_dmiss_patch - (uintptr_t)kaif_hdlr_dmiss)); *patch++ |= (uintptr_t)vatotte >> 10; *patch |= ((uintptr_t)vatotte) & 0x3ff; } static void kaif_install_immumiss(caddr_t tgt, caddr_t vatotte) { uint32_t *patch; bcopy((caddr_t)kaif_hdlr_imiss, tgt, 128); /* LINTED - pointer alignment */ patch = (uint32_t *)(tgt + ((uintptr_t)&kaif_hdlr_imiss_patch - (uintptr_t)kaif_hdlr_imiss)); *patch++ |= (uintptr_t)vatotte >> 10; *patch |= ((uintptr_t)vatotte) & 0x3ff; } static struct kaif_trap_handlers { uint_t th_tt; void (*th_install)(caddr_t, caddr_t); } kaif_trap_handlers[] = { { T_INSTR_EXCEPTION, kaif_install_generic }, #ifdef sun4v { T_INSTR_MMU_MISS, kaif_install_goto_tt64 }, #endif { T_IDIV0, kaif_install_generic }, { T_DATA_EXCEPTION, kaif_install_generic }, #ifdef sun4v { T_DATA_MMU_MISS, kaif_install_goto_tt68 }, #endif { T_DATA_ERROR, kaif_install_generic }, { T_ALIGNMENT, kaif_install_generic }, { T_FAST_INSTR_MMU_MISS, kaif_install_immumiss }, { T_FAST_DATA_MMU_MISS, kaif_install_dmmumiss }, { T_FAST_DATA_MMU_PROT, kaif_install_generic }, #ifdef sun4v { T_INSTR_MMU_MISS + T_TL1, kaif_install_goto_tt64 }, { T_DATA_MMU_MISS + T_TL1, kaif_install_goto_tt68 }, #endif { T_FAST_INSTR_MMU_MISS + T_TL1, kaif_install_immumiss }, { T_FAST_DATA_MMU_MISS + T_TL1, kaif_install_dmmumiss }, { 0 } }; static void kaif_trap_init(void) { caddr_t vatotte = kmdb_kdi_get_trap_vatotte(); uintptr_t brtgt; int i; /* * sun4u: * We rely upon OBP for the handling of a great many traps. As such, * we begin by populating our table with pointers to OBP's handlers. * We then copy in our own handlers where appropriate. At some point, * when we provide the bulk of the handlers, this process will be * reversed. * * sun4v: * The sun4v kernel dismisses OBP at boot. Both fast and slow TLB * misses are handled by KMDB. Breakpoint traps go directly KMDB. * All other trap entries are redirected to their respective * trap implemenation within the Solaris trap table. */ for (i = 0; i < kaif_tba_native_sz; i += 0x20) { /* LINTED - pointer alignment */ uint32_t *hdlr = (uint32_t *)(kaif_tba_native + i); #ifdef sun4v brtgt = (uintptr_t)(kaif_tba_kernel + i); #else brtgt = (uintptr_t)(kaif_tba_obp + i); #endif *hdlr++ = 0x03000000 | (brtgt >> 10); /* sethi brtgt, %g1 */ *hdlr++ = 0x81c06000 | (brtgt & 0x3ff); /* jmp %g1 + brtgt */ *hdlr++ = 0x01000000; /* nop */ } for (i = 0; kaif_trap_handlers[i].th_tt != 0; i++) { struct kaif_trap_handlers *th = &kaif_trap_handlers[i]; th->th_install(kaif_tba_native + th->th_tt * 0x20, vatotte); } membar_producer(); } /* * The kernel is ready for us to switch to our table (the HAT has been * initialized, the hments are walkable, and the trap table's pages * have been locked into the TLBs. */ static void kaif_vmready(void) { kaif_tba = kaif_tba_native; } /* * Called on the CPR master CPU. The driver has taken care of locking the * TLB entries. CPR restored the OBP image which contains kmdb_callback, * so there's nothing we need to do. This function should be removed entirely * in a future release. */ static void kaif_cpr_restart(void) { } static kdi_debugvec_t kaif_dvec = { NULL, /* dv_kctl_vmready */ NULL, /* dv_kctl_memavail */ NULL, /* dv_kctl_modavail */ NULL, /* dv_kctl_thravail */ kaif_vmready, NULL, /* dv_memavail */ kaif_mod_loaded, kaif_mod_unloading, NULL, /* dv_kctl_cpu_init */ kaif_cpu_init, kaif_cpr_restart }; /*ARGSUSED1*/ void kaif_activate(kdi_debugvec_t **dvecp, uint_t flags) { kaif_prom_install(); kaif_ktrap_install(0, kaif_ktrap); kaif_trap_init(); *dvecp = &kaif_dvec; } void kaif_deactivate(void) { kmdb_prom_interpret(" ['] noop is debugger-hook "); kaif_ktrap_restore(); }