2 * Copyright (c) 2008 Semihalf, Grzegorz Bernacki
3 * Copyright (c) 2006 Peter Wemm
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * From: FreeBSD: src/lib/libkvm/kvm_minidump_i386.c,v 1.2 2006/06/05 08:51:14
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
33 * ARM machine dependent routines for kvm and minidumps.
36 #include <sys/endian.h>
37 #include <sys/param.h>
45 #include "../../sys/arm/include/minidump.h"
47 #include "kvm_private.h"
50 #define arm_round_page(x) roundup2((kvaddr_t)(x), ARM_PAGE_SIZE)
53 struct minidumphdr hdr
;
56 unsigned char ei_data
;
60 _arm_minidump_probe(kvm_t
*kd
)
63 return (_kvm_probe_elf_kernel(kd
, ELFCLASS32
, EM_ARM
) &&
64 _kvm_is_minidump(kd
));
68 _arm_minidump_freevtop(kvm_t
*kd
)
70 struct vmstate
*vm
= kd
->vmst
;
72 _kvm_hpt_free(&vm
->hpt
);
80 _arm_minidump_initvtop(kvm_t
*kd
)
86 vmst
= _kvm_malloc(kd
, sizeof(*vmst
));
88 _kvm_err(kd
, kd
->program
, "cannot allocate vm");
94 if (pread(kd
->pmfd
, &vmst
->hdr
,
95 sizeof(vmst
->hdr
), 0) != sizeof(vmst
->hdr
)) {
96 _kvm_err(kd
, kd
->program
, "cannot read dump header");
100 if (strncmp(MINIDUMP_MAGIC
, vmst
->hdr
.magic
,
101 sizeof(vmst
->hdr
.magic
)) != 0) {
102 _kvm_err(kd
, kd
->program
, "not a minidump for this platform");
105 vmst
->hdr
.version
= _kvm32toh(kd
, vmst
->hdr
.version
);
106 if (vmst
->hdr
.version
!= MINIDUMP_VERSION
) {
107 _kvm_err(kd
, kd
->program
, "wrong minidump version. "
108 "Expected %d got %d", MINIDUMP_VERSION
, vmst
->hdr
.version
);
111 vmst
->hdr
.msgbufsize
= _kvm32toh(kd
, vmst
->hdr
.msgbufsize
);
112 vmst
->hdr
.bitmapsize
= _kvm32toh(kd
, vmst
->hdr
.bitmapsize
);
113 vmst
->hdr
.ptesize
= _kvm32toh(kd
, vmst
->hdr
.ptesize
);
114 vmst
->hdr
.kernbase
= _kvm32toh(kd
, vmst
->hdr
.kernbase
);
115 vmst
->hdr
.arch
= _kvm32toh(kd
, vmst
->hdr
.arch
);
116 vmst
->hdr
.mmuformat
= _kvm32toh(kd
, vmst
->hdr
.mmuformat
);
117 if (vmst
->hdr
.mmuformat
== MINIDUMP_MMU_FORMAT_UNKNOWN
) {
118 /* This is a safe default as 1K pages are not used. */
119 vmst
->hdr
.mmuformat
= MINIDUMP_MMU_FORMAT_V6
;
122 /* Skip header and msgbuf */
123 off
= ARM_PAGE_SIZE
+ arm_round_page(vmst
->hdr
.msgbufsize
);
125 bitmap
= _kvm_malloc(kd
, vmst
->hdr
.bitmapsize
);
126 if (bitmap
== NULL
) {
127 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for "
128 "bitmap", vmst
->hdr
.bitmapsize
);
132 if (pread(kd
->pmfd
, bitmap
, vmst
->hdr
.bitmapsize
, off
) !=
133 (ssize_t
)vmst
->hdr
.bitmapsize
) {
134 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for page bitmap",
135 vmst
->hdr
.bitmapsize
);
139 off
+= arm_round_page(vmst
->hdr
.bitmapsize
);
141 vmst
->ptemap
= _kvm_malloc(kd
, vmst
->hdr
.ptesize
);
142 if (vmst
->ptemap
== NULL
) {
143 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for "
144 "ptemap", vmst
->hdr
.ptesize
);
149 if (pread(kd
->pmfd
, vmst
->ptemap
, vmst
->hdr
.ptesize
, off
) !=
150 (ssize_t
)vmst
->hdr
.ptesize
) {
151 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for ptemap",
157 off
+= vmst
->hdr
.ptesize
;
159 /* Build physical address hash table for sparse pages */
160 _kvm_hpt_init(kd
, &vmst
->hpt
, bitmap
, vmst
->hdr
.bitmapsize
, off
,
161 ARM_PAGE_SIZE
, sizeof(*bitmap
));
168 _arm_minidump_kvatop(kvm_t
*kd
, kvaddr_t va
, off_t
*pa
)
172 arm_physaddr_t offset
, a
;
175 arm_pt_entry_t
*ptemap
;
178 _kvm_err(kd
, 0, "_arm_minidump_kvatop called in live kernel!");
185 if (va
>= vm
->hdr
.kernbase
) {
186 pteindex
= (va
- vm
->hdr
.kernbase
) >> ARM_PAGE_SHIFT
;
187 pte
= _kvm32toh(kd
, ptemap
[pteindex
]);
188 if ((pte
& ARM_L2_TYPE_MASK
) == ARM_L2_TYPE_INV
) {
189 _kvm_err(kd
, kd
->program
,
190 "_arm_minidump_kvatop: pte not valid");
193 if ((pte
& ARM_L2_TYPE_MASK
) == ARM_L2_TYPE_L
) {
194 /* 64K page -> convert to be like 4K page */
195 offset
= va
& ARM_L2_S_OFFSET
;
196 a
= (pte
& ARM_L2_L_FRAME
) +
197 (va
& ARM_L2_L_OFFSET
& ARM_L2_S_FRAME
);
199 if (kd
->vmst
->hdr
.mmuformat
== MINIDUMP_MMU_FORMAT_V4
&&
200 (pte
& ARM_L2_TYPE_MASK
) == ARM_L2_TYPE_T
) {
201 _kvm_err(kd
, kd
->program
,
202 "_arm_minidump_kvatop: pte not supported");
206 offset
= va
& ARM_L2_S_OFFSET
;
207 a
= pte
& ARM_L2_S_FRAME
;
210 ofs
= _kvm_hpt_find(&vm
->hpt
, a
);
212 _kvm_err(kd
, kd
->program
, "_arm_minidump_kvatop: "
213 "physical address 0x%jx not in minidump",
219 return (ARM_PAGE_SIZE
- offset
);
221 _kvm_err(kd
, kd
->program
, "_arm_minidump_kvatop: virtual "
222 "address 0x%jx not minidumped", (uintmax_t)va
);
225 _kvm_err(kd
, 0, "invalid address (0x%jx)", (uintmax_t)va
);
229 struct kvm_arch kvm_arm_minidump
= {
230 .ka_probe
= _arm_minidump_probe
,
231 .ka_initvtop
= _arm_minidump_initvtop
,
232 .ka_freevtop
= _arm_minidump_freevtop
,
233 .ka_kvatop
= _arm_minidump_kvatop
,
234 .ka_native
= _arm_native
,
237 KVM_ARCH(kvm_arm_minidump
);