~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to xen/common/libelf/libelf-dominfo.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * parse xen-specific informations out of elf kernel binaries.
 
3
 */
 
4
 
 
5
#include "libelf-private.h"
 
6
 
 
7
/* ------------------------------------------------------------------------ */
 
8
/* xen features                                                             */
 
9
 
 
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"
 
16
};
 
17
static const int elf_xen_features =
 
18
sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
 
19
 
 
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;
 
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
 
 
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_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 },
 
104
    };
 
105
/* *INDENT-ON* */
 
106
 
 
107
    const char *str = NULL;
 
108
    uint64_t val = 0;
 
109
    int type = elf_uval(elf, note, type);
 
110
 
 
111
    if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
 
112
         (note_desc[type].name == NULL) )
 
113
    {
 
114
        elf_msg(elf, "%s: unknown xen elf note (0x%x)\n",
 
115
                __FUNCTION__, type);
 
116
        return 0;
 
117
    }
 
118
 
 
119
    if ( note_desc[type].str )
 
120
    {
 
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;
 
126
    }
 
127
    else
 
128
    {
 
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;
 
134
    }
 
135
    parms->elf_notes[type].name = note_desc[type].name;
 
136
 
 
137
    switch ( type )
 
138
    {
 
139
    case XEN_ELFNOTE_LOADER:
 
140
        safe_strcpy(parms->loader, str);
 
141
        break;
 
142
    case XEN_ELFNOTE_GUEST_OS:
 
143
        safe_strcpy(parms->guest_os, str);
 
144
        break;
 
145
    case XEN_ELFNOTE_GUEST_VERSION:
 
146
        safe_strcpy(parms->guest_ver, str);
 
147
        break;
 
148
    case XEN_ELFNOTE_XEN_VERSION:
 
149
        safe_strcpy(parms->xen_ver, str);
 
150
        break;
 
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 */;
 
156
        break;
 
157
    case XEN_ELFNOTE_BSD_SYMTAB:
 
158
        if ( !strcmp(str, "yes") )
 
159
            parms->bsd_symtab = 1;
 
160
        break;
 
161
 
 
162
    case XEN_ELFNOTE_VIRT_BASE:
 
163
        parms->virt_base = val;
 
164
        break;
 
165
    case XEN_ELFNOTE_ENTRY:
 
166
        parms->virt_entry = val;
 
167
        break;
 
168
    case XEN_ELFNOTE_INIT_P2M:
 
169
        parms->p2m_base = val;
 
170
        break;
 
171
    case XEN_ELFNOTE_PADDR_OFFSET:
 
172
        parms->elf_paddr_offset = val;
 
173
        break;
 
174
    case XEN_ELFNOTE_HYPERCALL_PAGE:
 
175
        parms->virt_hypercall = val;
 
176
        break;
 
177
    case XEN_ELFNOTE_HV_START_LOW:
 
178
        parms->virt_hv_start_low = val;
 
179
        break;
 
180
 
 
181
    case XEN_ELFNOTE_FEATURES:
 
182
        if ( elf_xen_parse_features(str, parms->f_supported,
 
183
                                    parms->f_required) )
 
184
            return -1;
 
185
        break;
 
186
 
 
187
    }
 
188
    return 0;
 
189
}
 
190
 
 
191
static int elf_xen_parse_notes(struct elf_binary *elf,
 
192
                               struct elf_dom_parms *parms,
 
193
                               const void *start, const void *end)
 
194
{
 
195
    int xen_elfnotes = 0;
 
196
    const elf_note *note;
 
197
 
 
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) )
 
203
    {
 
204
        if ( strcmp(elf_note_name(elf, note), "Xen") )
 
205
            continue;
 
206
        if ( elf_xen_parse_note(elf, parms, note) )
 
207
            return -1;
 
208
        xen_elfnotes++;
 
209
    }
 
210
    return xen_elfnotes;
 
211
}
 
212
 
 
213
/* ------------------------------------------------------------------------ */
 
214
/* __xen_guest section                                                      */
 
215
 
 
216
int elf_xen_parse_guest_info(struct elf_binary *elf,
 
217
                             struct elf_dom_parms *parms)
 
