2 * Copyright (c) 1989, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software developed by the Computer Systems
6 * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
7 * BG 91-66 and contributed to Berkeley.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #if defined(LIBC_SCCS) && !defined(lint)
39 static char sccsid
[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93";
41 #endif /* LIBC_SCCS and not lint */
44 * AMD64 machine dependent routines for kvm. Hopefully, the forthcoming
45 * vm code will one day obsolete this module.
48 #include <sys/param.h>
49 #include <sys/endian.h>
58 #include "kvm_private.h"
59 #include "kvm_amd64.h"
68 * Translate a physical memory address to a file-offset in the crash-dump.
71 _kvm_pa2off(kvm_t
*kd
, uint64_t pa
, off_t
*ofs
)
73 struct vmstate
*vm
= kd
->vmst
;
79 return (AMD64_PAGE_SIZE
- (pa
& AMD64_PAGE_MASK
));
84 while (n
&& (pa
< p
->p_paddr
|| pa
>= p
->p_paddr
+ p
->p_memsz
))
88 *ofs
= (pa
- p
->p_paddr
) + p
->p_offset
;
89 return (AMD64_PAGE_SIZE
- (pa
& AMD64_PAGE_MASK
));
93 _amd64_freevtop(kvm_t
*kd
)
95 struct vmstate
*vm
= kd
->vmst
;
105 _amd64_probe(kvm_t
*kd
)
108 return (_kvm_probe_elf_kernel(kd
, ELFCLASS64
, EM_X86_64
) &&
109 !_kvm_is_minidump(kd
));
113 _amd64_initvtop(kvm_t
*kd
)
115 struct kvm_nlist nl
[2];
120 kd
->vmst
= (struct vmstate
*)_kvm_malloc(kd
, sizeof(*kd
->vmst
));
121 if (kd
->vmst
== NULL
) {
122 _kvm_err(kd
, kd
->program
, "cannot allocate vm");
127 if (kd
->rawdump
== 0) {
128 if (_kvm_read_core_phdrs(kd
, &kd
->vmst
->phnum
,
129 &kd
->vmst
->phdr
) == -1)
133 nl
[0].n_name
= "kernbase";
136 if (kvm_nlist2(kd
, nl
) != 0) {
137 _kvm_err(kd
, kd
->program
, "bad namelist - no kernbase");
140 kernbase
= nl
[0].n_value
;
142 nl
[0].n_name
= "KPML4phys";
145 if (kvm_nlist2(kd
, nl
) != 0) {
146 _kvm_err(kd
, kd
->program
, "bad namelist - no KPML4phys");
149 if (kvm_read2(kd
, (nl
[0].n_value
- kernbase
), &pa
, sizeof(pa
)) !=
151 _kvm_err(kd
, kd
->program
, "cannot read KPML4phys");
155 PML4
= _kvm_malloc(kd
, AMD64_PAGE_SIZE
);
157 _kvm_err(kd
, kd
->program
, "cannot allocate PML4");
160 if (kvm_read2(kd
, pa
, PML4
, AMD64_PAGE_SIZE
) != AMD64_PAGE_SIZE
) {
161 _kvm_err(kd
, kd
->program
, "cannot read KPML4phys");
165 kd
->vmst
->PML4
= PML4
;
170 _amd64_vatop(kvm_t
*kd
, kvaddr_t va
, off_t
*pa
)
173 amd64_physaddr_t offset
;
174 amd64_physaddr_t pdpe_pa
;
175 amd64_physaddr_t pde_pa
;
176 amd64_physaddr_t pte_pa
;
190 offset
= va
& AMD64_PAGE_MASK
;
193 * If we are initializing (kernel page table descriptor pointer
194 * not yet set) then return pa == va to avoid infinite recursion.
196 if (vm
->PML4
== NULL
) {
197 s
= _kvm_pa2off(kd
, va
, pa
);
199 _kvm_err(kd
, kd
->program
,
200 "_amd64_vatop: bootstrap data not in dump");
203 return (AMD64_PAGE_SIZE
- offset
);
206 pml4eindex
= (va
>> AMD64_PML4SHIFT
) & (AMD64_NPML4EPG
- 1);
207 pml4e
= le64toh(vm
->PML4
[pml4eindex
]);
208 if ((pml4e
& AMD64_PG_V
) == 0) {
209 _kvm_err(kd
, kd
->program
, "_amd64_vatop: pml4e not valid");
213 pdpeindex
= (va
>> AMD64_PDPSHIFT
) & (AMD64_NPDPEPG
- 1);
214 pdpe_pa
= (pml4e
& AMD64_PG_FRAME
) + (pdpeindex
* sizeof(amd64_pdpe_t
));
216 s
= _kvm_pa2off(kd
, pdpe_pa
, &ofs
);
217 if (s
< sizeof(pdpe
)) {
218 _kvm_err(kd
, kd
->program
, "_amd64_vatop: pdpe_pa not found");
221 if (pread(kd
->pmfd
, &pdpe
, sizeof(pdpe
), ofs
) != sizeof(pdpe
)) {
222 _kvm_syserr(kd
, kd
->program
, "_amd64_vatop: read pdpe");
225 pdpe
= le64toh(pdpe
);
226 if ((pdpe
& AMD64_PG_V
) == 0) {
227 _kvm_err(kd
, kd
->program
, "_amd64_vatop: pdpe not valid");
231 if (pdpe
& AMD64_PG_PS
) {
233 * No next-level page table; pdpe describes one 1GB page.
235 a
= (pdpe
& AMD64_PG_1GB_FRAME
) + (va
& AMD64_PDPMASK
);
236 s
= _kvm_pa2off(kd
, a
, pa
);
238 _kvm_err(kd
, kd
->program
,
239 "_amd64_vatop: 1GB page address not in dump");
242 return (AMD64_NBPDP
- (va
& AMD64_PDPMASK
));
245 pdeindex
= (va
>> AMD64_PDRSHIFT
) & (AMD64_NPDEPG
- 1);
246 pde_pa
= (pdpe
& AMD64_PG_FRAME
) + (pdeindex
* sizeof(amd64_pde_t
));
248 s
= _kvm_pa2off(kd
, pde_pa
, &ofs
);
249 if (s
< sizeof(pde
)) {
250 _kvm_syserr(kd
, kd
->program
, "_amd64_vatop: pde_pa not found");
253 if (pread(kd
->pmfd
, &pde
, sizeof(pde
), ofs
) != sizeof(pde
)) {
254 _kvm_syserr(kd
, kd
->program
, "_amd64_vatop: read pde");
258 if ((pde
& AMD64_PG_V
) == 0) {
259 _kvm_err(kd
, kd
->program
, "_amd64_vatop: pde not valid");
263 if (pde
& AMD64_PG_PS
) {
265 * No final-level page table; pde describes one 2MB page.
267 a
= (pde
& AMD64_PG_PS_FRAME
) + (va
& AMD64_PDRMASK
);
268 s
= _kvm_pa2off(kd
, a
, pa
);
270 _kvm_err(kd
, kd
->program
,
271 "_amd64_vatop: 2MB page address not in dump");
274 return (AMD64_NBPDR
- (va
& AMD64_PDRMASK
));
277 pteindex
= (va
>> AMD64_PAGE_SHIFT
) & (AMD64_NPTEPG
- 1);
278 pte_pa
= (pde
& AMD64_PG_FRAME
) + (pteindex
* sizeof(amd64_pte_t
));
280 s
= _kvm_pa2off(kd
, pte_pa
, &ofs
);
281 if (s
< sizeof(pte
)) {
282 _kvm_err(kd
, kd
->program
, "_amd64_vatop: pte_pa not found");
285 if (pread(kd
->pmfd
, &pte
, sizeof(pte
), ofs
) != sizeof(pte
)) {
286 _kvm_syserr(kd
, kd
->program
, "_amd64_vatop: read");
289 if ((pte
& AMD64_PG_V
) == 0) {
290 _kvm_err(kd
, kd
->program
, "_amd64_vatop: pte not valid");
294 a
= (pte
& AMD64_PG_FRAME
) + offset
;
295 s
= _kvm_pa2off(kd
, a
, pa
);
297 _kvm_err(kd
, kd
->program
, "_amd64_vatop: address not in dump");
300 return (AMD64_PAGE_SIZE
- offset
);
303 _kvm_err(kd
, 0, "invalid address (0x%jx)", (uintmax_t)va
);
308 _amd64_kvatop(kvm_t
*kd
, kvaddr_t va
, off_t
*pa
)
312 _kvm_err(kd
, 0, "kvm_kvatop called in live kernel!");
315 return (_amd64_vatop(kd
, va
, pa
));
319 _amd64_native(kvm_t
*kd
)
329 struct kvm_arch kvm_amd64
= {
330 .ka_probe
= _amd64_probe
,
331 .ka_initvtop
= _amd64_initvtop
,
332 .ka_freevtop
= _amd64_freevtop
,
333 .ka_kvatop
= _amd64_kvatop
,
334 .ka_native
= _amd64_native
,