direct-io.hg

view tools/libxc/xc_load_bin.c @ 12765:2dd4569e0640

[LIBXC] Add an error reporting API to the libxc library.

- An 'xc_error' struct is used to pass around error
details. Currently contains two members 'code' an enumeration of
error types, and 'message' a free text description of the specific
problem.

- The xc_get_last_error() method returns a const pointer to the
internal instance of this struct manged by libxc. By returning a
const pointer we can add extra members to the end of the struct at
any time without worrying about ABI of callers. This will let us
provide more fine-grained info if needed in the future.

- The xc_error instance is statically defined inside libxc and marked
__thread. This ensures that errors are recorded per-thread, and
that when dealing with errors we never need to call malloc - all
storage needed is statically allocated.

- The xc_clear_last_error() method resets any currently recorded
error details

- The xc_error_code_to_desc() method converts the integer error code
into a generic user facing messsage. eg "Invalid kernel". Together
with the 'message' field from xc_error, this provides the user
visible feedback. eg "Invalid kernel: Non PAE-kernel on PAE host."

- A callback can be registered with xc_set_error_handler to receive
notification whenever an error is recorded, rather than querying
for error details after the fact with xc_get_last_error

- If built with -DDEBUG set, a default error handler will be
registered which calls fprintf(stderr), thus maintaining current
behaviour of logging errors to stderr during developer builds.

- The python binding for libxc is updated to use xc_get_last_error
to pull out error details whenever appropriate, instead of
returning info based on 'errno'

- The xc_set_error method is private to libxc internals, and is used
for setting error details

- The ERROR and PERROR macros have been updated to call xc_set_error
automatically specifying XC_INTERNAL_ERROR as the error code. This
gives a generic error report for all current failure points

- Some uses of the ERROR macro have been replaced with explicit
calls to xc_set_error to enable finer grained error reporting. In
particular the code dealing with invalid kernel types uses this
to report about PAE/architecture/wordsize mismatches

The patch has been tested by calling xm create against a varietry of
config files defining invalid kernels of various kinds. It has also
been tested with libvirt talking to xend. In both cases the error
messages were propagated all the way back up the stack.

