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

« back to all changes in this revision

Viewing changes to tools/libxc/xc_dom_binloader.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
 *
 
3
 * Loads simple binary images. It's like a .COM file in MS-DOS. No headers are
 
4
 * present. The only requirement is that it must have a xen_bin_image table
 
5
 * somewhere in the first 8192 bytes, starting on a 32-bit aligned address.
 
6
 * Those familiar with the multiboot specification should recognize this, it's
 
7
 * (almost) the same as the multiboot header.
 
8
 * The layout of the xen_bin_image table is:
 
9
 *
 
10
 * Offset Type Name          Note
 
11
 * 0      uint32_t  magic         required
 
12
 * 4      uint32_t  flags         required
 
13
 * 8      uint32_t  checksum      required
 
14
 * 12     uint32_t  header_addr   required
 
15
 * 16     uint32_t  load_addr     required
 
16
 * 20     uint32_t  load_end_addr required
 
17
 * 24     uint32_t  bss_end_addr  required
 
18
 * 28     uint32_t  entry_addr    required
 
19
 *
 
20
 * - magic
 
21
 *   Magic number identifying the table. For images to be loaded by Xen 3, the
 
22
 *   magic value is 0x336ec578 ("xEn3" with the 0x80 bit of the "E" set).
 
23
 * - flags
 
24
 *   bit 0: indicates whether the image needs to be loaded on a page boundary
 
25
 *   bit 1: reserved, must be 0 (the multiboot spec uses this bit to indicate
 
26
 *          that memory info should be passed to the image)
 
27
 *   bit 2: reserved, must be 0 (the multiboot spec uses this bit to indicate
 
28
 *          that the bootloader should pass video mode info to the image)
 
29
 *   bit 16: reserved, must be 1 (the multiboot spec uses this bit to indicate
 
30
 *           that the values in the fields header_addr - entry_addr are
 
31
 *           valid)
 
32
 *   All other bits should be set to 0.
 
33
 * - checksum
 
34
 *   When added to "magic" and "flags", the resulting value should be 0.
 
35
 * - header_addr
 
36
 *   Contains the virtual address corresponding to the beginning of the
 
37
 *   table - the memory location at which the magic value is supposed to be
 
38
 *   loaded. This field serves to synchronize the mapping between OS image
 
39
 *   offsets and virtual memory addresses.
 
40
 * - load_addr
 
41
 *   Contains the virtual address of the beginning of the text segment. The
 
42
 *   offset in the OS image file at which to start loading is defined by the
 
43
 *   offset at which the table was found, minus (header addr - load addr).
 
44
 *   load addr must be less than or equal to header addr.
 
45
 * - load_end_addr
 
46
 *   Contains the virtual address of the end of the data segment.
 
47
 *   (load_end_addr - load_addr) specifies how much data to load. This implies
 
48
 *   that the text and data segments must be consecutive in the OS image. If
 
49
 *   this field is zero, the domain builder assumes that the text and data
 
50
 *   segments occupy the whole OS image file.
 
51
 * - bss_end_addr
 
52
 *   Contains the virtual address of the end of the bss segment. The domain
 
53
 *   builder initializes this area to zero, and reserves the memory it occupies
 
54
 *   to avoid placing boot modules and other data relevant to the loaded image
 
55
 *   in that area. If this field is zero, the domain builder assumes that no bss
 
56
 *   segment is present.
 
57
 * - entry_addr
 
58
 *   The virtual address at which to start execution of the loaded image.
 
59
 *
 
60
 * Some of the field descriptions were copied from "The Multiboot
 
61
 * Specification", Copyright 1995, 96 Bryan Ford <baford@cs.utah.edu>,
 
62
 * Erich Stefan Boleyn <erich@uruk.org> Copyright 1999, 2000, 2001, 2002
 
63
 * Free Software Foundation, Inc.
 
64
 */
 
65
 
 
66
#include <stdlib.h>
 
67
#include <inttypes.h>
 
68
 
 
69
#include "xg_private.h"
 
70
#include "xc_dom.h"
 
71
 
 
72
#define round_pgup(_p)    (((_p)+(PAGE_SIZE_X86-1))&PAGE_MASK_X86)
 
73
#define round_pgdown(_p)  ((_p)&PAGE_MASK_X86)
 
74
 
 
75
struct xen_bin_image_table
 
76
{
 
77
    uint32_t magic;
 
78
    uint32_t flags;
 
79
    uint32_t checksum;
 
80
    uint32_t header_addr;
 
81
    uint32_t load_addr;
 
82
    uint32_t load_end_addr;
 
83
    uint32_t bss_end_addr;
 
84
    uint32_t entry_addr;
 
85
};
 
86
 
 
87
#define XEN_MULTIBOOT_MAGIC3 0x336ec578
 
88
 
 
89
#define XEN_MULTIBOOT_FLAG_ALIGN4K     0x00000001
 
90
#define XEN_MULTIBOOT_FLAG_NEEDMEMINFO 0x00000002
 
91
#define XEN_MULTIBOOT_FLAG_NEEDVIDINFO 0x00000004
 
