ia64/xen-unstable

view xen/common/libelf/libelf-dominfo.c @ 18594:5e4e234d58be

x86: Define __per_cpu_shift label to help kdump/crashdump.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 08 13:11:06 2008 +0100 (2008-10-08)
parents 7ee30cf72fd3
children 292919f61238
line source
1 /*
2 * parse xen-specific informations out of elf kernel binaries.
3 */
5 #include "libelf-private.h"
7 /* ------------------------------------------------------------------------ */
8 /* xen features */
10 const char *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"
16 };
17 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,
21 uint32_t *supported,
22 uint32_t *required)
23 {
24 char feature[64];
25 int pos, len, i;
27 if ( features == NULL )
28 return 0;
30 for ( pos = 0; features[pos] != '\0'; pos += len )
31 {
32 memset(feature, 0, sizeof(feature));
33 for ( len = 0;; len++ )
34 {
35 if ( len >= sizeof(feature)-1 )
36 break;
37 if ( features[pos + len] == '\0' )
38 break;
39 if ( features[pos + len] == '|' )
40 {
41 len++;
42 break;
43 }
44 feature[len] = features[pos + len];
45 }
47 for ( i = 0; i < elf_xen_features; i++ )
48 {
49 if ( !elf_xen_feature_names[i] )
50 continue;
51 if ( (required != NULL) && (feature[0] == '!') )
52 {
53 /* required */
54 if ( !strcmp(feature + 1, elf_xen_feature_names[i]) )
55 {
56 elf_xen_feature_set(i, supported);
57 elf_xen_feature_set(i, required);
58 break;
59 }
60 }
61 else
62 {
63 /* supported */
64 if ( !strcmp(feature, elf_xen_feature_names[i]) )
65 {
66 elf_xen_feature_set(i, supported);
67 break;
68 }
69 }
70 }
71 if ( i == elf_xen_features )
72 return -1;
73 }
75 return 0;
76 }
78 /* ------------------------------------------------------------------------ */
79 /* xen elf notes */
81 int elf_xen_parse_note(struct elf_binary *elf,
82 struct elf_dom_parms *parms,
83 const elf_note *note)
84 {
85 /* *INDENT-OFF* */
86 static const struct {
87 char *name;
88 int str;
89 } note_desc[] = {
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_PADDR_OFFSET] = { "PADDR_OFFSET", 0},
94 [XEN_ELFNOTE_HV_START_LOW] = { "HV_START_LOW", 0},
95 [XEN_ELFNOTE_XEN_VERSION] = { "XEN_VERSION", 1},
96 [XEN_ELFNOTE_GUEST_OS] = { "GUEST_OS", 1},
97 [XEN_ELFNOTE_GUEST_VERSION] = { "GUEST_VERSION", 1},
98 [XEN_ELFNOTE_LOADER] = { "LOADER", 1},
99 [XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1},
100 [XEN_ELFNOTE_FEATURES] = { "FEATURES", 1},
101 [XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1},
102 [XEN_ELFNOTE_SUSPEND_CANCEL] = { "SUSPEND_CANCEL", 0 },
103 };
104 /* *INDENT-ON* */
106 const char *str = NULL;
107 uint64_t val = 0;
108 int type = elf_uval(elf, note, type);
110 if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
111 (note_desc[type].name == NULL) )
112 {
113 elf_msg(elf, "%s: unknown xen elf note (0x%x)\n",
114 __FUNCTION__, type);
115 return 0;
116 }
118 if ( note_desc[type].str )
119 {
120 str = elf_note_desc(elf, note);
121 elf_msg(elf, "%s: %s = \"%s\"\n", __FUNCTION__,
122 note_desc[type].name, str);
123 parms->elf_notes[type].type = XEN_ENT_STR;
124 parms->elf_notes[type].data.str = str;
125 }
126 else
127 {
128 val = elf_note_numeric(elf, note);
129 elf_msg(elf, "%s: %s = 0x%" PRIx64 "\n", __FUNCTION__,
130 note_desc[type].name, val);
131 parms->elf_notes[type].type = XEN_ENT_LONG;
132 parms->elf_notes[type].data.num = val;
133 }
134 parms->elf_notes[type].name = note_desc[type].name;
136 switch ( type )
137 {
138 case XEN_ELFNOTE_LOADER:
139 safe_strcpy(parms->loader, str);
140 break;
141 case XEN_ELFNOTE_GUEST_OS:
142 safe_strcpy(parms->guest_os, str);
143 break;
144 case XEN_ELFNOTE_GUEST_VERSION:
145 safe_strcpy(parms->guest_ver, str);
146 break;
147 case XEN_ELFNOTE_XEN_VERSION:
148 safe_strcpy(parms->xen_ver, str);
149 break;
150 case XEN_ELFNOTE_PAE_MODE:
151 if ( !strcmp(str, "yes") )
152 parms->pae = 2 /* extended_cr3 */;
153 if ( strstr(str, "bimodal") )
154 parms->pae = 3 /* bimodal */;
155 break;
156 case XEN_ELFNOTE_BSD_SYMTAB:
157 if ( !strcmp(str, "yes") )
158 parms->bsd_symtab = 1;
159 break;
161 case XEN_ELFNOTE_VIRT_BASE:
162 parms->virt_base = val;
163 break;
164 case XEN_ELFNOTE_ENTRY:
165 parms->virt_entry = val;
166 break;
167 case XEN_ELFNOTE_PADDR_OFFSET:
168 parms->elf_paddr_offset = val;
169 break;
170 case XEN_ELFNOTE_HYPERCALL_PAGE:
171 parms->virt_hypercall = val;
172 break;
173 case XEN_ELFNOTE_HV_START_LOW:
174 parms->virt_hv_start_low = val;
175 break;
177 case XEN_ELFNOTE_FEATURES:
178 if ( elf_xen_parse_features(str, parms->f_supported,
179 parms->f_required) )
180 return -1;
181 break;
183 }
184 return 0;
185 }
187 static int elf_xen_parse_notes(struct elf_binary *elf,
188 struct elf_dom_parms *parms,
189 const void *start, const void *end)
190 {
191 int xen_elfnotes = 0;
192 const elf_note *note;
194 parms->elf_note_start = start;
195 parms->elf_note_end = end;
196 for ( note = parms->elf_note_start;
197 (void *)note < parms->elf_note_end;
198 note = elf_note_next(elf, note) )
199 {
200 if ( strcmp(elf_note_name(elf, note), "Xen") )
201 continue;
202 if ( elf_xen_parse_note(elf, parms, note) )
203 return -1;
204 xen_elfnotes++;
205 }
206 return xen_elfnotes;
207 }
209 /* ------------------------------------------------------------------------ */
210 /* __xen_guest section */
212 int elf_xen_parse_guest_info(struct elf_binary *elf,
213 struct elf_dom_parms *parms)
214 {
215 const char *h;
216 char name[32], value[128];
217 int len;
219 h = parms->guest_info;
220 while ( *h )
221 {
222 memset(name, 0, sizeof(name));
223 memset(value, 0, sizeof(value));
224 for ( len = 0;; len++, h++ )
225 {
226 if ( len >= sizeof(name)-1 )
227 break;
228 if ( *h == '\0' )
229 break;
230 if ( *h == ',' )
231 {
232 h++;
233 break;
234 }
235 if ( *h == '=' )
236 {
237 h++;
238 for ( len = 0;; len++, h++ )
239 {
240 if ( len >= sizeof(value)-1 )
241 break;
242 if ( *h == '\0' )
243 break;
244 if ( *h == ',' )
245 {
246 h++;
247 break;
248 }
249 value[len] = *h;
250 }
251 break;
252 }
253 name[len] = *h;
254 }
255 elf_msg(elf, "%s: %s=\"%s\"\n", __FUNCTION__, name, value);
257 /* strings */
258 if ( !strcmp(name, "LOADER") )
259 safe_strcpy(parms->loader, value);
260 if ( !strcmp(name, "GUEST_OS") )
261 safe_strcpy(parms->guest_os, value);
262 if ( !strcmp(name, "GUEST_VER") )
263 safe_strcpy(parms->guest_ver, value);
264 if ( !strcmp(name, "XEN_VER") )
265 safe_strcpy(parms->xen_ver, value);
266 if ( !strcmp(name, "PAE") )
267 {
268 if ( !strcmp(value, "yes[extended-cr3]") )
269 parms->pae = 2 /* extended_cr3 */;
270 else if ( !strncmp(value, "yes", 3) )
271 parms->pae = 1 /* yes */;
272 }
273 if ( !strcmp(name, "BSD_SYMTAB") )
274 parms->bsd_symtab = 1;
276 /* longs */
277 if ( !strcmp(name, "VIRT_BASE") )
278 parms->virt_base = strtoull(value, NULL, 0);
279 if ( !strcmp(name, "VIRT_ENTRY") )
280 parms->virt_entry = strtoull(value, NULL, 0);
281 if ( !strcmp(name, "ELF_PADDR_OFFSET") )
282 parms->elf_paddr_offset = strtoull(value, NULL, 0);
283 if ( !strcmp(name, "HYPERCALL_PAGE") )
284 parms->virt_hypercall = (strtoull(value, NULL, 0) << 12) +
285 parms->virt_base;
287 /* other */
288 if ( !strcmp(name, "FEATURES") )
289 if ( elf_xen_parse_features(value, parms->f_supported,
290 parms->f_required) )
291 return -1;
292 }
293 return 0;
294 }
296 /* ------------------------------------------------------------------------ */
297 /* sanity checks */
299 static int elf_xen_note_check(struct elf_binary *elf,
300 struct elf_dom_parms *parms)
301 {
302 if ( (parms->elf_note_start == NULL) && (parms->guest_info == NULL) )
303 {
304 int machine = elf_uval(elf, elf->ehdr, e_machine);
305 if ( (machine == EM_386) || (machine == EM_X86_64) )
306 {
307 elf_err(elf, "%s: ERROR: Not a Xen-ELF image: "
308 "No ELF notes or '__xen_guest' section found.\n",
309 __FUNCTION__);
310 return -1;
311 }
312 return 0;
313 }
315 /* Check the contents of the Xen notes or guest string. */
316 if ( ((strlen(parms->loader) == 0) ||
317 strncmp(parms->loader, "generic", 7)) &&
318 ((strlen(parms->guest_os) == 0) ||
319 strncmp(parms->guest_os, "linux", 5)) )
320 {
321 elf_err(elf, "%s: ERROR: Will only load images built for the generic "
322 "loader or Linux images", __FUNCTION__);
323 return -1;
324 }
326 if ( (strlen(parms->xen_ver) == 0) ||
327 strncmp(parms->xen_ver, "xen-3.0", 7) )
328 {
329 elf_err(elf, "%s: ERROR: Xen will only load images built "
330 "for Xen v3.0\n", __FUNCTION__);
331 return -1;
332 }
333 return 0;
334 }
336 static int elf_xen_addr_calc_check(struct elf_binary *elf,
337 struct elf_dom_parms *parms)
338 {
339 if ( (parms->elf_paddr_offset != UNSET_ADDR) &&
340 (parms->virt_base == UNSET_ADDR) )
341 {
342 elf_err(elf, "%s: ERROR: ELF_PADDR_OFFSET set, VIRT_BASE unset\n",
343 __FUNCTION__);
344 return -1;
345 }
347 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
348 if ( parms->virt_base == UNSET_ADDR )
349 {
350 parms->virt_base = 0;
351 elf_msg(elf, "%s: VIRT_BASE unset, using 0x%" PRIx64 "\n",
352 __FUNCTION__, parms->virt_base);
353 }
355 /*
356 * If we are using the legacy __xen_guest section then elf_pa_off
357 * defaults to v_start in order to maintain compatibility with
358 * older hypervisors which set padd in the ELF header to
359 * virt_base.
360 *
361 * If we are using the modern ELF notes interface then the default
362 * is 0.
363 */
364 if ( parms->elf_paddr_offset == UNSET_ADDR )
365 {
366 if ( parms->elf_note_start )
367 parms->elf_paddr_offset = 0;
368 else
369 parms->elf_paddr_offset = parms->virt_base;
370 elf_msg(elf, "%s: ELF_PADDR_OFFSET unset, using 0x%" PRIx64 "\n",
371 __FUNCTION__, parms->elf_paddr_offset);
372 }
374 parms->virt_offset = parms->virt_base - parms->elf_paddr_offset;
375 parms->virt_kstart = elf->pstart + parms->virt_offset;
376 parms->virt_kend = elf->pend + parms->virt_offset;
378 if ( parms->virt_entry == UNSET_ADDR )
379 parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
381 if ( parms->bsd_symtab )
382 {
383 elf_parse_bsdsyms(elf, parms->virt_kend);
384 if ( elf->bsd_symtab_pend )
385 parms->virt_kend = elf->bsd_symtab_pend + parms->virt_offset;
386 }
388 elf_msg(elf, "%s: addresses:\n", __FUNCTION__);
389 elf_msg(elf, " virt_base = 0x%" PRIx64 "\n", parms->virt_base);
390 elf_msg(elf, " elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
391 elf_msg(elf, " virt_offset = 0x%" PRIx64 "\n", parms->virt_offset);
392 elf_msg(elf, " virt_kstart = 0x%" PRIx64 "\n", parms->virt_kstart);
393 elf_msg(elf, " virt_kend = 0x%" PRIx64 "\n", parms->virt_kend);
394 elf_msg(elf, " virt_entry = 0x%" PRIx64 "\n", parms->virt_entry);
396 if ( (parms->virt_kstart > parms->virt_kend) ||
397 (parms->virt_entry < parms->virt_kstart) ||
398 (parms->virt_entry > parms->virt_kend) ||
399 (parms->virt_base > parms->virt_kstart) )
400 {
401 elf_err(elf, "%s: ERROR: ELF start or entries are out of bounds.\n",
402 __FUNCTION__);
403 return -1;
404 }
406 return 0;
407 }
409 /* ------------------------------------------------------------------------ */
410 /* glue it all together ... */
412 int elf_xen_parse(struct elf_binary *elf,
413 struct elf_dom_parms *parms)
414 {
415 const elf_shdr *shdr;
416 const elf_phdr *phdr;
417 int xen_elfnotes = 0;
418 int i, count, rc;
420 memset(parms, 0, sizeof(*parms));
421 parms->virt_base = UNSET_ADDR;
422 parms->virt_entry = UNSET_ADDR;
423 parms->virt_hypercall = UNSET_ADDR;
424 parms->virt_hv_start_low = UNSET_ADDR;
425 parms->elf_paddr_offset = UNSET_ADDR;
427 /* Find and parse elf notes. */
428 count = elf_phdr_count(elf);
429 for ( i = 0; i < count; i++ )
430 {
431 phdr = elf_phdr_by_index(elf, i);
432 if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
433 continue;
435 /*
436 * Some versions of binutils do not correctly set p_offset for
437 * note segments.
438 */
439 if (elf_uval(elf, phdr, p_offset) == 0)
440 continue;
442 rc = elf_xen_parse_notes(elf, parms,
443 elf_segment_start(elf, phdr),
444 elf_segment_end(elf, phdr));
445 if ( rc == -1 )
446 return -1;
448 xen_elfnotes += rc;
449 }
451 /*
452 * Fall back to any SHT_NOTE sections if no valid note segments
453 * were found.
454 */
455 if ( xen_elfnotes == 0 )
456 {
457 count = elf_shdr_count(elf);
458 for ( i = 0; i < count; i++ )
459 {
460 shdr = elf_shdr_by_index(elf, i);
462 if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
463 continue;
465 rc = elf_xen_parse_notes(elf, parms,
466 elf_section_start(elf, shdr),
467 elf_section_end(elf, shdr));
469 if ( rc == -1 )
470 return -1;
472 if ( xen_elfnotes == 0 && rc > 0 )
473 elf_msg(elf, "%s: using notes from SHT_NOTE section\n", __FUNCTION__);
475 xen_elfnotes += rc;
476 }
478 }
480 /*
481 * Finally fall back to the __xen_guest section.
482 */
483 if ( xen_elfnotes == 0 )
484 {
485 count = elf_shdr_count(elf);
486 for ( i = 0; i < count; i++ )
487 {
488 shdr = elf_shdr_by_name(elf, "__xen_guest");
489 if ( shdr )
490 {
491 parms->guest_info = elf_section_start(elf, shdr);
492 parms->elf_note_start = NULL;
493 parms->elf_note_end = NULL;
494 elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
495 parms->guest_info);
496 elf_xen_parse_guest_info(elf, parms);
497 break;
498 }
499 }
500 }
502 if ( elf_xen_note_check(elf, parms) != 0 )
503 return -1;
504 if ( elf_xen_addr_calc_check(elf, parms) != 0 )
505 return -1;
506 return 0;
507 }
509 /*
510 * Local variables:
511 * mode: C
512 * c-set-style: "BSD"
513 * c-basic-offset: 4
514 * tab-width: 4
515 * indent-tabs-mode: nil
516 * End:
517 */