2
* parse xen-specific informations out of elf kernel binaries.
5
#include "libelf-private.h"
7
/* ------------------------------------------------------------------------ */
10
static const char *const elf_xen_feature_names[] = {
11
[XENFEAT_writable_page_tables] = "writable_page_tables",
12
[XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
13
[XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
14
[XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
15
[XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
17
static const int elf_xen_features =
18
sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
20
int elf_xen_parse_features(const char *features,
27
if ( features == NULL )
30
for ( pos = 0; features[pos] != '\0'; pos += len )
32
memset(feature, 0, sizeof(feature));
33
for ( len = 0;; len++ )
35
if ( len >= sizeof(feature)-1 )
37
if ( features[pos + len] == '\0' )
39
if ( features[pos + len] == '|' )
44
feature[len] = features[pos + len];
47
for ( i = 0; i < elf_xen_features; i++ )
49
if ( !elf_xen_feature_names[i] )
51
if ( (required != NULL) && (feature[0] == '!') )
54
if ( !strcmp(feature + 1, elf_xen_feature_names[i]) )
56
elf_xen_feature_set(i, supported);
57
elf_xen_feature_set(i, required);
64
if ( !strcmp(feature, elf_xen_feature_names[i]) )
66
elf_xen_feature_set(i, supported);
71
if ( i == elf_xen_features )
78
/* ------------------------------------------------------------------------ */
81
int elf_xen_parse_note(struct elf_binary *elf,
82
struct elf_dom_parms *parms,
90
[XEN_ELFNOTE_ENTRY] = { "ENTRY", 0},
91
[XEN_ELFNOTE_HYPERCALL_PAGE] = { "HYPERCALL_PAGE", 0},
92
[XEN_ELFNOTE_VIRT_BASE] = { "VIRT_BASE", 0},
93
[XEN_ELFNOTE_INIT_P2M] = { "INIT_P2M", 0},
94
[XEN_ELFNOTE_PADDR_OFFSET] = { "PADDR_OFFSET", 0},
95
[XEN_ELFNOTE_HV_START_LOW] = { "HV_START_LOW", 0},
96
[XEN_ELFNOTE_XEN_VERSION] = { "XEN_VERSION", 1},
97
[XEN_ELFNOTE_GUEST_OS] = { "GUEST_OS", 1},
98
[XEN_ELFNOTE_GUEST_VERSION] = { "GUEST_VERSION", 1},
99
[XEN_ELFNOTE_LOADER] = { "LOADER", 1},
100
[XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1},
101
[XEN_ELFNOTE_FEATURES] = { "FEATURES", 1},
102
[XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1},
103
[XEN_ELFNOTE_SUSPEND_CANCEL] = { "SUSPEND_CANCEL", 0 },
107
const char *str = NULL;
109
int type = elf_uval(elf, note, type);
111
if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
112
(note_desc[type].name == NULL) )
114
elf_msg(elf, "%s: unknown xen elf note (0x%x)\n",
119
if ( note_desc[type].str )
121
str = elf_note_desc(elf, note);
122
elf_msg(elf, "%s: %s = \"%s\"\n", __FUNCTION__,
123
note_desc[type].name, str);
124
parms->elf_notes[type].type = XEN_ENT_STR;
125
parms->elf_notes[type].data.str = str;
129
val = elf_note_numeric(elf, note);
130
elf_msg(elf, "%s: %s = 0x%" PRIx64 "\n", __FUNCTION__,
131
note_desc[type].name, val);
132
parms->elf_notes[type].type = XEN_ENT_LONG;
133
parms->elf_notes[type].data.num = val;
135
parms->elf_notes[type].name = note_desc[type].name;
139
case XEN_ELFNOTE_LOADER:
140
safe_strcpy(parms->loader, str);
142
case XEN_ELFNOTE_GUEST_OS:
143
safe_strcpy(parms->guest_os, str);
145
case XEN_ELFNOTE_GUEST_VERSION:
146
safe_strcpy(parms->guest_ver, str);
148
case XEN_ELFNOTE_XEN_VERSION:
149
safe_strcpy(parms->xen_ver, str);
151
case XEN_ELFNOTE_PAE_MODE:
152
if ( !strcmp(str, "yes") )
153
parms->pae = 2 /* extended_cr3 */;
154
if ( strstr(str, "bimodal") )
155
parms->pae = 3 /* bimodal */;
157
case XEN_ELFNOTE_BSD_SYMTAB:
158
if ( !strcmp(str, "yes") )
159
parms->bsd_symtab = 1;
162
case XEN_ELFNOTE_VIRT_BASE:
163
parms->virt_base = val;
165
case XEN_ELFNOTE_ENTRY:
166
parms->virt_entry = val;
168
case XEN_ELFNOTE_INIT_P2M:
169
parms->p2m_base = val;
171
case XEN_ELFNOTE_PADDR_OFFSET:
172
parms->elf_paddr_offset = val;
174
case XEN_ELFNOTE_HYPERCALL_PAGE:
175
parms->virt_hypercall = val;
177
case XEN_ELFNOTE_HV_START_LOW:
178
parms->virt_hv_start_low = val;
181
case XEN_ELFNOTE_FEATURES:
182
if ( elf_xen_parse_features(str, parms->f_supported,
191
static int elf_xen_parse_notes(struct elf_binary *elf,
192
struct elf_dom_parms *parms,
193
const void *start, const void *end)
195
int xen_elfnotes = 0;
196
const elf_note *note;
198
parms->elf_note_start = start;
199
parms->elf_note_end = end;
200
for ( note = parms->elf_note_start;
201
(void *)note < parms->elf_note_end;
202
note = elf_note_next(elf, note) )
204
if ( strcmp(elf_note_name(elf, note), "Xen") )
206
if ( elf_xen_parse_note(elf, parms, note) )
213
/* ------------------------------------------------------------------------ */
214
/* __xen_guest section */
216
int elf_xen_parse_guest_info(struct elf_binary *elf,
217
struct elf_dom_parms *parms)
220
char name[32], value[128];
223
h = parms->guest_info;
226
memset(name, 0, sizeof(name));
227
memset(value, 0, sizeof(value));
228
for ( len = 0;; len++, h++ )
230
if ( len >= sizeof(name)-1 )
242
for ( len = 0;; len++, h++ )
244
if ( len >= sizeof(value)-1 )
259
elf_msg(elf, "%s: %s=\"%s\"\n", __FUNCTION__, name, value);
262
if ( !strcmp(name, "LOADER") )
263
safe_strcpy(parms->loader, value);
264
if ( !strcmp(name, "GUEST_OS") )
265
safe_strcpy(parms->guest_os, value);
266
if ( !strcmp(name, "GUEST_VER") )
267
safe_strcpy(parms->guest_ver, value);
268
if ( !strcmp(name, "XEN_VER") )
269
safe_strcpy(parms->xen_ver, value);
270
if ( !strcmp(name, "PAE") )
272
if ( !strcmp(value, "yes[extended-cr3]") )
273
parms->pae = 2 /* extended_cr3 */;
274
else if ( !strncmp(value, "yes", 3) )
275
parms->pae = 1 /* yes */;
277
if ( !strcmp(name, "BSD_SYMTAB") )
278
parms->bsd_symtab = 1;
281
if ( !strcmp(name, "VIRT_BASE") )
282
parms->virt_base = strtoull(value, NULL, 0);
283
if ( !strcmp(name, "VIRT_ENTRY") )
284
parms->virt_entry = strtoull(value, NULL, 0);
285
if ( !strcmp(name, "ELF_PADDR_OFFSET") )
286
parms->elf_paddr_offset = strtoull(value, NULL, 0);
287
if ( !strcmp(name, "HYPERCALL_PAGE") )
288
parms->virt_hypercall = (strtoull(value, NULL, 0) << 12) +
292
if ( !strcmp(name, "FEATURES") )
293
if ( elf_xen_parse_features(value, parms->f_supported,
300
/* ------------------------------------------------------------------------ */
303
static int elf_xen_note_check(struct elf_binary *elf,
304
struct elf_dom_parms *parms)
306
if ( (parms->elf_note_start == NULL) && (parms->guest_info == NULL) )
308
int machine = elf_uval(elf, elf->ehdr, e_machine);
309
if ( (machine == EM_386) || (machine == EM_X86_64) )
311
elf_err(elf, "%s: ERROR: Not a Xen-ELF image: "
312
"No ELF notes or '__xen_guest' section found.\n",
319
/* Check the contents of the Xen notes or guest string. */
320
if ( ((strlen(parms->loader) == 0) ||
321
strncmp(parms->loader, "generic", 7)) &&
322
((strlen(parms->guest_os) == 0) ||
323
strncmp(parms->guest_os, "linux", 5)) )
325
elf_err(elf, "%s: ERROR: Will only load images built for the generic "
326
"loader or Linux images", __FUNCTION__);
330
if ( (strlen(parms->xen_ver) == 0) ||
331
strncmp(parms->xen_ver, "xen-3.0", 7) )
333
elf_err(elf, "%s: ERROR: Xen will only load images built "
334
"for Xen v3.0\n", __FUNCTION__);
340
static int elf_xen_addr_calc_check(struct elf_binary *elf,
341
struct elf_dom_parms *parms)
343
if ( (parms->elf_paddr_offset != UNSET_ADDR) &&
344
(parms->virt_base == UNSET_ADDR) )
346
elf_err(elf, "%s: ERROR: ELF_PADDR_OFFSET set, VIRT_BASE unset\n",
351
/* Initial guess for virt_base is 0 if it is not explicitly defined. */
352
if ( parms->virt_base == UNSET_ADDR )
354
parms->virt_base = 0;
355
elf_msg(elf, "%s: VIRT_BASE unset, using 0x%" PRIx64 "\n",
356
__FUNCTION__, parms->virt_base);
360
* If we are using the legacy __xen_guest section then elf_pa_off
361
* defaults to v_start in order to maintain compatibility with
362
* older hypervisors which set padd in the ELF header to
365
* If we are using the modern ELF notes interface then the default
368
if ( parms->elf_paddr_offset == UNSET_ADDR )
370
if ( parms->elf_note_start )
371
parms->elf_paddr_offset = 0;
373
parms->elf_paddr_offset = parms->virt_base;
374
elf_msg(elf, "%s: ELF_PADDR_OFFSET unset, using 0x%" PRIx64 "\n",
375
__FUNCTION__, parms->elf_paddr_offset);
378
parms->virt_offset = parms->virt_base - parms->elf_paddr_offset;
379
parms->virt_kstart = elf->pstart + parms->virt_offset;
380
parms->virt_kend = elf->pend + parms->virt_offset;
382
if ( parms->virt_entry == UNSET_ADDR )
383
parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
385
if ( parms->bsd_symtab )
387
elf_parse_bsdsyms(elf, parms->virt_kend);
388
if ( elf->bsd_symtab_pend )
389
parms->virt_kend = elf->bsd_symtab_pend + parms->virt_offset;
392
elf_msg(elf, "%s: addresses:\n", __FUNCTION__);
393
elf_msg(elf, " virt_base = 0x%" PRIx64 "\n", parms->virt_base);
394
elf_msg(elf, " elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
395
elf_msg(elf, " virt_offset = 0x%" PRIx64 "\n", parms->virt_offset);
396
elf_msg(elf, " virt_kstart = 0x%" PRIx64 "\n", parms->virt_kstart);
397
elf_msg(elf, " virt_kend = 0x%" PRIx64 "\n", parms->virt_kend);
398
elf_msg(elf, " virt_entry = 0x%" PRIx64 "\n", parms->virt_entry);
399
elf_msg(elf, " p2m_base = 0x%" PRIx64 "\n", parms->p2m_base);
401
if ( (parms->virt_kstart > parms->virt_kend) ||
402
(parms->virt_entry < parms->virt_kstart) ||
403
(parms->virt_entry > parms->virt_kend) ||
404
(parms->virt_base > parms->virt_kstart) )
406
elf_err(elf, "%s: ERROR: ELF start or entries are out of bounds.\n",
411
if ( (parms->p2m_base != UNSET_ADDR) &&
412
(parms->p2m_base >= parms->virt_kstart) &&
413
(parms->p2m_base < parms->virt_kend) )
415
elf_err(elf, "%s: ERROR: P->M table base is out of bounds.\n",
423
/* ------------------------------------------------------------------------ */
424
/* glue it all together ... */
426
int elf_xen_parse(struct elf_binary *elf,
427
struct elf_dom_parms *parms)
429
const elf_shdr *shdr;
430
const elf_phdr *phdr;
431
int xen_elfnotes = 0;
434
memset(parms, 0, sizeof(*parms));
435
parms->virt_base = UNSET_ADDR;
436
parms->virt_entry = UNSET_ADDR;
437
parms->virt_hypercall = UNSET_ADDR;
438
parms->virt_hv_start_low = UNSET_ADDR;
439
parms->p2m_base = UNSET_ADDR;
440
parms->elf_paddr_offset = UNSET_ADDR;
442
/* Find and parse elf notes. */
443
count = elf_phdr_count(elf);
444
for ( i = 0; i < count; i++ )
446
phdr = elf_phdr_by_index(elf, i);
447
if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
451
* Some versions of binutils do not correctly set p_offset for
454
if (elf_uval(elf, phdr, p_offset) == 0)
457
rc = elf_xen_parse_notes(elf, parms,
458
elf_segment_start(elf, phdr),
459
elf_segment_end(elf, phdr));
467
* Fall back to any SHT_NOTE sections if no valid note segments
470
if ( xen_elfnotes == 0 )
472
count = elf_shdr_count(elf);
473
for ( i = 0; i < count; i++ )
475
shdr = elf_shdr_by_index(elf, i);
477
if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
480
rc = elf_xen_parse_notes(elf, parms,
481
elf_section_start(elf, shdr),
482
elf_section_end(elf, shdr));
487
if ( xen_elfnotes == 0 && rc > 0 )
488
elf_msg(elf, "%s: using notes from SHT_NOTE section\n", __FUNCTION__);
496
* Finally fall back to the __xen_guest section.
498
if ( xen_elfnotes == 0 )
500
count = elf_shdr_count(elf);
501
for ( i = 0; i < count; i++ )
503
shdr = elf_shdr_by_name(elf, "__xen_guest");
506
parms->guest_info = elf_section_start(elf, shdr);
507
parms->elf_note_start = NULL;
508
parms->elf_note_end = NULL;
509
elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
511
elf_xen_parse_guest_info(elf, parms);
517
if ( elf_xen_note_check(elf, parms) != 0 )
519
if ( elf_xen_addr_calc_check(elf, parms) != 0 )
530
* indent-tabs-mode: nil