92
#define XEN_MULTIBOOT_FLAG_ADDRSVALID  0x00010000
 
93
#define XEN_MULTIBOOT_FLAG_PAE_SHIFT   14
 
94
#define XEN_MULTIBOOT_FLAG_PAE_MASK    (3 << XEN_MULTIBOOT_FLAG_PAE_SHIFT)
 
95
 
 
96
/* Flags we test for */
 
97
#define FLAGS_MASK     ((~ 0) & (~ XEN_MULTIBOOT_FLAG_ALIGN4K) & \
 
98
    (~ XEN_MULTIBOOT_FLAG_PAE_MASK))
 
99
#define FLAGS_REQUIRED XEN_MULTIBOOT_FLAG_ADDRSVALID
 
100
 
 
101
/* --------------------------------------------------------------------- */
 
102
 
 
103
static struct xen_bin_image_table *find_table(struct xc_dom_image *dom)
 
104
{
 
105
    struct xen_bin_image_table *table;
 
106
    uint32_t *probe_ptr;
 
107
    uint32_t *probe_end;
 
108
 
 
109
    probe_ptr = dom->kernel_blob;
 
110
    probe_end = dom->kernel_blob + dom->kernel_size - sizeof(*table);
 
111
    if ( (void*)probe_end > (dom->kernel_blob + 8192) )
 
112
        probe_end = dom->kernel_blob + 8192;
 
113
 
 
114
    for ( table = NULL; probe_ptr < probe_end; probe_ptr++ )
 
115
    {
 
116
        if ( *probe_ptr == XEN_MULTIBOOT_MAGIC3 )
 
117
        {
 
118
            table = (struct xen_bin_image_table *) probe_ptr;
 
119
            /* Checksum correct? */
 
120
            if ( (table->magic + table->flags + table->checksum) == 0 )
 
121
                return table;
 
122
        }
 
123
    }
 
124
    return NULL;
 
125
}
 
126
 
 
127
static int xc_dom_probe_bin_kernel(struct xc_dom_image *dom)
 
128
{
 
129
    return find_table(dom) ? 0 : -EINVAL;
 
130
}
 
131
 
 
132
static int xc_dom_parse_bin_kernel(struct xc_dom_image *dom)
 
133
{
 
134
    struct xen_bin_image_table *image_info;
 
135
    char *image = dom->kernel_blob;
 
136
    size_t image_size = dom->kernel_size;
 
137
    uint32_t start_addr;
 
138
    uint32_t load_end_addr;
 
139
    uint32_t bss_end_addr;
 
140
    uint32_t pae_flags;
 
141
 
 
142
    image_info = find_table(dom);
 
143
    if ( !image_info )
 
144
        return -EINVAL;
 
145
 
 
146
    xc_dom_printf("%s: multiboot header fields\n", __FUNCTION__);
 
147
    xc_dom_printf("  flags:         0x%" PRIx32 "\n", image_info->flags);
 
148
    xc_dom_printf("  header_addr:   0x%" PRIx32 "\n", image_info->header_addr);
 
149
    xc_dom_printf("  load_addr:     0x%" PRIx32 "\n", image_info->load_addr);
 
150
    xc_dom_printf("  load_end_addr: 0x%" PRIx32 "\n", image_info->load_end_addr);
 
151
    xc_dom_printf("  bss_end_addr:  0x%" PRIx32 "\n", image_info->bss_end_addr);
 
152
    xc_dom_printf("  entry_addr:    0x%" PRIx32 "\n", image_info->entry_addr);
 
153
 
 
154
    /* Check the flags */
 
155
    if ( (image_info->flags & FLAGS_MASK) != FLAGS_REQUIRED )
 
156
    {
 
157
        xc_dom_panic(XC_INVALID_KERNEL,
 
158
                     "%s: xen_bin_image_table flags required "
 
159
                     "0x%08" PRIx32 " found 0x%08" PRIx32 "\n",
 
160
                     __FUNCTION__, FLAGS_REQUIRED, image_info->flags & FLAGS_MASK);
 
161
        return -EINVAL;
 
162
    }
 
163
 
 
164
    /* Sanity check on the addresses */
 
165
    if ( (image_info->header_addr < image_info->load_addr) ||
 
166
         ((char *) image_info - image) <
 
167
         (image_info->header_addr - image_info->load_addr) )
 
168
    {
 
169
        xc_dom_panic(XC_INVALID_KERNEL, "%s: Invalid header_addr.",
 
170
                     __FUNCTION__);
 
171
        return -EINVAL;
 
172
    }
 
173
 
 
174
    start_addr = image_info->header_addr - ((char *)image_info - image);
 
175
    load_end_addr = image_info->load_end_addr ?: start_addr + image_size;
 
176
    bss_end_addr = image_info->bss_end_addr ?: load_end_addr;
 
177
 
 
178
    xc_dom_printf("%s: calculated addresses\n", __FUNCTION__);
 
179
    xc_dom_printf("  start_addr:    0x%" PRIx32 "\n", start_addr);
 
180
    xc_dom_printf("  load_end_addr: 0x%" PRIx32 "\n", load_end_addr);
 
181
    xc_dom_printf("  bss_end_addr:  0x%" PRIx32 "\n", bss_end_addr);
 
182
 
 
183
    if ( (start_addr + image_size) < load_end_addr )
 
184
    {
 
185
        xc_dom_panic(XC_INVALID_KERNEL, "%s: Invalid load_end_addr.\n",
 
186
                     __FUNCTION__);
 
187
        return -EINVAL;
 
188
    }
 
189
 
 
190
    if ( bss_end_addr < load_end_addr)
 
191
    {
 
192
        xc_dom_panic(XC_INVALID_KERNEL, "%s: Invalid bss_end_addr.\n",
 
193
                     __FUNCTION__);
 
194
        return -EINVAL;
 
195
    }
 
196
 
 
197
    dom->kernel_seg.vstart = image_info->load_addr;
 
198
    dom->kernel_seg.vend   = bss_end_addr;
 
199
    dom->parms.virt_base   = start_addr;
 
200
    dom->parms.virt_entry  = image_info->entry_addr;
 
201
 
 
202
    pae_flags = image_info->flags & XEN_MULTIBOOT_FLAG_PAE_MASK;
 
203
    switch (pae_flags >> XEN_MULTIBOOT_FLAG_PAE_SHIFT) {
 
204
    case 0:
 
205
        dom->guest_type = "xen-3.0-x86_32";
 
206
        break;
 
207
    case 1:
 
208
        dom->guest_type = "xen-3.0-x86_32p";
 
209
        break;
 
210
    case 2:
 
211
        dom->guest_type = "xen-3.0-x86_64";
 
212
        break;
 
213
    case 3:
 
214
        /* Kernel detects PAE at runtime.  So try to figure whenever
 
215
         * xen supports PAE and advertise a PAE-capable kernel in case
 
216
         * it does. */
 
217
        dom->guest_type = "xen-3.0-x86_32";
 
218
        if ( strstr(dom->xen_caps, "xen-3.0-x86_32p") )
 
219
        {
 
220
            xc_dom_printf("%s: PAE fixup\n", __FUNCTION__);
 
221
            dom->guest_type = "xen-3.0-x86_32p";
 
222
            dom->parms.pae  = 2;
 
223
        }
 
224
        break;
 
225
    }
 
226
    return 0;
 
227
}
 
