source: trunk/packages/xen-3.1/xen-3.1/xen/common/libelf/libelf-dominfo.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 15.6 KB
Line 
1/*
2 * parse xen-specific informations out of elf kernel binaries.
3 */
4
5#include "libelf-private.h"
6
7/* ------------------------------------------------------------------------ */
8/* xen features                                                             */
9
10const 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};
17const int elf_xen_features =
18sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
19
20int 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;
26
27    if ( features == NULL )
28        return 0;
29
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        }
46
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    }
74
75    return 0;
76}
77
78/* ------------------------------------------------------------------------ */
79/* xen elf notes                                                            */
80
81int 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* */
105
106    const char *str = NULL;
107    uint64_t val = 0;
108    int type = elf_uval(elf, note, type);
109
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    }
117
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;
135
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;
160
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;
176
177    case XEN_ELFNOTE_FEATURES:
178        if ( elf_xen_parse_features(str, parms->f_supported,
179                                    parms->f_required) )
180            return -1;
181        break;
182
183    }
184    return 0;
185}
186
187static 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;
193
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}
208
209/* ------------------------------------------------------------------------ */
210/* __xen_guest section                                                      */
211
212int 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;
218
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);
256
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;
275
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;
286
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}
295
296/* ------------------------------------------------------------------------ */
297/* sanity checks                                                            */
298
299static 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    }
314
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    }
325
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}
335
336static 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    }
346
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    }
354
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    }
373
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;
377
378    if ( parms->virt_entry == UNSET_ADDR )
379        parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
380
381    elf_msg(elf, "%s: addresses:\n", __FUNCTION__);
382    elf_msg(elf, "    virt_base        = 0x%" PRIx64 "\n", parms->virt_base);
383    elf_msg(elf, "    elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
384    elf_msg(elf, "    virt_offset      = 0x%" PRIx64 "\n", parms->virt_offset);
385    elf_msg(elf, "    virt_kstart      = 0x%" PRIx64 "\n", parms->virt_kstart);
386    elf_msg(elf, "    virt_kend        = 0x%" PRIx64 "\n", parms->virt_kend);
387    elf_msg(elf, "    virt_entry       = 0x%" PRIx64 "\n", parms->virt_entry);
388
389    if ( (parms->virt_kstart > parms->virt_kend) ||
390         (parms->virt_entry < parms->virt_kstart) ||
391         (parms->virt_entry > parms->virt_kend) ||
392         (parms->virt_base > parms->virt_kstart) )
393    {
394        elf_err(elf, "%s: ERROR: ELF start or entries are out of bounds.\n",
395                __FUNCTION__);
396        return -1;
397    }
398
399    return 0;
400}
401
402/* ------------------------------------------------------------------------ */
403/* glue it all together ...                                                 */
404
405int elf_xen_parse(struct elf_binary *elf,
406                  struct elf_dom_parms *parms)
407{
408    const elf_shdr *shdr;
409    const elf_phdr *phdr;
410    int xen_elfnotes = 0;
411    int i, count, rc;
412
413    memset(parms, 0, sizeof(*parms));
414    parms->virt_base = UNSET_ADDR;
415    parms->virt_entry = UNSET_ADDR;
416    parms->virt_hypercall = UNSET_ADDR;
417    parms->virt_hv_start_low = UNSET_ADDR;
418    parms->elf_paddr_offset = UNSET_ADDR;
419
420    /* Find and parse elf notes. */
421    count = elf_phdr_count(elf);
422    for ( i = 0; i < count; i++ )
423    {
424        phdr = elf_phdr_by_index(elf, i);
425        if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
426            continue;
427
428        /*
429         * Some versions of binutils do not correctly set p_offset for
430         * note segments.
431         */
432        if (elf_uval(elf, phdr, p_offset) == 0)
433             continue;
434
435        rc = elf_xen_parse_notes(elf, parms,
436                                 elf_segment_start(elf, phdr),
437                                 elf_segment_end(elf, phdr));
438        if ( rc == -1 )
439            return -1;
440
441        xen_elfnotes += rc;
442    }
443
444    /*
445     * Fall back to any SHT_NOTE sections if no valid note segments
446     * were found.
447     */
448    if ( xen_elfnotes == 0 )
449    {
450        count = elf_shdr_count(elf);
451        for ( i = 0; i < count; i++ )
452        {
453            shdr = elf_shdr_by_index(elf, i);
454
455            if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
456                continue;
457
458            rc = elf_xen_parse_notes(elf, parms,
459                                     elf_section_start(elf, shdr),
460                                     elf_section_end(elf, shdr));
461
462            if ( rc == -1 )
463                return -1;
464
465            if ( xen_elfnotes == 0 && rc > 0 )
466                elf_msg(elf, "%s: using notes from SHT_NOTE section\n", __FUNCTION__);
467
468            xen_elfnotes += rc;
469        }
470
471    }
472
473    /*
474     * Finally fall back to the __xen_guest section.
475     */
476    if ( xen_elfnotes == 0 )
477    {
478        count = elf_shdr_count(elf);
479        for ( i = 0; i < count; i++ )
480        {
481            shdr = elf_shdr_by_name(elf, "__xen_guest");
482            if ( shdr )
483            {
484                parms->guest_info = elf_section_start(elf, shdr);
485                parms->elf_note_start = NULL;
486                parms->elf_note_end   = NULL;
487                elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
488                        parms->guest_info);
489                elf_xen_parse_guest_info(elf, parms);
490                break;
491            }
492        }
493    }
494
495    if ( elf_xen_note_check(elf, parms) != 0 )
496        return -1;
497    if ( elf_xen_addr_calc_check(elf, parms) != 0 )
498        return -1;
499    return 0;
500}
501
502/*
503 * Local variables:
504 * mode: C
505 * c-set-style: "BSD"
506 * c-basic-offset: 4
507 * tab-width: 4
508 * indent-tabs-mode: nil
509 * End:
510 */
Note: See TracBrowser for help on using the repository browser.