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
27 * AMD64 machine dependent routines for kvm and minidumps.
30 #include <sys/user.h> /* MUST BE FIRST */
31 #include <sys/param.h>
35 #include <sys/fnv_hash.h>
44 #include <vm/vm_param.h>
46 #include <machine/elf.h>
47 #include <machine/cpufunc.h>
48 #include <machine/minidump.h>
52 #include "kvm_private.h"
62 /* minidump must be the first item! */
64 int minidump
; /* 1 = minidump mode */
65 struct minidumphdr hdr
;
66 void *hpt_head
[HPT_SIZE
];
72 hpt_insert(kvm_t
*kd
, vm_paddr_t pa
, int64_t off
)
75 uint32_t fnv
= FNV1_32_INIT
;
77 fnv
= fnv_32_buf(&pa
, sizeof(pa
), fnv
);
78 fnv
&= (HPT_SIZE
- 1);
79 hpte
= malloc(sizeof(*hpte
));
82 hpte
->next
= kd
->vmst
->hpt_head
[fnv
];
83 kd
->vmst
->hpt_head
[fnv
] = hpte
;
87 hpt_find(kvm_t
*kd
, vm_paddr_t pa
)
90 uint32_t fnv
= FNV1_32_INIT
;
92 fnv
= fnv_32_buf(&pa
, sizeof(pa
), fnv
);
93 fnv
&= (HPT_SIZE
- 1);
94 for (hpte
= kd
->vmst
->hpt_head
[fnv
]; hpte
!= NULL
; hpte
= hpte
->next
) {
102 inithash(kvm_t
*kd
, uint64_t *base
, int len
, off_t off
)
108 for (idx
= 0; idx
< len
/ sizeof(*base
); idx
++) {
112 bits
&= ~(1ul << bit
);
113 pa
= (idx
* sizeof(*base
) * NBBY
+ bit
) * PAGE_SIZE
;
114 hpt_insert(kd
, pa
, off
);
122 _kvm_minidump_freevtop(kvm_t
*kd
)
124 struct vmstate
*vm
= kd
->vmst
;
135 _kvm_minidump_initvtop(kvm_t
*kd
)
137 struct vmstate
*vmst
;
140 vmst
= _kvm_malloc(kd
, sizeof(*vmst
));
142 _kvm_err(kd
, kd
->program
, "cannot allocate vm");
146 bzero(vmst
, sizeof(*vmst
));
148 if (pread(kd
->pmfd
, &vmst
->hdr
, sizeof(vmst
->hdr
), 0) !=
150 _kvm_err(kd
, kd
->program
, "cannot read dump header");
153 if (strncmp(MINIDUMP_MAGIC
, vmst
->hdr
.magic
, sizeof(vmst
->hdr
.magic
)) != 0) {
154 _kvm_err(kd
, kd
->program
, "not a minidump for this platform");
157 if (vmst
->hdr
.version
!= MINIDUMP_VERSION
) {
158 _kvm_err(kd
, kd
->program
, "wrong minidump version. expected %d got %d",
159 MINIDUMP_VERSION
, vmst
->hdr
.version
);
163 /* Skip header and msgbuf */
164 off
= PAGE_SIZE
+ round_page(vmst
->hdr
.msgbufsize
);
166 vmst
->bitmap
= _kvm_malloc(kd
, vmst
->hdr
.bitmapsize
);
167 if (vmst
->bitmap
== NULL
) {
168 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for bitmap", vmst
->hdr
.bitmapsize
);
171 if (pread(kd
->pmfd
, vmst
->bitmap
, vmst
->hdr
.bitmapsize
, off
) !=
172 vmst
->hdr
.bitmapsize
) {
173 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for page bitmap", vmst
->hdr
.bitmapsize
);
176 off
+= round_page(vmst
->hdr
.bitmapsize
);
178 vmst
->ptemap
= _kvm_malloc(kd
, vmst
->hdr
.ptesize
);
179 if (vmst
->ptemap
== NULL
) {
180 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for ptemap", vmst
->hdr
.ptesize
);
183 if (pread(kd
->pmfd
, vmst
->ptemap
, vmst
->hdr
.ptesize
, off
) !=
185 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for ptemap", vmst
->hdr
.ptesize
);
188 off
+= vmst
->hdr
.ptesize
;
190 /* build physical address hash table for sparse pages */
191 inithash(kd
, vmst
->bitmap
, vmst
->hdr
.bitmapsize
, off
);
197 _kvm_minidump_vatop(kvm_t
*kd
, u_long va
, off_t
*pa
)
207 offset
= va
& (PAGE_SIZE
- 1);
209 if (va
>= vm
->hdr
.kernbase
) {
210 pteindex
= (va
- vm
->hdr
.kernbase
) >> PAGE_SHIFT
;
211 pte
= vm
->ptemap
[pteindex
];
212 if (((u_long
)pte
& X86_PG_V
) == 0) {
213 _kvm_err(kd
, kd
->program
, "_kvm_vatop: pte not valid");
217 ofs
= hpt_find(kd
, a
);
219 _kvm_err(kd
, kd
->program
, "_kvm_vatop: physical address 0x%lx not in minidump", a
);
223 return (PAGE_SIZE
- offset
);
224 } else if (va
>= vm
->hdr
.dmapbase
&& va
< vm
->hdr
.dmapend
) {
225 a
= (va
- vm
->hdr
.dmapbase
) & ~PAGE_MASK
;
226 ofs
= hpt_find(kd
, a
);
228 _kvm_err(kd
, kd
->program
, "_kvm_vatop: direct map address 0x%lx not in minidump", va
);
232 return (PAGE_SIZE
- offset
);
234 _kvm_err(kd
, kd
->program
, "_kvm_vatop: virtual address 0x%lx not minidumped", va
);
239 _kvm_err(kd
, 0, "invalid address (0x%lx)", va
);
244 _kvm_minidump_kvatop(kvm_t
*kd
, u_long va
, off_t
*pa
)
246 if (kvm_ishost(kd
)) {
247 _kvm_err(kd
, 0, "kvm_vatop called in live kernel!");
251 return (_kvm_minidump_vatop(kd
, va
, pa
));