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/param.h>
34 #include <sys/fnv_hash.h>
43 #include <vm/vm_param.h>
45 #include <machine/elf.h>
46 #include <machine/cpufunc.h>
47 #include <machine/minidump.h>
51 #include "kvm_private.h"
53 #define PG_FRAME_PAE (~((uint64_t)PAGE_MASK))
63 /* minidump must be the first item! */
65 int minidump
; /* 1 = minidump mode */
66 struct minidumphdr hdr
;
67 void *hpt_head
[HPT_SIZE
];
73 hpt_insert(kvm_t
*kd
, uint64_t pa
, int64_t off
)
76 uint32_t fnv
= FNV1_32_INIT
;
78 fnv
= fnv_32_buf(&pa
, sizeof(pa
), fnv
);
79 fnv
&= (HPT_SIZE
- 1);
80 hpte
= malloc(sizeof(*hpte
));
83 hpte
->next
= kd
->vmst
->hpt_head
[fnv
];
84 kd
->vmst
->hpt_head
[fnv
] = hpte
;
88 hpt_find(kvm_t
*kd
, uint64_t pa
)
91 uint32_t fnv
= FNV1_32_INIT
;
93 fnv
= fnv_32_buf(&pa
, sizeof(pa
), fnv
);
94 fnv
&= (HPT_SIZE
- 1);
95 for (hpte
= kd
->vmst
->hpt_head
[fnv
]; hpte
!= NULL
; hpte
= hpte
->next
) {
103 inithash(kvm_t
*kd
, uint32_t *base
, int len
, off_t off
)
109 for (idx
= 0; idx
< len
/ sizeof(*base
); idx
++) {
113 bits
&= ~(1ul << bit
);
114 pa
= (idx
* sizeof(*base
) * NBBY
+ bit
) * PAGE_SIZE
;
115 hpt_insert(kd
, pa
, off
);
123 _kvm_minidump_freevtop(kvm_t
*kd
)
125 struct vmstate
*vm
= kd
->vmst
;
136 _kvm_minidump_initvtop(kvm_t
*kd
)
138 struct vmstate
*vmst
;
141 vmst
= _kvm_malloc(kd
, sizeof(*vmst
));
143 _kvm_err(kd
, kd
->program
, "cannot allocate vm");
147 bzero(vmst
, sizeof(*vmst
));
149 if (pread(kd
->pmfd
, &vmst
->hdr
, sizeof(vmst
->hdr
), 0) !=
151 _kvm_err(kd
, kd
->program
, "cannot read dump header");
154 if (strncmp(MINIDUMP_MAGIC
, vmst
->hdr
.magic
, sizeof(vmst
->hdr
.magic
)) != 0) {
155 _kvm_err(kd
, kd
->program
, "not a minidump for this platform");
158 if (vmst
->hdr
.version
!= MINIDUMP_VERSION
) {
159 _kvm_err(kd
, kd
->program
, "wrong minidump version. expected %d got %d",
160 MINIDUMP_VERSION
, vmst
->hdr
.version
);
164 /* Skip header and msgbuf */
165 off
= PAGE_SIZE
+ round_page(vmst
->hdr
.msgbufsize
);
167 vmst
->bitmap
= _kvm_malloc(kd
, vmst
->hdr
.bitmapsize
);
168 if (vmst
->bitmap
== NULL
) {
169 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for bitmap", vmst
->hdr
.bitmapsize
);
172 if (pread(kd
->pmfd
, vmst
->bitmap
, vmst
->hdr
.bitmapsize
, off
) !=
173 vmst
->hdr
.bitmapsize
) {
174 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for page bitmap", vmst
->hdr
.bitmapsize
);
177 off
+= round_page(vmst
->hdr
.bitmapsize
);
179 vmst
->ptemap
= _kvm_malloc(kd
, vmst
->hdr
.ptesize
);
180 if (vmst
->ptemap
== NULL
) {
181 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for ptemap", vmst
->hdr
.ptesize
);
184 if (pread(kd
->pmfd
, vmst
->ptemap
, vmst
->hdr
.ptesize
, off
) !=
186 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for ptemap", vmst
->hdr
.ptesize
);
189 off
+= vmst
->hdr
.ptesize
;
191 /* build physical address hash table for sparse pages */
192 inithash(kd
, vmst
->bitmap
, vmst
->hdr
.bitmapsize
, off
);
198 _kvm_minidump_vatop(kvm_t
*kd
, u_long va
, off_t
*pa
)
210 offset
= va
& (PAGE_SIZE
- 1);
212 if (va
>= vm
->hdr
.kernbase
) {
213 pteindex
= (va
- vm
->hdr
.kernbase
) >> PAGE_SHIFT
;
214 pte
= ptemap
[pteindex
];
215 if ((pte
& PG_V
) == 0) {
216 _kvm_err(kd
, kd
->program
, "_kvm_vatop: pte not valid");
220 ofs
= hpt_find(kd
, a
);
222 _kvm_err(kd
, kd
->program
, "_kvm_vatop: physical address 0x%lx not in minidump", a
);
226 return (PAGE_SIZE
- offset
);
228 _kvm_err(kd
, kd
->program
, "_kvm_vatop: virtual address 0x%lx not minidumped", va
);
233 _kvm_err(kd
, 0, "invalid address (0x%lx)", va
);
238 _kvm_minidump_kvatop(kvm_t
*kd
, u_long va
, off_t
*pa
)
241 if (kvm_ishost(kd
)) {
242 _kvm_err(kd
, 0, "vatop called in live kernel!");
246 return (_kvm_minidump_vatop(kd
, va
, pa
));