/* * 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" /* * Debugger entry for both master and slave CPUs */ #if defined(__lint) #include #endif #include #include #include #include #include #include #include #include #include #ifdef _ASM #include #include /* clobbers %rdx, %rcx, returns addr in %rax, CPU ID in %rbx */ #define GET_CPUSAVE_ADDR \ movzbq %gs:CPU_ID, %rbx; \ movq %rbx, %rax; \ movq $KRS_SIZE, %rcx; \ mulq %rcx; \ movq $kdi_cpusave, %rdx; \ /*CSTYLED*/ \ addq (%rdx), %rax /* * Save copies of the IDT and GDT descriptors. Note that we only save the IDT * and GDT if the IDT isn't ours, as we may be legitimately re-entering the * debugger through the trap handler. We don't want to clobber the saved IDT * in the process, as we'd end up resuming the world on our IDT. */ #define SAVE_IDTGDT \ movq %gs:CPU_IDT, %r11; \ leaq kdi_idt(%rip), %rsi; \ cmpq %rsi, %r11; \ je 1f; \ movq %r11, KRS_IDT(%rax); \ movq %gs:CPU_GDT, %r11; \ movq %r11, KRS_GDT(%rax); \ 1: /* %ss, %rsp, %rflags, %cs, %rip, %err, %trapno already on stack */ #define KDI_SAVE_REGS(base) \ movq %rdi, REG_OFF(KDIREG_RDI)(base); \ movq %rsi, REG_OFF(KDIREG_RSI)(base); \ movq %rdx, REG_OFF(KDIREG_RDX)(base); \ movq %rcx, REG_OFF(KDIREG_RCX)(base); \ movq %r8, REG_OFF(KDIREG_R8)(base); \ movq %r9, REG_OFF(KDIREG_R9)(base); \ movq %rax, REG_OFF(KDIREG_RAX)(base); \ movq %rbx, REG_OFF(KDIREG_RBX)(base); \ movq %rbp, REG_OFF(KDIREG_RBP)(base); \ movq %r10, REG_OFF(KDIREG_R10)(base); \ movq %r11, REG_OFF(KDIREG_R11)(base); \ movq %r12, REG_OFF(KDIREG_R12)(base); \ movq %r13, REG_OFF(KDIREG_R13)(base); \ movq %r14, REG_OFF(KDIREG_R14)(base); \ movq %r15, REG_OFF(KDIREG_R15)(base); \ movq %rbp, REG_OFF(KDIREG_SAVFP)(base); \ movq REG_OFF(KDIREG_RIP)(base), %rax; \ movq %rax, REG_OFF(KDIREG_SAVPC)(base); \ clrq %rax; \ movw %ds, %ax; \ movq %rax, REG_OFF(KDIREG_DS)(base); \ movw %es, %ax; \ movq %rax, REG_OFF(KDIREG_ES)(base); \ movw %fs, %ax; \ movq %rax, REG_OFF(KDIREG_FS)(base); \ movw %gs, %ax; \ movq %rax, REG_OFF(KDIREG_GS)(base); \ movl $MSR_AMD_GSBASE, %ecx; \ rdmsr; \ shlq $32, %rdx; \ orq %rax, %rdx; \ movq %rdx, REG_OFF(KDIREG_GSBASE)(base) #define KDI_RESTORE_REGS(base) \ movq base, %rdi; \ movq REG_OFF(KDIREG_GSBASE)(%rdi), %rdx; \ movq %rdx, %rax; \ shrq $32, %rdx; \ movl $MSR_AMD_GSBASE, %ecx; \ wrmsr; \ movq REG_OFF(KDIREG_ES)(%rdi), %rax; \ movw %ax, %es; \ movq REG_OFF(KDIREG_DS)(%rdi), %rax; \ movw %ax, %ds; \ movq REG_OFF(KDIREG_R15)(%rdi), %r15; \ movq REG_OFF(KDIREG_R14)(%rdi), %r14; \ movq REG_OFF(KDIREG_R13)(%rdi), %r13; \ movq REG_OFF(KDIREG_R12)(%rdi), %r12; \ movq REG_OFF(KDIREG_R11)(%rdi), %r11; \ movq REG_OFF(KDIREG_R10)(%rdi), %r10; \ movq REG_OFF(KDIREG_RBP)(%rdi), %rbp; \ movq REG_OFF(KDIREG_RBX)(%rdi), %rbx; \ movq REG_OFF(KDIREG_RAX)(%rdi), %rax; \ movq REG_OFF(KDIREG_R9)(%rdi), %r9; \ movq REG_OFF(KDIREG_R8)(%rdi), %r8; \ movq REG_OFF(KDIREG_RCX)(%rdi), %rcx; \ movq REG_OFF(KDIREG_RDX)(%rdi), %rdx; \ movq REG_OFF(KDIREG_RSI)(%rdi), %rsi; \ movq REG_OFF(KDIREG_RDI)(%rdi), %rdi /* * Each cpusave buffer has an area set aside for a ring buffer of breadcrumbs. * The following macros manage the buffer. */ /* Advance the ring buffer */ #define ADVANCE_CRUMB_POINTER(cpusave, tmp1, tmp2) \ movq KRS_CURCRUMBIDX(cpusave), tmp1; \ cmpq $[KDI_NCRUMBS - 1], tmp1; \ jge 1f; \ /* Advance the pointer and index */ \ addq $1, tmp1; \ movq tmp1, KRS_CURCRUMBIDX(cpusave); \ movq KRS_CURCRUMB(cpusave), tmp1; \ addq $KRM_SIZE, tmp1; \ jmp 2f; \ 1: /* Reset the pointer and index */ \ movq $0, KRS_CURCRUMBIDX(cpusave); \ leaq KRS_CRUMBS(cpusave), tmp1; \ 2: movq tmp1, KRS_CURCRUMB(cpusave); \ /* Clear the new crumb */ \ movq $KDI_NCRUMBS, tmp2; \ 3: movq $0, -4(tmp1, tmp2, 4); \ decq tmp2; \ jnz 3b /* Set a value in the current breadcrumb buffer */ #define ADD_CRUMB(cpusave, offset, value, tmp) \ movq KRS_CURCRUMB(cpusave), tmp; \ movq value, offset(tmp) #endif /* _ASM */ /* * The main entry point for master CPUs. It also serves as the trap handler * for all traps and interrupts taken during single-step. */ #if defined(__lint) void kdi_cmnint(void) { } #else /* __lint */ /* XXX implement me */ ENTRY_NP(kdi_nmiint) clrq %rcx movq (%rcx), %rcx SET_SIZE(kdi_nmiint) ENTRY_NP(kdi_cmnint) ALTENTRY(kdi_master_entry) pushq %rax CLI(%rax) popq %rax /* Save current register state */ subq $REG_OFF(KDIREG_TRAPNO), %rsp KDI_SAVE_REGS(%rsp) /* * Switch to the kernel's GSBASE. Neither GSBASE nor the ill-named * KGSBASE can be trusted, as the kernel may or may not have already * done a swapgs. All is not lost, as the kernel can divine the correct * value for us. Note that the previous GSBASE is saved in the * KDI_SAVE_REGS macro to prevent a usermode process's GSBASE from being * blown away. */ subq $10, %rsp sgdt (%rsp) movq 2(%rsp), %rdi /* gdt base now in %rdi */ addq $10, %rsp call kdi_gdt2gsbase /* returns kernel's GSBASE in %rax */ movq %rax, %rdx shrq $32, %rdx movl $MSR_AMD_GSBASE, %ecx wrmsr GET_CPUSAVE_ADDR /* %rax = cpusave, %rbx = CPU ID */ ADVANCE_CRUMB_POINTER(%rax, %rcx, %rdx) ADD_CRUMB(%rax, KRM_CPU_STATE, $KDI_CPU_STATE_MASTER, %rdx) movq REG_OFF(KDIREG_RIP)(%rsp), %rcx ADD_CRUMB(%rax, KRM_PC, %rcx, %rdx) ADD_CRUMB(%rax, KRM_SP, %rsp, %rdx) movq REG_OFF(KDIREG_TRAPNO)(%rsp), %rcx ADD_CRUMB(%rax, KRM_TRAPNO, %rcx, %rdx) movq %rsp, %rbp pushq %rax /* * Were we in the debugger when we took the trap (i.e. was %esp in one * of the debugger's memory ranges)? */ leaq kdi_memranges, %rcx movl kdi_nmemranges, %edx 1: cmpq MR_BASE(%rcx), %rsp jl 2f /* below this range -- try the next one */ cmpq MR_LIM(%rcx), %rsp jg 2f /* above this range -- try the next one */ jmp 3f /* matched within this range */ 2: decl %edx jz kdi_save_common_state /* %rsp not within debugger memory */ addq $MR_SIZE, %rcx jmp 1b 3: /* * The master is still set. That should only happen if we hit a trap * while running in the debugger. Note that it may be an intentional * fault. kmdb_dpi_handle_fault will sort it all out. */ movq REG_OFF(KDIREG_TRAPNO)(%rbp), %rdi movq REG_OFF(KDIREG_RIP)(%rbp), %rsi movq REG_OFF(KDIREG_RSP)(%rbp), %rdx movq %rbx, %rcx /* cpuid */ call kdi_dvec_handle_fault /* * If we're here, we ran into a debugger problem, and the user * elected to solve it by having the debugger debug itself. The * state we're about to save is that of the debugger when it took * the fault. */ jmp kdi_save_common_state SET_SIZE(kdi_master_entry) SET_SIZE(kdi_cmnint) #endif /* __lint */ /* * The cross-call handler for slave CPUs. * * The debugger is single-threaded, so only one CPU, called the master, may be * running it at any given time. The other CPUs, known as slaves, spin in a * busy loop until there's something for them to do. This is the entry point * for the slaves - they'll be sent here in response to a cross-call sent by the * master. */ #if defined(__lint) char kdi_slave_entry_patch; void kdi_slave_entry(void) { } #else /* __lint */ .globl kdi_slave_entry_patch; ENTRY_NP(kdi_slave_entry) /* kdi_msr_add_clrentry knows where this is */ kdi_slave_entry_patch: KDI_MSR_PATCH; /* * Cross calls are implemented as function calls, so our stack currently * looks like one you'd get from a zero-argument function call. That * is, there's the return %rip at %rsp, and that's about it. We need * to make it look like an interrupt stack. When we first save, we'll * reverse the saved %ss and %rip, which we'll fix back up when we've * freed up some general-purpose registers. We'll also need to fix up * the saved %rsp. */ pushq %rsp /* pushed value off by 8 */ pushfq CLI(%rax) pushq $KCS_SEL clrq %rax movw %ss, %ax pushq %rax /* rip should be here */ pushq $-1 /* phony trap error code */ pushq $-1 /* phony trap number */ subq $REG_OFF(KDIREG_TRAPNO), %rsp KDI_SAVE_REGS(%rsp) movq REG_OFF(KDIREG_SS)(%rsp), %rax xchgq REG_OFF(KDIREG_RIP)(%rsp), %rax movq %rax, REG_OFF(KDIREG_SS)(%rsp) movq REG_OFF(KDIREG_RSP)(%rsp), %rax addq $8, %rax movq %rax, REG_OFF(KDIREG_RSP)(%rsp) /* * We've saved all of the general-purpose registers, and have a stack * that is irettable (after we strip down to the error code) */ GET_CPUSAVE_ADDR /* %rax = cpusave, %rbx = CPU ID */ ADVANCE_CRUMB_POINTER(%rax, %rcx, %rdx) ADD_CRUMB(%rax, KRM_CPU_STATE, $KDI_CPU_STATE_SLAVE, %rdx) movq REG_OFF(KDIREG_RIP)(%rsp), %rcx ADD_CRUMB(%rax, KRM_PC, %rcx, %rdx) pushq %rax jmp kdi_save_common_state SET_SIZE(kdi_slave_entry) #endif /* __lint */ #if !defined(__lint) ENTRY_NP(kdi_save_common_state) /* * The state of the world: * * The stack has a complete set of saved registers and segment * selectors, arranged in the kdi_regs.h order. It also has a pointer * to our cpusave area. * * We need to save, into the cpusave area, a pointer to these saved * registers. After that, we save a few more registers, ready the * machine for debugger entry, and enter the debugger. */ popq %rax /* the cpusave area */ movq %rsp, KRS_GREGS(%rax) /* save ptr to current saved regs */ SAVE_IDTGDT /* Save off %cr0, and clear write protect */ movq %cr0, %rcx movq %rcx, KRS_CR0(%rax) andq $_BITNOT(CR0_WP), %rcx movq %rcx, %cr0 /* Save the debug registers and disable any active watchpoints */ movq %rax, %r15 /* save cpusave area ptr */ movl $7, %edi call kdi_dreg_get movq %rax, KRS_DRCTL(%r15) andq $_BITNOT(KDIREG_DRCTL_WPALLEN_MASK), %rax movq %rax, %rsi movl $7, %edi call kdi_dreg_set movl $6, %edi call kdi_dreg_get movq %rax, KRS_DRSTAT(%r15) movl $0, %edi call kdi_dreg_get movq %rax, KRS_DROFF(0)(%r15) movl $1, %edi call kdi_dreg_get movq %rax, KRS_DROFF(1)(%r15) movl $2, %edi call kdi_dreg_get movq %rax, KRS_DROFF(2)(%r15) movl $3, %edi call kdi_dreg_get movq %rax, KRS_DROFF(3)(%r15) movq %r15, %rax /* restore cpu save area to rax */ /* * Save any requested MSRs. */ movq KRS_MSR(%rax), %rcx cmpq $0, %rcx je no_msr pushq %rax /* rdmsr clobbers %eax */ movq %rcx, %rbx 1: movl MSR_NUM(%rbx), %ecx cmpl $0, %ecx je msr_done movl MSR_TYPE(%rbx), %edx cmpl $KDI_MSR_READ, %edx jne msr_next rdmsr /* addr in %ecx, value into %edx:%eax */ movl %eax, MSR_VAL(%rbx) movl %edx, _CONST(MSR_VAL + 4)(%rbx) msr_next: addq $MSR_SIZE, %rbx jmp 1b msr_done: popq %rax no_msr: clrq %rbp /* stack traces should end here */ pushq %rax movq %rax, %rdi /* cpusave */ call kdi_debugger_entry /* Pass cpusave and debugger return code for "call" to resume */ popq %rdi movq %rax, %rsi jmp kdi_resume SET_SIZE(kdi_save_common_state) #endif /* !__lint */ /* * Given the address of the current CPU's cpusave area in %rax, the following * macro restores the debugging state to said CPU. Restored state includes * the debug registers from the global %dr variables, and debugging MSRs from * the CPU save area. This code would be in a separate routine, but for the * fact that some of the MSRs are jump-sensitive. As such, we need to minimize * the number of jumps taken subsequent to the update of said MSRs. We can * remove one jump (the ret) by using a macro instead of a function for the * debugging state restoration code. * * Takes the cpusave area in %rdi as a parameter, clobbers %rax-%rdx */ #define KDI_RESTORE_DEBUGGING_STATE \ pushq %rdi; \ leaq kdi_drreg, %r15; \ movl $7, %edi; \ movq DR_CTL(%r15), %rsi; \ call kdi_dreg_set; \ \ movl $6, %edi; \ movq $KDIREG_DRSTAT_RESERVED, %rsi; \ call kdi_dreg_set; \ \ movl $0, %edi; \ movq DRADDR_OFF(0)(%r15), %rsi; \ call kdi_dreg_set; \ movl $1, %edi; \ movq DRADDR_OFF(1)(%r15), %rsi; \ call kdi_dreg_set; \ movl $2, %edi; \ movq DRADDR_OFF(2)(%r15), %rsi; \ call kdi_dreg_set; \ movl $3, %edi; \ movq DRADDR_OFF(3)(%r15), %rsi; \ call kdi_dreg_set; \ popq %rdi; \ \ /* \ * Write any requested MSRs. \ */ \ movq KRS_MSR(%rdi), %rbx; \ cmpq $0, %rbx; \ je 3f; \ 1: \ movl MSR_NUM(%rbx), %ecx; \ cmpl $0, %ecx; \ je 3f; \ \ movl MSR_TYPE(%rbx), %edx; \ cmpl $KDI_MSR_WRITE, %edx; \ jne 2f; \ \ movq MSR_VALP(%rbx), %rdx; \ movl 0(%rdx), %eax; \ movl 4(%rdx), %edx; \ wrmsr; \ 2: \ addq $MSR_SIZE, %rbx; \ jmp 1b; \ 3: \ /* \ * We must not branch after re-enabling LBR. If \ * kdi_wsr_wrexit_msr is set, it contains the number \ * of the MSR that controls LBR. kdi_wsr_wrexit_valp \ * contains the value that is to be written to enable \ * LBR. \ */ \ movl kdi_msr_wrexit_msr, %ecx; \ cmpl $0, %ecx; \ je 1f; \ \ movq kdi_msr_wrexit_valp, %rdx; \ movl 0(%rdx), %eax; \ movl 4(%rdx), %edx; \ \ wrmsr; \ 1: #if defined(__lint) /*ARGSUSED*/ void kdi_cpu_debug_init(kdi_cpusave_t *save) { } #else /* __lint */ ENTRY_NP(kdi_cpu_debug_init) pushq %rbp movq %rsp, %rbp pushq %rbx /* macro will clobber %rbx */ KDI_RESTORE_DEBUGGING_STATE popq %rbx leave ret SET_SIZE(kdi_cpu_debug_init) #endif /* !__lint */ /* * Resume the world. The code that calls kdi_resume has already * decided whether or not to restore the IDT. */ #if defined(__lint) void kdi_resume(void) { } #else /* __lint */ ENTRY_NP(kdi_resume) /* cpusave in %rdi, debugger command in %rsi */ cmpq $KDI_RESUME_PASS_TO_KERNEL, %rsi je kdi_pass_to_kernel /* * Send this CPU back into the world */ movq KRS_CR0(%rdi), %rdx movq %rdx, %cr0 KDI_RESTORE_DEBUGGING_STATE movq KRS_GREGS(%rdi), %rsp KDI_RESTORE_REGS(%rsp) addq $REG_OFF(KDIREG_RIP), %rsp /* Discard state, trapno, err */ IRET /*NOTREACHED*/ SET_SIZE(kdi_resume) #endif /* __lint */ #if !defined(__lint) ENTRY_NP(kdi_pass_to_kernel) /* cpusave is still in %rdi */ movq KRS_CR0(%rdi), %rdx movq %rdx, %cr0 /* * When we replaced the kernel's handlers in the IDT, we made note of * the handlers being replaced, thus allowing us to pass traps directly * to said handlers here. We won't have any registers available for use * after we start popping, and we know we're single-threaded here, so * we have to use a global to store the handler address. */ movq KRS_GREGS(%rdi), %rsp movq REG_OFF(KDIREG_TRAPNO)(%rsp), %rdi call kdi_kernel_trap2hdlr movq %rax, kdi_kernel_handler /* * The trap handler will expect the stack to be in trap order, with * %rip being the last entry. Our stack is currently in kdi_regs.h * order, so we'll need to pop (and restore) our way back down. */ KDI_RESTORE_REGS(%rsp) addq $REG_OFF(KDIREG_RIP), %rsp /* Discard state, trapno, err */ jmp *%cs:kdi_kernel_handler /*NOTREACHED*/ SET_SIZE(kdi_pass_to_kernel) /* * Reboot the system. This routine is to be called only by the master * CPU. */ ENTRY_NP(kdi_reboot) movl $AD_BOOT, %edi movl $A_SHUTDOWN, %esi call *psm_shutdownf /* * psm_shutdown didn't work or it wasn't set, try pc_reset. */ call pc_reset /*NOTREACHED*/ SET_SIZE(kdi_reboot) #endif /* !__lint */