1/*-
2 * Copyright (c) 2001 Jake Burkholder.
3 * All rights reserved.
4 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD$
28 */
29
30#include <sys/param.h>
31
32#include <vm/vm.h>
33
34#include <machine/asi.h>
35#include <machine/cpufunc.h>
36#include <machine/lsu.h>
37#include <machine/watch.h>
38
39#include <ddb/ddb.h>
40#include <ddb/db_access.h>
41#include <ddb/db_sym.h>
42#include <ddb/db_variables.h>
43#include <ddb/db_watch.h>
44
45static void db_watch_print(vm_offset_t wp, int bm);
46
47int
48watch_phys_set_mask(vm_paddr_t pa, u_long mask)
49{
50	u_long lsucr;
51
52	stxa_sync(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3));
53	lsucr = ldxa(0, ASI_LSU_CTL_REG);
54	lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) |
55	    (mask << LSU_PM_SHIFT);
56	stxa_sync(0, ASI_LSU_CTL_REG, lsucr);
57	return (0);
58}
59
60int
61watch_phys_set(vm_paddr_t pa, int sz)
62{
63	u_long off;
64
65	off = (u_long)pa & 7;
66	/* Test for misaligned watch points. */
67	if (off + sz > 8)
68		return (-1);
69	return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off));
70}
71
72vm_paddr_t
73watch_phys_get(int *bm)
74{
75	vm_paddr_t pa;
76	u_long lsucr;
77
78	if (!watch_phys_active())
79		return (0);
80
81	pa = ldxa(AA_DMMU_PWPR, ASI_DMMU);
82	lsucr = ldxa(0, ASI_LSU_CTL_REG);
83	*bm = (lsucr & LSU_PM_MASK) >> LSU_PM_SHIFT;
84
85	return (pa);
86}
87
88void
89watch_phys_clear()
90{
91	stxa_sync(0, ASI_LSU_CTL_REG,
92	    ldxa(0, ASI_LSU_CTL_REG) & ~LSU_PW);
93}
94
95int
96watch_phys_active()
97{
98
99	return (ldxa(0, ASI_LSU_CTL_REG) & LSU_PW);
100}
101
102int
103watch_virt_set_mask(vm_offset_t va, u_long mask)
104{
105	u_long lsucr;
106
107	stxa_sync(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3));
108	lsucr = ldxa(0, ASI_LSU_CTL_REG);
109	lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) |
110	    (mask << LSU_VM_SHIFT);
111	stxa_sync(0, ASI_LSU_CTL_REG, lsucr);
112	return (0);
113}
114
115int
116watch_virt_set(vm_offset_t va, int sz)
117{
118	u_long off;
119
120	off = (u_long)va & 7;
121	/* Test for misaligned watch points. */
122	if (off + sz > 8)
123		return (-1);
124	return (watch_virt_set_mask(va, ((1 << sz) - 1) << off));
125}
126
127vm_offset_t
128watch_virt_get(int *bm)
129{
130	u_long va;
131	u_long lsucr;
132
133	if (!watch_virt_active())
134		return (0);
135
136	va = ldxa(AA_DMMU_VWPR, ASI_DMMU);
137	lsucr = ldxa(0, ASI_LSU_CTL_REG);
138	*bm = (lsucr & LSU_VM_MASK) >> LSU_VM_SHIFT;
139
140	return ((vm_offset_t)va);
141}
142
143void
144watch_virt_clear()
145{
146	stxa_sync(0, ASI_LSU_CTL_REG,
147	    ldxa(0, ASI_LSU_CTL_REG) & ~LSU_VW);
148}
149
150int
151watch_virt_active()
152{
153
154	return (ldxa(0, ASI_LSU_CTL_REG) & LSU_VW);
155}
156
157int
158db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
159{
160	int dummy;
161
162	if (watch_virt_active()) {
163		db_printf("Overwriting previously active watch point at "
164		    "0x%lx\n", watch_virt_get(&dummy));
165	}
166	return (watch_virt_set(addr, size));
167}
168
169int
170db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
171{
172
173	watch_virt_clear();
174	return (0);
175}
176
177void
178db_watch_print(vm_offset_t wp, int bm)
179{
180	int i;
181
182	db_printf("\tat 0x%lx, active bytes: ", (u_long)wp);
183	for (i = 0; i < 8; i++) {
184		if ((bm & (1 << i)) != 0)
185			db_printf("%d ", i);
186	}
187	if (bm == 0)
188		db_printf("none");
189	db_printf("\n");
190}
191
192void
193db_md_list_watchpoints(void)
194{
195	vm_offset_t va;
196	vm_paddr_t pa;
197	int bm;
198
199	db_printf("Physical address watchpoint:\n");
200	if (watch_phys_active()) {
201		pa = watch_phys_get(&bm);
202		db_watch_print(pa, bm);
203	} else
204		db_printf("\tnot active.\n");
205	db_printf("Virtual address watchpoint:\n");
206	if (watch_virt_active()) {
207		va = watch_virt_get(&bm);
208		db_watch_print(va, bm);
209	} else
210		db_printf("\tnot active.\n");
211}
212