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