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