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.
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.
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]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
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.
35 #include <sys/cpuvar.h>
36 #include <sys/kdi_impl.h>
37 #include <sys/errno.h>
38 #include <sys/systm.h>
39 #include <sys/sysmacros.h>
41 #include <sys/bootconf.h>
42 #include <sys/cmn_err.h>
43 #include <vm/seg_kmem.h>
44 #include <vm/hat_i86.h>
46 #include <sys/hypervisor.h>
48 #include <sys/bootinfo.h>
49 #include <vm/kboot_mmu.h>
50 #include <sys/machsystm.h>
53 * The debugger needs direct access to the PTE of one page table entry
54 * in order to implement vtop and physical read/writes
56 static uintptr_t hat_kdi_page
= 0; /* vaddr for phsical page accesses */
57 static uint_t use_kbm
= 1;
58 uint_t hat_kdi_use_pae
; /* if 0, use x86pte32_t for pte type */
61 static x86pte_t
*hat_kdi_pte
= NULL
; /* vaddr of pte for hat_kdi_page */
65 * Get the address for remapping physical pages during boot
68 hat_boot_kdi_init(void)
70 hat_kdi_page
= (uintptr_t)kbm_push(0); /* first call gets address... */
74 * Switch to using a page in the kernel's va range for physical memory access.
75 * We need to allocate a virtual page, then permanently map in the page that
76 * contains the PTE to it.
81 /*LINTED:set but not used in function*/
85 * Get an kernel page VA to use for phys mem access. Then make sure
86 * the VA has a page table.
88 hat_kdi_use_pae
= mmu
.pae_hat
;
89 hat_kdi_page
= (uintptr_t)vmem_alloc(heap_arena
, PAGESIZE
, VM_SLEEP
);
90 ht
= htable_create(kas
.a_hat
, hat_kdi_page
, 0, NULL
);
95 * Get an address at which to put the pagetable and devload it.
97 hat_kdi_pte
= vmem_xalloc(heap_arena
, MMU_PAGESIZE
, MMU_PAGESIZE
, 0,
98 0, NULL
, NULL
, VM_SLEEP
);
99 hat_devload(kas
.a_hat
, (caddr_t
)hat_kdi_pte
, MMU_PAGESIZE
, ht
->ht_pfn
,
100 PROT_READ
| PROT_WRITE
| HAT_NOSYNC
| HAT_UNORDERED_OK
,
101 HAT_LOAD
| HAT_LOAD_NOCONSIST
);
103 PT_INDEX_PTR(hat_kdi_pte
, htable_va2entry(hat_kdi_page
, ht
));
105 HTABLE_INC(ht
->ht_valid_cnt
);
113 * translate machine address to physical address
116 kdi_ptom(uint64_t pa
)
118 extern pfn_t
*mfn_list
;
119 ulong_t mfn
= mfn_list
[mmu_btop(pa
)];
121 return (pfn_to_pa(mfn
) | (pa
& MMU_PAGEOFFSET
));
125 * This is like mfn_to_pfn(), but we can't use ontrap() from kmdb.
126 * Instead we let the fault happen and kmdb deals with it.
129 kdi_mtop(uint64_t ma
)
132 mfn_t mfn
= ma
>> MMU_PAGESHIFT
;
134 if (HYPERVISOR_memory_op(XENMEM_maximum_ram_page
, NULL
) < mfn
)
135 return (ma
| PFN_IS_FOREIGN_MFN
);
137 pfn
= mfn_to_pfn_mapping
[mfn
];
138 if (pfn
>= mfn_count
|| pfn_to_mfn(pfn
) != mfn
)
139 return (ma
| PFN_IS_FOREIGN_MFN
);
140 return (pfn_to_pa(pfn
) | (ma
& MMU_PAGEOFFSET
));
144 #define kdi_mtop(m) (m)
145 #define kdi_ptom(p) (p)
150 kdi_vtop(uintptr_t va
, uint64_t *pap
)
152 uintptr_t vaddr
= va
;
161 * if the mmu struct isn't relevant yet, we need to probe
162 * the boot loader's pagetables.
165 if (kbm_probe(&vaddr
, &len
, &pfn
, &prot
) == 0)
170 pfn
+= mmu_btop(va
- vaddr
);
171 *pap
= pfn_to_pa(pfn
) + (vaddr
& MMU_PAGEOFFSET
);
176 * We can't go through normal hat routines, so we'll use
177 * kdi_pread() to walk the page tables
180 *pap
= pfn_to_pa(CPU
->cpu_current_hat
->hat_htable
->ht_pfn
);
182 *pap
= getcr3() & MMU_PAGEMASK
;
184 for (level
= mmu
.max_level
; ; --level
) {
185 index
= (va
>> LEVEL_SHIFT(level
)) & (mmu
.ptes_per_table
- 1);
186 *pap
+= index
<< mmu
.pte_size_shift
;
188 if (kdi_pread((caddr_t
)&pte
, mmu
.pte_size
, *pap
, &len
) != 0)
192 if (level
> 0 && level
<= mmu
.max_page_level
&&
193 (pte
& PT_PAGESIZE
)) {
194 *pap
= kdi_mtop(pte
& PT_PADDR_LGPG
);
197 *pap
= kdi_mtop(pte
& PT_PADDR
);
202 *pap
+= va
& LEVEL_OFFSET(level
);
207 kdi_prw(caddr_t buf
, size_t nbytes
, uint64_t pa
, size_t *ncopiedp
, int doread
)
218 * if this is called before any initialization - fail
220 if (hat_kdi_page
== 0)
225 * figure out the addresses and construct a minimal PTE
227 pgoff
= pa
& MMU_PAGEOFFSET
;
228 sz
= MIN(nbytes
, MMU_PAGESIZE
- pgoff
);
229 va
= (caddr_t
)hat_kdi_page
+ pgoff
;
230 pte
= kdi_ptom(mmu_ptob(mmu_btop(pa
))) | PT_VALID
;
235 PTE_SET(pte
, PT_WRITABLE
);
241 * map the physical page
247 (void) HYPERVISOR_update_va_mapping(
248 (uintptr_t)va
, pte
, UVMF_INVLPG
);
250 else if (hat_kdi_use_pae
)
253 *(x86pte32_t
*)hat_kdi_pte
= pte
;
254 mmu_tlbflush_entry((caddr_t
)hat_kdi_page
);
266 (void) HYPERVISOR_update_va_mapping(
267 (uintptr_t)va
, 0, UVMF_INVLPG
);
269 else if (hat_kdi_use_pae
)
272 *(x86pte32_t
*)hat_kdi_pte
= 0;
273 mmu_tlbflush_entry((caddr_t
)hat_kdi_page
);
290 kdi_pread(caddr_t buf
, size_t nbytes
, uint64_t addr
, size_t *ncopiedp
)
292 return (kdi_prw(buf
, nbytes
, addr
, ncopiedp
, 1));
296 kdi_pwrite(caddr_t buf
, size_t nbytes
, uint64_t addr
, size_t *ncopiedp
)
298 return (kdi_prw(buf
, nbytes
, addr
, ncopiedp
, 0));
303 * Return the number of bytes, relative to the beginning of a given range, that
304 * are non-toxic (can be read from and written to with relative impunity).
308 kdi_range_is_nontoxic(uintptr_t va
, size_t sz
, int write
)
311 extern uintptr_t toxic_addr
;
312 extern size_t toxic_size
;
315 * Check 64 bit toxic range.
317 if (toxic_addr
!= 0 &&
318 va
+ sz
>= toxic_addr
&&
319 va
< toxic_addr
+ toxic_size
)
320 return (va
< toxic_addr
? toxic_addr
- va
: 0);
323 * avoid any Virtual Address hole
325 if (va
+ sz
>= hole_start
&& va
< hole_end
)
326 return (va
< hole_start
? hole_start
- va
: 0);
330 #elif defined(__i386)
331 extern void *device_arena_contains(void *, size_t, size_t *);
334 v
= (uintptr_t)device_arena_contains((void *)va
, sz
, NULL
);