228
 
 
229
static int xc_dom_load_bin_kernel(struct xc_dom_image *dom)
 
230
{
 
231
    struct xen_bin_image_table *image_info;
 
232
    char *image = dom->kernel_blob;
 
233
    char *dest;
 
234
    size_t image_size = dom->kernel_size;
 
235
    uint32_t start_addr;
 
236
    uint32_t load_end_addr;
 
237
    uint32_t bss_end_addr;
 
238
    uint32_t skip, text_size, bss_size;
 
239
 
 
240
    image_info = find_table(dom);
 
241
    if ( !image_info )
 
242
        return -EINVAL;
 
243
 
 
244
    start_addr = image_info->header_addr - ((char *)image_info - image);
 
245
    load_end_addr = image_info->load_end_addr ?: start_addr + image_size;
 
246
    bss_end_addr = image_info->bss_end_addr ?: load_end_addr;
 
247
 
 
248
    /* It's possible that we need to skip the first part of the image */
 
249
    skip = image_info->load_addr - start_addr;
 
250
    text_size = load_end_addr - image_info->load_addr;
 
251
    bss_size = bss_end_addr - load_end_addr;
 
252
 
 
253
    xc_dom_printf("%s: calculated sizes\n", __FUNCTION__);
 
254
    xc_dom_printf("  skip:      0x%" PRIx32 "\n", skip);
 
255
    xc_dom_printf("  text_size: 0x%" PRIx32 "\n", text_size);
 
256
    xc_dom_printf("  bss_size:  0x%" PRIx32 "\n", bss_size);
 
257
 
 
258
    dest = xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart);
 
259
    memcpy(dest, image + skip, text_size);
 
260
    memset(dest + text_size, 0, bss_size);
 
261
 
 
262
    return 0;
 
263
}
 
264
 
 
265
/* ------------------------------------------------------------------------ */
 
266
 
 
267
static struct xc_dom_loader bin_loader = {
 
268
    .name = "multiboot-binary",
 
269
    .probe = xc_dom_probe_bin_kernel,
 
270
    .parser = xc_dom_parse_bin_kernel,
 
271
    .loader = xc_dom_load_bin_kernel,
 
272
};
 
273
 
 
274
static void __init register_loader(void)
 
275
{
 
276
    xc_dom_register_loader(&bin_loader);
 
277
}
 
278
 
 
279
/*
 
280
 * Local variables:
 
281
 * mode: C
 
282
 * c-set-style: "BSD"
 
283
 * c-basic-offset: 4
 
284
 * tab-width: 4
 
285
 * indent-tabs-mode: nil
 
286
 * End:
 
287
 */