218
{
 
219
    const char *h;
 
220
    char name[32], value[128];
 
221
    int len;
 
222
 
 
223
    h = parms->guest_info;
 
224
    while ( *h )
 
225
    {
 
226
        memset(name, 0, sizeof(name));
 
227
        memset(value, 0, sizeof(value));
 
228
        for ( len = 0;; len++, h++ )
 
229
        {
 
230
            if ( len >= sizeof(name)-1 )
 
231
                break;
 
232
            if ( *h == '\0' )
 
233
                break;
 
234
            if ( *h == ',' )
 
235
            {
 
236
                h++;
 
237
                break;
 
238
            }
 
239
            if ( *h == '=' )
 
240
            {
 
241
                h++;
 
242
                for ( len = 0;; len++, h++ )
 
243
                {
 
244
                    if ( len >= sizeof(value)-1 )
 
245
                        break;
 
246
                    if ( *h == '\0' )
 
247
                        break;
 
248
                    if ( *h == ',' )
 
249
                    {
 
250
                        h++;
 
251
                        break;
 
252
                    }
 
253
                    value[len] = *h;
 
254
                }
 
255
                break;
 
256
            }
 
257
            name[len] = *h;
 
258
        }
 
259
        elf_msg(elf, "%s: %s=\"%s\"\n", __FUNCTION__, name, value);
 
260
 
 
261
        /* strings */
 
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") )
 
271
        {
 
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 */;
 
276
        }
 
277
        if ( !strcmp(name, "BSD_SYMTAB") )
 
278
            parms->bsd_symtab = 1;
 
279
 
 
280
        /* longs */
 
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) +
 
289
                parms->virt_base;
 
290
 
 
291
        /* other */
 
292
        if ( !strcmp(name, "FEATURES") )
 
293
            if ( elf_xen_parse_features(value, parms->f_supported,
 
294
                                        parms->f_required) )
 
295
                return -1;
 
296
    }
 
297
    return 0;
 
298
}
 
299
 
 
300
/* ------------------------------------------------------------------------ */
 
301
/* sanity checks                                                            */
 
302
 
 
303
static int elf_xen_note_check(struct elf_binary *elf,
 
304
                              struct elf_dom_parms *parms)
 
305
{
 
306
    if ( (parms->elf_note_start == NULL) && (parms->guest_info == NULL) )
 
307
    {
 
308
        int machine = elf_uval(elf, elf->ehdr, e_machine);
 
309
        if ( (machine == EM_386) || (machine == EM_X86_64) )
 
310
        {
 
311
            elf_err(elf, "%s: ERROR: Not a Xen-ELF image: "
 
312
                    "No ELF notes or '__xen_guest' section found.\n",
 
313
                    __FUNCTION__);
 
314
            return -1;
 
315
        }
 
316
        return 0;
 
317
    }
 
318
 
 
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)) )
 
324
    {
 
325
        elf_err(elf, "%s: ERROR: Will only load images built for the generic "
 
326
                "loader or Linux images", __FUNCTION__);
 
327
        return -1;
 
328
    }
 
329
 
 
330
    if ( (strlen(parms->xen_ver) == 0) ||
 
331
         strncmp(parms->xen_ver, "xen-3.0", 7) )
 
332
    {
 
333
        elf_err(elf, "%s: ERROR: Xen will only load images built "
 
334
                "for Xen v3.0\n", __FUNCTION__);
 
335
        return -1;
 
336
    }
 
337
    return 0;
 
338
}
 
339
 
 
340
static int elf_xen_addr_calc_check(struct elf_binary *elf,
 
341
                                   struct elf_dom_parms *parms)
 
342
{
 
343
    if ( (parms->elf_paddr_offset != UNSET_ADDR) &&
 
344
         (parms->virt_base == UNSET_ADDR) )
 
345
    {
 
346
        elf_err(elf, "%s: ERROR: ELF_PADDR_OFFSET set, VIRT_BASE unset\n",
 
347
                __FUNCTION__);
 
348
        return -1;
 
349
    }
 
350
 
 
351
    /* Initial guess for virt_base is 0 if it is not explicitly defined. */
 
352
    if ( parms->virt_base == UNSET_ADDR )
 
353
    {
 
354
        parms->virt_base = 0;
 
355
        elf_msg(elf, "%s: VIRT_BASE unset, using 0x%" PRIx64 "\n",
 
356
                __FUNCTION__, parms->virt_base);
 
357
    }
 
358
 
 
359
    /*
 
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
 
363
     * virt_base.
 
364
     *
 
365
     * If we are using the modern ELF notes interface then the default
 
366
     * is 0.
 
367
     */
 
368
    if ( parms->elf_paddr_offset == UNSET_ADDR )
 
369
    {
 
370
        if ( parms->elf_note_start )
 
371
            parms->elf_paddr_offset = 0;
 
372
        else
 
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);
 
376
    }
 
377
 
 
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;
 
