xref: /onnv-gate/usr/src/uts/intel/os/arch_kdi.c (revision 11066:cebb50cbe4f9)
13446Smrj /*
23446Smrj  * CDDL HEADER START
33446Smrj  *
43446Smrj  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
73446Smrj  *
83446Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93446Smrj  * or http://www.opensolaris.org/os/licensing.
103446Smrj  * See the License for the specific language governing permissions
113446Smrj  * and limitations under the License.
123446Smrj  *
133446Smrj  * When distributing Covered Code, include this CDDL HEADER in each
143446Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153446Smrj  * If applicable, add the following below this CDDL HEADER, with the
163446Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
173446Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
183446Smrj  *
193446Smrj  * CDDL HEADER END
203446Smrj  */
213446Smrj /*
22*11066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
233446Smrj  * Use is subject to license terms.
243446Smrj  */
253446Smrj 
263446Smrj /*
273446Smrj  * Kernel/Debugger Interface (KDI) routines.  Called during debugger under
283446Smrj  * various system states (boot, while running, while the debugger has control).
293446Smrj  * Functions intended for use while the debugger has control may not grab any
303446Smrj  * locks or perform any functions that assume the availability of other system
313446Smrj  * services.
323446Smrj  */
333446Smrj 
343446Smrj #include <sys/systm.h>
353446Smrj #include <sys/x86_archext.h>
363446Smrj #include <sys/kdi_impl.h>
373446Smrj #include <sys/smp_impldefs.h>
383446Smrj #include <sys/psm_types.h>
393446Smrj #include <sys/segments.h>
403446Smrj #include <sys/archsystm.h>
413446Smrj #include <sys/controlregs.h>
423446Smrj #include <sys/trap.h>
433446Smrj #include <sys/kobj.h>
443446Smrj #include <sys/kobj_impl.h>
45*11066Srafael.vanoni@sun.com #include <sys/clock_impl.h>
463446Smrj 
473446Smrj static void
kdi_system_claim(void)483446Smrj kdi_system_claim(void)
493446Smrj {
50*11066Srafael.vanoni@sun.com 	lbolt_debug_entry();
51*11066Srafael.vanoni@sun.com 
523446Smrj 	psm_notifyf(PSM_DEBUG_ENTER);
533446Smrj }
543446Smrj 
553446Smrj static void
kdi_system_release(void)563446Smrj kdi_system_release(void)
573446Smrj {
583446Smrj 	psm_notifyf(PSM_DEBUG_EXIT);
59*11066Srafael.vanoni@sun.com 
60*11066Srafael.vanoni@sun.com 	lbolt_debug_return();
613446Smrj }
623446Smrj 
633446Smrj static cpu_t *
kdi_gdt2cpu(uintptr_t gdtbase)643446Smrj kdi_gdt2cpu(uintptr_t gdtbase)
653446Smrj {
663446Smrj 	cpu_t *cp = cpu_list;
673446Smrj 
683446Smrj 	if (cp == NULL)
693446Smrj 		return (NULL);
703446Smrj 
713446Smrj 	do {
723446Smrj 		if (gdtbase == (uintptr_t)cp->cpu_gdt)
733446Smrj 			return (cp);
743446Smrj 	} while ((cp = cp->cpu_next) != cpu_list);
753446Smrj 
763446Smrj 	return (NULL);
773446Smrj }
783446Smrj 
793446Smrj #if defined(__amd64)
803446Smrj uintptr_t
kdi_gdt2gsbase(uintptr_t gdtbase)813446Smrj kdi_gdt2gsbase(uintptr_t gdtbase)
823446Smrj {
833446Smrj 	return ((uintptr_t)kdi_gdt2cpu(gdtbase));
843446Smrj }
853446Smrj #endif
863446Smrj 
873446Smrj static uintptr_t
kdi_get_userlimit(void)883446Smrj kdi_get_userlimit(void)
893446Smrj {
903446Smrj 	return (_userlimit);
913446Smrj }
923446Smrj 
933446Smrj static int
kdi_get_cpuinfo(uint_t * vendorp,uint_t * familyp,uint_t * modelp)943446Smrj kdi_get_cpuinfo(uint_t *vendorp, uint_t *familyp, uint_t *modelp)
953446Smrj {
963446Smrj 	desctbr_t gdtr;
973446Smrj 	cpu_t *cpu;
983446Smrj 
993446Smrj 	/*
1003446Smrj 	 * CPU doesn't work until the GDT and gs/GSBASE have been set up.
1013446Smrj 	 * Boot-loaded kmdb will call us well before then, so we have to
1023446Smrj 	 * find the current cpu_t the hard way.
1033446Smrj 	 */
1043446Smrj 	rd_gdtr(&gdtr);
1053446Smrj 	if ((cpu = kdi_gdt2cpu(gdtr.dtr_base)) == NULL ||
1063446Smrj 	    !cpuid_checkpass(cpu, 1))
1073446Smrj 		return (EAGAIN); /* cpuid isn't done yet */
1083446Smrj 
1093446Smrj 	*vendorp = cpuid_getvendor(cpu);
1103446Smrj 	*familyp = cpuid_getfamily(cpu);
1113446Smrj 	*modelp = cpuid_getmodel(cpu);
1123446Smrj 
1133446Smrj 	return (0);
1143446Smrj }
1153446Smrj 
1163446Smrj void
kdi_idtr_set(gate_desc_t * idt,size_t limit)1173446Smrj kdi_idtr_set(gate_desc_t *idt, size_t limit)
1183446Smrj {
1193446Smrj 	desctbr_t idtr;
1203446Smrj 
1213446Smrj 	/*
1223446Smrj 	 * This rare case could happen if we entered kmdb whilst still on the
1233446Smrj 	 * fake CPU set up by boot_kdi_tmpinit().  We're trying to restore the
1243446Smrj 	 * kernel's IDT that we saved on entry, but it was from the fake cpu_t
1253446Smrj 	 * rather than the real IDT (which is still boot's).  It's unpleasant,
1263446Smrj 	 * but we just encode knowledge that it's idt0 we want to restore.
1273446Smrj 	 */
1283446Smrj 	if (idt == NULL)
1293446Smrj 		idt = idt0;
1303446Smrj 
1313446Smrj 	CPU->cpu_m.mcpu_idt = idt;
1323446Smrj 	idtr.dtr_base = (uintptr_t)idt;
1333446Smrj 	idtr.dtr_limit = limit;
1343446Smrj 	kdi_idtr_write(&idtr);
1353446Smrj }
1363446Smrj 
1373446Smrj static void
kdi_plat_call(void (* platfn)(void))1383446Smrj kdi_plat_call(void (*platfn)(void))
1393446Smrj {
1403446Smrj 	if (platfn != NULL)
1413446Smrj 		platfn();
1423446Smrj }
1433446Smrj 
1443446Smrj /*
1453446Smrj  * On Intel, most of these are shared between i86*, so this is really an
1463446Smrj  * arch_kdi_init().
1473446Smrj  */
1483446Smrj void
mach_kdi_init(kdi_t * kdi)1493446Smrj mach_kdi_init(kdi_t *kdi)
1503446Smrj {
1513446Smrj 	kdi->kdi_plat_call = kdi_plat_call;
1523446Smrj 	kdi->kdi_kmdb_enter = kmdb_enter;
1533446Smrj 	kdi->mkdi_activate = kdi_activate;
1543446Smrj 	kdi->mkdi_deactivate = kdi_deactivate;
1553446Smrj 	kdi->mkdi_idt_switch = kdi_idt_switch;
1563446Smrj 	kdi->mkdi_update_drreg = kdi_update_drreg;
1573446Smrj 	kdi->mkdi_set_debug_msrs = kdi_set_debug_msrs;
1583446Smrj 	kdi->mkdi_get_userlimit = kdi_get_userlimit;
1593446Smrj 	kdi->mkdi_get_cpuinfo = kdi_get_cpuinfo;
1603446Smrj 	kdi->mkdi_stop_slaves = kdi_stop_slaves;
1613446Smrj 	kdi->mkdi_start_slaves = kdi_start_slaves;
1623446Smrj 	kdi->mkdi_slave_wait = kdi_slave_wait;
1633446Smrj 	kdi->mkdi_memrange_add = kdi_memrange_add;
1643446Smrj 	kdi->mkdi_reboot = kdi_reboot;
1653446Smrj }
1663446Smrj 
1673446Smrj void
plat_kdi_init(kdi_t * kdi)1683446Smrj plat_kdi_init(kdi_t *kdi)
1693446Smrj {
1703446Smrj 	kdi->pkdi_system_claim = kdi_system_claim;
1713446Smrj 	kdi->pkdi_system_release = kdi_system_release;
1723446Smrj }
173