17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5c7bf320johnlev * Common Development and Distribution License (the "License").
6c7bf320johnlev * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22ae115bcmrj * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
24399ca3aJohn Levon *
25399ca3aJohn Levon * Copyright 2018 Joyent, Inc.
267c478bdstevel@tonic-gate */
277c478bdstevel@tonic-gate
287c478bdstevel@tonic-gate/*
297c478bdstevel@tonic-gate * The debugger/"PROM" interface layer
307c478bdstevel@tonic-gate *
31ae115bcmrj * It makes more sense on SPARC. In reality, these interfaces deal with three
32ae115bcmrj * things: setting break/watchpoints, stepping, and interfacing with the KDI to
33ae115bcmrj * set up kmdb's IDT handlers.
347c478bdstevel@tonic-gate */
357c478bdstevel@tonic-gate
367c478bdstevel@tonic-gate#include <kmdb/kmdb_dpi_impl.h>
377c478bdstevel@tonic-gate#include <kmdb/kmdb_kdi.h>
387c478bdstevel@tonic-gate#include <kmdb/kmdb_umemglue.h>
397c478bdstevel@tonic-gate#include <kmdb/kaif.h>
40c7bf320johnlev#include <kmdb/kmdb_io.h>
41ae115bcmrj#include <kmdb/kaif_start.h>
427c478bdstevel@tonic-gate#include <mdb/mdb_err.h>
437c478bdstevel@tonic-gate#include <mdb/mdb_debug.h>
447c478bdstevel@tonic-gate#include <mdb/mdb_isautil.h>
457c478bdstevel@tonic-gate#include <mdb/mdb_io_impl.h>
46ae115bcmrj#include <mdb/mdb_kreg_impl.h>
477c478bdstevel@tonic-gate#include <mdb/mdb.h>
487c478bdstevel@tonic-gate
497c478bdstevel@tonic-gate#include <sys/types.h>
507c478bdstevel@tonic-gate#include <sys/bitmap.h>
51c7bf320johnlev#include <sys/termios.h>
52ae115bcmrj#include <sys/kdi_impl.h>
5374ecdb5John Levon#include <sys/sysmacros.h>
547c478bdstevel@tonic-gate
55ae115bcmrj/*
56ae115bcmrj * This is the area containing the saved state when we enter
57ae115bcmrj * via kmdb's IDT entries.
58ae115bcmrj */
59ae115bcmrjkdi_cpusave_t	*kaif_cpusave;
607c478bdstevel@tonic-gateint		kaif_ncpusave;
61ae115bcmrjkdi_drreg_t	kaif_drreg;
627c478bdstevel@tonic-gate
637c478bdstevel@tonic-gateuint32_t	kaif_waptmap;
647c478bdstevel@tonic-gate
657c478bdstevel@tonic-gateint		kaif_trap_switch;
667c478bdstevel@tonic-gate
677c478bdstevel@tonic-gatevoid (*kaif_modchg_cb)(struct modctl *, int);
687c478bdstevel@tonic-gate
697c478bdstevel@tonic-gateenum {
707c478bdstevel@tonic-gate	M_SYSRET	= 0x07, /* after M_ESC */
717c478bdstevel@tonic-gate	M_ESC		= 0x0f,
727c478bdstevel@tonic-gate	M_SYSEXIT	= 0x35, /* after M_ESC */
737c478bdstevel@tonic-gate	M_REX_LO	= 0x40, /* first REX prefix */
747c478bdstevel@tonic-gate	M_REX_HI	= 0x4f, /* last REX prefix */
757c478bdstevel@tonic-gate	M_PUSHF		= 0x9c,	/* pushfl and pushfq */
767c478bdstevel@tonic-gate	M_POPF		= 0x9d,	/* popfl and popfq */
777c478bdstevel@tonic-gate	M_INT3		= 0xcc,
787c478bdstevel@tonic-gate	M_INTX		= 0xcd,
797c478bdstevel@tonic-gate	M_INTO		= 0xce,
807c478bdstevel@tonic-gate	M_IRET		= 0xcf,
817c478bdstevel@tonic-gate	M_CLI		= 0xfa,
827c478bdstevel@tonic-gate	M_STI		= 0xfb
837c478bdstevel@tonic-gate};
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate#define	KAIF_BREAKPOINT_INSTR	M_INT3
867c478bdstevel@tonic-gate
877c478bdstevel@tonic-gate#define	KAIF_WPPRIV2ID(wp)	(int)(uintptr_t)((wp)->wp_priv)
887c478bdstevel@tonic-gate
897c478bdstevel@tonic-gate#ifdef __amd64
907c478bdstevel@tonic-gate#define	FLAGS_REG_NAME		"rflags"
917c478bdstevel@tonic-gate#else
927c478bdstevel@tonic-gate#define	FLAGS_REG_NAME		"eflags"
937c478bdstevel@tonic-gate#endif
947c478bdstevel@tonic-gate
957c478bdstevel@tonic-gate/*
967c478bdstevel@tonic-gate * Called during normal debugger operation and during debugger faults.
977c478bdstevel@tonic-gate */
987c478bdstevel@tonic-gatestatic void
997c478bdstevel@tonic-gatekaif_enter_mon(void)
1007c478bdstevel@tonic-gate{
1017c478bdstevel@tonic-gate	char c;
1027c478bdstevel@tonic-gate
1037c478bdstevel@tonic-gate	for (;;) {
1047c478bdstevel@tonic-gate		mdb_iob_printf(mdb.m_out,
1057c478bdstevel@tonic-gate		    "%s: Do you really want to reboot? (y/n) ",
1067c478bdstevel@tonic-gate		    mdb.m_pname);
1077c478bdstevel@tonic-gate		mdb_iob_flush(mdb.m_out);
108c7bf320johnlev		mdb_iob_clearlines(mdb.m_out);
1097c478bdstevel@tonic-gate
110c7bf320johnlev		c = kmdb_getchar();
1117c478bdstevel@tonic-gate
112c7bf320johnlev		if (c == 'n' || c == 'N' || c == CTRL('c'))
1137c478bdstevel@tonic-gate			return;
1147c478bdstevel@tonic-gate		else if (c == 'y' || c == 'Y') {
1157c478bdstevel@tonic-gate			mdb_iob_printf(mdb.m_out, "Rebooting...\n");
1167c478bdstevel@tonic-gate
1177c478bdstevel@tonic-gate			kmdb_dpi_reboot();
1187c478bdstevel@tonic-gate		}
1197c478bdstevel@tonic-gate	}
1207c478bdstevel@tonic-gate}
1217c478bdstevel@tonic-gate
122acbc304johnlevstatic kaif_cpusave_t *
123acbc304johnlevkaif_cpuid2save(int cpuid)
124acbc304johnlev{
125acbc304johnlev	kaif_cpusave_t *save;
126acbc304johnlev
127acbc304johnlev	if (cpuid == DPI_MASTER_CPUID)
128acbc304johnlev		return (&kaif_cpusave[kaif_master_cpuid]);
129acbc304johnlev
130acbc304johnlev	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
131acbc304johnlev		(void) set_errno(EINVAL);
132acbc304johnlev		return (NULL);
133acbc304johnlev	}
134acbc304johnlev
135acbc304johnlev	save = &kaif_cpusave[cpuid];
136acbc304johnlev
137acbc304johnlev	if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER &&
138acbc304johnlev	    save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) {
139acbc304johnlev		(void) set_errno(EINVAL);
140acbc304johnlev		return (NULL);
141acbc304johnlev	}
142acbc304johnlev
143acbc304johnlev	return (save);
144acbc304johnlev}
145acbc304johnlev
1467c478bdstevel@tonic-gatestatic int
1477c478bdstevel@tonic-gatekaif_get_cpu_state(int cpuid)
1487c478bdstevel@tonic-gate{
149acbc304johnlev	kaif_cpusave_t *save;
1507c478bdstevel@tonic-gate
151acbc304johnlev	if ((save = kaif_cpuid2save(cpuid)) == NULL)
152acbc304johnlev		return (-1); /* errno is set for us */
1537c478bdstevel@tonic-gate
154acbc304johnlev	switch (save->krs_cpu_state) {
1557c478bdstevel@tonic-gate	case KAIF_CPU_STATE_MASTER:
1567c478bdstevel@tonic-gate		return (DPI_CPU_STATE_MASTER);
1577c478bdstevel@tonic-gate	case KAIF_CPU_STATE_SLAVE:
1587c478bdstevel@tonic-gate		return (DPI_CPU_STATE_SLAVE);
1597c478bdstevel@tonic-gate	default:
1607c478bdstevel@tonic-gate		return (set_errno(EINVAL));
1617c478bdstevel@tonic-gate	}
1627c478bdstevel@tonic-gate}
1637c478bdstevel@tonic-gate
1647c478bdstevel@tonic-gatestatic int
1657c478bdstevel@tonic-gatekaif_get_master_cpuid(void)
1667c478bdstevel@tonic-gate{
1677c478bdstevel@tonic-gate	return (kaif_master_cpuid);
1687c478bdstevel@tonic-gate}
1697c478bdstevel@tonic-gate
170ae115bcmrjstatic mdb_tgt_gregset_t *
171ae115bcmrjkaif_kdi_to_gregs(int cpuid)
1727c478bdstevel@tonic-gate{
173acbc304johnlev	kaif_cpusave_t *save;
1747c478bdstevel@tonic-gate
175acbc304johnlev	if ((save = kaif_cpuid2save(cpuid)) == NULL)
176acbc304johnlev		return (NULL); /* errno is set for us */
1777c478bdstevel@tonic-gate
178