1843e198johnlev/*
2843e198johnlev * CDDL HEADER START
3843e198johnlev *
4843e198johnlev * The contents of this file are subject to the terms of the
5843e198johnlev * Common Development and Distribution License (the "License").
6843e198johnlev * You may not use this file except in compliance with the License.
7843e198johnlev *
8843e198johnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e198johnlev * or http://www.opensolaris.org/os/licensing.
10843e198johnlev * See the License for the specific language governing permissions
11843e198johnlev * and limitations under the License.
12843e198johnlev *
13843e198johnlev * When distributing Covered Code, include this CDDL HEADER in each
14843e198johnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e198johnlev * If applicable, add the following below this CDDL HEADER, with the
16843e198johnlev * fields enclosed by brackets "[]" replaced with your own identifying
17843e198johnlev * information: Portions Copyright [yyyy] [name of copyright owner]
18843e198johnlev *
19843e198johnlev * CDDL HEADER END
20843e198johnlev */
21843e198johnlev/*
22843e198johnlev * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23843e198johnlev * Use is subject to license terms.
24843e198johnlev */
250a47c91Robert Mustacchi/*
260a47c91Robert Mustacchi * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
270a47c91Robert Mustacchi */
28843e198johnlev
29843e198johnlev/*
30843e198johnlev * Libkvm Kernel Target Intel component
31843e198johnlev *
32843e198johnlev * This file provides the Intel-dependent portion of the libkvm kernel target.
33843e198johnlev * For more details on the implementation refer to mdb_kvm.c.
34843e198johnlev */
35843e198johnlev
36843e198johnlev#include <mdb/mdb_target_impl.h>
37843e198johnlev#include <mdb/mdb_kreg_impl.h>
38843e198johnlev#include <mdb/mdb_errno.h>
39843e198johnlev#include <mdb/mdb_err.h>
40843e198johnlev#include <mdb/mdb_kvm.h>
41843e198johnlev#include <mdb/mdb_ks.h>
42843e198johnlev#include <mdb/mdb.h>
43843e198johnlev#include <mdb/kvm_isadep.h>
44843e198johnlev
45843e198johnlev#include <sys/cpuvar.h>
46843e198johnlev#include <sys/privmregs.h>
47843e198johnlev
48843e198johnlevint
49843e198johnlevkt_getareg(mdb_tgt_t *t, mdb_tgt_tid_t tid,
50843e198johnlev    const char *rname, mdb_tgt_reg_t *rp)
51843e198johnlev{
52843e198johnlev	const mdb_tgt_regdesc_t *rdp;
53843e198johnlev	kt_data_t *kt = t->t_data;
54843e198johnlev
55843e198johnlev	if (tid != kt->k_tid)
56843e198johnlev		return (set_errno(EMDB_NOREGS));
57843e198johnlev
58843e198johnlev	for (rdp = kt->k_rds; rdp->rd_name != NULL; rdp++) {
59843e198johnlev		if (strcmp(rname, rdp->rd_name) == 0) {
60843e198johnlev			*rp = kt->k_regs->kregs[rdp->rd_num];
610a47c91Robert Mustacchi			if (rdp->rd_flags & MDB_TGT_R_32)
620a47c91Robert Mustacchi				*rp &= 0xffffffffULL;
630a47c91Robert Mustacchi			else if (rdp->rd_flags & MDB_TGT_R_16)
640a47c91Robert Mustacchi				*rp &= 0xffffULL;
650a47c91Robert Mustacchi			else if (rdp->rd_flags & MDB_TGT_R_8H)
660a47c91Robert Mustacchi				*rp = (*rp & 0xff00ULL) >> 8;
670a47c91Robert Mustacchi			else if (rdp->rd_flags & MDB_TGT_R_8L)
680a47c91Robert Mustacchi				*rp &= 0xffULL;
69843e198johnlev			return (0);
70843e198johnlev		}
71843e198johnlev	}
72843e198johnlev
73843e198johnlev	return (set_errno(EMDB_BADREG));
74843e198johnlev}
75843e198johnlev
76843e198johnlevint
77843e198johnlevkt_putareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, const char *rname, mdb_tgt_reg_t r)
78843e198johnlev{
79843e198johnlev	const mdb_tgt_regdesc_t *rdp;
80843e198johnlev	kt_data_t *kt = t->t_data;
81843e198johnlev
82843e198johnlev	if (tid != kt->k_tid)
83843e198johnlev		return (set_errno(EMDB_NOREGS));
84843e198johnlev
85843e198johnlev	for (rdp = kt->k_rds; rdp->rd_name != NULL; rdp++) {
86843e198johnlev		if (strcmp(rname, rdp->rd_name) == 0) {
870a47c91Robert Mustacchi			if (rdp->rd_flags & MDB_TGT_R_32)
880a47c91Robert Mustacchi				r &= 0xffffffffULL;
890a47c91Robert Mustacchi			else if (rdp->rd_flags & MDB_TGT_R_16)
900a47c91Robert Mustacchi				r &= 0xffffULL;
910a47c91Robert Mustacchi			else if (rdp->rd_flags & MDB_TGT_R_8H)
920a47c91Robert Mustacchi				r = (r & 0xffULL) << 8;
930a47c91Robert Mustacchi			else if (rdp->rd_flags & MDB_TGT_R_8L)
940a47c91Robert Mustacchi				r &= 0xffULL;
950a47c91Robert Mustacchi
96843e198johnlev			kt->k_regs->kregs[rdp->rd_num] = (kreg_t)r;
97843e198johnlev			return (0);
98843e198johnlev		}
99843e198johnlev	}
100843e198johnlev
101843e198johnlev	return (set_errno(EMDB_BADREG));
102843e198johnlev}
103843e198johnlev
104843e198johnlevint
105843e198johnlevkt_kvmregs(mdb_tgt_t *t, uint_t cpuid, mdb_tgt_gregset_t *kregs)
106843e198johnlev{
107843e198johnlev	kt_data_t *kt = t->t_data;
108843e198johnlev	privmregs_t mregs;
109843e198johnlev	int ret;
110843e198johnlev
111843e198johnlev	if ((ret = kt->k_kb_ops->kb_getmregs(kt->k_cookie, cpuid, &mregs)) != 0)
112843e198johnlev		return (ret);
113843e198johnlev
114843e198johnlev	kt_regs_to_kregs(&mregs.pm_gregs, kregs);
115843e198johnlev	return (0);
116843e198johnlev}
117843e198johnlev
118843e198johnlevstatic int
119843e198johnlevkt_cpu2cpuid(uintptr_t cpup)
120843e198johnlev{
121843e198johnlev	cpu_t cpu;
122843e198johnlev
123843e198johnlev	if (mdb_vread(&cpu, sizeof (cpu_t), cpup) != sizeof (cpu_t))
124843e198johnlev		return (-1);
125843e198johnlev
126843e198johnlev	return (cpu.cpu_id);
127843e198johnlev}
128843e198johnlev
129843e198johnlevint
130843e198johnlevkt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
131843e198johnlev{
132843e198johnlev	mdb_tgt_t *t = mdb.m_target;
133843e198johnlev	mdb_tgt_gregset_t regs;
134843e198johnlev	intptr_t cpuid = 0;
135843e198johnlev	uint_t verbose = 0;
136843e198johnlev	int i;
137843e198johnlev
138843e198johnlev	if (flags & DCMD_ADDRSPEC) {
139843e198johnlev		if ((cpuid = kt_cpu2cpuid(addr)) < 0) {
140843e198johnlev			(void) set_errno(EMDB_NOMAP);
141843e198johnlev			mdb_warn("failed to find cpuid for cpu at %p", addr);
142843e198johnlev			return (DCMD_ERR);
143843e198johnlev		}
144843e198johnlev		flags &= ~DCMD_ADDRSPEC;
145843e198johnlev	}
146843e198johnlev
147843e198johnlev
148843e198johnlev	i = mdb_getopts(argc, argv,
149843e198johnlev	    'c', MDB_OPT_UINTPTR, &cpuid,
150843e198johnlev	    'v', MDB_OPT_SETBITS, 1, &verbose,
151843e198johnlev	    NULL);
152843e198johnlev
153843e198johnlev	argc -= i;
154843e198johnlev	argv += i;
155843e198johnlev
156843e198johnlev	if (kt_kvmregs(t, cpuid, &regs) != 0) {
157843e198johnlev		mdb_warn("failed to get regs for cpu %d\n", cpuid);
158843e198johnlev		return (DCMD_ERR);
159843e198johnlev	}
160843e198johnlev
161843e198johnlev	/*
162843e198johnlev	 * Tell the stack walker that we have regs.
163843e198johnlev	 */
164843e198johnlev	flags |= DCMD_ADDRSPEC;
165843e198johnlev	addr = regs.kregs[KREG_FP];
166843e198johnlev
167843e198johnlev	if (verbose)
168843e198johnlev		return (kt_stackv(addr, flags, argc, argv));
169843e198johnlev	else
170843e198johnlev		return (kt_stack(addr, flags, argc, argv));
171843e198johnlev}
172843e198johnlev
173843e198johnlev/*ARGSUSED*/
174843e198johnlevint
175843e198johnlevkt_cpuregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
176843e198johnlev{
177843e198johnlev	mdb_tgt_t *t = mdb.m_target;
178843e198johnlev	mdb_tgt_gregset_t regs;
179843e198johnlev	intptr_t cpuid = 0;
180843e198johnlev	int i;
181843e198johnlev
182843e198johnlev	if (flags & DCMD_ADDRSPEC) {
183843e198johnlev		if (argc != 0)
184843e198johnlev			return (DCMD_USAGE);
185843e198johnlev		if ((cpuid = kt_cpu2cpuid(addr)) < 0) {
186843e198johnlev			(void) set_errno(EMDB_NOMAP);
187843e198johnlev			mdb_warn("failed to find cpuid for cpu at %p", addr);
188843e198johnlev			return (DCMD_ERR);
189843e198johnlev		}
190843e198johnlev	}
191843e198johnlev
192843e198johnlev
193843e198johnlev	i = mdb_getopts(argc, argv,
194843e198johnlev	    'c', MDB_OPT_UINTPTR, &cpuid,
195843e198johnlev	    NULL);
196843e198johnlev
197843e198johnlev	argc -= i;
198843e198johnlev	argv += i;
199843e198johnlev
200843e198johnlev	if (argc != 0)
201843e198johnlev		return (DCMD_USAGE);
202843e198johnlev
203843e198johnlev	if (kt_kvmregs(t, cpuid, &regs) != 0) {
204843e198johnlev		mdb_warn("failed to get regs for cpu %d\n", cpuid);
205843e198johnlev		return (DCMD_ERR);
206843e198johnlev	}
207843e198johnlev
208843e198johnlev	return (kt_regs((uintptr_t)&regs, flags, argc, argv));
209843e198johnlev}
210