1263323Smarcel/*-
2263323Smarcel * Copyright (c) 2014 Marcel Moolenaar
3263323Smarcel * All rights reserved.
4263323Smarcel *
5263323Smarcel * Redistribution and use in source and binary forms, with or without
6263323Smarcel * modification, are permitted provided that the following conditions
7263323Smarcel * are met:
8263323Smarcel * 1. Redistributions of source code must retain the above copyright
9263323Smarcel *    notice, this list of conditions and the following disclaimer.
10263323Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11263323Smarcel *    notice, this list of conditions and the following disclaimer in the
12263323Smarcel *    documentation and/or other materials provided with the distribution.
13263323Smarcel *
14263323Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15263323Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16263323Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17263323Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18263323Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19263323Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20263323Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21263323Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22263323Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23263323Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24263323Smarcel * SUCH DAMAGE.
25263323Smarcel */
26263323Smarcel
27263323Smarcel#include "opt_ddb.h"
28263323Smarcel#include "opt_xtrace.h"
29263323Smarcel
30263323Smarcel#include <sys/cdefs.h>
31263323Smarcel__FBSDID("$FreeBSD: releng/10.3/sys/ia64/ia64/xtrace.c 271211 2014-09-06 22:17:54Z marcel $");
32263323Smarcel
33263323Smarcel#include <sys/param.h>
34263323Smarcel#include <sys/systm.h>
35263323Smarcel#include <sys/kernel.h>
36263323Smarcel#include <sys/ktr.h>
37263323Smarcel#include <sys/malloc.h>
38263323Smarcel#include <sys/pcpu.h>
39263323Smarcel#include <machine/md_var.h>
40263323Smarcel#include <machine/pte.h>
41263323Smarcel#include <vm/vm.h>
42263323Smarcel#include <vm/vm_extern.h>
43263323Smarcel#include <vm/vm_kern.h>
44263323Smarcel
45263323Smarcel#define	XTRACE_LOG2SZ	14	/* 16KB trace buffers */
46263323Smarcel
47263323Smarcelstruct ia64_xtrace_record {
48263323Smarcel	uint64_t	ivt;
49263323Smarcel	uint64_t	itc;
50263323Smarcel	uint64_t	iip;
51263323Smarcel	uint64_t	ifa;
52263323Smarcel	uint64_t	isr;
53263323Smarcel	uint64_t	ipsr;
54263323Smarcel	uint64_t	itir;
55263323Smarcel	uint64_t	iipa;
56263323Smarcel
57263323Smarcel	uint64_t	ifs;
58263323Smarcel	uint64_t	iim;
59263323Smarcel	uint64_t	iha;
60263323Smarcel	uint64_t	unat;
61263323Smarcel	uint64_t	rsc;
62263323Smarcel	uint64_t	bsp;
63263323Smarcel	uint64_t	tp;
64263323Smarcel	uint64_t	sp;
65263323Smarcel};
66263323Smarcel
67263323Smarcelextern uint32_t ia64_xtrace_enabled;
68263323Smarcelextern uint64_t ia64_xtrace_mask;
69263323Smarcel
70263323Smarcelstatic uint64_t ia64_xtrace_base;
71263323Smarcel
72263323Smarcelstatic void
73263323Smarcelia64_xtrace_init_common(vm_paddr_t pa)
74263323Smarcel{
75263323Smarcel	uint64_t psr;
76263323Smarcel	pt_entry_t pte;
77263323Smarcel
78263323Smarcel	pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
79263323Smarcel	    PTE_PL_KERN | PTE_AR_RW;
80263323Smarcel	pte |= pa & PTE_PPN_MASK;
81263323Smarcel
82263323Smarcel	__asm __volatile("ptr.d %0,%1" :: "r"(ia64_xtrace_base),
83263323Smarcel	    "r"(XTRACE_LOG2SZ << 2));
84263323Smarcel
85263323Smarcel	__asm __volatile("mov   %0=psr" : "=r"(psr));
86263323Smarcel	__asm __volatile("rsm   psr.ic|psr.i");
87263323Smarcel	ia64_srlz_i();
88263323Smarcel
89263323Smarcel	ia64_set_ifa(ia64_xtrace_base);
90263323Smarcel	ia64_set_itir(XTRACE_LOG2SZ << 2);
91263323Smarcel	ia64_srlz_d();
92263323Smarcel	__asm __volatile("itr.d dtr[%0]=%1" :: "r"(6), "r"(pte));
93263323Smarcel
94263323Smarcel	__asm __volatile("mov   psr.l=%0" :: "r" (psr));
95263323Smarcel	ia64_srlz_i();
96263323Smarcel
97271211Smarcel	pcpup->pc_md.xtrace_tail = ia64_xtrace_base;
98263323Smarcel	ia64_set_k3(ia64_xtrace_base);
99263323Smarcel}
100263323Smarcel
101263323Smarcelvoid *
102263323Smarcelia64_xtrace_alloc(void)
103263323Smarcel{
104263323Smarcel	uintptr_t buf;
105263323Smarcel	size_t sz;
106263323Smarcel
107263323Smarcel	sz = 1UL << XTRACE_LOG2SZ;
108263323Smarcel	buf = kmem_alloc_contig(kernel_arena, sz, M_WAITOK | M_ZERO,
109263323Smarcel	    0UL, ~0UL, sz, 0, VM_MEMATTR_DEFAULT);
110263323Smarcel	return ((void *)buf);
111263323Smarcel}
112263323Smarcel
113263323Smarcelvoid
114263323Smarcelia64_xtrace_init_ap(void *buf)
115263323Smarcel{
116263323Smarcel	vm_paddr_t pa;
117263323Smarcel
118263323Smarcel	if (buf == NULL) {
119263323Smarcel		ia64_set_k3(0);
120263323Smarcel		return;
121263323Smarcel	}
122271211Smarcel	pcpup->pc_md.xtrace_buffer = buf;
123263323Smarcel	pa = ia64_tpa((uintptr_t)buf);
124263323Smarcel	ia64_xtrace_init_common(pa);
125263323Smarcel}
126263323Smarcel
127263323Smarcelvoid
128263323Smarcelia64_xtrace_init_bsp(void)
129263323Smarcel{
130263323Smarcel	void *buf;
131263323Smarcel	vm_paddr_t pa;
132263323Smarcel	size_t sz;
133263323Smarcel
134263323Smarcel	sz = 1UL << XTRACE_LOG2SZ;
135263323Smarcel	ia64_xtrace_base = VM_MIN_KERNEL_ADDRESS + (sz << 1);
136263323Smarcel	ia64_xtrace_mask = ~sz;
137263323Smarcel
138263323Smarcel	buf = ia64_physmem_alloc(sz, sz);
139263323Smarcel	if (buf == NULL) {
140263323Smarcel		ia64_set_k3(0);
141263323Smarcel		return;
142263323Smarcel	}
143271211Smarcel	pcpup->pc_md.xtrace_buffer = buf;
144263323Smarcel	pa = IA64_RR_MASK((uintptr_t)buf);
145263323Smarcel	ia64_xtrace_init_common(pa);
146263323Smarcel}
147263323Smarcel
148263323Smarcelstatic void
149263323Smarcelia64_xtrace_init(void *dummy __unused)
150263323Smarcel{
151263323Smarcel
152263323Smarcel	TUNABLE_INT_FETCH("machdep.xtrace.enabled", &ia64_xtrace_enabled);
153263323Smarcel}
154263323SmarcelSYSINIT(xtrace, SI_SUB_CPU, SI_ORDER_ANY, ia64_xtrace_init, NULL);
155263323Smarcel
156263323Smarcelvoid
157263323Smarcelia64_xtrace_save(void)
158263323Smarcel{
159263323Smarcel	struct ia64_xtrace_record *rec;
160263323Smarcel	uint64_t head, tail;
161263323Smarcel
162263323Smarcel	critical_enter();
163263323Smarcel	head = ia64_get_k3();
164263323Smarcel	tail = PCPU_GET(md.xtrace_tail);
165263323Smarcel	if (head == 0 || tail == 0) {
166263323Smarcel		critical_exit();
167263323Smarcel		return;
168263323Smarcel	}
169263323Smarcel	while (head != tail) {
170263323Smarcel		rec = (void *)(uintptr_t)tail;
171263323Smarcel		CTR6(KTR_TRAP, "XTRACE: itc=%lu, ticks=%d: "
172263323Smarcel		    "IVT=%#lx, IIP=%#lx, IFA=%#lx, ISR=%#lx",
173263323Smarcel		    rec->itc, ticks,
174263323Smarcel		    rec->ivt, rec->iip, rec->ifa, rec->isr);
175263323Smarcel		tail += sizeof(*rec);
176263323Smarcel		tail &= ia64_xtrace_mask;
177263323Smarcel	}
178263323Smarcel	PCPU_SET(md.xtrace_tail, tail);
179263323Smarcel	critical_exit();
180263323Smarcel}
181263323Smarcel
182263323Smarcelvoid
183263323Smarcelia64_xtrace_stop(void)
184263323Smarcel{
185263323Smarcel	ia64_xtrace_enabled = 0;
186263323Smarcel}
187263323Smarcel
188263323Smarcel#if 0
189263323Smarcel#ifdef DDB
190263323Smarcel
191263323Smarcel#include <ddb/ddb.h>
192263323Smarcel
193263323SmarcelDB_SHOW_COMMAND(xtrace, db_xtrace)
194263323Smarcel{
195263323Smarcel        struct ia64_xtrace_record *p, *r;
196263323Smarcel
197263323Smarcel        p = (ia64_xtptr == 0) ? ia64_xtptr1 : ia64_xtptr;
198263323Smarcel        if (p == 0) {
199263323Smarcel                db_printf("Exception trace buffer not allocated\n");
200263323Smarcel                return;
201263323Smarcel        }
202263323Smarcel
203263323Smarcel        r = (p->ivt == 0) ? ia64_xtbase : p;
204263323Smarcel        if (r->ivt == 0) {
205263323Smarcel                db_printf("No exception trace records written\n");
206263323Smarcel                return;
207263323Smarcel        }
208263323Smarcel
209263323Smarcel        db_printf("IVT\t\t ITC\t\t  IIP\t\t   IFA\n");
210263323Smarcel        do {
211263323Smarcel                db_printf("%016lx %016lx %016lx %016lx\n",
212263323Smarcel                    r->ivt, r->itc, r->iip, r->ifa);
213263323Smarcel                r++;
214263323Smarcel                if (r == ia64_xtlim)
215263323Smarcel                        r = ia64_xtbase;
216263323Smarcel        } while (r != p);
217263323Smarcel}
218263323Smarcel
219263323Smarcel#endif /* DDB */
220263323Smarcel#endif
221