182007Sjake/*-
282007Sjake * Copyright (c) 2001 Jake Burkholder.
382007Sjake * All rights reserved.
482007Sjake * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.  All rights reserved.
582007Sjake *
682007Sjake * Redistribution and use in source and binary forms, with or without
782007Sjake * modification, are permitted provided that the following conditions
882007Sjake * are met:
982007Sjake * 1. Redistributions of source code must retain the above copyright
1082007Sjake *    notice, this list of conditions and the following disclaimer.
1182007Sjake * 2. Redistributions in binary form must reproduce the above copyright
1282007Sjake *    notice, this list of conditions and the following disclaimer in the
1382007Sjake *    documentation and/or other materials provided with the distribution.
1482007Sjake *
1582007Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1682007Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1782007Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1882007Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1982007Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2082007Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2182007Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2282007Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2382007Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2482007Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2582007Sjake * SUCH DAMAGE.
2682007Sjake *
2782007Sjake * $FreeBSD$
2882007Sjake */
2982007Sjake
3082007Sjake#include <sys/param.h>
3182007Sjake
3282007Sjake#include <vm/vm.h>
3382007Sjake
3482007Sjake#include <machine/asi.h>
3582007Sjake#include <machine/cpufunc.h>
3682007Sjake#include <machine/lsu.h>
3782007Sjake#include <machine/watch.h>
3882007Sjake
3982007Sjake#include <ddb/ddb.h>
4082007Sjake#include <ddb/db_access.h>
4182007Sjake#include <ddb/db_sym.h>
4282007Sjake#include <ddb/db_variables.h>
4382007Sjake#include <ddb/db_watch.h>
4482007Sjake
4582007Sjakestatic void db_watch_print(vm_offset_t wp, int bm);
4682007Sjake
4782007Sjakeint
48113238Sjakewatch_phys_set_mask(vm_paddr_t pa, u_long mask)
4982007Sjake{
5082007Sjake	u_long lsucr;
5182007Sjake
5290621Stmm	stxa_sync(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3));
5382007Sjake	lsucr = ldxa(0, ASI_LSU_CTL_REG);
5482007Sjake	lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) |
5582007Sjake	    (mask << LSU_PM_SHIFT);
5690621Stmm	stxa_sync(0, ASI_LSU_CTL_REG, lsucr);
5782007Sjake	return (0);
5882007Sjake}
5982007Sjake
6082007Sjakeint
61113238Sjakewatch_phys_set(vm_paddr_t pa, int sz)
6282007Sjake{
6382007Sjake	u_long off;
6482007Sjake
6582007Sjake	off = (u_long)pa & 7;
6682007Sjake	/* Test for misaligned watch points. */
6782007Sjake	if (off + sz > 8)
6882007Sjake		return (-1);
6982007Sjake	return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off));
7082007Sjake}
7182007Sjake
72113238Sjakevm_paddr_t
7382007Sjakewatch_phys_get(int *bm)
7482007Sjake{
75113238Sjake	vm_paddr_t pa;
7682007Sjake	u_long lsucr;
7782007Sjake
7882007Sjake	if (!watch_phys_active())
7982007Sjake		return (0);
8082007Sjake
8182007Sjake	pa = ldxa(AA_DMMU_PWPR, ASI_DMMU);
8282007Sjake	lsucr = ldxa(0, ASI_LSU_CTL_REG);
8382007Sjake	*bm = (lsucr & LSU_PM_MASK) >> LSU_PM_SHIFT;
8482007Sjake
85113238Sjake	return (pa);
8682007Sjake}
8782007Sjake
8882007Sjakevoid
8982007Sjakewatch_phys_clear()
9082007Sjake{
9190621Stmm	stxa_sync(0, ASI_LSU_CTL_REG,
9282007Sjake	    ldxa(0, ASI_LSU_CTL_REG) & ~LSU_PW);
9382007Sjake}
9482007Sjake
9582007Sjakeint
9682007Sjakewatch_phys_active()
9782007Sjake{
9882007Sjake
9982007Sjake	return (ldxa(0, ASI_LSU_CTL_REG) & LSU_PW);
10082007Sjake}
10182007Sjake
10282007Sjakeint
10382007Sjakewatch_virt_set_mask(vm_offset_t va, u_long mask)
10482007Sjake{
10582007Sjake	u_long lsucr;
10682007Sjake
10790621Stmm	stxa_sync(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3));
10882007Sjake	lsucr = ldxa(0, ASI_LSU_CTL_REG);
10982007Sjake	lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) |
11082007Sjake	    (mask << LSU_VM_SHIFT);
11190621Stmm	stxa_sync(0, ASI_LSU_CTL_REG, lsucr);
11282007Sjake	return (0);
11382007Sjake}
11482007Sjake
11582007Sjakeint
11682007Sjakewatch_virt_set(vm_offset_t va, int sz)
11782007Sjake{
11882007Sjake	u_long off;
11982007Sjake
12082007Sjake	off = (u_long)va & 7;
12182007Sjake	/* Test for misaligned watch points. */
12282007Sjake	if (off + sz > 8)
12382007Sjake		return (-1);
12482007Sjake	return (watch_virt_set_mask(va, ((1 << sz) - 1) << off));
12582007Sjake}
12682007Sjake
12782007Sjakevm_offset_t
12882007Sjakewatch_virt_get(int *bm)
12982007Sjake{
13082007Sjake	u_long va;
13182007Sjake	u_long lsucr;
13282007Sjake
13382007Sjake	if (!watch_virt_active())
13482007Sjake		return (0);
13582007Sjake
13682007Sjake	va = ldxa(AA_DMMU_VWPR, ASI_DMMU);
13782007Sjake	lsucr = ldxa(0, ASI_LSU_CTL_REG);
13882007Sjake	*bm = (lsucr & LSU_VM_MASK) >> LSU_VM_SHIFT;
13982007Sjake
14082007Sjake	return ((vm_offset_t)va);
14182007Sjake}
14282007Sjake
14382007Sjakevoid
14482007Sjakewatch_virt_clear()
14582007Sjake{
14690621Stmm	stxa_sync(0, ASI_LSU_CTL_REG,
14782007Sjake	    ldxa(0, ASI_LSU_CTL_REG) & ~LSU_VW);
14882007Sjake}
14982007Sjake
15082007Sjakeint
15182007Sjakewatch_virt_active()
15282007Sjake{
15382007Sjake
15482007Sjake	return (ldxa(0, ASI_LSU_CTL_REG) & LSU_VW);
15582007Sjake}
15682007Sjake
15782007Sjakeint
15882007Sjakedb_md_set_watchpoint(db_expr_t addr, db_expr_t size)
15982007Sjake{
16082007Sjake	int dummy;
16182007Sjake
16282007Sjake	if (watch_virt_active()) {
16382007Sjake		db_printf("Overwriting previously active watch point at "
16482007Sjake		    "0x%lx\n", watch_virt_get(&dummy));
16582007Sjake	}
16682007Sjake	return (watch_virt_set(addr, size));
16782007Sjake}
16882007Sjake
16982007Sjakeint
17082007Sjakedb_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
17182007Sjake{
17282007Sjake
17382007Sjake	watch_virt_clear();
17482007Sjake	return (0);
17582007Sjake}
17682007Sjake
17782007Sjakevoid
17882007Sjakedb_watch_print(vm_offset_t wp, int bm)
17982007Sjake{
18082007Sjake	int i;
18182007Sjake
18282007Sjake	db_printf("\tat 0x%lx, active bytes: ", (u_long)wp);
18382007Sjake	for (i = 0; i < 8; i++) {
18482007Sjake		if ((bm & (1 << i)) != 0)
18582007Sjake			db_printf("%d ", i);
18682007Sjake	}
18782007Sjake	if (bm == 0)
18882007Sjake		db_printf("none");
18982007Sjake	db_printf("\n");
19082007Sjake}
19182007Sjake
19282007Sjakevoid
19382007Sjakedb_md_list_watchpoints(void)
19482007Sjake{
195113238Sjake	vm_offset_t va;
196113238Sjake	vm_paddr_t pa;
19782007Sjake	int bm;
19882007Sjake
19982007Sjake	db_printf("Physical address watchpoint:\n");
20082007Sjake	if (watch_phys_active()) {
201113238Sjake		pa = watch_phys_get(&bm);
202113238Sjake		db_watch_print(pa, bm);
20382007Sjake	} else
20482007Sjake		db_printf("\tnot active.\n");
20582007Sjake	db_printf("Virtual address watchpoint:\n");
20682007Sjake	if (watch_virt_active()) {
207113238Sjake		va = watch_virt_get(&bm);
208113238Sjake		db_watch_print(va, bm);
20982007Sjake	} else
21082007Sjake		db_printf("\tnot active.\n");
21182007Sjake}
212