ia64/xen-unstable

view tools/libxc/xc_load_bin.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 06d84bf87159
children b3a255e88810
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 }
301 /*
302 * Local variables:
303 * mode: C
304 * c-set-style: "BSD"
305 * c-basic-offset: 4
306 * tab-width: 4
307 * indent-tabs-mode: nil
308 * End:
309 */