381
 
 
382
    if ( parms->virt_entry == UNSET_ADDR )
 
383
        parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
 
384
 
 
385
    if ( parms->bsd_symtab )
 
386
    {
 
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;
 
390
    }
 
391
 
 
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);
 
400
 
 
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) )
 
405
    {
 
406
        elf_err(elf, "%s: ERROR: ELF start or entries are out of bounds.\n",
 
407
                __FUNCTION__);
 
408
        return -1;
 
409
    }
 
410
 
 
411
    if ( (parms->p2m_base != UNSET_ADDR) &&
 
412
         (parms->p2m_base >= parms->virt_kstart) &&
 
413
         (parms->p2m_base < parms->virt_kend) )
 
414
    {
 
415
        elf_err(elf, "%s: ERROR: P->M table base is out of bounds.\n",
 
416
                __FUNCTION__);
 
417
        return -1;
 
418
    }
 
419
 
 
420
    return 0;
 
421
}
 
422
 
 
423
/* ------------------------------------------------------------------------ */
 
424
/* glue it all together ...                                                 */
 
425
 
 
426
int elf_xen_parse(struct elf_binary *elf,
 
427
                  struct elf_dom_parms *parms)
 
428
{
 
429
    const elf_shdr *shdr;
 
430
    const elf_phdr *phdr;
 
431
    int xen_elfnotes = 0;
 
432
    int i, count, rc;
 
433
 
 
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;
 
441
 
 
442
    /* Find and parse elf notes. */
 
443
    count = elf_phdr_count(elf);
 
444
    for ( i = 0; i < count; i++ )
 
445
    {
 
446
        phdr = elf_phdr_by_index(elf, i);
 
447
        if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
 
448
            continue;
 
449
 
 
450
        /*
 
451
         * Some versions of binutils do not correctly set p_offset for
 
452
         * note segments.
 
453
         */
 
454
        if (elf_uval(elf, phdr, p_offset) == 0)
 
455
             continue;
 
456
 
 
457
        rc = elf_xen_parse_notes(elf, parms,
 
458
                                 elf_segment_start(elf, phdr),
 
459
                                 elf_segment_end(elf, phdr));
 
460
        if ( rc == -1 )
 
461
            return -1;
 
462
 
 
463
        xen_elfnotes += rc;
 
464
    }
 
465
 
 
466
    /*
 
467
     * Fall back to any SHT_NOTE sections if no valid note segments
 
468
     * were found.
 
469
     */
 
470
    if ( xen_elfnotes == 0 )
 
471
    {
 
472
        count = elf_shdr_count(elf);
 
473
        for ( i = 0; i < count; i++ )
 
474
        {
 
475
            shdr = elf_shdr_by_index(elf, i);
 
476
 
 
477
            if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
 
478
                continue;
 
479
 
 
480
            rc = elf_xen_parse_notes(elf, parms,
 
481
                                     elf_section_start(elf, shdr),
 
482
                                     elf_section_end(elf, shdr));
 
483
 
 
484
            if ( rc == -1 )
 
485
                return -1;
 
486
 
 
487
            if ( xen_elfnotes == 0 && rc > 0 )
 
488
                elf_msg(elf, "%s: using notes from SHT_NOTE section\n", __FUNCTION__);
 
489
 
 
490
            xen_elfnotes += rc;
 
491
        }
 
492
 
 
493
    }
 
494
 
 
495
    /*
 
496
     * Finally fall back to the __xen_guest section.
 
497
     */
 
498
    if ( xen_elfnotes == 0 )
 
499
    {
 
500
        count = elf_shdr_count(elf);
 
501
        for ( i = 0; i < count; i++ )
 
502
        {
 
503
            shdr = elf_shdr_by_name(elf, "__xen_guest");
 
504
            if ( shdr )
 
505
            {
 
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__,
 
510
                        parms->guest_info);
 
511
                elf_xen_parse_guest_info(elf, parms);
 
512
                break;
 
513
            }
 
514
        }
 
515
    }
 
516
 
 
517
    if ( elf_xen_note_check(elf, parms) != 0 )
 
518
        return -1;
 
519
    if ( elf_xen_addr_calc_check(elf, parms) != 0 )
 
520
        return -1;
 
521
    return 0;
 
522
}
 
523
 
 
524
/*
 
525
 * Local variables:
 
526
 * mode: C
 
527
 * c-set-style: "BSD"
 
528
 * c-basic-offset: 4
 
529
 * tab-width: 4
 
530
 * indent-tabs-mode: nil
 
531
 * End:
 
532
 */