xref: /illumos-gate/usr/src/uts/i86xpv/os/mach_kdi.c (revision 86ef0a63)
1*843e1988Sjohnlev /*
2*843e1988Sjohnlev  * CDDL HEADER START
3*843e1988Sjohnlev  *
4*843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5*843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6*843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7*843e1988Sjohnlev  *
8*843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10*843e1988Sjohnlev  * See the License for the specific language governing permissions
11*843e1988Sjohnlev  * and limitations under the License.
12*843e1988Sjohnlev  *
13*843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14*843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16*843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17*843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18*843e1988Sjohnlev  *
19*843e1988Sjohnlev  * CDDL HEADER END
20*843e1988Sjohnlev  */
21*843e1988Sjohnlev /*
22*843e1988Sjohnlev  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*843e1988Sjohnlev  * Use is subject to license terms.
24*843e1988Sjohnlev  */
25*843e1988Sjohnlev 
26*843e1988Sjohnlev /*
27*843e1988Sjohnlev  * Kernel/Debugger Interface (KDI) routines.  Called during debugger under
28*843e1988Sjohnlev  * various system states (boot, while running, while the debugger has control).
29*843e1988Sjohnlev  * Functions intended for use while the debugger has control may not grab any
30*843e1988Sjohnlev  * locks or perform any functions that assume the availability of other system
31*843e1988Sjohnlev  * services.
32*843e1988Sjohnlev  */
33*843e1988Sjohnlev 
34*843e1988Sjohnlev #include <sys/systm.h>
35*843e1988Sjohnlev #include <sys/x86_archext.h>
36*843e1988Sjohnlev #include <sys/kdi_impl.h>
37*843e1988Sjohnlev #include <sys/smp_impldefs.h>
38*843e1988Sjohnlev #include <sys/psm_types.h>
39*843e1988Sjohnlev #include <sys/segments.h>
40*843e1988Sjohnlev #include <sys/archsystm.h>
41*843e1988Sjohnlev #include <sys/controlregs.h>
42*843e1988Sjohnlev #include <sys/trap.h>
43*843e1988Sjohnlev #include <sys/kobj.h>
44*843e1988Sjohnlev #include <sys/kobj_impl.h>
45*843e1988Sjohnlev #include <sys/hypervisor.h>
46*843e1988Sjohnlev #include <sys/bootconf.h>
47*843e1988Sjohnlev #include <sys/bootinfo.h>
48*843e1988Sjohnlev #include <sys/promif.h>
49*843e1988Sjohnlev #include <sys/evtchn_impl.h>
50*843e1988Sjohnlev #include <sys/cpu.h>
51*843e1988Sjohnlev #include <vm/kboot_mmu.h>
52*843e1988Sjohnlev #include <vm/hat_pte.h>
53*843e1988Sjohnlev 
54*843e1988Sjohnlev static volatile int kdi_slaves_go;
55*843e1988Sjohnlev 
56*843e1988Sjohnlev /*
57*843e1988Sjohnlev  * These are not safe against dropping into kmdb when fbt::: is active. This is
58*843e1988Sjohnlev  * also broken on i86pc...
59*843e1988Sjohnlev  */
60*843e1988Sjohnlev 
61*843e1988Sjohnlev void
kdi_idtr_write(desctbr_t * idtr)62*843e1988Sjohnlev kdi_idtr_write(desctbr_t *idtr)
63*843e1988Sjohnlev {
64*843e1988Sjohnlev 	gate_desc_t *idt = (gate_desc_t *)idtr->dtr_base;
65*843e1988Sjohnlev 	uint_t nidt = (idtr->dtr_limit + 1) / sizeof (*idt);
66*843e1988Sjohnlev 	uint_t vec;
67*843e1988Sjohnlev 
68*843e1988Sjohnlev 	for (vec = 0; vec < nidt; vec++, idt++)
69*843e1988Sjohnlev 		xen_idt_write(idt, vec);
70*843e1988Sjohnlev }
71*843e1988Sjohnlev 
72*843e1988Sjohnlev void
kdi_idt_write(gate_desc_t * gate,uint_t vec)73*843e1988Sjohnlev kdi_idt_write(gate_desc_t *gate, uint_t vec)
74*843e1988Sjohnlev {
75*843e1988Sjohnlev 	gate_desc_t *idt = CPU->cpu_m.mcpu_idt;
76*843e1988Sjohnlev 
77*843e1988Sjohnlev 	/*
78*843e1988Sjohnlev 	 * See kdi_idtr_set().
79*843e1988Sjohnlev 	 */
80*843e1988Sjohnlev 	if (idt != NULL)
81*843e1988Sjohnlev 		idt[vec] = *gate;
82*843e1988Sjohnlev 
83*843e1988Sjohnlev 	xen_idt_write(gate, vec);
84*843e1988Sjohnlev }
85*843e1988Sjohnlev 
86*843e1988Sjohnlev ulong_t
kdi_dreg_get(int reg)87*843e1988Sjohnlev kdi_dreg_get(int reg)
88*843e1988Sjohnlev {
89*843e1988Sjohnlev 	return (__hypercall1(__HYPERVISOR_get_debugreg, (long)reg));
90*843e1988Sjohnlev }
91*843e1988Sjohnlev 
92*843e1988Sjohnlev void
kdi_dreg_set(int reg,ulong_t value)93*843e1988Sjohnlev kdi_dreg_set(int reg, ulong_t value)
94*843e1988Sjohnlev {
95*843e1988Sjohnlev 	(void) __hypercall2(__HYPERVISOR_set_debugreg, (long)reg, value);
96*843e1988Sjohnlev }
97*843e1988Sjohnlev 
98*843e1988Sjohnlev void
kdi_flush_caches(void)99*843e1988Sjohnlev kdi_flush_caches(void)
100*843e1988Sjohnlev {
101*843e1988Sjohnlev }
102*843e1988Sjohnlev 
103*843e1988Sjohnlev /*
104*843e1988Sjohnlev  * To avoid domains sucking up CPU while sitting in kmdb, we make all the slave
105*843e1988Sjohnlev  * CPUs wait for a wake-up evtchn.  The master CPU, meanwhile, sleeps for
106*843e1988Sjohnlev  * console activity.
107*843e1988Sjohnlev  */
108*843e1988Sjohnlev 
109*843e1988Sjohnlev extern void kdi_slave_entry(void);
110*843e1988Sjohnlev 
111*843e1988Sjohnlev void
kdi_stop_slaves(int cpu,int doxc)112*843e1988Sjohnlev kdi_stop_slaves(int cpu, int doxc)
113*843e1988Sjohnlev {
114*843e1988Sjohnlev 	if (doxc)
115*843e1988Sjohnlev 		kdi_xc_others(cpu, kdi_slave_entry);
116*843e1988Sjohnlev 	kdi_slaves_go = 0;
117*843e1988Sjohnlev }
118*843e1988Sjohnlev 
119*843e1988Sjohnlev void
kdi_start_slaves(void)120*843e1988Sjohnlev kdi_start_slaves(void)
121*843e1988Sjohnlev {
122*843e1988Sjohnlev 	int c;
123*843e1988Sjohnlev 
124*843e1988Sjohnlev 	kdi_slaves_go = 1;
125*843e1988Sjohnlev 
126*843e1988Sjohnlev 	for (c = 0; c < NCPU; c++) {
127*843e1988Sjohnlev 		if (cpu[c] == NULL || !(cpu[c]->cpu_flags & CPU_READY))
128*843e1988Sjohnlev 			continue;
129*843e1988Sjohnlev 		ec_try_ipi(XC_CPUPOKE_PIL, c);
130*843e1988Sjohnlev 	}
131*843e1988Sjohnlev }
132*843e1988Sjohnlev 
133*843e1988Sjohnlev /*ARGSUSED*/
134*843e1988Sjohnlev static int
check_slave(void * arg)135*843e1988Sjohnlev check_slave(void *arg)
136*843e1988Sjohnlev {
137*843e1988Sjohnlev 	return (kdi_slaves_go == 1);
138*843e1988Sjohnlev }
139*843e1988Sjohnlev 
140*843e1988Sjohnlev void
kdi_slave_wait(void)141*843e1988Sjohnlev kdi_slave_wait(void)
142*843e1988Sjohnlev {
143*843e1988Sjohnlev 	if (!(cpu[CPU->cpu_id]->cpu_flags & CPU_READY))
144*843e1988Sjohnlev 		return;
145*843e1988Sjohnlev 
146*843e1988Sjohnlev 	ec_wait_on_ipi(XC_CPUPOKE_PIL, check_slave, NULL);
147*843e1988Sjohnlev }
148*843e1988Sjohnlev 
149*843e1988Sjohnlev /*
150*843e1988Sjohnlev  * Caution.
151*843e1988Sjohnlev  * These routines are called -extremely- early, during kmdb initialization.
152*843e1988Sjohnlev  *
153*843e1988Sjohnlev  * Many common kernel functions assume that %gs has been initialized,
154*843e1988Sjohnlev  * and fail horribly if it hasn't.  At this point, the boot code has
155*843e1988Sjohnlev  * reserved a descriptor for us (KMDBGS_SEL) in it's GDT; arrange for it
156*843e1988Sjohnlev  * to point at a dummy cpu_t, temporarily at least.
157*843e1988Sjohnlev  *
158*843e1988Sjohnlev  * Note that kmdb entry relies on the fake cpu_t having zero cpu_idt/cpu_id.
159*843e1988Sjohnlev  */
160*843e1988Sjohnlev 
161*843e1988Sjohnlev 
162*843e1988Sjohnlev void *
boot_kdi_tmpinit(void)163*843e1988Sjohnlev boot_kdi_tmpinit(void)
164*843e1988Sjohnlev {
165*843e1988Sjohnlev 	cpu_t *cpu = kobj_zalloc(sizeof (*cpu), KM_TMP);
166*843e1988Sjohnlev 	user_desc_t *bgdt;
167*843e1988Sjohnlev 	uint64_t gdtpa;
168*843e1988Sjohnlev 	ulong_t ma[1];
169*843e1988Sjohnlev 
170*843e1988Sjohnlev 	cpu->cpu_self = cpu;
171*843e1988Sjohnlev 
172*843e1988Sjohnlev 	/*
173*843e1988Sjohnlev 	 * (Note that we had better switch to a -new- GDT before
174*843e1988Sjohnlev 	 * we discard the KM_TMP mappings, or disaster will ensue.)
175*843e1988Sjohnlev 	 */
176*843e1988Sjohnlev 	bgdt = kobj_zalloc(PAGESIZE, KM_TMP);
177*843e1988Sjohnlev 	ASSERT(((uintptr_t)bgdt & PAGEOFFSET) == 0);
178*843e1988Sjohnlev 
179*843e1988Sjohnlev 	init_boot_gdt(bgdt);
180*843e1988Sjohnlev 
181*843e1988Sjohnlev 	gdtpa = pfn_to_pa(va_to_pfn(bgdt));
182*843e1988Sjohnlev 	ma[0] = (ulong_t)(pa_to_ma(gdtpa) >> PAGESHIFT);
183*843e1988Sjohnlev 	kbm_read_only((uintptr_t)bgdt, gdtpa);
184*843e1988Sjohnlev 	if (HYPERVISOR_set_gdt(ma, PAGESIZE / sizeof (user_desc_t)))
185*843e1988Sjohnlev 		panic("boot_kdi_tmpinit:HYPERVISOR_set_gdt() failed");
186*843e1988Sjohnlev 
187*843e1988Sjohnlev 	load_segment_registers(B64CODE_SEL, 0, 0, B32DATA_SEL);
188*843e1988Sjohnlev 
189*843e1988Sjohnlev 	/*
190*843e1988Sjohnlev 	 * Now point %gsbase to our temp cpu structure.
191*843e1988Sjohnlev 	 */
192*843e1988Sjohnlev 	xen_set_segment_base(SEGBASE_GS_KERNEL, (ulong_t)cpu);
193*843e1988Sjohnlev 	return (0);
194*843e1988Sjohnlev }
195*843e1988Sjohnlev 
196*843e1988Sjohnlev /*ARGSUSED*/
197*843e1988Sjohnlev void
boot_kdi_tmpfini(void * old)198*843e1988Sjohnlev boot_kdi_tmpfini(void *old)
199*843e1988Sjohnlev {
200*843e1988Sjohnlev 	/*
201*843e1988Sjohnlev 	 * This breaks, why do we need it anyway?
202*843e1988Sjohnlev 	 */
203*843e1988Sjohnlev #if 0	/* XXPV */
204*843e1988Sjohnlev 	load_segment_registers(B64CODE_SEL, 0, KMDBGS_SEL, B32DATA_SEL);
205*843e1988Sjohnlev #endif
206*843e1988Sjohnlev }
207