2 * Copyright (c) 2006 Peter Wemm
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
29 * AMD64 machine dependent routines for kvm and minidumps.
32 #include <sys/param.h>
37 #include <sys/fnv_hash.h>
46 #include <vm/vm_param.h>
48 #include <machine/elf.h>
49 #include <machine/cpufunc.h>
50 #include <machine/minidump.h>
54 #include "kvm_private.h"
56 #define PG_FRAME_PAE (~((uint64_t)PAGE_MASK))
66 /* minidump must be the first item! */
68 int minidump
; /* 1 = minidump mode */
69 struct minidumphdr hdr
;
70 void *hpt_head
[HPT_SIZE
];
76 hpt_insert(kvm_t
*kd
, uint64_t pa
, int64_t off
)
79 uint32_t fnv
= FNV1_32_INIT
;
81 fnv
= fnv_32_buf(&pa
, sizeof(pa
), fnv
);
82 fnv
&= (HPT_SIZE
- 1);
83 hpte
= malloc(sizeof(*hpte
));
86 hpte
->next
= kd
->vmst
->hpt_head
[fnv
];
87 kd
->vmst
->hpt_head
[fnv
] = hpte
;
91 hpt_find(kvm_t
*kd
, uint64_t pa
)
94 uint32_t fnv
= FNV1_32_INIT
;
96 fnv
= fnv_32_buf(&pa
, sizeof(pa
), fnv
);
97 fnv
&= (HPT_SIZE
- 1);
98 for (hpte
= kd
->vmst
->hpt_head
[fnv
]; hpte
!= NULL
; hpte
= hpte
->next
) {
106 inithash(kvm_t
*kd
, uint32_t *base
, int len
, off_t off
)
112 for (idx
= 0; idx
< len
/ sizeof(*base
); idx
++) {
116 bits
&= ~(1ul << bit
);
117 pa
= (idx
* sizeof(*base
) * NBBY
+ bit
) * PAGE_SIZE
;
118 hpt_insert(kd
, pa
, off
);
126 _kvm_minidump_freevtop(kvm_t
*kd
)
128 struct vmstate
*vm
= kd
->vmst
;
139 _kvm_minidump_initvtop(kvm_t
*kd
)
141 struct vmstate
*vmst
;
144 vmst
= _kvm_malloc(kd
, sizeof(*vmst
));
146 _kvm_err(kd
, kd
->program
, "cannot allocate vm");
150 bzero(vmst
, sizeof(*vmst
));
152 if (pread(kd
->pmfd
, &vmst
->hdr
, sizeof(vmst
->hdr
), 0) !=
154 _kvm_err(kd
, kd
->program
, "cannot read dump header");
157 if (strncmp(MINIDUMP_MAGIC
, vmst
->hdr
.magic
, sizeof(vmst
->hdr
.magic
)) != 0) {
158 _kvm_err(kd
, kd
->program
, "not a minidump for this platform");
161 if (vmst
->hdr
.version
!= MINIDUMP_VERSION
) {
162 _kvm_err(kd
, kd
->program
, "wrong minidump version. expected %d got %d",
163 MINIDUMP_VERSION
, vmst
->hdr
.version
);
167 /* Skip header and msgbuf */
168 off
= PAGE_SIZE
+ round_page(vmst
->hdr
.msgbufsize
);
170 vmst
->bitmap
= _kvm_malloc(kd
, vmst
->hdr
.bitmapsize
);
171 if (vmst
->bitmap
== NULL
) {
172 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for bitmap", vmst
->hdr
.bitmapsize
);
175 if (pread(kd
->pmfd
, vmst
->bitmap
, vmst
->hdr
.bitmapsize
, off
) !=
176 vmst
->hdr
.bitmapsize
) {
177 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for page bitmap", vmst
->hdr
.bitmapsize
);
180 off
+= round_page(vmst
->hdr
.bitmapsize
);
182 vmst
->ptemap
= _kvm_malloc(kd
, vmst
->hdr
.ptesize
);
183 if (vmst
->ptemap
== NULL
) {
184 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for ptemap", vmst
->hdr
.ptesize
);
187 if (pread(kd
->pmfd
, vmst
->ptemap
, vmst
->hdr
.ptesize
, off
) !=
189 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for ptemap", vmst
->hdr
.ptesize
);
192 off
+= vmst
->hdr
.ptesize
;
194 /* build physical address hash table for sparse pages */
195 inithash(kd
, vmst
->bitmap
, vmst
->hdr
.bitmapsize
, off
);
201 _kvm_minidump_vatop(kvm_t
*kd
, u_long va
, off_t
*pa
)
213 offset
= va
& (PAGE_SIZE
- 1);
215 if (va
>= vm
->hdr
.kernbase
) {
216 pteindex
= (va
- vm
->hdr
.kernbase
) >> PAGE_SHIFT
;
217 pte
= ptemap
[pteindex
];
218 if ((pte
& PG_V
) == 0) {
219 _kvm_err(kd
, kd
->program
, "_kvm_vatop: pte not valid");
223 ofs
= hpt_find(kd
, a
);
225 _kvm_err(kd
, kd
->program
, "_kvm_vatop: physical address 0x%lx not in minidump", a
);
229 return (PAGE_SIZE
- offset
);
231 _kvm_err(kd
, kd
->program
, "_kvm_vatop: virtual address 0x%lx not minidumped", va
);
236 _kvm_err(kd
, 0, "invalid address (0x%lx)", va
);
241 _kvm_minidump_kvatop(kvm_t
*kd
, u_long va
, off_t
*pa
)
244 if (kvm_ishost(kd
)) {
245 _kvm_err(kd
, 0, "vatop called in live kernel!");
249 return (_kvm_minidump_vatop(kd
, va
, pa
));