1294740Szbb/*
2294740Szbb * Copyright (c) 2015 Juniper Networks Inc.
3294740Szbb * All rights reserved.
4294740Szbb *
5294740Szbb * Developed by Semihalf.
6294740Szbb *
7294740Szbb * Redistribution and use in source and binary forms, with or without
8294740Szbb * modification, are permitted provided that the following conditions
9294740Szbb * are met:
10294740Szbb * 1. Redistributions of source code must retain the above copyright
11294740Szbb *    notice, this list of conditions and the following disclaimer.
12294740Szbb * 2. Redistributions in binary form must reproduce the above copyright
13294740Szbb *    notice, this list of conditions and the following disclaimer in the
14294740Szbb *    documentation and/or other materials provided with the distribution.
15294740Szbb *
16294740Szbb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17294740Szbb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18294740Szbb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19294740Szbb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20294740Szbb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21294740Szbb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22294740Szbb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23294740Szbb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24294740Szbb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25294740Szbb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26294740Szbb * SUCH DAMAGE.
27294740Szbb */
28294740Szbb
29294740Szbb#include <sys/cdefs.h>
30294740Szbb__FBSDID("$FreeBSD: stable/11/sys/arm/arm/debug_monitor.c 317976 2017-05-08 20:09:23Z gonzo $");
31294740Szbb
32294740Szbb#include "opt_ddb.h"
33294740Szbb
34294740Szbb#include <sys/param.h>
35294740Szbb#include <sys/types.h>
36294740Szbb#include <sys/kdb.h>
37294740Szbb#include <sys/pcpu.h>
38294987Szbb#include <sys/smp.h>
39294740Szbb#include <sys/systm.h>
40294740Szbb
41294987Szbb#include <machine/atomic.h>
42294740Szbb#include <machine/armreg.h>
43294740Szbb#include <machine/cpu.h>
44294740Szbb#include <machine/debug_monitor.h>
45294740Szbb#include <machine/kdb.h>
46294740Szbb#include <machine/pcb.h>
47294987Szbb#include <machine/reg.h>
48294740Szbb
49294740Szbb#include <ddb/ddb.h>
50294740Szbb#include <ddb/db_access.h>
51294740Szbb#include <ddb/db_sym.h>
52294740Szbb
53294740Szbbenum dbg_t {
54294740Szbb	DBG_TYPE_BREAKPOINT = 0,
55294740Szbb	DBG_TYPE_WATCHPOINT = 1,
56294740Szbb};
57294740Szbb
58294740Szbbstruct dbg_wb_conf {
59294740Szbb	enum dbg_t		type;
60294740Szbb	enum dbg_access_t	access;
61294740Szbb	db_addr_t		address;
62294740Szbb	db_expr_t		size;
63294740Szbb	u_int			slot;
64294740Szbb};
65294740Szbb
66294740Szbbstatic int dbg_reset_state(void);
67294740Szbbstatic int dbg_setup_breakpoint(db_expr_t, db_expr_t, u_int);
68294740Szbbstatic int dbg_remove_breakpoint(u_int);
69294740Szbbstatic u_int dbg_find_slot(enum dbg_t, db_expr_t);
70294740Szbbstatic boolean_t dbg_check_slot_free(enum dbg_t, u_int);
71294740Szbb
72294740Szbbstatic int dbg_remove_xpoint(struct dbg_wb_conf *);
73294740Szbbstatic int dbg_setup_xpoint(struct dbg_wb_conf *);
74294740Szbb
75300969Szbbstatic int dbg_capable_var;	/* Indicates that machine is capable of using
76294740Szbb				   HW watchpoints/breakpoints */
77294740Szbb
78294740Szbbstatic uint32_t dbg_model;	/* Debug Arch. Model */
79294740Szbbstatic boolean_t dbg_ossr;	/* OS Save and Restore implemented */
80294740Szbb
81294740Szbbstatic uint32_t dbg_watchpoint_num;
82294740Szbbstatic uint32_t dbg_breakpoint_num;
83294740Szbb
84294740Szbb/* ID_DFR0 - Debug Feature Register 0 */
85294740Szbb#define	ID_DFR0_CP_DEBUG_M_SHIFT	0
86294740Szbb#define	ID_DFR0_CP_DEBUG_M_MASK		(0xF << ID_DFR0_CP_DEBUG_M_SHIFT)
87294740Szbb#define	ID_DFR0_CP_DEBUG_M_NS		(0x0) /* Not supported */
88294740Szbb#define	ID_DFR0_CP_DEBUG_M_V6		(0x2) /* v6 Debug arch. CP14 access */
89294740Szbb#define	ID_DFR0_CP_DEBUG_M_V6_1		(0x3) /* v6.1 Debug arch. CP14 access */
90294740Szbb#define	ID_DFR0_CP_DEBUG_M_V7		(0x4) /* v7 Debug arch. CP14 access */
91294740Szbb#define	ID_DFR0_CP_DEBUG_M_V7_1		(0x5) /* v7.1 Debug arch. CP14 access */
92294740Szbb
93294740Szbb/* DBGDIDR - Debug ID Register */
94294740Szbb#define	DBGDIDR_WRPS_SHIFT		28
95294740Szbb#define	DBGDIDR_WRPS_MASK		(0xF << DBGDIDR_WRPS_SHIFT)
96294740Szbb#define	DBGDIDR_WRPS_NUM(reg)		\
97294740Szbb    ((((reg) & DBGDIDR_WRPS_MASK) >> DBGDIDR_WRPS_SHIFT) + 1)
98294740Szbb
99294740Szbb#define	DBGDIDR_BRPS_SHIFT		24
100294740Szbb#define	DBGDIDR_BRPS_MASK		(0xF << DBGDIDR_BRPS_SHIFT)
101294740Szbb#define	DBGDIDR_BRPS_NUM(reg)		\
102294740Szbb    ((((reg) & DBGDIDR_BRPS_MASK) >> DBGDIDR_BRPS_SHIFT) + 1)
103294740Szbb
104294740Szbb/* DBGPRSR - Device Powerdown and Reset Status Register */
105294740Szbb#define	DBGPRSR_PU			(1 << 0) /* Powerup status */
106294740Szbb
107294740Szbb/* DBGOSLSR - OS Lock Status Register */
108294740Szbb#define	DBGOSLSR_OSLM0			(1 << 0)
109294740Szbb
110294740Szbb/* DBGOSDLR - OS Double Lock Register */
111294740Szbb#define	DBGPRSR_DLK			(1 << 0) /* OS Double Lock set */
112294740Szbb
113294740Szbb/* DBGDSCR - Debug Status and Control Register */
114294740Szbb#define	DBGSCR_MDBG_EN			(1 << 15) /* Monitor debug-mode enable */
115294740Szbb
116294740Szbb/* DBGWVR - Watchpoint Value Register */
117294740Szbb#define	DBGWVR_ADDR_MASK		(~0x3U)
118294740Szbb
119294740Szbb/* Watchpoints/breakpoints control register bitfields */
120294740Szbb#define	DBG_WB_CTRL_LEN_1		(0x1 << 5)
121294740Szbb#define	DBG_WB_CTRL_LEN_2		(0x3 << 5)
122294740Szbb#define	DBG_WB_CTRL_LEN_4		(0xf << 5)
123294740Szbb#define	DBG_WB_CTRL_LEN_8		(0xff << 5)
124294740Szbb#define	DBG_WB_CTRL_LEN_MASK(x)	((x) & (0xff << 5))
125294740Szbb#define	DBG_WB_CTRL_EXEC		(0x0 << 3)
126294740Szbb#define	DBG_WB_CTRL_LOAD		(0x1 << 3)
127294740Szbb#define	DBG_WB_CTRL_STORE		(0x2 << 3)
128294740Szbb#define	DBG_WB_CTRL_ACCESS_MASK(x)	((x) & (0x3 << 3))
129294740Szbb
130294740Szbb/* Common for breakpoint and watchpoint */
131294740Szbb#define	DBG_WB_CTRL_PL1		(0x1 << 1)
132294740Szbb#define	DBG_WB_CTRL_PL0		(0x2 << 1)
133294740Szbb#define	DBG_WB_CTRL_PLX_MASK(x)	((x) & (0x3 << 1))
134294740Szbb#define	DBG_WB_CTRL_E		(0x1 << 0)
135294740Szbb
136294740Szbb/*
137294740Szbb * Watchpoint/breakpoint helpers
138294740Szbb */
139294740Szbb#define	DBG_BKPT_BT_SLOT	0	/* Slot for branch taken */
140294740Szbb#define	DBG_BKPT_BNT_SLOT	1	/* Slot for branch not taken */
141294740Szbb
142294740Szbb#define	OP2_SHIFT		4
143294740Szbb
144294740Szbb/* Opc2 numbers for coprocessor instructions */
145294740Szbb#define	DBG_WB_BVR	4
146294740Szbb#define	DBG_WB_BCR	5
147294740Szbb#define	DBG_WB_WVR	6
148294740Szbb#define	DBG_WB_WCR	7
149294740Szbb
150294740Szbb#define	DBG_REG_BASE_BVR	(DBG_WB_BVR << OP2_SHIFT)
151294740Szbb#define	DBG_REG_BASE_BCR	(DBG_WB_BCR << OP2_SHIFT)
152294740Szbb#define	DBG_REG_BASE_WVR	(DBG_WB_WVR << OP2_SHIFT)
153294740Szbb#define	DBG_REG_BASE_WCR	(DBG_WB_WCR << OP2_SHIFT)
154294740Szbb
155294740Szbb#define	DBG_WB_READ(cn, cm, op2, val) do {					\
156294740Szbb	__asm __volatile("mrc p14, 0, %0, " #cn "," #cm "," #op2 : "=r" (val));	\
157294740Szbb} while (0)
158294740Szbb
159294740Szbb#define	DBG_WB_WRITE(cn, cm, op2, val) do {					\
160294740Szbb	__asm __volatile("mcr p14, 0, %0, " #cn "," #cm "," #op2 :: "r" (val));	\
161294740Szbb} while (0)
162294740Szbb
163294740Szbb#define	READ_WB_REG_CASE(op2, m, val)			\
164294740Szbb	case (((op2) << OP2_SHIFT) + m):		\
165294740Szbb		DBG_WB_READ(c0, c ## m, op2, val);	\
166294740Szbb		break
167294740Szbb
168294740Szbb#define	WRITE_WB_REG_CASE(op2, m, val)			\
169294740Szbb	case (((op2) << OP2_SHIFT) + m):		\
170294740Szbb		DBG_WB_WRITE(c0, c ## m, op2, val);	\
171294740Szbb		break
172294740Szbb
173294740Szbb#define	SWITCH_CASES_READ_WB_REG(op2, val)	\
174294740Szbb	READ_WB_REG_CASE(op2,  0, val);		\
175294740Szbb	READ_WB_REG_CASE(op2,  1, val);		\
176294740Szbb	READ_WB_REG_CASE(op2,  2, val);		\
177294740Szbb	READ_WB_REG_CASE(op2,  3, val);		\
178294740Szbb	READ_WB_REG_CASE(op2,  4, val);		\
179294740Szbb	READ_WB_REG_CASE(op2,  5, val);		\
180294740Szbb	READ_WB_REG_CASE(op2,  6, val);		\
181294740Szbb	READ_WB_REG_CASE(op2,  7, val);		\
182294740Szbb	READ_WB_REG_CASE(op2,  8, val);		\
183294740Szbb	READ_WB_REG_CASE(op2,  9, val);		\
184294740Szbb	READ_WB_REG_CASE(op2, 10, val);		\
185294740Szbb	READ_WB_REG_CASE(op2, 11, val);		\
186294740Szbb	READ_WB_REG_CASE(op2, 12, val);		\
187294740Szbb	READ_WB_REG_CASE(op2, 13, val);		\
188294740Szbb	READ_WB_REG_CASE(op2, 14, val);		\
189294740Szbb	READ_WB_REG_CASE(op2, 15, val)
190294740Szbb
191294740Szbb#define	SWITCH_CASES_WRITE_WB_REG(op2, val)	\
192294740Szbb	WRITE_WB_REG_CASE(op2,  0, val);	\
193294740Szbb	WRITE_WB_REG_CASE(op2,  1, val);	\
194294740Szbb	WRITE_WB_REG_CASE(op2,  2, val);	\
195294740Szbb	WRITE_WB_REG_CASE(op2,  3, val);	\
196294740Szbb	WRITE_WB_REG_CASE(op2,  4, val);	\
197294740Szbb	WRITE_WB_REG_CASE(op2,  5, val);	\
198294740Szbb	WRITE_WB_REG_CASE(op2,  6, val);	\
199294740Szbb	WRITE_WB_REG_CASE(op2,  7, val);	\
200294740Szbb	WRITE_WB_REG_CASE(op2,  8, val);	\
201294740Szbb	WRITE_WB_REG_CASE(op2,  9, val);	\
202294740Szbb	WRITE_WB_REG_CASE(op2, 10, val);	\
203294740Szbb	WRITE_WB_REG_CASE(op2, 11, val);	\
204294740Szbb	WRITE_WB_REG_CASE(op2, 12, val);	\
205294740Szbb	WRITE_WB_REG_CASE(op2, 13, val);	\
206294740Szbb	WRITE_WB_REG_CASE(op2, 14, val);	\
207294740Szbb	WRITE_WB_REG_CASE(op2, 15, val)
208294740Szbb
209294740Szbbstatic uint32_t
210294740Szbbdbg_wb_read_reg(int reg, int n)
211294740Szbb{
212294740Szbb	uint32_t val;
213294740Szbb
214294740Szbb	val = 0;
215294740Szbb
216294740Szbb	switch (reg + n) {
217294740Szbb	SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, val);
218294740Szbb	SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, val);
219294740Szbb	SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, val);
220294740Szbb	SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, val);
221294740Szbb	default:
222294740Szbb		db_printf(
223294740Szbb		    "trying to read from CP14 reg. using wrong opc2 %d\n",
224294740Szbb		    reg >> OP2_SHIFT);
225294740Szbb	}
226294740Szbb
227294740Szbb	return (val);
228294740Szbb}
229294740Szbb
230294740Szbbstatic void
231294740Szbbdbg_wb_write_reg(int reg, int n, uint32_t val)
232294740Szbb{
233294740Szbb
234294740Szbb	switch (reg + n) {
235294740Szbb	SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, val);
236294740Szbb	SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, val);
237294740Szbb	SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, val);
238294740Szbb	SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, val);
239294740Szbb	default:
240294740Szbb		db_printf(
241294740Szbb		    "trying to write to CP14 reg. using wrong opc2 %d\n",
242294740Szbb		    reg >> OP2_SHIFT);
243294740Szbb	}
244294740Szbb	isb();
245294740Szbb}
246294740Szbb
247300969Szbbstatic __inline boolean_t
248300969Szbbdbg_capable(void)
249300969Szbb{
250300969Szbb
251300969Szbb	return (atomic_cmpset_int(&dbg_capable_var, 0, 0) == 0);
252300969Szbb}
253300969Szbb
254294740Szbbboolean_t
255294740Szbbkdb_cpu_pc_is_singlestep(db_addr_t pc)
256294740Szbb{
257300968Szbb	/*
258300968Szbb	 * XXX: If the platform fails to enable its debug arch.
259300968Szbb	 *      there will be no stepping capabilities
260300968Szbb	 *      (SOFTWARE_SSTEP is not defined for __ARM_ARCH >= 6).
261300968Szbb	 */
262300969Szbb	if (!dbg_capable())
263300968Szbb		return (FALSE);
264294740Szbb
265294740Szbb	if (dbg_find_slot(DBG_TYPE_BREAKPOINT, pc) != ~0U)
266294740Szbb		return (TRUE);
267294740Szbb
268294740Szbb	return (FALSE);
269294740Szbb}
270294740Szbb
271294740Szbbvoid
272294740Szbbkdb_cpu_set_singlestep(void)
273294740Szbb{
274294740Szbb	db_expr_t inst;
275294740Szbb	db_addr_t pc, brpc;
276294740Szbb	uint32_t wcr;
277294740Szbb	u_int i;
278294740Szbb
279300969Szbb	if (!dbg_capable())
280300968Szbb		return;
281300968Szbb
282294740Szbb	/*
283294740Szbb	 * Disable watchpoints, e.g. stepping over watched instruction will
284294740Szbb	 * trigger break exception instead of single-step exception and locks
285294740Szbb	 * CPU on that instruction for ever.
286294740Szbb	 */
287294740Szbb	for (i = 0; i < dbg_watchpoint_num; i++) {
288294740Szbb		wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
289294740Szbb		if ((wcr & DBG_WB_CTRL_E) != 0) {
290294740Szbb			dbg_wb_write_reg(DBG_REG_BASE_WCR, i,
291294740Szbb			    (wcr & ~DBG_WB_CTRL_E));
292294740Szbb		}
293294740Szbb	}
294294740Szbb
295294740Szbb	pc = PC_REGS();
296294740Szbb
297294740Szbb	inst = db_get_value(pc, sizeof(pc), FALSE);
298294740Szbb	if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
299294740Szbb		brpc = branch_taken(inst, pc);
300294740Szbb		dbg_setup_breakpoint(brpc, INSN_SIZE, DBG_BKPT_BT_SLOT);
301294740Szbb	}
302294740Szbb	pc = next_instr_address(pc, 0);
303294740Szbb	dbg_setup_breakpoint(pc, INSN_SIZE, DBG_BKPT_BNT_SLOT);
304294740Szbb}
305294740Szbb
306294740Szbbvoid
307294740Szbbkdb_cpu_clear_singlestep(void)
308294740Szbb{
309294740Szbb	uint32_t wvr, wcr;
310294740Szbb	u_int i;
311294740Szbb
312300969Szbb	if (!dbg_capable())
313300968Szbb		return;
314300968Szbb
315294740Szbb	dbg_remove_breakpoint(DBG_BKPT_BT_SLOT);
316294740Szbb	dbg_remove_breakpoint(DBG_BKPT_BNT_SLOT);
317294740Szbb
318294740Szbb	/* Restore all watchpoints */
319294740Szbb	for (i = 0; i < dbg_watchpoint_num; i++) {
320294740Szbb		wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
321294740Szbb		wvr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i);
322294740Szbb		/* Watchpoint considered not empty if address value is not 0 */
323294740Szbb		if ((wvr & DBGWVR_ADDR_MASK) != 0) {
324294740Szbb			dbg_wb_write_reg(DBG_REG_BASE_WCR, i,
325294740Szbb			    (wcr | DBG_WB_CTRL_E));
326294740Szbb		}
327294740Szbb	}
328294740Szbb}
329294740Szbb
330294740Szbbint
331294740Szbbdbg_setup_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_access_t access)
332294740Szbb{
333294740Szbb	struct dbg_wb_conf conf;
334294740Szbb
335294740Szbb	if (access == HW_BREAKPOINT_X) {
336294740Szbb		db_printf("Invalid access type for watchpoint: %d\n", access);
337294740Szbb		return (EINVAL);
338294740Szbb	}
339294740Szbb
340294740Szbb	conf.address = addr;
341294740Szbb	conf.size = size;
342294740Szbb	conf.access = access;
343294740Szbb	conf.type = DBG_TYPE_WATCHPOINT;
344294740Szbb
345294740Szbb	return (dbg_setup_xpoint(&conf));
346294740Szbb}
347294740Szbb
348294740Szbbint
349294740Szbbdbg_remove_watchpoint(db_expr_t addr, db_expr_t size __unused)
350294740Szbb{
351294740Szbb	struct dbg_wb_conf conf;
352294740Szbb
353294740Szbb	conf.address = addr;
354294740Szbb	conf.type = DBG_TYPE_WATCHPOINT;
355294740Szbb
356294740Szbb	return (dbg_remove_xpoint(&conf));
357294740Szbb}
358294740Szbb
359294740Szbbstatic int
360294740Szbbdbg_setup_breakpoint(db_expr_t addr, db_expr_t size, u_int slot)
361294740Szbb{
362294740Szbb	struct dbg_wb_conf conf;
363294740Szbb
364294740Szbb	conf.address = addr;
365294740Szbb	conf.size = size;
366294740Szbb	conf.access = HW_BREAKPOINT_X;
367294740Szbb	conf.type = DBG_TYPE_BREAKPOINT;
368294740Szbb	conf.slot = slot;
369294740Szbb
370294740Szbb	return (dbg_setup_xpoint(&conf));
371294740Szbb}
372294740Szbb
373294740Szbbstatic int
374294740Szbbdbg_remove_breakpoint(u_int slot)
375294740Szbb{
376294740Szbb	struct dbg_wb_conf conf;
377294740Szbb
378294740Szbb	/* Slot already cleared. Don't recurse */
379294740Szbb	if (dbg_check_slot_free(DBG_TYPE_BREAKPOINT, slot))
380294740Szbb		return (0);
381294740Szbb
382294740Szbb	conf.slot = slot;
383294740Szbb	conf.type = DBG_TYPE_BREAKPOINT;
384294740Szbb
385294740Szbb	return (dbg_remove_xpoint(&conf));
386294740Szbb}
387294740Szbb
388294740Szbbstatic const char *
389294740Szbbdbg_watchtype_str(uint32_t type)
390294740Szbb{
391294740Szbb
392294740Szbb	switch (type) {
393294740Szbb		case DBG_WB_CTRL_EXEC:
394294740Szbb			return ("execute");
395294740Szbb		case DBG_WB_CTRL_STORE:
396294740Szbb			return ("write");
397294740Szbb		case DBG_WB_CTRL_LOAD:
398294740Szbb			return ("read");
399294740Szbb		case DBG_WB_CTRL_LOAD | DBG_WB_CTRL_STORE:
400294740Szbb			return ("read/write");
401294740Szbb		default:
402294740Szbb			return ("invalid");
403294740Szbb	}
404294740Szbb}
405294740Szbb
406294740Szbbstatic int
407294740Szbbdbg_watchtype_len(uint32_t len)
408294740Szbb{
409294740Szbb
410294740Szbb	switch (len) {
411294740Szbb	case DBG_WB_CTRL_LEN_1:
412294740Szbb		return (1);
413294740Szbb	case DBG_WB_CTRL_LEN_2:
414294740Szbb		return (2);
415294740Szbb	case DBG_WB_CTRL_LEN_4:
416294740Szbb		return (4);
417294740Szbb	case DBG_WB_CTRL_LEN_8:
418294740Szbb		return (8);
419294740Szbb	default:
420294740Szbb		return (0);
421294740Szbb	}
422294740Szbb}
423294740Szbb
424294740Szbbvoid
425294740Szbbdbg_show_watchpoint(void)
426294740Szbb{
427294740Szbb	uint32_t wcr, len, type;
428294740Szbb	uint32_t addr;
429294740Szbb	boolean_t is_enabled;
430294740Szbb	int i;
431294740Szbb
432300969Szbb	if (!dbg_capable()) {
433294740Szbb		db_printf("Architecture does not support HW "
434294740Szbb		    "breakpoints/watchpoints\n");
435294740Szbb		return;
436294740Szbb	}
437294740Szbb
438294740Szbb	db_printf("\nhardware watchpoints:\n");
439294740Szbb	db_printf("  watch    status        type  len     address              symbol\n");
440294740Szbb	db_printf("  -----  --------  ----------  ---  ----------  ------------------\n");
441294740Szbb	for (i = 0; i < dbg_watchpoint_num; i++) {
442294740Szbb		wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
443294740Szbb		if ((wcr & DBG_WB_CTRL_E) != 0)
444294740Szbb			is_enabled = TRUE;
445294740Szbb		else
446294740Szbb			is_enabled = FALSE;
447294740Szbb
448294740Szbb		type = DBG_WB_CTRL_ACCESS_MASK(wcr);
449294740Szbb		len = DBG_WB_CTRL_LEN_MASK(wcr);
450294740Szbb		addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i) & DBGWVR_ADDR_MASK;
451294740Szbb		db_printf("  %-5d  %-8s  %10s  %3d  0x%08x  ", i,
452294740Szbb		    is_enabled ? "enabled" : "disabled",
453294740Szbb		    is_enabled ? dbg_watchtype_str(type) : "",
454294740Szbb		    is_enabled ? dbg_watchtype_len(len) : 0,
455294740Szbb		    addr);
456294740Szbb		db_printsym((db_addr_t)addr, DB_STGY_ANY);
457294740Szbb		db_printf("\n");
458294740Szbb	}
459294740Szbb}
460294740Szbb
461294740Szbbstatic boolean_t
462294740Szbbdbg_check_slot_free(enum dbg_t type, u_int slot)
463294740Szbb{
464294740Szbb	uint32_t cr, vr;
465294740Szbb	uint32_t max;
466294740Szbb
467294740Szbb	switch(type) {
468294740Szbb	case DBG_TYPE_BREAKPOINT:
469294740Szbb		max = dbg_breakpoint_num;
470294740Szbb		cr = DBG_REG_BASE_BCR;
471294740Szbb		vr = DBG_REG_BASE_BVR;
472294740Szbb		break;
473294740Szbb	case DBG_TYPE_WATCHPOINT:
474294740Szbb		max = dbg_watchpoint_num;
475294740Szbb		cr = DBG_REG_BASE_WCR;
476294740Szbb		vr = DBG_REG_BASE_WVR;
477294740Szbb		break;
478294740Szbb	default:
479294740Szbb		db_printf("%s: Unsupported event type %d\n", __func__, type);
480294740Szbb		return (FALSE);
481294740Szbb	}
482294740Szbb
483294740Szbb	if (slot >= max) {
484294740Szbb		db_printf("%s: Invalid slot number %d, max %d\n",
485294740Szbb		    __func__, slot, max - 1);
486294740Szbb		return (FALSE);
487294740Szbb	}
488294740Szbb
489294740Szbb	if ((dbg_wb_read_reg(cr, slot) & DBG_WB_CTRL_E) == 0 &&
490294740Szbb	    (dbg_wb_read_reg(vr, slot) & DBGWVR_ADDR_MASK) == 0)
491294740Szbb		return (TRUE);
492294740Szbb
493294740Szbb	return (FALSE);
494294740Szbb}
495294740Szbb
496294740Szbbstatic u_int
497294740Szbbdbg_find_free_slot(enum dbg_t type)
498294740Szbb{
499294740Szbb	u_int max, i;
500294740Szbb
501294740Szbb	switch(type) {
502294740Szbb	case DBG_TYPE_BREAKPOINT:
503294740Szbb		max = dbg_breakpoint_num;
504294740Szbb		break;
505294740Szbb	case DBG_TYPE_WATCHPOINT:
506294740Szbb		max = dbg_watchpoint_num;
507294740Szbb		break;
508294740Szbb	default:
509294740Szbb		db_printf("Unsupported debug type\n");
510294740Szbb		return (~0U);
511294740Szbb	}
512294740Szbb
513294740Szbb	for (i = 0; i < max; i++) {
514294740Szbb		if (dbg_check_slot_free(type, i))
515294740Szbb			return (i);
516294740Szbb	}
517294740Szbb
518294740Szbb	return (~0U);
519294740Szbb}
520294740Szbb
521294740Szbbstatic u_int
522294740Szbbdbg_find_slot(enum dbg_t type, db_expr_t addr)
523294740Szbb{
524294740Szbb	uint32_t reg_addr, reg_ctrl;
525294740Szbb	u_int max, i;
526294740Szbb
527294740Szbb	switch(type) {
528294740Szbb	case DBG_TYPE_BREAKPOINT:
529294740Szbb		max = dbg_breakpoint_num;
530294740Szbb		reg_addr = DBG_REG_BASE_BVR;
531294740Szbb		reg_ctrl = DBG_REG_BASE_BCR;
532294740Szbb		break;
533294740Szbb	case DBG_TYPE_WATCHPOINT:
534294740Szbb		max = dbg_watchpoint_num;
535294740Szbb		reg_addr = DBG_REG_BASE_WVR;
536294740Szbb		reg_ctrl = DBG_REG_BASE_WCR;
537294740Szbb		break;
538294740Szbb	default:
539294740Szbb		db_printf("Unsupported debug type\n");
540294740Szbb		return (~0U);
541294740Szbb	}
542294740Szbb
543294740Szbb	for (i = 0; i < max; i++) {
544294740Szbb		if ((dbg_wb_read_reg(reg_addr, i) == addr) &&
545294740Szbb		    ((dbg_wb_read_reg(reg_ctrl, i) & DBG_WB_CTRL_E) != 0))
546294740Szbb			return (i);
547294740Szbb	}
548294740Szbb
549294740Szbb	return (~0U);
550294740Szbb}
551294740Szbb
552294740Szbbstatic __inline boolean_t
553294740Szbbdbg_monitor_is_enabled(void)
554294740Szbb{
555294740Szbb
556294740Szbb	return ((cp14_dbgdscrint_get() & DBGSCR_MDBG_EN) != 0);
557294740Szbb}
558294740Szbb
559294740Szbbstatic int
560294740Szbbdbg_enable_monitor(void)
561294740Szbb{
562294740Szbb	uint32_t dbg_dscr;
563294740Szbb
564294987Szbb	/* Already enabled? Just return */
565294987Szbb	if (dbg_monitor_is_enabled())
566294740Szbb		return (0);
567294740Szbb
568294740Szbb	dbg_dscr = cp14_dbgdscrint_get();
569294740Szbb
570294740Szbb	switch (dbg_model) {
571294740Szbb	case ID_DFR0_CP_DEBUG_M_V6:
572294740Szbb	case ID_DFR0_CP_DEBUG_M_V6_1: /* fall through */
573294740Szbb		cp14_dbgdscr_v6_set(dbg_dscr | DBGSCR_MDBG_EN);
574294740Szbb		break;
575294740Szbb	case ID_DFR0_CP_DEBUG_M_V7: /* fall through */
576294740Szbb	case ID_DFR0_CP_DEBUG_M_V7_1:
577294740Szbb		cp14_dbgdscr_v7_set(dbg_dscr | DBGSCR_MDBG_EN);
578294740Szbb		break;
579294740Szbb	default:
580294740Szbb		break;
581294740Szbb	}
582294740Szbb	isb();
583294740Szbb
584294740Szbb	/* Verify that Monitor mode is set */
585294987Szbb	if (dbg_monitor_is_enabled())
586294740Szbb		return (0);
587294740Szbb
588294740Szbb	return (ENXIO);
589294740Szbb}
590294740Szbb
591294740Szbbstatic int
592294740Szbbdbg_setup_xpoint(struct dbg_wb_conf *conf)
593294740Szbb{
594294987Szbb	struct pcpu *pcpu;
595294987Szbb	struct dbreg *d;
596294740Szbb	const char *typestr;
597294740Szbb	uint32_t cr_size, cr_priv, cr_access;
598294740Szbb	uint32_t reg_ctrl, reg_addr, ctrl, addr;
599294740Szbb	boolean_t is_bkpt;
600300969Szbb	u_int cpu;
601294740Szbb	u_int i;
602294740Szbb
603300969Szbb	if (!dbg_capable())
604294740Szbb		return (ENXIO);
605294740Szbb
606294740Szbb	is_bkpt = (conf->type == DBG_TYPE_BREAKPOINT);
607294740Szbb	typestr = is_bkpt ? "breakpoint" : "watchpoint";
608294740Szbb
609294740Szbb	if (is_bkpt) {
610294740Szbb		if (dbg_breakpoint_num == 0) {
611294740Szbb			db_printf("Breakpoints not supported on this architecture\n");
612294740Szbb			return (ENXIO);
613294740Szbb		}
614294740Szbb		i = conf->slot;
615294740Szbb		if (!dbg_check_slot_free(DBG_TYPE_BREAKPOINT, i)) {
616294740Szbb			/*
617294740Szbb			 * This should never happen. If it does it means that
618294740Szbb			 * there is an erroneus scenario somewhere. Still, it can
619294740Szbb			 * be done but let's inform the user.
620294740Szbb			 */
621294740Szbb			db_printf("ERROR: Breakpoint already set. Replacing...\n");
622294740Szbb		}
623294740Szbb	} else {
624294740Szbb		i = dbg_find_free_slot(DBG_TYPE_WATCHPOINT);
625294740Szbb		if (i == ~0U) {
626294740Szbb			db_printf("Can not find slot for %s, max %d slots supported\n",
627294740Szbb			    typestr, dbg_watchpoint_num);
628294740Szbb			return (ENXIO);
629294740Szbb		}
630294740Szbb	}
631294740Szbb
632294740Szbb	/* Kernel access only */
633294740Szbb	cr_priv = DBG_WB_CTRL_PL1;
634294740Szbb
635294740Szbb	switch(conf->size) {
636294740Szbb	case 1:
637294740Szbb		cr_size = DBG_WB_CTRL_LEN_1;
638294740Szbb		break;
639294740Szbb	case 2:
640294740Szbb		cr_size = DBG_WB_CTRL_LEN_2;
641294740Szbb		break;
642294740Szbb	case 4:
643294740Szbb		cr_size = DBG_WB_CTRL_LEN_4;
644294740Szbb		break;
645294740Szbb	case 8:
646294740Szbb		cr_size = DBG_WB_CTRL_LEN_8;
647294740Szbb		break;
648294740Szbb	default:
649294740Szbb		db_printf("Unsupported address size for %s\n", typestr);
650294740Szbb		return (EINVAL);
651294740Szbb	}
652294740Szbb
653294740Szbb	if (is_bkpt) {
654294740Szbb		cr_access = DBG_WB_CTRL_EXEC;
655294740Szbb		reg_ctrl = DBG_REG_BASE_BCR;
656294740Szbb		reg_addr = DBG_REG_BASE_BVR;
657294740Szbb		/* Always unlinked BKPT */
658294740Szbb		ctrl = (cr_size | cr_access | cr_priv | DBG_WB_CTRL_E);
659294740Szbb	} else {
660294740Szbb		switch(conf->access) {
661294740Szbb		case HW_WATCHPOINT_R:
662294740Szbb			cr_access = DBG_WB_CTRL_LOAD;
663294740Szbb			break;
664294740Szbb		case HW_WATCHPOINT_W:
665294740Szbb			cr_access = DBG_WB_CTRL_STORE;
666294740Szbb			break;
667294740Szbb		case HW_WATCHPOINT_RW:
668294740Szbb			cr_access = DBG_WB_CTRL_LOAD | DBG_WB_CTRL_STORE;
669294740Szbb			break;
670294740Szbb		default:
671294740Szbb			db_printf("Unsupported exception level for %s\n", typestr);
672294740Szbb			return (EINVAL);
673294740Szbb		}
674294740Szbb
675294740Szbb		reg_ctrl = DBG_REG_BASE_WCR;
676294740Szbb		reg_addr = DBG_REG_BASE_WVR;
677294740Szbb		ctrl = (cr_size | cr_access | cr_priv | DBG_WB_CTRL_E);
678294740Szbb	}
679294740Szbb
680294740Szbb	addr = conf->address;
681294740Szbb
682294740Szbb	dbg_wb_write_reg(reg_addr, i, addr);
683294740Szbb	dbg_wb_write_reg(reg_ctrl, i, ctrl);
684294740Szbb
685294987Szbb	/*
686294987Szbb	 * Save watchpoint settings for all CPUs.
687294987Szbb	 * We don't need to do the same with breakpoints since HW breakpoints
688294987Szbb	 * are only used to perform single stepping.
689294987Szbb	 */
690294987Szbb	if (!is_bkpt) {
691294987Szbb		CPU_FOREACH(cpu) {
692294987Szbb			pcpu = pcpu_find(cpu);
693294987Szbb			/* Fill out the settings for watchpoint */
694294987Szbb			d = (struct dbreg *)pcpu->pc_dbreg;
695294987Szbb			d->dbg_wvr[i] = addr;
696294987Szbb			d->dbg_wcr[i] = ctrl;
697294987Szbb			/* Skip update command for the current CPU */
698300969Szbb			if (cpu != PCPU_GET(cpuid))
699294987Szbb				pcpu->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
700294987Szbb		}
701294987Szbb	}
702294987Szbb	/* Ensure all data is written before waking other CPUs */
703294987Szbb	atomic_thread_fence_rel();
704294987Szbb
705294987Szbb	return (0);
706294740Szbb}
707294740Szbb
708294740Szbbstatic int
709294740Szbbdbg_remove_xpoint(struct dbg_wb_conf *conf)
710294740Szbb{
711294987Szbb	struct pcpu *pcpu;
712294987Szbb	struct dbreg *d;
713294740Szbb	uint32_t reg_ctrl, reg_addr, addr;
714294987Szbb	boolean_t is_bkpt;
715300969Szbb	u_int cpu;
716294740Szbb	u_int i;
717294740Szbb
718300969Szbb	if (!dbg_capable())
719294740Szbb		return (ENXIO);
720294740Szbb
721294987Szbb	is_bkpt = (conf->type == DBG_TYPE_BREAKPOINT);
722294740Szbb	addr = conf->address;
723294740Szbb
724294987Szbb	if (is_bkpt) {
725294740Szbb		i = conf->slot;
726294740Szbb		reg_ctrl = DBG_REG_BASE_BCR;
727294740Szbb		reg_addr = DBG_REG_BASE_BVR;
728294740Szbb	} else {
729294740Szbb		i = dbg_find_slot(DBG_TYPE_WATCHPOINT, addr);
730294740Szbb		if (i == ~0U) {
731294740Szbb			db_printf("Can not find watchpoint for address 0%x\n", addr);
732294740Szbb			return (EINVAL);
733294740Szbb		}
734294740Szbb		reg_ctrl = DBG_REG_BASE_WCR;
735294740Szbb		reg_addr = DBG_REG_BASE_WVR;
736294740Szbb	}
737294740Szbb
738294740Szbb	dbg_wb_write_reg(reg_ctrl, i, 0);
739294740Szbb	dbg_wb_write_reg(reg_addr, i, 0);
740294740Szbb
741294987Szbb	/*
742294987Szbb	 * Save watchpoint settings for all CPUs.
743294987Szbb	 * We don't need to do the same with breakpoints since HW breakpoints
744294987Szbb	 * are only used to perform single stepping.
745294987Szbb	 */
746294987Szbb	if (!is_bkpt) {
747294987Szbb		CPU_FOREACH(cpu) {
748294987Szbb			pcpu = pcpu_find(cpu);
749294987Szbb			/* Fill out the settings for watchpoint */
750294987Szbb			d = (struct dbreg *)pcpu->pc_dbreg;
751294987Szbb			d->dbg_wvr[i] = 0;
752294987Szbb			d->dbg_wcr[i] = 0;
753294987Szbb			/* Skip update command for the current CPU */
754300969Szbb			if (cpu != PCPU_GET(cpuid))
755294987Szbb				pcpu->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
756294987Szbb		}
757294987Szbb		/* Ensure all data is written before waking other CPUs */
758294987Szbb		atomic_thread_fence_rel();
759294987Szbb	}
760294987Szbb
761294987Szbb	return (0);
762294740Szbb}
763294740Szbb
764294740Szbbstatic __inline uint32_t
765294740Szbbdbg_get_debug_model(void)
766294740Szbb{
767294740Szbb	uint32_t dbg_m;
768294740Szbb
769294740Szbb	dbg_m = ((cpuinfo.id_dfr0 & ID_DFR0_CP_DEBUG_M_MASK) >>
770294740Szbb	    ID_DFR0_CP_DEBUG_M_SHIFT);
771294740Szbb
772294740Szbb	return (dbg_m);
773294740Szbb}
774294740Szbb
775294740Szbbstatic __inline boolean_t
776294740Szbbdbg_get_ossr(void)
777294740Szbb{
778294740Szbb
779294740Szbb	switch (dbg_model) {
780300968Szbb	case ID_DFR0_CP_DEBUG_M_V7:
781294740Szbb		if ((cp14_dbgoslsr_get() & DBGOSLSR_OSLM0) != 0)
782294740Szbb			return (TRUE);
783294740Szbb
784294740Szbb		return (FALSE);
785294740Szbb	case ID_DFR0_CP_DEBUG_M_V7_1:
786294740Szbb		return (TRUE);
787294740Szbb	default:
788294740Szbb		return (FALSE);
789294740Szbb	}
790294740Szbb}
791294740Szbb
792294740Szbbstatic __inline boolean_t
793294740Szbbdbg_arch_supported(void)
794294740Szbb{
795317976Sgonzo	uint32_t dbg_didr;
796294740Szbb
797294740Szbb	switch (dbg_model) {
798294740Szbb	case ID_DFR0_CP_DEBUG_M_V6:
799294740Szbb	case ID_DFR0_CP_DEBUG_M_V6_1:
800317976Sgonzo		dbg_didr = cp14_dbgdidr_get();
801317976Sgonzo		/*
802317976Sgonzo		 * read-all-zeroes is used by QEMU
803317976Sgonzo		 * to indicate that ARMv6 debug support
804317976Sgonzo		 * is not implemented. Real hardware has at
805317976Sgonzo		 * least version bits set
806317976Sgonzo		 */
807317976Sgonzo		if (dbg_didr == 0)
808317976Sgonzo			return (FALSE);
809317976Sgonzo		return (TRUE);
810294740Szbb	case ID_DFR0_CP_DEBUG_M_V7:
811294740Szbb	case ID_DFR0_CP_DEBUG_M_V7_1:	/* fall through */
812294740Szbb		return (TRUE);
813294740Szbb	default:
814294740Szbb		/* We only support valid v6.x/v7.x modes through CP14 */
815294740Szbb		return (FALSE);
816294740Szbb	}
817294740Szbb}
818294740Szbb
819294740Szbbstatic __inline uint32_t
820294740Szbbdbg_get_wrp_num(void)
821294740Szbb{
822294740Szbb	uint32_t dbg_didr;
823294740Szbb
824294740Szbb	dbg_didr = cp14_dbgdidr_get();
825294740Szbb
826294740Szbb	return (DBGDIDR_WRPS_NUM(dbg_didr));
827294740Szbb}
828294740Szbb
829294740Szbbstatic __inline uint32_t
830294740Szbbdgb_get_brp_num(void)
831294740Szbb{
832294740Szbb	uint32_t dbg_didr;
833294740Szbb
834294740Szbb	dbg_didr = cp14_dbgdidr_get();
835294740Szbb
836294740Szbb	return (DBGDIDR_BRPS_NUM(dbg_didr));
837294740Szbb}
838294740Szbb
839294740Szbbstatic int
840294740Szbbdbg_reset_state(void)
841294740Szbb{
842294740Szbb	u_int cpuid;
843294740Szbb	size_t i;
844294740Szbb	int err;
845294740Szbb
846294740Szbb	cpuid = PCPU_GET(cpuid);
847294740Szbb	err = 0;
848294740Szbb
849294740Szbb	switch (dbg_model) {
850294740Szbb	case ID_DFR0_CP_DEBUG_M_V6:
851300968Szbb	case ID_DFR0_CP_DEBUG_M_V6_1: /* fall through */
852300968Szbb		/*
853300968Szbb		 * Arch needs monitor mode selected and enabled
854300968Szbb		 * to be able to access breakpoint/watchpoint registers.
855300968Szbb		 */
856300968Szbb		err = dbg_enable_monitor();
857300968Szbb		if (err != 0)
858300968Szbb			return (err);
859300968Szbb		goto vectr_clr;
860300968Szbb	case ID_DFR0_CP_DEBUG_M_V7:
861294740Szbb		/* Is core power domain powered up? */
862294740Szbb		if ((cp14_dbgprsr_get() & DBGPRSR_PU) == 0)
863294740Szbb			err = ENXIO;
864294740Szbb
865294740Szbb		if (err != 0)
866294740Szbb			break;
867294740Szbb
868294740Szbb		if (dbg_ossr)
869294740Szbb			goto vectr_clr;
870294740Szbb		break;
871294740Szbb	case ID_DFR0_CP_DEBUG_M_V7_1:
872294740Szbb		/* Is double lock set? */
873294740Szbb		if ((cp14_dbgosdlr_get() & DBGPRSR_DLK) != 0)
874294740Szbb			err = ENXIO;
875294740Szbb
876294740Szbb		break;
877294740Szbb	default:
878294740Szbb		break;
879294740Szbb	}
880294740Szbb
881294740Szbb	if (err != 0) {
882294740Szbb		db_printf("Debug facility locked (CPU%d)\n", cpuid);
883294740Szbb		return (err);
884294740Szbb	}
885294740Szbb
886294740Szbb	/*
887294740Szbb	 * DBGOSLAR is always implemented for v7.1 Debug Arch. however is
888294740Szbb	 * optional for v7 (depends on OS save and restore support).
889294740Szbb	 */
890294740Szbb	if (((dbg_model & ID_DFR0_CP_DEBUG_M_V7_1) != 0) || dbg_ossr) {
891294740Szbb		/*
892294740Szbb		 * Clear OS lock.
893294740Szbb		 * Writing any other value than 0xC5ACCESS will unlock.
894294740Szbb		 */
895294740Szbb		cp14_dbgoslar_set(0);
896294740Szbb		isb();
897294740Szbb	}
898294740Szbb
899294740Szbbvectr_clr:
900294740Szbb	/*
901294740Szbb	 * After reset we must ensure that DBGVCR has a defined value.
902294740Szbb	 * Disable all vector catch events. Safe to use - required in all
903294740Szbb	 * implementations.
904294740Szbb	 */
905294740Szbb	cp14_dbgvcr_set(0);
906294740Szbb	isb();
907294740Szbb
908294740Szbb	/*
909294740Szbb	 * We have limited number of {watch,break}points, each consists of
910294740Szbb	 * two registers:
911294740Szbb	 * - wcr/bcr regsiter configurates corresponding {watch,break}point
912294740Szbb	 *   behaviour
913294740Szbb	 * - wvr/bvr register keeps address we are hunting for
914294740Szbb	 *
915294740Szbb	 * Reset all breakpoints and watchpoints.
916294740Szbb	 */
917294740Szbb	for (i = 0; i < dbg_watchpoint_num; ++i) {
918294740Szbb		dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
919294740Szbb		dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
920294740Szbb	}
921294740Szbb
922294740Szbb	for (i = 0; i < dbg_breakpoint_num; ++i) {
923294740Szbb		dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
924294740Szbb		dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
925294740Szbb	}
926294740Szbb
927294740Szbb	return (0);
928294740Szbb}
929294740Szbb
930294740Szbbvoid
931294740Szbbdbg_monitor_init(void)
932294740Szbb{
933294740Szbb	int err;
934294740Szbb
935294740Szbb	/* Fetch ARM Debug Architecture model */
936294740Szbb	dbg_model = dbg_get_debug_model();
937294740Szbb
938294740Szbb	if (!dbg_arch_supported()) {
939294740Szbb		db_printf("ARM Debug Architecture not supported\n");
940294740Szbb		return;
941294740Szbb	}
942294740Szbb
943294740Szbb	if (bootverbose) {
944294740Szbb		db_printf("ARM Debug Architecture %s\n",
945294740Szbb		    (dbg_model == ID_DFR0_CP_DEBUG_M_V6) ? "v6" :
946294740Szbb		    (dbg_model == ID_DFR0_CP_DEBUG_M_V6_1) ? "v6.1" :
947294740Szbb		    (dbg_model == ID_DFR0_CP_DEBUG_M_V7) ? "v7" :
948294740Szbb		    (dbg_model == ID_DFR0_CP_DEBUG_M_V7_1) ? "v7.1" : "unknown");
949294740Szbb	}
950294740Szbb
951294740Szbb	/* Do we have OS Save and Restore mechanism? */
952294740Szbb	dbg_ossr = dbg_get_ossr();
953294740Szbb
954294740Szbb	/* Find out many breakpoints and watchpoints we can use */
955294740Szbb	dbg_watchpoint_num = dbg_get_wrp_num();
956294740Szbb	dbg_breakpoint_num = dgb_get_brp_num();
957294740Szbb
958294740Szbb	if (bootverbose) {
959294740Szbb		db_printf("%d watchpoints and %d breakpoints supported\n",
960294740Szbb		    dbg_watchpoint_num, dbg_breakpoint_num);
961294740Szbb	}
962294740Szbb
963294740Szbb	err = dbg_reset_state();
964294740Szbb	if (err == 0) {
965300968Szbb		err = dbg_enable_monitor();
966300968Szbb		if (err == 0) {
967300969Szbb			atomic_set_int(&dbg_capable_var, 1);
968300968Szbb			return;
969300968Szbb		}
970294740Szbb	}
971294740Szbb
972294740Szbb	db_printf("HW Breakpoints/Watchpoints not enabled on CPU%d\n",
973294740Szbb	    PCPU_GET(cpuid));
974294740Szbb}
975294987Szbb
976294987SzbbCTASSERT(sizeof(struct dbreg) == sizeof(((struct pcpu *)NULL)->pc_dbreg));
977294987Szbb
978294987Szbbvoid
979300969Szbbdbg_monitor_init_secondary(void)
980300969Szbb{
981300969Szbb	u_int cpuid;
982300969Szbb	int err;
983300969Szbb	/*
984300969Szbb	 * This flag is set on the primary CPU
985300969Szbb	 * and its meaning is valid for other CPUs too.
986300969Szbb	 */
987300969Szbb	if (!dbg_capable())
988300969Szbb		return;
989300969Szbb
990300969Szbb	cpuid = PCPU_GET(cpuid);
991300969Szbb
992300969Szbb	err = dbg_reset_state();
993300969Szbb	if (err != 0) {
994300969Szbb		/*
995300969Szbb		 * Something is very wrong.
996300969Szbb		 * WPs/BPs will not work correctly on this CPU.
997300969Szbb		 */
998300969Szbb		KASSERT(0, ("%s: Failed to reset Debug Architecture "
999300969Szbb		    "state on CPU%d", __func__, cpuid));
1000300969Szbb		/* Disable HW debug capabilities for all CPUs */
1001300969Szbb		atomic_set_int(&dbg_capable_var, 0);
1002300969Szbb		return;
1003300969Szbb	}
1004300969Szbb	err = dbg_enable_monitor();
1005300969Szbb	if (err != 0) {
1006300969Szbb		KASSERT(0, ("%s: Failed to enable Debug Monitor"
1007300969Szbb		    " on CPU%d", __func__, cpuid));
1008300969Szbb		atomic_set_int(&dbg_capable_var, 0);
1009300969Szbb	}
1010300969Szbb}
1011300969Szbb
1012300969Szbbvoid
1013294987Szbbdbg_resume_dbreg(void)
1014294987Szbb{
1015294987Szbb	struct dbreg *d;
1016294987Szbb	u_int i;
1017294987Szbb
1018294987Szbb	/*
1019294987Szbb	 * This flag is set on the primary CPU
1020294987Szbb	 * and its meaning is valid for other CPUs too.
1021294987Szbb	 */
1022300969Szbb	if (!dbg_capable())
1023294987Szbb		return;
1024294987Szbb
1025294987Szbb	atomic_thread_fence_acq();
1026294987Szbb
1027294987Szbb	switch (PCPU_GET(dbreg_cmd)) {
1028294987Szbb	case PC_DBREG_CMD_LOAD:
1029294987Szbb		d = (struct dbreg *)PCPU_PTR(dbreg);
1030294987Szbb
1031294987Szbb		/* Restore watchpoints */
1032294987Szbb		for (i = 0; i < dbg_watchpoint_num; i++) {
1033294987Szbb			dbg_wb_write_reg(DBG_REG_BASE_WVR, i, d->dbg_wvr[i]);
1034294987Szbb			dbg_wb_write_reg(DBG_REG_BASE_WCR, i, d->dbg_wcr[i]);
1035294987Szbb		}
1036294987Szbb
1037294987Szbb		PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE);
1038294987Szbb		break;
1039294987Szbb	}
1040294987Szbb}
1041