ia64/xen-unstable

view tools/libxc/xc_load_bin.c @ 6435:b4b3f6be5226

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 17:27:49 2005 +0000 (2005-08-25)
parents 0610add7c3fe fdfd511768a3
children 8799d14bef77 9312a3e8a6f8
line source
1 /******************************************************************************
2 * xc_bin_load.c
3 *
4 * Based on xc_elf_load.c
5 *
6 * Loads simple binary images. It's like a .COM file in MS-DOS. No headers are
7 * present. The only requirement is that it must have a xen_bin_image table
8 * somewhere in the first 8192 bytes, starting on a 32-bit aligned address.
9 * Those familiar with the multiboot specification should recognize this, it's
10 * (almost) the same as the multiboot header.
11 * The layout of the xen_bin_image table is:
12 *
13 * Offset Type Name Note
14 * 0 u32 magic required
15 * 4 u32 flags required
16 * 8 u32 checksum required
17 * 12 u32 header_addr required
18 * 16 u32 load_addr required
19 * 20 u32 load_end_addr required
20 * 24 u32 bss_end_addr required
21 * 28 u32 entry_addr required
22 *
23 * - magic
24 * Magic number identifying the table. For images to be loaded by Xen 3, the
25 * magic value is 0x336ec578 ("xEn3" with the 0x80 bit of the "E" set).
26 * - flags
27 * bit 0: indicates whether the image needs to be loaded on a page boundary
28 * bit 1: reserved, must be 0 (the multiboot spec uses this bit to indicate
29 * that memory info should be passed to the image)
30 * bit 2: reserved, must be 0 (the multiboot spec uses this bit to indicate
31 * that the bootloader should pass video mode info to the image)
32 * bit 16: reserved, must be 1 (the multiboot spec uses this bit to indicate
33 * that the values in the fields header_addr - entry_addr are
34 * valid)
35 * All other bits should be set to 0.
36 * - checksum
37 * When added to "magic" and "flags", the resulting value should be 0.
38 * - header_addr
39 * Contains the virtual address corresponding to the beginning of the
40 * table - the memory location at which the magic value is supposed to be
41 * loaded. This field serves to synchronize the mapping between OS image
42 * offsets and virtual memory addresses.
43 * - load_addr
44 * Contains the virtual address of the beginning of the text segment. The
45 * offset in the OS image file at which to start loading is defined by the
46 * offset at which the table was found, minus (header addr - load addr).
47 * load addr must be less than or equal to header addr.
48 * - load_end_addr
49 * Contains the virtual address of the end of the data segment.
50 * (load_end_addr - load_addr) specifies how much data to load. This implies
51 * that the text and data segments must be consecutive in the OS image. If
52 * this field is zero, the domain builder assumes that the text and data
53 * segments occupy the whole OS image file.
54 * - bss_end_addr
55 * Contains the virtual address of the end of the bss segment. The domain
56 * builder initializes this area to zero, and reserves the memory it occupies
57 * to avoid placing boot modules and other data relevant to the loaded image
58 * in that area. If this field is zero, the domain builder assumes that no bss
59 * segment is present.
60 * - entry_addr
61 * The virtual address at which to start execution of the loaded image.
62 *
63 * Some of the field descriptions were copied from "The Multiboot
64 * Specification", Copyright 1995, 96 Bryan Ford <baford@cs.utah.edu>,
65 * Erich Stefan Boleyn <erich@uruk.org> Copyright 1999, 2000, 2001, 2002
66 * Free Software Foundation, Inc.
67 */
69 #include "xg_private.h"
70 #include <stdlib.h>
72 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
73 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
75 #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
76 #define round_pgdown(_p) ((_p)&PAGE_MASK)
78 struct xen_bin_image_table
79 {
80 unsigned long magic;
81 unsigned long flags;
82 unsigned long checksum;
83 unsigned long header_addr;
84 unsigned long load_addr;
85 unsigned long load_end_addr;
86 unsigned long bss_end_addr;
87 unsigned long entry_addr;
88 };
90 #define XEN_REACTOS_MAGIC3 0x336ec578
92 #define XEN_REACTOS_FLAG_ALIGN4K 0x00000001
93 #define XEN_REACTOS_FLAG_NEEDMEMINFO 0x00000002
94 #define XEN_REACTOS_FLAG_NEEDVIDINFO 0x00000004
95 #define XEN_REACTOS_FLAG_ADDRSVALID 0x00010000
97 /* Flags we test for */
98 #define FLAGS_MASK ((~ 0) & (~ XEN_REACTOS_FLAG_ALIGN4K))
99 #define FLAGS_REQUIRED XEN_REACTOS_FLAG_ADDRSVALID
101 static struct xen_bin_image_table *
102 findtable(char *image, unsigned long image_size);
103 static int
104 parsebinimage(
105 char *image, unsigned long image_size, struct domain_setup_info *dsi);
106 static int
107 loadbinimage(
108 char *image, unsigned long image_size, int xch, u32 dom,
109 unsigned long *parray, struct domain_setup_info *dsi);
111 int probe_bin(char *image,
112 unsigned long image_size,
113 struct load_funcs *load_funcs)
114 {
115 if ( NULL == findtable(image, image_size) )
116 {
117 return -EINVAL;
118 }
120 load_funcs->parseimage = parsebinimage;
121 load_funcs->loadimage = loadbinimage;
123 return 0;
124 }
126 static struct xen_bin_image_table *
127 findtable(char *image, unsigned long image_size)
128 {
129 struct xen_bin_image_table *table;
130 unsigned long *probe_ptr;
131 unsigned probe_index;
132 unsigned probe_count;
134 /* Don't go outside the image */
135 if ( image_size < sizeof(struct xen_bin_image_table) )
136 {
137 return NULL;
138 }
139 probe_count = image_size;
140 /* Restrict to first 8k */
141 if ( 8192 < probe_count )
142 {
143 probe_count = 8192;
144 }
145 probe_count = (probe_count - sizeof(struct xen_bin_image_table)) /
146 sizeof(unsigned long);
148 /* Search for the magic header */
149 probe_ptr = (unsigned long *) image;
150 table = NULL;
151 for ( probe_index = 0; probe_index < probe_count; probe_index++ )
152 {
153 if ( XEN_REACTOS_MAGIC3 == *probe_ptr )
154 {
155 table = (struct xen_bin_image_table *) probe_ptr;
156 /* Checksum correct? */
157 if ( 0 == table->magic + table->flags + table->checksum )
158 {
159 return table;
160 }
161 }
162 probe_ptr++;
163 }
165 return NULL;
166 }
168 static int parsebinimage(char *image,
169 unsigned long image_size,
170 struct domain_setup_info *dsi)
171 {
172 struct xen_bin_image_table *image_info;
173 unsigned long start_addr;
174 unsigned long end_addr;
176 image_info = findtable(image, image_size);
177 if ( NULL == image_info )
178 {
179 ERROR("Image does not have a valid xen_bin_image_table table.");
180 return -EINVAL;
181 }
183 /* Check the flags */
184 if ( FLAGS_REQUIRED != (image_info->flags & FLAGS_MASK) )
185 {
186 ERROR("xen_bin_image_table flags required 0x%08x found 0x%08lx",
187 FLAGS_REQUIRED, image_info->flags & FLAGS_MASK);
188 return -EINVAL;
189 }
191 /* Sanity check on the addresses */
192 if ( image_info->header_addr < image_info->load_addr ||
193 ((char *) image_info - image) <
194 (image_info->header_addr - image_info->load_addr) )
195 {
196 ERROR("Invalid header_addr.");
197 return -EINVAL;
198 }
199 start_addr = image_info->header_addr - ((char *) image_info - image);
200 if ( 0 != image_info->load_end_addr &&
201 ( image_info->load_end_addr < image_info->load_end_addr ||
202 start_addr + image_size < image_info->load_end_addr ) )
203 {
204 ERROR("Invalid load_end_addr");
205 return -EINVAL;
206 }
207 end_addr = (0 == image_info->load_end_addr ? start_addr + image_size :
208 image_info->load_end_addr);
209 if ( 0 != image_info->bss_end_addr &&
210 image_info->bss_end_addr < end_addr )
211 {
212 ERROR("Invalid bss_end_addr");
213 return -EINVAL;
214 }
216 dsi->v_start = image_info->load_addr;
217 if ( 0 != image_info->bss_end_addr )
218 {
219 dsi->v_end = image_info->bss_end_addr;
220 }
221 else if ( 0 != image_info->load_end_addr )
222 {
223 dsi->v_end = image_info->load_end_addr;
224 }
225 else
226 {
227 dsi->v_end = image_info->load_addr + image_size -
228 (((char *) image_info - image) -
229 (image_info->header_addr - image_info->load_addr));
230 }
231 dsi->v_kernstart = dsi->v_start;
232 dsi->v_kernend = dsi->v_end;
233 dsi->v_kernentry = image_info->entry_addr;
235 return 0;
236 }
238 static int
239 loadbinimage(
240 char *image, unsigned long image_size, int xch, u32 dom,
241 unsigned long *parray, struct domain_setup_info *dsi)
242 {
243 unsigned long size;
244 char *va;
245 unsigned long done, chunksz;
246 struct xen_bin_image_table *image_info;
248 image_info = findtable(image, image_size);
249 if ( NULL == image_info )
250 {
251 ERROR("Image does not have a valid xen_bin_image_table table.");
252 return -EINVAL;
253 }
255 /* Determine image size */
256 if ( 0 == image_info->load_end_addr )
257 {
258 size = image_size - (((char *) image_info - image) -
259 (image_info->header_addr -
260 image_info->load_addr));
261 }
262 else
263 {
264 size = image_info->load_end_addr - image_info->load_addr;
265 }
267 /* It's possible that we need to skip the first part of the image */
268 image += ((char *)image_info - image) -
269 (image_info->header_addr - image_info->load_addr);
271 for ( done = 0; done < size; done += chunksz )
272 {
273 va = xc_map_foreign_range(
274 xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]);
275 chunksz = size - done;
276 if ( chunksz > PAGE_SIZE )
277 chunksz = PAGE_SIZE;
278 memcpy(va, image + done, chunksz);
279 munmap(va, PAGE_SIZE);
280 }
282 if ( 0 != image_info->bss_end_addr &&
283 image_info->load_addr + size < image_info->bss_end_addr )
284 {
285 size = image_info->bss_end_addr - image_info->load_addr;
286 }
287 for ( ; done < size; done += chunksz )
288 {
289 va = xc_map_foreign_range(
290 xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]);
291 chunksz = size - done;
292 if ( chunksz > (PAGE_SIZE - (done & (PAGE_SIZE-1))) )
293 chunksz = PAGE_SIZE - (done & (PAGE_SIZE-1));
294 memset(va + (done & (PAGE_SIZE-1)), 0, chunksz);
295 munmap(va, PAGE_SIZE);
296 }
298 return 0;
299 }