There is only one place where I need to do further work. The suspend
& restore APIs in Xend invoke external helper programs rather than
calling libxc directly. This means that error details are essentially
lost. Since there is already code in XenD which scans STDERR from
these programs I will investigate adapting this to extract actual
error messages from these helpers.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author kfraser@localhost.localdomain
date Thu Dec 07 11:36:26 2006 +0000 (2006-12-07)
parents cc006f78cbe2
children 3e2d3d737624
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 uint32_t magic required
15 * 4 uint32_t flags required
16 * 8 uint32_t checksum required
17 * 12 uint32_t header_addr required
18 * 16 uint32_t load_addr required
19 * 20 uint32_t load_end_addr required
20 * 24 uint32_t bss_end_addr required
21 * 28 uint32_t 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(const char *image, unsigned long image_size);
103 static int
104 parsebinimage(
105 const char *image, unsigned long image_size,
106 struct domain_setup_info *dsi);
107 static int
108 loadbinimage(
109 const char *image, unsigned long image_size, int xch, uint32_t dom,
110 xen_pfn_t *parray, struct domain_setup_info *dsi);
112 int probe_bin(const char *image,
113 unsigned long image_size,
114 struct load_funcs *load_funcs)
115 {
116 if ( findtable(image, image_size) == NULL )
117 return -EINVAL;
119 load_funcs->parseimage = parsebinimage;
120 load_funcs->loadimage = loadbinimage;
122 return 0;
123 }
125 static struct xen_bin_image_table *
126 findtable(const char *image, unsigned long image_size)
127 {
128 struct xen_bin_image_table *table;
129 unsigned long *probe_ptr;
130 unsigned probe_index;
131 unsigned probe_count;
133 /* Don't go outside the image */
134 if ( image_size < sizeof(struct xen_bin_image_table) )
135 return NULL;
137 probe_count = image_size;
138 /* Restrict to first 8k */
139 if ( probe_count > 8192 )
140 probe_count = 8192;
141 probe_count = (probe_count - sizeof(struct xen_bin_image_table)) /
142 sizeof(unsigned long);
144 /* Search for the magic header */
145 probe_ptr = (unsigned long *) image;
146 table = NULL;
147 for ( probe_index = 0; probe_index < probe_count; probe_index++ )
148 {
149 if ( XEN_REACTOS_MAGIC3 == *probe_ptr )
150 {
151 table = (struct xen_bin_image_table *) probe_ptr;
152 /* Checksum correct? */
153 if ( 0 == table->magic + table->flags + table->checksum )
154 {
155 return table;
156 }
157 }
158 probe_ptr++;
159 }
161 return NULL;
162 }
164 static int parsebinimage(const char *image,
165 unsigned long image_size,
166 struct domain_setup_info *dsi)
167 {
168 struct xen_bin_image_table *image_info;
169 unsigned long start_addr;
170 unsigned long end_addr;
172 image_info = findtable(image, image_size);
173 if ( NULL == image_info )
174 {
175 ERROR("Image does not have a valid xen_bin_image_table table.");
176 return -EINVAL;
177 }
179 /* Check the flags */
180 if ( FLAGS_REQUIRED != (image_info->flags & FLAGS_MASK) )
181 {
182 ERROR("xen_bin_image_table flags required 0x%08x found 0x%08lx",
183 FLAGS_REQUIRED, image_info->flags & FLAGS_MASK);
184 return -EINVAL;
185 }
187 /* Sanity check on the addresses */
188 if ( image_info->header_addr < image_info->load_addr ||
189 ((char *) image_info - image) <
190 (image_info->header_addr - image_info->load_addr) )
191 {
192 ERROR("Invalid header_addr.");
193 return -EINVAL;
194 }
195 start_addr = image_info->header_addr - ((char *) image_info - image);
196 if ( 0 != image_info->load_end_addr &&
197 ( image_info->load_end_addr < image_info->load_end_addr ||
198 start_addr + image_size < image_info->load_end_addr ) )
199 {
200 ERROR("Invalid load_end_addr");
201 return -EINVAL;
202 }
203 end_addr = (0 == image_info->load_end_addr ? start_addr + image_size :
204 image_info->load_end_addr);
205 if ( 0 != image_info->bss_end_addr &&
206 image_info->bss_end_addr < end_addr )
207 {
208 ERROR("Invalid bss_end_addr");
209 return -EINVAL;
210 }
212 dsi->v_start = image_info->load_addr;
213 if ( 0 != image_info->bss_end_addr )
214 {
215 dsi->v_end = image_info->bss_end_addr;
216 }
217 else if ( 0 != image_info->load_end_addr )
218 {
219 dsi->v_end = image_info->load_end_addr;
220 }
221 else
222 {
223 dsi->v_end = image_info->load_addr + image_size -
224 (((char *) image_info - image) -
225 (image_info->header_addr - image_info->load_addr));
226 }
227 dsi->v_kernstart = dsi->v_start;
228 dsi->v_kernend = dsi->v_end;
229 dsi->v_kernentry = image_info->entry_addr;
230 dsi->__xen_guest_string = NULL;
232 return 0;
233 }
235 static int
236 loadbinimage(
237 const char *image, unsigned long image_size, int xch, uint32_t dom,
238 xen_pfn_t *parray, struct domain_setup_info *dsi)
239 {
240 unsigned long size;
241 char *va;
242 unsigned long done, chunksz;
243 struct xen_bin_image_table *image_info;
245 image_info = findtable(image, image_size);
246 if ( NULL == image_info )
247 {
248 ERROR("Image does not have a valid xen_bin_image_table table.");
249 return -EINVAL;
250 }
252 /* Determine image size */
253 if ( 0 == image_info->load_end_addr )
254 {
255 size = image_size - (((char *) image_info - image) -
256 (image_info->header_addr -
257 image_info->load_addr));
258 }
259 else
260 {
261 size = image_info->load_end_addr - image_info->load_addr;
262 }
264 /* It's possible that we need to skip the first part of the image */
265 image += ((char *)image_info - image) -
266 (image_info->header_addr - image_info->load_addr);
268 for ( done = 0; done < size; done += chunksz )
269 {
270 va = xc_map_foreign_range(
271 xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]);
272 chunksz = size - done;
273 if ( chunksz > PAGE_SIZE )
274 chunksz = PAGE_SIZE;
275 memcpy(va, image + done, chunksz);
276 munmap(va, PAGE_SIZE);
277 }
279 if ( 0 != image_info->bss_end_addr &&
280 image_info->load_addr + size < image_info->bss_end_addr )
281 {
282 size = image_info->bss_end_addr - image_info->load_addr;
283 }
284 for ( ; done < size; done += chunksz )
285 {
286 va = xc_map_foreign_range(
287 xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]);
288 chunksz = size - done;
289 if ( chunksz > (PAGE_SIZE - (done & (PAGE_SIZE-1))) )
290 chunksz = PAGE_SIZE - (done & (PAGE_SIZE-1));
291 memset(va + (done & (PAGE_SIZE-1)), 0, chunksz);
292 munmap(va, PAGE_SIZE);
293 }
295 return 0;
296 }
298 /*
299 * Local variables:
300 * mode: C
301 * c-set-style: "BSD"
302 * c-basic-offset: 4
303 * tab-width: 4
304 * indent-tabs-mode: nil
305 * End:
306 */