Skip to content

Commit aab2783

Browse files
author
Delphix Engineering
committed
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
2 parents f9810dc + d456847 commit aab2783

17 files changed

+438
-0
lines changed

include/libkdumpfile/addrxlat.h.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ typedef enum _addrxlat_sym_type {
263263
* - @c val = @c offsetof(args[0],args[1])
264264
*/
265265
ADDRXLAT_SYM_OFFSETOF,
266+
267+
/** Number value.
268+
* Input:
269+
* - @c args[0] = number name
270+
* Output:
271+
* - @c val = number value
272+
*/
273+
ADDRXLAT_SYM_NUMBER,
266274
} addrxlat_sym_type_t;
267275

268276
/** Maximum argument count for @ref addrxlat_sym_t. */
@@ -281,6 +289,7 @@ addrxlat_sym_argc(addrxlat_sym_type_t type)
281289
case ADDRXLAT_SYM_REG:
282290
case ADDRXLAT_SYM_VALUE:
283291
case ADDRXLAT_SYM_SIZEOF:
292+
case ADDRXLAT_SYM_NUMBER:
284293
return 1;
285294

286295
case ADDRXLAT_SYM_OFFSETOF:

src/addrxlat/aarch64.c

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <stdlib.h>
3232

3333
#include "addrxlat-priv.h"
34+
#include <linux/version.h>
3435

3536
/* Maximum physical address bits (architectural limit) */
3637
#define PA_MAX_BITS 48
@@ -140,3 +141,201 @@ pgt_aarch64(addrxlat_step_t *step)
140141

