xtrace.c revision 268200
1/*-
2 * Copyright (c) 2014 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include "opt_ddb.h"
28#include "opt_xtrace.h"
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/10/sys/ia64/ia64/xtrace.c 268200 2014-07-02 23:47:43Z marcel $");
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/ktr.h>
37#include <sys/malloc.h>
38#include <sys/pcpu.h>
39#include <machine/md_var.h>
40#include <machine/pte.h>
41#include <vm/vm.h>
42#include <vm/vm_extern.h>
43#include <vm/vm_kern.h>
44
45#define	XTRACE_LOG2SZ	14	/* 16KB trace buffers */
46
47struct ia64_xtrace_record {
48	uint64_t	ivt;
49	uint64_t	itc;
50	uint64_t	iip;
51	uint64_t	ifa;
52	uint64_t	isr;
53	uint64_t	ipsr;
54	uint64_t	itir;
55	uint64_t	iipa;
56
57	uint64_t	ifs;
58	uint64_t	iim;
59	uint64_t	iha;
60	uint64_t	unat;
61	uint64_t	rsc;
62	uint64_t	bsp;
63	uint64_t	tp;
64	uint64_t	sp;
65};
66
67extern uint32_t ia64_xtrace_enabled;
68extern uint64_t ia64_xtrace_mask;
69
70static uint64_t ia64_xtrace_base;
71
72static void
73ia64_xtrace_init_common(vm_paddr_t pa)
74{
75	uint64_t psr;
76	pt_entry_t pte;
77
78	pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
79	    PTE_PL_KERN | PTE_AR_RW;
80	pte |= pa & PTE_PPN_MASK;
81
82	__asm __volatile("ptr.d %0,%1" :: "r"(ia64_xtrace_base),
83	    "r"(XTRACE_LOG2SZ << 2));
84
85	__asm __volatile("mov   %0=psr" : "=r"(psr));
86	__asm __volatile("rsm   psr.ic|psr.i");
87	ia64_srlz_i();
88
89	ia64_set_ifa(ia64_xtrace_base);
90	ia64_set_itir(XTRACE_LOG2SZ << 2);
91	ia64_srlz_d();
92	__asm __volatile("itr.d dtr[%0]=%1" :: "r"(6), "r"(pte));
93
94	__asm __volatile("mov   psr.l=%0" :: "r" (psr));
95	ia64_srlz_i();
96
97	PCPU_SET(md.xtrace_tail, ia64_xtrace_base);
98	ia64_set_k3(ia64_xtrace_base);
99}
100
101void *
102ia64_xtrace_alloc(void)
103{
104	uintptr_t buf;
105	size_t sz;
106
107	sz = 1UL << XTRACE_LOG2SZ;
108	buf = kmem_alloc_contig(kernel_arena, sz, M_WAITOK | M_ZERO,
109	    0UL, ~0UL, sz, 0, VM_MEMATTR_DEFAULT);
110	return ((void *)buf);
111}
112
113void
114ia64_xtrace_init_ap(void *buf)
115{
116	vm_paddr_t pa;
117
118	if (buf == NULL) {
119		ia64_set_k3(0);
120		return;
121	}
122	PCPU_SET(md.xtrace_buffer, buf);
123	pa = ia64_tpa((uintptr_t)buf);
124	ia64_xtrace_init_common(pa);
125}
126
127void
128ia64_xtrace_init_bsp(void)
129{
130	void *buf;
131	vm_paddr_t pa;
132	size_t sz;
133
134	sz = 1UL << XTRACE_LOG2SZ;
135	ia64_xtrace_base = VM_MIN_KERNEL_ADDRESS + (sz << 1);
136	ia64_xtrace_mask = ~sz;
137
138	buf = ia64_physmem_alloc(sz, sz);
139	if (buf == NULL) {
140		ia64_set_k3(0);
141		return;
142	}
143	PCPU_SET(md.xtrace_buffer, buf);
144	pa = IA64_RR_MASK((uintptr_t)buf);
145	ia64_xtrace_init_common(pa);
146}
147
148static void
149ia64_xtrace_init(void *dummy __unused)
150{
151
152	TUNABLE_INT_FETCH("machdep.xtrace.enabled", &ia64_xtrace_enabled);
153}
154SYSINIT(xtrace, SI_SUB_CPU, SI_ORDER_ANY, ia64_xtrace_init, NULL);
155
156void
157ia64_xtrace_save(void)
158{
159	struct ia64_xtrace_record *rec;
160	uint64_t head, tail;
161
162	critical_enter();
163	head = ia64_get_k3();
164	tail = PCPU_GET(md.xtrace_tail);
165	if (head == 0 || tail == 0) {
166		critical_exit();
167		return;
168	}
169	while (head != tail) {
170		rec = (void *)(uintptr_t)tail;
171		CTR6(KTR_TRAP, "XTRACE: itc=%lu, ticks=%d: "
172		    "IVT=%#lx, IIP=%#lx, IFA=%#lx, ISR=%#lx",
173		    rec->itc, ticks,
174		    rec->ivt, rec->iip, rec->ifa, rec->isr);
175		tail += sizeof(*rec);
176		tail &= ia64_xtrace_mask;
177	}
178	PCPU_SET(md.xtrace_tail, tail);
179	critical_exit();
180}
181
182void
183ia64_xtrace_stop(void)
184{
185	ia64_xtrace_enabled = 0;
186}
187
188#if 0
189#ifdef DDB
190
191#include <ddb/ddb.h>
192
193DB_SHOW_COMMAND(xtrace, db_xtrace)
194{
195        struct ia64_xtrace_record *p, *r;
196
197        p = (ia64_xtptr == 0) ? ia64_xtptr1 : ia64_xtptr;
198        if (p == 0) {
199                db_printf("Exception trace buffer not allocated\n");
200                return;
201        }
202
203        r = (p->ivt == 0) ? ia64_xtbase : p;
204        if (r->ivt == 0) {
205                db_printf("No exception trace records written\n");
206                return;
207        }
208
209        db_printf("IVT\t\t ITC\t\t  IIP\t\t   IFA\n");
210        do {
211                db_printf("%016lx %016lx %016lx %016lx\n",
212                    r->ivt, r->itc, r->iip, r->ifa);
213                r++;
214                if (r == ia64_xtlim)
215                        r = ia64_xtbase;
216        } while (r != p);
217}
218
219#endif /* DDB */
220#endif
221