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
;
55 unsigned char ei_data
;
59 _arm_minidump_probe(kvm_t
*kd
)
62 return (_kvm_probe_elf_kernel(kd
, ELFCLASS32
, EM_ARM
) &&
63 _kvm_is_minidump(kd
));
67 _arm_minidump_freevtop(kvm_t
*kd
)
69 struct vmstate
*vm
= kd
->vmst
;
77 _arm_minidump_initvtop(kvm_t
*kd
)
80 off_t off
, sparse_off
;
82 vmst
= _kvm_malloc(kd
, sizeof(*vmst
));
84 _kvm_err(kd
, kd
->program
, "cannot allocate vm");
90 if (pread(kd
->pmfd
, &vmst
->hdr
,
91 sizeof(vmst
->hdr
), 0) != sizeof(vmst
->hdr
)) {
92 _kvm_err(kd
, kd
->program
, "cannot read dump header");
96 if (strncmp(MINIDUMP_MAGIC
, vmst
->hdr
.magic
,
97 sizeof(vmst
->hdr
.magic
)) != 0) {
98 _kvm_err(kd
, kd
->program
, "not a minidump for this platform");
101 vmst
->hdr
.version
= _kvm32toh(kd
, vmst
->hdr
.version
);
102 if (vmst
->hdr
.version
!= MINIDUMP_VERSION
) {
103 _kvm_err(kd
, kd
->program
, "wrong minidump version. "
104 "Expected %d got %d", MINIDUMP_VERSION
, vmst
->hdr
.version
);
107 vmst
->hdr
.msgbufsize
= _kvm32toh(kd
, vmst
->hdr
.msgbufsize
);
108 vmst
->hdr
.bitmapsize
= _kvm32toh(kd
, vmst
->hdr
.bitmapsize
);
109 vmst
->hdr
.ptesize
= _kvm32toh(kd
, vmst
->hdr
.ptesize
);
110 vmst
->hdr
.kernbase
= _kvm32toh(kd
, vmst
->hdr
.kernbase
);
111 vmst
->hdr
.arch
= _kvm32toh(kd
, vmst
->hdr
.arch
);
112 vmst
->hdr
.mmuformat
= _kvm32toh(kd
, vmst
->hdr
.mmuformat
);
113 if (vmst
->hdr
.mmuformat
== MINIDUMP_MMU_FORMAT_UNKNOWN
) {
114 /* This is a safe default as 1K pages are not used. */
115 vmst
->hdr
.mmuformat
= MINIDUMP_MMU_FORMAT_V6
;
118 /* Skip header and msgbuf */
119 off
= ARM_PAGE_SIZE
+ arm_round_page(vmst
->hdr
.msgbufsize
);
121 sparse_off
= off
+ arm_round_page(vmst
->hdr
.bitmapsize
) +
122 arm_round_page(vmst
->hdr
.ptesize
);
123 if (_kvm_pt_init(kd
, vmst
->hdr
.bitmapsize
, off
, sparse_off
,
124 ARM_PAGE_SIZE
, sizeof(uint32_t)) == -1) {
125 _kvm_err(kd
, kd
->program
, "cannot load core bitmap");
128 off
+= arm_round_page(vmst
->hdr
.bitmapsize
);
130 vmst
->ptemap
= _kvm_malloc(kd
, vmst
->hdr
.ptesize
);
131 if (vmst
->ptemap
== NULL
) {
132 _kvm_err(kd
, kd
->program
, "cannot allocate %d bytes for "
133 "ptemap", vmst
->hdr
.ptesize
);
137 if (pread(kd
->pmfd
, vmst
->ptemap
, vmst
->hdr
.ptesize
, off
) !=
138 (ssize_t
)vmst
->hdr
.ptesize
) {
139 _kvm_err(kd
, kd
->program
, "cannot read %d bytes for ptemap",
143 off
+= arm_round_page(vmst
->hdr
.ptesize
);
149 _arm_minidump_kvatop(kvm_t
*kd
, kvaddr_t va
, off_t
*pa
)
153 arm_physaddr_t offset
, a
;
156 arm_pt_entry_t
*ptemap
;
159 _kvm_err(kd
, 0, "_arm_minidump_kvatop called in live kernel!");
166 if (va
>= vm
->hdr
.kernbase
) {
167 pteindex
= (va
- vm
->hdr
.kernbase
) >> ARM_PAGE_SHIFT
;
168 if (pteindex
>= vm
->hdr
.ptesize
/ sizeof(*ptemap
))
170 pte
= _kvm32toh(kd
, ptemap
[pteindex
]);
171 if ((pte
& ARM_L2_TYPE_MASK
) == ARM_L2_TYPE_INV
) {
172 _kvm_err(kd
, kd
->program
,
173 "_arm_minidump_kvatop: pte not valid");
176 if ((pte
& ARM_L2_TYPE_MASK
) == ARM_L2_TYPE_L
) {
177 /* 64K page -> convert to be like 4K page */
178 offset
= va
& ARM_L2_S_OFFSET
;
179 a
= (pte
& ARM_L2_L_FRAME
) +
180 (va
& ARM_L2_L_OFFSET
& ARM_L2_S_FRAME
);
182 if (kd
->vmst
->hdr
.mmuformat
== MINIDUMP_MMU_FORMAT_V4
&&
183 (pte
& ARM_L2_TYPE_MASK
) == ARM_L2_TYPE_T
) {
184 _kvm_err(kd
, kd
->program
,
185 "_arm_minidump_kvatop: pte not supported");
189 offset
= va
& ARM_L2_S_OFFSET
;
190 a
= pte
& ARM_L2_S_FRAME
;
193 ofs
= _kvm_pt_find(kd
, a
);
195 _kvm_err(kd
, kd
->program
, "_arm_minidump_kvatop: "
196 "physical address 0x%jx not in minidump",
202 return (ARM_PAGE_SIZE
- offset
);
204 _kvm_err(kd
, kd
->program
, "_arm_minidump_kvatop: virtual "
205 "address 0x%jx not minidumped", (uintmax_t)va
);
208 _kvm_err(kd
, 0, "invalid address (0x%jx)", (uintmax_t)va
);
212 struct kvm_arch kvm_arm_minidump
= {
213 .ka_probe
= _arm_minidump_probe
,
214 .ka_initvtop
= _arm_minidump_initvtop
,
215 .ka_freevtop
= _arm_minidump_freevtop
,
216 .ka_kvatop
= _arm_minidump_kvatop
,
217 .ka_native
= _arm_native
,
220 KVM_ARCH(kvm_arm_minidump
);