141142
return ADDRXLAT_OK;
142143
}
144+
145+
#define is_linear_addr(addr, kernel_ver, va_bits) \
146+
(((kernel_ver) < KERNEL_VERSION(5, 4, 0)) ? \
147+
(!!((unsigned long)(addr) & (1UL << ((va_bits) - 1)))) : \
148+
(!((unsigned long)(addr) & (1UL << ((va_bits) - 1)))))
149+
150+
static unsigned long
151+
get_page_offset(unsigned long kernel_ver, addrxlat_addr_t va_bits) {
152+
unsigned long page_offset;
153+
154+
if (kernel_ver < KERNEL_VERSION(5, 4, 0))
155+
page_offset = ((0xffffffffffffffffUL) -
156+
((1UL) << (va_bits - 1)) + 1);
157+
else
158+
page_offset = (-(1UL << va_bits));
159+
return page_offset;
160+
}
161+
162+
/** Determine Linux page table root.
163+
* @param ctl Initialization data.
164+
* @param[out] root Page table root address (set on successful return).
165+
* @returns Error status.
166+
*/
167+
static addrxlat_status
168+
get_linux_pgtroot(struct os_init_data *ctl, addrxlat_fulladdr_t *root)
169+
{
170+
addrxlat_status status;
171+
addrxlat_addr_t root_va;
172+
173+
addrxlat_addr_t va_bits;
174+
addrxlat_addr_t phys_base;
175+
addrxlat_addr_t kimage_voffset;
176+
int no_kimage_voffset = 0;
177+
178+
unsigned long page_offset;
179+
unsigned long kernel_ver;
180+
181+
182+
status = get_symval(ctl->ctx, "swapper_pg_dir",
183+
&root_va);
184+
if (status != ADDRXLAT_OK)
185+
return set_error(ctl->ctx, status,
186+
"Cannot determine page table virtual address");
187+
188+
/*
189+
* This code will only work with vmcores produced by
190+
* Linux Kernel versions 4.12 and above. Makedumpfile
191+
* for kernels before 4.12 uses a heuristic based on
192+
* reading vmcore load segment addressess and finds
193+
* va_bits and phys_offset. This code does not support
194+
* such logic.
195+
*/
196+
status = get_number(ctl->ctx, "VA_BITS",
197+
&va_bits);
198+
if (status != ADDRXLAT_OK)
199+
return set_error(ctl->ctx, status,
200+
"Cannot determine VA_BITS");
201+
202+
status = get_number(ctl->ctx, "kimage_voffset" ,
203+
&kimage_voffset);
204+
if (status != ADDRXLAT_OK)
205+
no_kimage_voffset = 1;
206+
207+
kernel_ver = ctl->osdesc->ver;
208+
209+
210+
if (no_kimage_voffset || is_linear_addr(root_va, kernel_ver, va_bits)) {
211+
status = get_number(ctl->ctx, "PHYS_OFFSET" ,
212+
&phys_base);
213+
if (status != ADDRXLAT_OK)
214+
return set_error(ctl->ctx, status,
215+
"Cannot determine PHYS_OFFSET");
216+
217+
page_offset = get_page_offset(kernel_ver, va_bits);
218+
219+
if (kernel_ver < KERNEL_VERSION(5, 4, 0)) {
220+
root->addr = ((root_va & ~page_offset) + phys_base);
221+
} else {
222+
root->addr = (root_va + phys_base - page_offset);
223+
}
224+
} else {
225+
root->addr = root_va - kimage_voffset;
226+
}
227+
228+
root->as = ADDRXLAT_KPHYSADDR;
229+
230+
return ADDRXLAT_OK;
231+
}
232+
233+
/* Maximum physical address bits (architectural limit) */
234+
#define PHYSADDR_BITS_MAX 52
235+
#define PHYSADDR_MASK ADDR_MASK(PHYSADDR_BITS_MAX)
236+
#define VIRTADDR_MAX UINT64_MAX
237+
238+
239+
/** Initialize a translation map for Linux/aarch64.
240+
* @param ctl Initialization data.
241+
* @returns Error status.
242+
*/
243+
static addrxlat_status
244+
map_linux_aarch64(struct os_init_data *ctl)
245+
{
246+
static const addrxlat_paging_form_t aarch64_pf = {
247+
.pte_format = ADDRXLAT_PTE_AARCH64,
248+
.nfields = 5,
249+
.fieldsz = { 12, 9, 9, 9, 9, 9 }
250+
};
251+
252+
/*
253+
* Generic aarch64 layout, depends on current va_bits
254+
*
255+
* Aarch64 kernel does have a linear mapping region, the location
256+
* of which changed in the 5.4 kernel. But since it is covered
257+
* by swapper pgt anyway we don't bother to reflect it here.
258+
*/
259+
struct sys_region aarch64_layout_generic[] = {
260+
{ 0, 0, /* lower half */
261+
ADDRXLAT_SYS_METH_PGT },
262+
263+
{ 0, VIRTADDR_MAX, /* higher half */
264+
ADDRXLAT_SYS_METH_PGT },
265+
SYS_REGION_END
266+
};
267+
268+
addrxlat_map_t *map;
269+
addrxlat_meth_t *meth;
270+
addrxlat_status status;
271+
addrxlat_addr_t va_bits;
272+
273+
meth = &ctl->sys->meth[ADDRXLAT_SYS_METH_PGT];
274+
meth->kind = ADDRXLAT_PGT;
275+
meth->target_as = ADDRXLAT_MACHPHYSADDR;
276+
277+
if (ctl->popt.val[OPT_rootpgt].set)
278+
meth->param.pgt.root = ctl->popt.val[OPT_rootpgt].fulladdr;
279+
else {
280+
status = get_linux_pgtroot(ctl, &meth->param.pgt.root);
281+
if (status != ADDRXLAT_OK)
282+
return status;
283+
}
284+
285+
meth->param.pgt.pte_mask =
286+
opt_num_default(&ctl->popt, OPT_pte_mask, 0);
287+
meth->param.pgt.pf = aarch64_pf;
288+
289+
status = get_number(ctl->ctx, "VA_BITS",
290+
&va_bits);
291+
if (status != ADDRXLAT_OK)
292+
return set_error(ctl->ctx, status,
293+
"Cannot determine VA_BITS");
294+
295+
if (ctl->popt.val[OPT_levels].set) {
296+
long levels = ctl->popt.val[OPT_levels].num;
297+
if (levels < 3 || levels > 5)
298+
return bad_paging_levels(ctl->ctx, levels);
299+
meth->param.pgt.pf.nfields = levels + 1;
300+
} else
301+
meth->param.pgt.pf.nfields = ((va_bits - 12) / 9) + 1;
302+
303+
/* layout depends on current value of va_bits */
304+
aarch64_layout_generic[0].last = ~(-(1ull) << (va_bits));
305+
aarch64_layout_generic[1].first = (-(1ull) << (va_bits));
306+
307+
status = sys_set_layout(ctl, ADDRXLAT_SYS_MAP_HW,
308+
aarch64_layout_generic);
309+
if (status != ADDRXLAT_OK)
310+
return status;
311+
312+
map = internal_map_copy(ctl->sys->map[ADDRXLAT_SYS_MAP_HW]);
313+
if (!map)
314+
return set_error(ctl->ctx, ADDRXLAT_ERR_NOMEM,
315+
"Cannot duplicate hardware mapping");
316+
ctl->sys->map[ADDRXLAT_SYS_MAP_KV_PHYS] = map;
317+
318+
status = sys_set_physmaps(ctl, PHYSADDR_MASK);
319+
if (status != ADDRXLAT_OK)
320+
return status;
321+
322+
return ADDRXLAT_OK;
323+
}
324+
325+
326+
/** Initialize a translation map for an aarch64 OS.
327+
* @param ctl Initialization data.
328+
* @returns Error status.
329+
*/
330+
addrxlat_status
331+
sys_aarch64(struct os_init_data *ctl)
332+
{
333+
switch (ctl->osdesc->type) {
334+
case ADDRXLAT_OS_LINUX:
335+
return map_linux_aarch64(ctl);
336+
337+
default:
338+
return set_error(ctl->ctx, ADDRXLAT_ERR_NOTIMPL,
339+
"OS type not implemented");
340+
}
341+
}

