1 | /* |
---|
2 | * Xen domain builder -- core bits. |
---|
3 | * |
---|
4 | * The core code goes here: |
---|
5 | * - allocate and release domain structs. |
---|
6 | * - memory management functions. |
---|
7 | * - misc helper functions. |
---|
8 | * |
---|
9 | * This code is licenced under the GPL. |
---|
10 | * written 2006 by Gerd Hoffmann <kraxel@suse.de>. |
---|
11 | * |
---|
12 | */ |
---|
13 | #include <stdio.h> |
---|
14 | #include <stdlib.h> |
---|
15 | #include <string.h> |
---|
16 | #include <stdarg.h> |
---|
17 | #include <inttypes.h> |
---|
18 | #include <zlib.h> |
---|
19 | |
---|
20 | #include "xg_private.h" |
---|
21 | #include "xc_dom.h" |
---|
22 | |
---|
23 | /* ------------------------------------------------------------------------ */ |
---|
24 | /* debugging */ |
---|
25 | |
---|
26 | FILE *xc_dom_logfile = NULL; |
---|
27 | |
---|
28 | void xc_dom_loginit(void) |
---|
29 | { |
---|
30 | if ( xc_dom_logfile ) |
---|
31 | return; |
---|
32 | xc_dom_logfile = fopen("/var/log/xen/domain-builder-ng.log", "a"); |
---|
33 | setvbuf(xc_dom_logfile, NULL, _IONBF, 0); |
---|
34 | xc_dom_printf("### ----- xc domain builder logfile opened -----\n"); |
---|
35 | } |
---|
36 | |
---|
37 | int xc_dom_printf(const char *fmt, ...) |
---|
38 | { |
---|
39 | va_list args; |
---|
40 | char buf[1024]; |
---|
41 | int rc; |
---|
42 | |
---|
43 | if ( !xc_dom_logfile ) |
---|
44 | return 0; |
---|
45 | |
---|
46 | va_start(args, fmt); |
---|
47 | rc = vsnprintf(buf, sizeof(buf), fmt, args); |
---|
48 | va_end(args); |
---|
49 | rc = fwrite(buf, rc, 1, xc_dom_logfile); |
---|
50 | |
---|
51 | return rc; |
---|
52 | } |
---|
53 | |
---|
54 | int xc_dom_panic_func(const char *file, int line, xc_error_code err, |
---|
55 | const char *fmt, ...) |
---|
56 | { |
---|
57 | va_list args; |
---|
58 | FILE *fp = stderr; |
---|
59 | int rc = 0; |
---|
60 | char pos[256]; |
---|
61 | char msg[XC_MAX_ERROR_MSG_LEN]; |
---|
62 | |
---|
63 | if ( xc_dom_logfile ) |
---|
64 | fp = xc_dom_logfile; |
---|
65 | |
---|
66 | snprintf(pos, sizeof(pos), "%s:%d: panic: ", file, line); |
---|
67 | va_start(args, fmt); |
---|
68 | vsnprintf(msg, sizeof(msg), fmt, args); |
---|
69 | va_end(args); |
---|
70 | xc_set_error(err, "%s", msg); |
---|
71 | rc = fprintf(fp, "%s%s", pos, msg); |
---|
72 | return rc; |
---|
73 | } |
---|
74 | |
---|
75 | static void print_mem(const char *name, size_t mem) |
---|
76 | { |
---|
77 | if ( mem > (32 * 1024 * 1024) ) |
---|
78 | xc_dom_printf("%-24s : %zd MB\n", name, mem / (1024 * 1024)); |
---|
79 | else if ( mem > (32 * 1024) ) |
---|
80 | xc_dom_printf("%-24s : %zd kB\n", name, mem / 1024); |
---|
81 | else |
---|
82 | xc_dom_printf("%-24s : %zd bytes\n", name, mem); |
---|
83 | } |
---|
84 | |
---|
85 | void xc_dom_log_memory_footprint(struct xc_dom_image *dom) |
---|
86 | { |
---|
87 | xc_dom_printf("domain builder memory footprint\n"); |
---|
88 | xc_dom_printf(" allocated\n"); |
---|
89 | print_mem(" malloc", dom->alloc_malloc); |
---|
90 | print_mem(" anon mmap", dom->alloc_mem_map); |
---|
91 | xc_dom_printf(" mapped\n"); |
---|
92 | print_mem(" file mmap", dom->alloc_file_map); |
---|
93 | print_mem(" domU mmap", dom->alloc_domU_map); |
---|
94 | } |
---|
95 | |
---|
96 | /* ------------------------------------------------------------------------ */ |
---|
97 | /* simple memory pool */ |
---|
98 | |
---|
99 | void *xc_dom_malloc(struct xc_dom_image *dom, size_t size) |
---|
100 | { |
---|
101 | struct xc_dom_mem *block; |
---|
102 | |
---|
103 | block = malloc(sizeof(*block) + size); |
---|
104 | if ( block == NULL ) |
---|
105 | return NULL; |
---|
106 | memset(block, 0, sizeof(*block) + size); |
---|
107 | block->next = dom->memblocks; |
---|
108 | dom->memblocks = block; |
---|
109 | dom->alloc_malloc += sizeof(*block) + size; |
---|
110 | if ( size > (100 * 1024) ) |
---|
111 | print_mem(__FUNCTION__, size); |
---|
112 | return block->memory; |
---|
113 | } |
---|
114 | |
---|
115 | void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size) |
---|
116 | { |
---|
117 | struct xc_dom_mem *block; |
---|
118 | |
---|
119 | block = malloc(sizeof(*block)); |
---|
120 | if ( block == NULL ) |
---|
121 | return NULL; |
---|
122 | memset(block, 0, sizeof(*block)); |
---|
123 | block->mmap_len = size; |
---|
124 | block->mmap_ptr = mmap(NULL, block->mmap_len, |
---|
125 | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, |
---|
126 | -1, 0); |
---|
127 | if ( block->mmap_ptr == MAP_FAILED ) |
---|
128 | { |
---|
129 | free(block); |
---|
130 | return NULL; |
---|
131 | } |
---|
132 | block->next = dom->memblocks; |
---|
133 | dom->memblocks = block; |
---|
134 | dom->alloc_malloc += sizeof(*block); |
---|
135 | dom->alloc_mem_map += block->mmap_len; |
---|
136 | if ( size > (100 * 1024) ) |
---|
137 | print_mem(__FUNCTION__, size); |
---|
138 | return block->mmap_ptr; |
---|
139 | } |
---|
140 | |
---|
141 | void *xc_dom_malloc_filemap(struct xc_dom_image *dom, |
---|
142 | const char *filename, size_t * size) |
---|
143 | { |
---|
144 | struct xc_dom_mem *block = NULL; |
---|
145 | int fd = -1; |
---|
146 | |
---|
147 | fd = open(filename, O_RDONLY); |
---|
148 | if ( fd == -1 ) |
---|
149 | goto err; |
---|
150 | |
---|
151 | lseek(fd, 0, SEEK_SET); |
---|
152 | *size = lseek(fd, 0, SEEK_END); |
---|
153 | |
---|
154 | block = malloc(sizeof(*block)); |
---|
155 | if ( block == NULL ) |
---|
156 | goto err; |
---|
157 | memset(block, 0, sizeof(*block)); |
---|
158 | block->mmap_len = *size; |
---|
159 | block->mmap_ptr = mmap(NULL, block->mmap_len, PROT_READ, |
---|
160 | MAP_SHARED, fd, 0); |
---|
161 | if ( block->mmap_ptr == MAP_FAILED ) |
---|
162 | goto err; |
---|
163 | block->next = dom->memblocks; |
---|
164 | dom->memblocks = block; |
---|
165 | dom->alloc_malloc += sizeof(*block); |
---|
166 | dom->alloc_file_map += block->mmap_len; |
---|
167 | close(fd); |
---|
168 | if ( *size > (100 * 1024) ) |
---|
169 | print_mem(__FUNCTION__, *size); |
---|
170 | return block->mmap_ptr; |
---|
171 | |
---|
172 | err: |
---|
173 | if ( fd != -1 ) |
---|
174 | close(fd); |
---|
175 | if ( block != NULL ) |
---|
176 | free(block); |
---|
177 | return NULL; |
---|
178 | } |
---|
179 | |
---|
180 | static void xc_dom_free_all(struct xc_dom_image *dom) |
---|
181 | { |
---|
182 | struct xc_dom_mem *block; |
---|
183 | |
---|
184 | while ( (block = dom->memblocks) != NULL ) |
---|
185 | { |
---|
186 | dom->memblocks = block->next; |
---|
187 | if ( block->mmap_ptr ) |
---|
188 | munmap(block->mmap_ptr, block->mmap_len); |
---|
189 | free(block); |
---|
190 | } |
---|
191 | } |
---|
192 | |
---|
193 | char *xc_dom_strdup(struct xc_dom_image *dom, const char *str) |
---|
194 | { |
---|
195 | size_t len = strlen(str) + 1; |
---|
196 | char *nstr = xc_dom_malloc(dom, len); |
---|
197 | |
---|
198 | if ( nstr == NULL ) |
---|
199 | return NULL; |
---|
200 | memcpy(nstr, str, len); |
---|
201 | return nstr; |
---|
202 | } |
---|
203 | |
---|
204 | /* ------------------------------------------------------------------------ */ |
---|
205 | /* read files, copy memory blocks, with transparent gunzip */ |
---|
206 | |
---|
207 | size_t xc_dom_check_gzip(void *blob, size_t ziplen) |
---|
208 | { |
---|
209 | unsigned char *gzlen; |
---|
210 | size_t unziplen; |
---|
211 | |
---|
212 | if ( strncmp(blob, "\037\213", 2) ) |
---|
213 | /* not gzipped */ |
---|
214 | return 0; |
---|
215 | |
---|
216 | gzlen = blob + ziplen - 4; |
---|
217 | unziplen = gzlen[3] << 24 | gzlen[2] << 16 | gzlen[1] << 8 | gzlen[0]; |
---|
218 | if ( (unziplen < 0) || (unziplen > (1024*1024*1024)) ) /* 1GB limit */ |
---|
219 | { |
---|
220 | xc_dom_printf |
---|
221 | ("%s: size (zip %zd, unzip %zd) looks insane, skip gunzip\n", |
---|
222 | __FUNCTION__, ziplen, unziplen); |
---|
223 | return 0; |
---|
224 | } |
---|
225 | |
---|
226 | return unziplen + 16; |
---|
227 | } |
---|
228 | |
---|
229 | int xc_dom_do_gunzip(void *src, size_t srclen, void *dst, size_t dstlen) |
---|
230 | { |
---|
231 | z_stream zStream; |
---|
232 | int rc; |
---|
233 | |
---|
234 | memset(&zStream, 0, sizeof(zStream)); |
---|
235 | zStream.next_in = src; |
---|
236 | zStream.avail_in = srclen; |
---|
237 | zStream.next_out = dst; |
---|
238 | zStream.avail_out = dstlen; |
---|
239 | rc = inflateInit2(&zStream, (MAX_WBITS + 32)); /* +32 means "handle gzip" */ |
---|
240 | if ( rc != Z_OK ) |
---|
241 | { |
---|
242 | xc_dom_panic(XC_INTERNAL_ERROR, |
---|
243 | "%s: inflateInit2 failed (rc=%d)\n", __FUNCTION__, rc); |
---|
244 | return -1; |
---|
245 | } |
---|
246 | rc = inflate(&zStream, Z_FINISH); |
---|
247 | if ( rc != Z_STREAM_END ) |
---|
248 | { |
---|
249 | xc_dom_panic(XC_INTERNAL_ERROR, |
---|
250 | "%s: inflate failed (rc=%d)\n", __FUNCTION__, rc); |
---|
251 | return -1; |
---|
252 | } |
---|
253 | |
---|
254 | xc_dom_printf("%s: unzip ok, 0x%zx -> 0x%zx\n", |
---|
255 | __FUNCTION__, srclen, dstlen); |
---|
256 | return 0; |
---|
257 | } |
---|
258 | |
---|
259 | int xc_dom_try_gunzip(struct xc_dom_image *dom, void **blob, size_t * size) |
---|
260 | { |
---|
261 | void *unzip; |
---|
262 | size_t unziplen; |
---|
263 | |
---|
264 | unziplen = xc_dom_check_gzip(*blob, *size); |
---|
265 | if ( unziplen == 0 ) |
---|
266 | return 0; |
---|
267 | |
---|
268 | unzip = xc_dom_malloc(dom, unziplen); |
---|
269 | if ( unzip == NULL ) |
---|
270 | return -1; |
---|
271 | |
---|
272 | if ( xc_dom_do_gunzip(*blob, *size, unzip, unziplen) == -1 ) |
---|
273 | return -1; |
---|
274 | |
---|
275 | *blob = unzip; |
---|
276 | *size = unziplen; |
---|
277 | return 0; |
---|
278 | } |
---|
279 | |
---|
280 | /* ------------------------------------------------------------------------ */ |
---|
281 | /* domain memory */ |
---|
282 | |
---|
283 | void *xc_dom_pfn_to_ptr(struct xc_dom_image *dom, xen_pfn_t pfn, |
---|
284 | xen_pfn_t count) |
---|
285 | { |
---|
286 | struct xc_dom_phys *phys; |
---|
287 | unsigned int page_shift = XC_DOM_PAGE_SHIFT(dom); |
---|
288 | char *mode = "unset"; |
---|
289 | |
---|
290 | if ( pfn > dom->total_pages ) |
---|
291 | { |
---|
292 | xc_dom_printf("%s: pfn out of range (0x%" PRIpfn " > 0x%" PRIpfn ")\n", |
---|
293 | __FUNCTION__, pfn, dom->total_pages); |
---|
294 | return NULL; |
---|
295 | } |
---|
296 | |
---|
297 | /* already allocated? */ |
---|
298 | for ( phys = dom->phys_pages; phys != NULL; phys = phys->next ) |
---|
299 | { |
---|
300 | if ( pfn >= (phys->first + phys->count) ) |
---|
301 | continue; |
---|
302 | if ( count ) |
---|
303 | { |
---|
304 | /* size given: must be completely within the already allocated block */ |
---|
305 | if ( (pfn + count) <= phys->first ) |
---|
306 | continue; |
---|
307 | if ( (pfn < phys->first) || |
---|
308 | ((pfn + count) > (phys->first + phys->count)) ) |
---|
309 | { |
---|
310 | xc_dom_printf("%s: request overlaps allocated block" |
---|
311 | " (req 0x%" PRIpfn "+0x%" PRIpfn "," |
---|
312 | " blk 0x%" PRIpfn "+0x%" PRIpfn ")\n", |
---|
313 | __FUNCTION__, pfn, count, phys->first, |
---|
314 | phys->count); |
---|
315 | return NULL; |
---|
316 | } |
---|
317 | } |
---|
318 | else |
---|
319 | { |
---|
320 | /* no size given: block must be allocated already, |
---|
321 | just hand out a pointer to it */ |
---|
322 | if ( pfn < phys->first ) |
---|
323 | continue; |
---|
324 | } |
---|
325 | return phys->ptr + ((pfn - phys->first) << page_shift); |
---|
326 | } |
---|
327 | |
---|
328 | /* allocating is allowed with size specified only */ |
---|
329 | if ( count == 0 ) |
---|
330 | { |
---|
331 | xc_dom_printf("%s: no block found, no size given," |
---|
332 | " can't malloc (pfn 0x%" PRIpfn ")\n", |
---|
333 | __FUNCTION__, pfn); |
---|
334 | return NULL; |
---|
335 | } |
---|
336 | |
---|
337 | /* not found, no overlap => allocate */ |
---|
338 | phys = xc_dom_malloc(dom, sizeof(*phys)); |
---|
339 | if ( phys == NULL ) |
---|
340 | return NULL; |
---|
341 | memset(phys, 0, sizeof(*phys)); |
---|
342 | phys->first = pfn; |
---|
343 | phys->count = count; |
---|
344 | |
---|
345 | if ( dom->guest_domid ) |
---|
346 | { |
---|
347 | mode = "domU mapping"; |
---|
348 | phys->ptr = xc_dom_boot_domU_map(dom, phys->first, phys->count); |
---|
349 | if ( phys->ptr == NULL ) |
---|
350 | return NULL; |
---|
351 | dom->alloc_domU_map += phys->count << page_shift; |
---|
352 | } |
---|
353 | else |
---|
354 | { |
---|
355 | mode = "anonymous memory"; |
---|
356 | phys->ptr = mmap(NULL, phys->count << page_shift, |
---|
357 | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, |
---|
358 | -1, 0); |
---|
359 | if ( phys->ptr == MAP_FAILED ) |
---|
360 | { |
---|
361 | xc_dom_panic(XC_OUT_OF_MEMORY, |
---|
362 | "%s: oom: can't allocate 0x%" PRIpfn " pages\n", |
---|
363 | __FUNCTION__, count); |
---|
364 | return NULL; |
---|
365 | } |
---|
366 | dom->alloc_mem_map += phys->count << page_shift; |
---|
367 | } |
---|
368 | |
---|
369 | #if 1 |
---|
370 | xc_dom_printf("%s: %s: pfn 0x%" PRIpfn "+0x%" PRIpfn " at %p\n", |
---|
371 | __FUNCTION__, mode, phys->first, phys->count, phys->ptr); |
---|
372 | #endif |
---|
373 | phys->next = dom->phys_pages; |
---|
374 | dom->phys_pages = phys; |
---|
375 | return phys->ptr; |
---|
376 | } |
---|
377 | |
---|
378 | int xc_dom_alloc_segment(struct xc_dom_image *dom, |
---|
379 | struct xc_dom_seg *seg, char *name, |
---|
380 | xen_vaddr_t start, xen_vaddr_t size) |
---|
381 | { |
---|
382 | unsigned int page_size = XC_DOM_PAGE_SIZE(dom); |
---|
383 | xen_pfn_t pages = (size + page_size - 1) / page_size; |
---|
384 | void *ptr; |
---|
385 | |
---|
386 | if ( start == 0 ) |
---|
387 | start = dom->virt_alloc_end; |
---|
388 | |
---|
389 | if ( start & (page_size - 1) ) |
---|
390 | { |
---|
391 | xc_dom_panic(XC_INTERNAL_ERROR, |
---|
392 | "%s: segment start isn't page aligned (0x%" PRIx64 ")\n", |
---|
393 | __FUNCTION__, start); |
---|
394 | return -1; |
---|
395 | } |
---|
396 | if ( start < dom->virt_alloc_end ) |
---|
397 | { |
---|
398 | xc_dom_panic(XC_INTERNAL_ERROR, |
---|
399 | "%s: segment start too low (0x%" PRIx64 " < 0x%" PRIx64 |
---|
400 | ")\n", __FUNCTION__, start, dom->virt_alloc_end); |
---|
401 | return -1; |
---|
402 | } |
---|
403 | |
---|
404 | seg->vstart = start; |
---|
405 | seg->vend = start + pages * page_size; |
---|
406 | seg->pfn = (seg->vstart - dom->parms.virt_base) / page_size; |
---|
407 | dom->virt_alloc_end = seg->vend; |
---|
408 | |
---|
409 | xc_dom_printf("%-20s: %-12s : 0x%" PRIx64 " -> 0x%" PRIx64 |
---|
410 | " (pfn 0x%" PRIpfn " + 0x%" PRIpfn " pages)\n", |
---|
411 | __FUNCTION__, name, seg->vstart, seg->vend, seg->pfn, pages); |
---|
412 | |
---|
413 | /* map and clear pages */ |
---|
414 | ptr = xc_dom_seg_to_ptr(dom, seg); |
---|
415 | if ( ptr == NULL ) |
---|
416 | return -1; |
---|
417 | memset(ptr, 0, pages * page_size); |
---|
418 | |
---|
419 | return 0; |
---|
420 | } |
---|
421 | |
---|
422 | int xc_dom_alloc_page(struct xc_dom_image *dom, char *name) |
---|
423 | { |
---|
424 | unsigned int page_size = XC_DOM_PAGE_SIZE(dom); |
---|
425 | xen_vaddr_t start; |
---|
426 | xen_pfn_t pfn; |
---|
427 | |
---|
428 | start = dom->virt_alloc_end; |
---|
429 | dom->virt_alloc_end += page_size; |
---|
430 | pfn = (start - dom->parms.virt_base) / page_size; |
---|
431 | |
---|
432 | xc_dom_printf("%-20s: %-12s : 0x%" PRIx64 " (pfn 0x%" PRIpfn ")\n", |
---|
433 | __FUNCTION__, name, start, pfn); |
---|
434 | return pfn; |
---|
435 | } |
---|
436 | |
---|
437 | void xc_dom_unmap_one(struct xc_dom_image *dom, xen_pfn_t pfn) |
---|
438 | { |
---|
439 | unsigned int page_shift = XC_DOM_PAGE_SHIFT(dom); |
---|
440 | struct xc_dom_phys *phys, *prev = NULL; |
---|
441 | |
---|
442 | for ( phys = dom->phys_pages; phys != NULL; phys = phys->next ) |
---|
443 | { |
---|
444 | if ( (pfn >= phys->first) && (pfn < (phys->first + phys->count)) ) |
---|
445 | break; |
---|
446 | prev = phys; |
---|
447 | } |
---|
448 | if ( !phys ) |
---|
449 | { |
---|
450 | xc_dom_printf("%s: Huh? no mapping with pfn 0x%" PRIpfn "\n", |
---|
451 | __FUNCTION__, pfn); |
---|
452 | return; |
---|
453 | } |
---|
454 | |
---|
455 | munmap(phys->ptr, phys->count << page_shift); |
---|
456 | if ( prev ) |
---|
457 | prev->next = phys->next; |
---|
458 | else |
---|
459 | dom->phys_pages = phys->next; |
---|
460 | } |
---|
461 | |
---|
462 | void xc_dom_unmap_all(struct xc_dom_image *dom) |
---|
463 | { |
---|
464 | while ( dom->phys_pages ) |
---|
465 | xc_dom_unmap_one(dom, dom->phys_pages->first); |
---|
466 | } |
---|
467 | |
---|
468 | /* ------------------------------------------------------------------------ */ |
---|
469 | /* pluggable kernel loaders */ |
---|
470 | |
---|
471 | static struct xc_dom_loader *first_loader = NULL; |
---|
472 | static struct xc_dom_arch *first_hook = NULL; |
---|
473 | |
---|
474 | void xc_dom_register_loader(struct xc_dom_loader *loader) |
---|
475 | { |
---|
476 | loader->next = first_loader; |
---|
477 | first_loader = loader; |
---|
478 | } |
---|
479 | |
---|
480 | static struct xc_dom_loader *xc_dom_find_loader(struct xc_dom_image *dom) |
---|
481 | { |
---|
482 | struct xc_dom_loader *loader = first_loader; |
---|
483 | |
---|
484 | while ( loader != NULL ) |
---|
485 | { |
---|
486 | xc_dom_printf("%s: trying %s loader ... ", __FUNCTION__, loader->name); |
---|
487 | if ( loader->probe(dom) == 0 ) |
---|
488 | { |
---|
489 | xc_dom_printf("OK\n"); |
---|
490 | return loader; |
---|
491 | } |
---|
492 | xc_dom_printf("failed\n"); |
---|
493 | loader = loader->next; |
---|
494 | } |
---|
495 | xc_dom_panic(XC_INVALID_KERNEL, "%s: no loader found\n", __FUNCTION__); |
---|
496 | return NULL; |
---|
497 | } |
---|
498 | |
---|
499 | void xc_dom_register_arch_hooks(struct xc_dom_arch *hooks) |
---|
500 | { |
---|
501 | hooks->next = first_hook; |
---|
502 | first_hook = hooks; |
---|
503 | } |
---|
504 | |
---|
505 | static struct xc_dom_arch *xc_dom_find_arch_hooks(char *guest_type) |
---|
506 | { |
---|
507 | struct xc_dom_arch *hooks = first_hook; |
---|
508 | |
---|
509 | while ( hooks != NULL ) |
---|
510 | { |
---|
511 | if ( !strcmp(hooks->guest_type, guest_type)) |
---|
512 | return hooks; |
---|
513 | hooks = hooks->next; |
---|
514 | } |
---|
515 | xc_dom_panic(XC_INVALID_KERNEL, |
---|
516 | "%s: not found (type %s)\n", __FUNCTION__, guest_type); |
---|
517 | return NULL; |
---|
518 | } |
---|
519 | |
---|
520 | /* ------------------------------------------------------------------------ */ |
---|
521 | /* public interface */ |
---|
522 | |
---|
523 | void xc_dom_release(struct xc_dom_image *dom) |
---|
524 | { |
---|
525 | xc_dom_printf("%s: called\n", __FUNCTION__); |
---|
526 | if ( dom->phys_pages ) |
---|
527 | xc_dom_unmap_all(dom); |
---|
528 | xc_dom_free_all(dom); |
---|
529 | free(dom); |
---|
530 | } |
---|
531 | |
---|
532 | struct xc_dom_image *xc_dom_allocate(const char *cmdline, const char *features) |
---|
533 | { |
---|
534 | struct xc_dom_image *dom; |
---|
535 | |
---|
536 | xc_dom_printf("%s: cmdline=\"%s\", features=\"%s\"\n", |
---|
537 | __FUNCTION__, cmdline, features); |
---|
538 | dom = malloc(sizeof(*dom)); |
---|
539 | if ( !dom ) |
---|
540 | goto err; |
---|
541 | |
---|
542 | memset(dom, 0, sizeof(*dom)); |
---|
543 | if ( cmdline ) |
---|
544 | dom->cmdline = xc_dom_strdup(dom, cmdline); |
---|
545 | if ( features ) |
---|
546 | elf_xen_parse_features(features, dom->f_requested, NULL); |
---|
547 | |
---|
548 | dom->parms.virt_base = UNSET_ADDR; |
---|
549 | dom->parms.virt_entry = UNSET_ADDR; |
---|
550 | dom->parms.virt_hypercall = UNSET_ADDR; |
---|
551 | dom->parms.virt_hv_start_low = UNSET_ADDR; |
---|
552 | dom->parms.elf_paddr_offset = UNSET_ADDR; |
---|
553 | |
---|
554 | dom->alloc_malloc += sizeof(*dom); |
---|
555 | return dom; |
---|
556 | |
---|
557 | err: |
---|
558 | if ( dom ) |
---|
559 | xc_dom_release(dom); |
---|
560 | return NULL; |
---|
561 | } |
---|
562 | |
---|
563 | int xc_dom_kernel_file(struct xc_dom_image *dom, const char *filename) |
---|
564 | { |
---|
565 | xc_dom_printf("%s: filename=\"%s\"\n", __FUNCTION__, filename); |
---|
566 | dom->kernel_blob = xc_dom_malloc_filemap(dom, filename, &dom->kernel_size); |
---|
567 | if ( dom->kernel_blob == NULL ) |
---|
568 | return -1; |
---|
569 | return xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size); |
---|
570 | } |
---|
571 | |
---|
572 | int xc_dom_ramdisk_file(struct xc_dom_image *dom, const char *filename) |
---|
573 | { |
---|
574 | xc_dom_printf("%s: filename=\"%s\"\n", __FUNCTION__, filename); |
---|
575 | dom->ramdisk_blob = |
---|
576 | xc_dom_malloc_filemap(dom, filename, &dom->ramdisk_size); |
---|
577 | if ( dom->ramdisk_blob == NULL ) |
---|
578 | return -1; |
---|
579 | // return xc_dom_try_gunzip(dom, &dom->ramdisk_blob, &dom->ramdisk_size); |
---|
580 | return 0; |
---|
581 | } |
---|
582 | |
---|
583 | int xc_dom_kernel_mem(struct xc_dom_image *dom, const void *mem, size_t memsize) |
---|
584 | { |
---|
585 | xc_dom_printf("%s: called\n", __FUNCTION__); |
---|
586 | dom->kernel_blob = (void *)mem; |
---|
587 | dom->kernel_size = memsize; |
---|
588 | return xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size); |
---|
589 | } |
---|
590 | |
---|
591 | int xc_dom_ramdisk_mem(struct xc_dom_image *dom, const void *mem, |
---|
592 | size_t memsize) |
---|
593 | { |
---|
594 | xc_dom_printf("%s: called\n", __FUNCTION__); |
---|
595 | dom->ramdisk_blob = (void *)mem; |
---|
596 | dom->ramdisk_size = memsize; |
---|
597 | // return xc_dom_try_gunzip(dom, &dom->ramdisk_blob, &dom->ramdisk_size); |
---|
598 | return 0; |
---|
599 | } |
---|
600 | |
---|
601 | int xc_dom_parse_image(struct xc_dom_image *dom) |
---|
602 | { |
---|
603 | int i; |
---|
604 | |
---|
605 | xc_dom_printf("%s: called\n", __FUNCTION__); |
---|
606 | |
---|
607 | /* parse kernel image */ |
---|
608 | dom->kernel_loader = xc_dom_find_loader(dom); |
---|
609 | if ( dom->kernel_loader == NULL ) |
---|
610 | goto err; |
---|
611 | if ( dom->kernel_loader->parser(dom) != 0 ) |
---|
612 | goto err; |
---|
613 | if ( dom->guest_type == NULL ) |
---|
614 | { |
---|
615 | xc_dom_panic(XC_INTERNAL_ERROR, |
---|
616 | "%s: guest_type not set\n", __FUNCTION__); |
---|
617 | goto err; |
---|
618 | } |
---|
619 | |
---|
620 | /* check features */ |
---|
621 | for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ ) |
---|
622 | { |
---|
623 | dom->f_active[i] |= dom->f_requested[i]; /* cmd line */ |
---|
624 | dom->f_active[i] |= dom->parms.f_required[i]; /* kernel */ |
---|
625 | if ( (dom->f_active[i] & dom->parms.f_supported[i]) != |
---|
626 | dom->f_active[i] ) |
---|
627 | { |
---|
628 | xc_dom_panic(XC_INVALID_PARAM, |
---|
629 | "%s: unsupported feature requested\n", __FUNCTION__); |
---|
630 | goto err; |
---|
631 | } |
---|
632 | } |
---|
633 | return 0; |
---|
634 | |
---|
635 | err: |
---|
636 | return -1; |
---|
637 | } |
---|
638 | |
---|
639 | int xc_dom_mem_init(struct xc_dom_image *dom, unsigned int mem_mb) |
---|
640 | { |
---|
641 | unsigned int page_shift; |
---|
642 | xen_pfn_t nr_pages; |
---|
643 | |
---|
644 | dom->arch_hooks = xc_dom_find_arch_hooks(dom->guest_type); |
---|
645 | if ( dom->arch_hooks == NULL ) |
---|
646 | { |
---|
647 | xc_dom_panic(XC_INTERNAL_ERROR, "%s: arch hooks not set\n", |
---|
648 | __FUNCTION__); |
---|
649 | return -1; |
---|
650 | } |
---|
651 | |
---|
652 | page_shift = XC_DOM_PAGE_SHIFT(dom); |
---|
653 | nr_pages = mem_mb << (20 - page_shift); |
---|
654 | |
---|
655 | xc_dom_printf("%s: mem %d MB, pages 0x%" PRIpfn " pages, %dk each\n", |
---|
656 | __FUNCTION__, mem_mb, nr_pages, 1 << (page_shift-10)); |
---|
657 | dom->total_pages = nr_pages; |
---|
658 | |
---|
659 | xc_dom_printf("%s: 0x%" PRIpfn " pages\n", |
---|
660 | __FUNCTION__, dom->total_pages); |
---|
661 | |
---|
662 | return 0; |
---|
663 | } |
---|
664 | |
---|
665 | int xc_dom_update_guest_p2m(struct xc_dom_image *dom) |
---|
666 | { |
---|
667 | uint32_t *p2m_32; |
---|
668 | uint64_t *p2m_64; |
---|
669 | xen_pfn_t i; |
---|
670 | |
---|
671 | if ( !dom->p2m_guest ) |
---|
672 | return 0; |
---|
673 | |
---|
674 | switch ( dom->arch_hooks->sizeof_pfn ) |
---|
675 | { |
---|
676 | case 4: |
---|
677 | xc_dom_printf("%s: dst 32bit, pages 0x%" PRIpfn " \n", |
---|
678 | __FUNCTION__, dom->total_pages); |
---|
679 | p2m_32 = dom->p2m_guest; |
---|
680 | for ( i = 0; i < dom->total_pages; i++ ) |
---|
681 | if ( dom->p2m_host[i] != INVALID_P2M_ENTRY ) |
---|
682 | p2m_32[i] = dom->p2m_host[i]; |
---|
683 | else |
---|
684 | p2m_32[i] = (uint32_t) - 1; |
---|
685 | break; |
---|
686 | case 8: |
---|
687 | xc_dom_printf("%s: dst 64bit, pages 0x%" PRIpfn " \n", |
---|
688 | __FUNCTION__, dom->total_pages); |
---|
689 | p2m_64 = dom->p2m_guest; |
---|
690 | for ( i = 0; i < dom->total_pages; i++ ) |
---|
691 | if ( dom->p2m_host[i] != INVALID_P2M_ENTRY ) |
---|
692 | p2m_64[i] = dom->p2m_host[i]; |
---|
693 | else |
---|
694 | p2m_64[i] = (uint64_t) - 1; |
---|
695 | break; |
---|
696 | default: |
---|
697 | xc_dom_panic(XC_INTERNAL_ERROR, |
---|
698 | "sizeof_pfn is invalid (is %d, can be 4 or 8)", |
---|
699 | dom->arch_hooks->sizeof_pfn); |
---|
700 | return -1; |
---|
701 | } |
---|
702 | return 0; |
---|
703 | } |
---|
704 | |
---|
705 | int xc_dom_build_image(struct xc_dom_image *dom) |
---|
706 | { |
---|
707 | unsigned int page_size; |
---|
708 | |
---|
709 | xc_dom_printf("%s: called\n", __FUNCTION__); |
---|
710 | |
---|
711 | /* check for arch hooks */ |
---|
712 | if ( dom->arch_hooks == NULL ) |
---|
713 | { |
---|
714 | xc_dom_panic(XC_INTERNAL_ERROR, "%s: arch hooks not set\n", |
---|
715 | __FUNCTION__); |
---|
716 | goto err; |
---|
717 | } |
---|
718 | page_size = XC_DOM_PAGE_SIZE(dom); |
---|
719 | |
---|
720 | /* load kernel */ |
---|
721 | if ( xc_dom_alloc_segment(dom, &dom->kernel_seg, "kernel", |
---|
722 | dom->kernel_seg.vstart, |
---|
723 | dom->kernel_seg.vend - |
---|
724 | dom->kernel_seg.vstart) != 0 ) |
---|
725 | goto err; |
---|
726 | if ( dom->kernel_loader->loader(dom) != 0 ) |
---|
727 | goto err; |
---|
728 | |
---|
729 | /* load ramdisk */ |
---|
730 | if ( dom->ramdisk_blob ) |
---|
731 | { |
---|
732 | size_t unziplen, ramdisklen; |
---|
733 | void *ramdiskmap; |
---|
734 | |
---|
735 | unziplen = xc_dom_check_gzip(dom->ramdisk_blob, dom->ramdisk_size); |
---|
736 | ramdisklen = unziplen ? unziplen : dom->ramdisk_size; |
---|
737 | if ( xc_dom_alloc_segment(dom, &dom->ramdisk_seg, "ramdisk", 0, |
---|
738 | ramdisklen) != 0 ) |
---|
739 | goto err; |
---|
740 | ramdiskmap = xc_dom_seg_to_ptr(dom, &dom->ramdisk_seg); |
---|
741 | if ( unziplen ) |
---|
742 | { |
---|
743 | if ( xc_dom_do_gunzip(dom->ramdisk_blob, dom->ramdisk_size, |
---|
744 | ramdiskmap, ramdisklen) == -1 ) |
---|
745 | goto err; |
---|
746 | } |
---|
747 | else |
---|
748 | memcpy(ramdiskmap, dom->ramdisk_blob, dom->ramdisk_size); |
---|
749 | } |
---|
750 | |
---|
751 | /* allocate other pages */ |
---|
752 | if ( dom->arch_hooks->alloc_magic_pages(dom) != 0 ) |
---|
753 | goto err; |
---|
754 | if ( dom->arch_hooks->count_pgtables ) |
---|
755 | { |
---|
756 | dom->arch_hooks->count_pgtables(dom); |
---|
757 | if ( (dom->pgtables > 0) && |
---|
758 | (xc_dom_alloc_segment(dom, &dom->pgtables_seg, "page tables", 0, |
---|
759 | dom->pgtables * page_size) != 0) ) |
---|
760 | goto err; |
---|
761 | } |
---|
762 | if ( dom->alloc_bootstack ) |
---|
763 | dom->bootstack_pfn = xc_dom_alloc_page(dom, "boot stack"); |
---|
764 | xc_dom_printf("%-20s: virt_alloc_end : 0x%" PRIx64 "\n", |
---|
765 | __FUNCTION__, dom->virt_alloc_end); |
---|
766 | xc_dom_printf("%-20s: virt_pgtab_end : 0x%" PRIx64 "\n", |
---|
767 | __FUNCTION__, dom->virt_pgtab_end); |
---|
768 | return 0; |
---|
769 | |
---|
770 | err: |
---|
771 | return -1; |
---|
772 | } |
---|
773 | |
---|
774 | /* |
---|
775 | * Local variables: |
---|
776 | * mode: C |
---|
777 | * c-set-style: "BSD" |
---|
778 | * c-basic-offset: 4 |
---|
779 | * tab-width: 4 |
---|
780 | * indent-tabs-mode: nil |
---|
781 | * End: |
---|
782 | */ |
---|