1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * HAT interfaces used by the kernel debugger to interact with the VM system. 29 * These interfaces are invoked when the world is stopped. As such, no blocking 30 * operations may be performed. 31 */ 32 33 #include <sys/cpuvar.h> 34 #include <sys/kdi_impl.h> 35 #include <sys/errno.h> 36 #include <sys/systm.h> 37 #include <sys/sysmacros.h> 38 #include <sys/mman.h> 39 #include <sys/bootconf.h> 40 #include <sys/cmn_err.h> 41 #include <vm/seg_kmem.h> 42 #include <vm/hat_i86.h> 43 #if defined(__xpv) 44 #include <sys/hypervisor.h> 45 #endif 46 #include <sys/bootinfo.h> 47 #include <vm/kboot_mmu.h> 48 #include <sys/machsystm.h> 49 50 /* 51 * The debugger needs direct access to the PTE of one page table entry 52 * in order to implement vtop and physical read/writes 53 */ 54 static uintptr_t hat_kdi_page = 0; /* vaddr for phsical page accesses */ 55 static uint_t use_kbm = 1; 56 uint_t hat_kdi_use_pae; /* if 0, use x86pte32_t for pte type */ 57 58 #if !defined(__xpv) 59 static x86pte_t *hat_kdi_pte = NULL; /* vaddr of pte for hat_kdi_page */ 60 #endif 61 62 /* 63 * Get the address for remapping physical pages during boot 64 */ 65 void 66 hat_boot_kdi_init(void) 67 { 68 hat_kdi_page = (uintptr_t)kbm_push(0); /* first call gets address... */ 69 } 70 71 /* 72 * Switch to using a page in the kernel's va range for physical memory access. 73 * We need to allocate a virtual page, then permanently map in the page that 74 * contains the PTE to it. 75 */ 76 void 77 hat_kdi_init(void) 78 { 79 /*LINTED:set but not used in function*/ 80 htable_t *ht __unused; 81 82 /* 83 * Get an kernel page VA to use for phys mem access. Then make sure 84 * the VA has a page table. 85 */ 86 hat_kdi_use_pae = mmu.pae_hat; 87 hat_kdi_page = (uintptr_t)vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 88 ht = htable_create(kas.a_hat, hat_kdi_page, 0, NULL); 89 use_kbm = 0; 90 91 #ifndef __xpv 92 /* 93 * Get an address at which to put the pagetable and devload it. 94 */ 95 hat_kdi_pte = vmem_xalloc(heap_arena, MMU_PAGESIZE, MMU_PAGESIZE, 0, 96 0, NULL, NULL, VM_SLEEP); 97 hat_devload(kas.a_hat, (caddr_t)hat_kdi_pte, MMU_PAGESIZE, ht->ht_pfn, 98 PROT_READ | PROT_WRITE | HAT_NOSYNC | HAT_UNORDERED_OK, 99 HAT_LOAD | HAT_LOAD_NOCONSIST); 100 hat_kdi_pte = 101 PT_INDEX_PTR(hat_kdi_pte, htable_va2entry(hat_kdi_page, ht)); 102 103 HTABLE_INC(ht->ht_valid_cnt); 104 htable_release(ht); 105 #endif 106 } 107 108 #ifdef __xpv 109 110 /* 111 * translate machine address to physical address 112 */ 113 static uint64_t 114 kdi_ptom(uint64_t pa) 115 { 116 extern pfn_t *mfn_list; 117 ulong_t mfn = mfn_list[mmu_btop(pa)]; 118 119 return (pfn_to_pa(mfn) | (pa & MMU_PAGEOFFSET)); 120 } 121 122 /* 123 * This is like mfn_to_pfn(), but we can't use ontrap() from kmdb. 124 * Instead we let the fault happen and kmdb deals with it. 125 */ 126 static uint64_t 127 kdi_mtop(uint64_t ma) 128 { 129 pfn_t pfn; 130 mfn_t mfn = ma >> MMU_PAGESHIFT; 131 132 if (HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL) < mfn) 133 return (ma | PFN_IS_FOREIGN_MFN); 134 135 pfn = mfn_to_pfn_mapping[mfn]; 136 if (pfn >= mfn_count || pfn_to_mfn(pfn) != mfn) 137 return (ma | PFN_IS_FOREIGN_MFN); 138 return (pfn_to_pa(pfn) | (ma & MMU_PAGEOFFSET)); 139 } 140 141 #else 142 #define kdi_mtop(m) (m) 143 #define kdi_ptom(p) (p) 144 #endif 145 146 /*ARGSUSED*/ 147 int 148 kdi_vtop(uintptr_t va, uint64_t *pap) 149 { 150 uintptr_t vaddr = va; 151 size_t len; 152 pfn_t pfn; 153 uint_t prot; 154 int level; 155 x86pte_t pte; 156 int index; 157 158 /* 159 * if the mmu struct isn't relevant yet, we need to probe 160 * the boot loader's pagetables. 161 */ 162 if (!khat_running) { 163 if (kbm_probe(&vaddr, &len, &pfn, &prot) == 0) 164 return (ENOENT); 165 if (vaddr > va) 166 return (ENOENT); 167 if (vaddr < va) 168 pfn += mmu_btop(va - vaddr); 169 *pap = pfn_to_pa(pfn) + (vaddr & MMU_PAGEOFFSET); 170 return (0); 171 } 172 173 /* 174 * We can't go through normal hat routines, so we'll use 175 * kdi_pread() to walk the page tables 176 */ 177 #if defined(__xpv) 178 *pap = pfn_to_pa(CPU->cpu_current_hat->hat_htable->ht_pfn); 179 #else 180 *pap = getcr3() & MMU_PAGEMASK; 181 #endif 182 for (level = mmu.max_level; ; --level) { 183 index = (va >> LEVEL_SHIFT(level)) & (mmu.ptes_per_table - 1); 184 *pap += index << mmu.pte_size_shift; 185 pte = 0; 186 if (kdi_pread((caddr_t)&pte, mmu.pte_size, *pap, &len) != 0) 187 return (ENOENT); 188 if (pte == 0) 189 return (ENOENT); 190 if (level > 0 && level <= mmu.max_page_level && 191 (pte & PT_PAGESIZE)) { 192 *pap = kdi_mtop(pte & PT_PADDR_LGPG); 193 break; 194 } else { 195 *pap = kdi_mtop(pte & PT_PADDR); 196 if (level == 0) 197 break; 198 } 199 } 200 *pap += va & LEVEL_OFFSET(level); 201 return (0); 202 } 203 204 static int 205 kdi_prw(caddr_t buf, size_t nbytes, uint64_t pa, size_t *ncopiedp, int doread) 206 { 207 size_t ncopied = 0; 208 off_t pgoff; 209 size_t sz; 210 caddr_t va; 211 caddr_t from; 212 caddr_t to; 213 x86pte_t pte; 214 215 /* 216 * if this is called before any initialization - fail 217 */ 218 if (hat_kdi_page == 0) 219 return (EAGAIN); 220 221 while (nbytes > 0) { 222 /* 223 * figure out the addresses and construct a minimal PTE 224 */ 225 pgoff = pa & MMU_PAGEOFFSET; 226 sz = MIN(nbytes, MMU_PAGESIZE - pgoff); 227 va = (caddr_t)hat_kdi_page + pgoff; 228 pte = kdi_ptom(mmu_ptob(mmu_btop(pa))) | PT_VALID; 229 if (doread) { 230 from = va; 231 to = buf; 232 } else { 233 PTE_SET(pte, PT_WRITABLE); 234 from = buf; 235 to = va; 236 } 237 238 /* 239 * map the physical page 240 */ 241 if (use_kbm) 242 (void) kbm_push(pa); 243 #if defined(__xpv) 244 else 245 (void) HYPERVISOR_update_va_mapping( 246 (uintptr_t)va, pte, UVMF_INVLPG); 247 #else 248 else if (hat_kdi_use_pae) 249 *hat_kdi_pte = pte; 250 else 251 *(x86pte32_t *)hat_kdi_pte = pte; 252 mmu_tlbflush_entry((caddr_t)hat_kdi_page); 253 #endif 254 255 bcopy(from, to, sz); 256 257 /* 258 * erase the mapping 259 */ 260 if (use_kbm) 261 kbm_pop(); 262 #if defined(__xpv) 263 else 264 (void) HYPERVISOR_update_va_mapping( 265 (uintptr_t)va, 0, UVMF_INVLPG); 266 #else 267 else if (hat_kdi_use_pae) 268 *hat_kdi_pte = 0; 269 else 270 *(x86pte32_t *)hat_kdi_pte = 0; 271 mmu_tlbflush_entry((caddr_t)hat_kdi_page); 272 #endif 273 274 buf += sz; 275 pa += sz; 276 nbytes -= sz; 277 ncopied += sz; 278 } 279 280 if (ncopied == 0) 281 return (ENOENT); 282 283 *ncopiedp = ncopied; 284 return (0); 285 } 286 287 int 288 kdi_pread(caddr_t buf, size_t nbytes, uint64_t addr, size_t *ncopiedp) 289 { 290 return (kdi_prw(buf, nbytes, addr, ncopiedp, 1)); 291 } 292 293 int 294 kdi_pwrite(caddr_t buf, size_t nbytes, uint64_t addr, size_t *ncopiedp) 295 { 296 return (kdi_prw(buf, nbytes, addr, ncopiedp, 0)); 297 } 298 299 300 /* 301 * Return the number of bytes, relative to the beginning of a given range, that 302 * are non-toxic (can be read from and written to with relative impunity). 303 */ 304 /*ARGSUSED*/ 305 size_t 306 kdi_range_is_nontoxic(uintptr_t va, size_t sz, int write) 307 { 308 #if defined(__amd64) 309 extern uintptr_t toxic_addr; 310 extern size_t toxic_size; 311 312 /* 313 * Check 64 bit toxic range. 314 */ 315 if (toxic_addr != 0 && 316 va + sz >= toxic_addr && 317 va < toxic_addr + toxic_size) 318 return (va < toxic_addr ? toxic_addr - va : 0); 319 320 /* 321 * avoid any Virtual Address hole 322 */ 323 if (va + sz >= hole_start && va < hole_end) 324 return (va < hole_start ? hole_start - va : 0); 325 326 return (sz); 327 328 #elif defined(__i386) 329 extern void *device_arena_contains(void *, size_t, size_t *); 330 uintptr_t v; 331 332 v = (uintptr_t)device_arena_contains((void *)va, sz, NULL); 333 if (v == 0) 334 return (sz); 335 else if (v <= va) 336 return (0); 337 else 338 return (v - va); 339 340 #endif /* __i386 */ 341 } 342