src/addrxlat/addrxlat-priv.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ INTERNAL_DECL(addrxlat_status, get_offsetof,
178178
(addrxlat_ctx_t *ctx, const char *type, const char *memb,
179179
addrxlat_addr_t *off));
180180

181+
INTERNAL_DECL(addrxlat_status, get_number,
182+
(addrxlat_ctx_t *ctx, const char *name, addrxlat_addr_t *num));
183+
181184
/** Maximum symbol specifier name length. */
182185
#define SYM_SPEC_NAMELEN 24
183186

@@ -457,6 +460,8 @@ struct os_init_data {
457460
*/
458461
typedef addrxlat_status sys_arch_fn(struct os_init_data *ctl);
459462

463+
INTERNAL_DECL(sys_arch_fn, sys_aarch64, );
464+
460465
INTERNAL_DECL(sys_arch_fn, sys_ia32, );
461466

462467
INTERNAL_DECL(sys_arch_fn, sys_ppc64, );

src/addrxlat/ctx.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,36 @@ get_offsetof(addrxlat_ctx_t *ctx, const char *type, const char *memb,
546546
return status;
547547
}
548548

549+
/** Resolve a number value.
550+
* @param ctx Address translation context.
551+
* @param name Number name.
552+
* @param[out] num Number value returned on success.
553+
* @returns Error status.
554+
*
555+
* The size is determined using a user-supplied callback.
556+
*/
557+
addrxlat_status
558+
get_number(addrxlat_ctx_t *ctx, const char *name, addrxlat_addr_t *num)
559+
{
560+
addrxlat_sym_t sym;
561+
addrxlat_status status;
562+
563+
if (!ctx->cb.sym)
564+
return set_error(ctx, ADDRXLAT_ERR_NODATA,
565+
"No symbolic information callback");
566+
567+
sym.type = ADDRXLAT_SYM_NUMBER;
568+
sym.args[0] = name;
569+
status = ctx->cb.sym(ctx->cb.data, &sym);
570+
if (status != ADDRXLAT_OK)
571+
return set_error(ctx, status, "Cannot get number(%s)",
572+
sym.args[0]);
573+
574+
*num = sym.val;
575+
return status;
576+
}
577+
578+
549579
/** Get the first successfuly resolved value from a specifier list.
550580
* @param ctx Address translation context.
551581
* @param spec Vector of specifiers.

src/addrxlat/sys.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ addrxlat_sys_os_init(addrxlat_sys_t *sys, addrxlat_ctx_t *ctx,
9898
arch_fn = sys_s390x;
9999
else if (!strcmp(osdesc->arch, "ppc64"))
100100
arch_fn = sys_ppc64;
101+
else if (!strcmp(osdesc->arch, "aarch64"))
102+
arch_fn = sys_aarch64;
101103
else
102104
return set_error(ctx, ADDRXLAT_ERR_NOTIMPL,
103105
"Unsupported architecture");

src/kdumpfile/vtop.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,12 @@ addrxlat_sym(void *data, addrxlat_sym_t *sym)
578578
{ ADDRXLAT_OS_UNKNOWN }
579579
};
580580

581+
static const struct ostype_attr_map number_map[] = {
582+
{ ADDRXLAT_OS_LINUX, GKI_linux_number },
583+
{ ADDRXLAT_OS_XEN, GKI_xen_number },
584+
{ ADDRXLAT_OS_UNKNOWN }
585+
};
586+
581587
kdump_ctx_t *ctx = (kdump_ctx_t*) data;
582588
const struct attr_data *base;
583589
struct attr_data *attr;
@@ -608,6 +614,14 @@ addrxlat_sym(void *data, addrxlat_sym_t *sym)
608614
"Unsupported OS");
609615
break;
610616

617+
case ADDRXLAT_SYM_NUMBER:
618+
base = ostype_attr(ctx, number_map);
619+
if (!base)
620+
return addrxlat_ctx_err(
621+
ctx->xlatctx, ADDRXLAT_ERR_NOTIMPL,
622+
"Unsupported OS");
623+
break;
624+
611625
case ADDRXLAT_SYM_REG:
612626
rwlock_rdlock(&ctx->shared->lock);
613627
base = lookup_attr(ctx->dict, "cpu.0.reg");

tests/Makefile.am

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ test_scripts = \
228228
xlat-os-s390x-4l \
229229
xlat-os-s390x-5l \
230230
xlat-os-x86_64-none \
231+
xlat-linux-aarch64-5.2-va39 \
232+
xlat-linux-aarch64-5.8-va39 \
233+
xlat-linux-aarch64-5.8-va48 \
231234
xlat-linux-ia32 \
232235
xlat-linux-ia32-pae \
233236
xlat-linux-ppc64-64k \
@@ -327,6 +330,12 @@ dist_check_DATA = \
327330
xlat-os-s390x-5l.data \
328331
xlat-os-s390x-5l.expect \
329332
xlat-os-x86_64-none.expect \
333+
xlat-linux-aarch64-5.2-va39.expect \
334+
xlat-linux-aarch64-5.2-va39.sym \
335+
xlat-linux-aarch64-5.8-va39.expect \
336+
xlat-linux-aarch64-5.8-va39.sym \
337+
xlat-linux-aarch64-5.8-va48.expect \
338+
xlat-linux-aarch64-5.8-va48.sym \
330339
xlat-linux-ia32.data \
331340
xlat-linux-ia32.expect \
332341
xlat-linux-ia32-pae.data \

tests/xlat-linux-aarch64-5.2-va39

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#! /bin/sh
2+
3+
#
4+
# Check Linux 5.2 AArch64 translation with 39-bit virtual addresses
5+
# using data from VMCOREINFO.
6+
#
7+
8+
arch=aarch64
9+
ostype=1
10+
osver=0x050200
11+
opts=
12+
13+
. "$srcdir"/xlat-os-common
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
@rootpgt: PGT
2+
target_as=MACHPHYSADDR
3+
root=KPHYSADDR:0x40b82000
4+
pte_mask=0x0
5+
pte_format=aarch64
6+
fields=12,9,9,9
7+
8+
@machphys_kphys: LINEAR
9+
target_as=KPHYSADDR
10+
off=0x0
11+
12+
@kphys_machphys: LINEAR
13+
target_as=MACHPHYSADDR
14+
off=0x0
15+
16+
KV -> HW:
17+
0-7fffffffff: @rootpgt
18+
8000000000-ffffff7fffffffff: NONE
19+
ffffff8000000000-ffffffffffffffff: @rootpgt
20+
21+
KV -> PHYS:
22+
0-7fffffffff: @rootpgt
23+
8000000000-ffffff7fffffffff: NONE
24+
ffffff8000000000-ffffffffffffffff: @rootpgt
25+
26+
KPHYS -> DIRECT:
27+
28+
MACHPHYS -> KPHYS:
29+
0-fffffffffffff: @machphys_kphys
30+
10000000000000-ffffffffffffffff: NONE
31+
32+
KPHYS -> MACHPHYS:
33+
0-fffffffffffff: @kphys_machphys
34+
10000000000000-ffffffffffffffff: NONE

0 commit comments

Comments
 (0)