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