debuggers.hg

view tools/libxc/xc_dom_binloader.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents c051ed67258a
children 3ffdb094c2c0
line source
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 */
66 #include <stdlib.h>
67 #include <inttypes.h>
69 #include "xg_private.h"
70 #include "xc_dom.h"
72 #define round_pgup(_p) (((_p)+(PAGE_SIZE_X86-1))&PAGE_MASK_X86)
73 #define round_pgdown(_p) ((_p)&PAGE_MASK_X86)
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 };
87 #define XEN_MULTIBOOT_MAGIC3 0x336ec578
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)
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
101 /* --------------------------------------------------------------------- */
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;
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;
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 }
127 static int xc_dom_probe_bin_kernel(struct xc_dom_image *dom)
128 {
129 return find_table(dom) ? 0 : -EINVAL;
130 }
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;
142 image_info = find_table(dom);
143 if ( !image_info )
144 return -EINVAL;
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);
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 }
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 }
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;
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);
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 }
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 }
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;
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 }
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;
240 image_info = find_table(dom);
241 if ( !image_info )
242 return -EINVAL;
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;
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;
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);
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);
262 return 0;
263 }
265 /* ------------------------------------------------------------------------ */
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 };
274 static void __init register_loader(void)
275 {
276 xc_dom_register_loader(&bin_loader);
277 }
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 */