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 library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation;
12 * version 2.1 of the License.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
21 *
22 * written 2006 by Gerd Hoffmann <kraxel@suse.de>.
23 *
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <inttypes.h>
31 #include <zlib.h>
32 #include <assert.h>
33
34 #include "xg_private.h"
35 #include "xc_dom.h"
36 #include "_paths.h"
37
38 /* ------------------------------------------------------------------------ */
39 /* debugging */
40
41
42
43 static const char *default_logfile = XEN_LOG_DIR "/domain-builder-ng.log";
44
xc_dom_loginit(xc_interface * xch)45 int xc_dom_loginit(xc_interface *xch) {
46 if (xch->dombuild_logger) return 0;
47
48 if (!xch->dombuild_logger_file) {
49 xch->dombuild_logger_file = fopen(default_logfile, "a");
50 if (!xch->dombuild_logger_file) {
51 PERROR("Could not open logfile `%s'", default_logfile);
52 return -1;
53 }
54 }
55
56 xch->dombuild_logger = xch->dombuild_logger_tofree =
57 (xentoollog_logger*)
58 xtl_createlogger_stdiostream(xch->dombuild_logger_file, XTL_DETAIL,
59 XTL_STDIOSTREAM_SHOW_DATE|XTL_STDIOSTREAM_SHOW_PID);
60 if (!xch->dombuild_logger)
61 return -1;
62
63 xc_dom_printf(xch, "### ----- xc domain builder logfile opened -----");
64
65 return 0;
66 }
67
xc_dom_printf(xc_interface * xch,const char * fmt,...)68 void xc_dom_printf(xc_interface *xch, const char *fmt, ...)
69 {
70 va_list args;
71 if (!xch->dombuild_logger) return;
72 va_start(args, fmt);
73 xtl_logv(xch->dombuild_logger, XTL_DETAIL, -1, "domainbuilder", fmt, args);
74 va_end(args);
75 }
76
xc_dom_panic_func(xc_interface * xch,const char * file,int line,xc_error_code err,const char * fmt,...)77 void xc_dom_panic_func(xc_interface *xch,
78 const char *file, int line, xc_error_code err,
79 const char *fmt, ...)
80 {
81 va_list args;
82 char msg[XC_MAX_ERROR_MSG_LEN];
83
84 va_start(args, fmt);
85 vsnprintf(msg, sizeof(msg), fmt, args);
86 va_end(args);
87 msg[sizeof(msg)-1] = 0;
88
89 xc_report(xch,
90 xch->dombuild_logger ? xch->dombuild_logger : xch->error_handler,
91 XTL_ERROR, err, "panic: %s:%d: %s",
92 file, line, msg);
93 }
94
print_mem(struct xc_dom_image * dom,const char * name,size_t mem)95 static void print_mem(struct xc_dom_image *dom, const char *name, size_t mem)
96 {
97 if ( mem > (32 * 1024 * 1024) )
98 DOMPRINTF("%-24s : %zd MB", name, mem / (1024 * 1024));
99 else if ( mem > (32 * 1024) )
100 DOMPRINTF("%-24s : %zd kB", name, mem / 1024);
101 else
102 DOMPRINTF("%-24s : %zd bytes", name, mem);
103 }
104
xc_dom_log_memory_footprint(struct xc_dom_image * dom)105 void xc_dom_log_memory_footprint(struct xc_dom_image *dom)
106 {
107 DOMPRINTF("domain builder memory footprint");
108 DOMPRINTF(" allocated");
109 print_mem(dom, " malloc", dom->alloc_malloc);
110 print_mem(dom, " anon mmap", dom->alloc_mem_map);
111 DOMPRINTF(" mapped");
112 print_mem(dom, " file mmap", dom->alloc_file_map);
113 print_mem(dom, " domU mmap", dom->alloc_domU_map);
114 }
115
116 /* ------------------------------------------------------------------------ */
117 /* simple memory pool */
118
xc_dom_malloc(struct xc_dom_image * dom,size_t size)119 void *xc_dom_malloc(struct xc_dom_image *dom, size_t size)
120 {
121 struct xc_dom_mem *block;
122
123 if ( size > SIZE_MAX - sizeof(*block) )
124 {
125 DOMPRINTF("%s: unreasonable allocation size", __FUNCTION__);
126 return NULL;
127 }
128 block = malloc(sizeof(*block) + size);
129 if ( block == NULL )
130 {
131 DOMPRINTF("%s: allocation failed", __FUNCTION__);
132 return NULL;
133 }
134 memset(block, 0, sizeof(*block) + size);
135 block->type = XC_DOM_MEM_TYPE_MALLOC_INTERNAL;
136 block->next = dom->memblocks;
137 dom->memblocks = block;
138 dom->alloc_malloc += sizeof(*block) + size;
139 if ( size > (100 * 1024) )
140 print_mem(dom, __FUNCTION__, size);
141 return block->memory;
142 }
143
xc_dom_malloc_page_aligned(struct xc_dom_image * dom,size_t size)144 void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size)
145 {
146 struct xc_dom_mem *block;
147
148 block = malloc(sizeof(*block));
149 if ( block == NULL )
150 {
151 DOMPRINTF("%s: allocation failed", __FUNCTION__);
152 return NULL;
153 }
154 memset(block, 0, sizeof(*block));
155 block->len = size;
156 block->ptr = mmap(NULL, block->len,
157 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
158 -1, 0);
159 if ( block->ptr == MAP_FAILED )
160 {
161 DOMPRINTF("%s: mmap failed", __FUNCTION__);
162 free(block);
163 return NULL;
164 }
165 block->type = XC_DOM_MEM_TYPE_MMAP;
166 block->next = dom->memblocks;
167 dom->memblocks = block;
168 dom->alloc_malloc += sizeof(*block);
169 dom->alloc_mem_map += block->len;
170 if ( size > (100 * 1024) )
171 print_mem(dom, __FUNCTION__, size);
172 return block->ptr;
173 }
174
xc_dom_register_external(struct xc_dom_image * dom,void * ptr,size_t size)175 int xc_dom_register_external(struct xc_dom_image *dom, void *ptr, size_t size)
176 {
177 struct xc_dom_mem *block;
178
179 block = malloc(sizeof(*block));
180 if ( block == NULL )
181 {
182 DOMPRINTF("%s: allocation failed", __FUNCTION__);
183 return -1;
184 }
185 memset(block, 0, sizeof(*block));
186 block->ptr = ptr;
187 block->len = size;
188 block->type = XC_DOM_MEM_TYPE_MALLOC_EXTERNAL;
189 block->next = dom->memblocks;
190 dom->memblocks = block;
191 dom->alloc_malloc += sizeof(*block);
192 dom->alloc_mem_map += block->len;
193 return 0;
194 }
195
xc_dom_malloc_filemap(struct xc_dom_image * dom,const char * filename,size_t * size,const size_t max_size)196 void *xc_dom_malloc_filemap(struct xc_dom_image *dom,
197 const char *filename, size_t * size,
198 const size_t max_size)
199 {
200 struct xc_dom_mem *block = NULL;
201 int fd = -1;
202 off_t offset;
203
204 fd = open(filename, O_RDONLY);
205 if ( fd == -1 ) {
206 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
207 "failed to open file '%s': %s",
208 filename, strerror(errno));
209 goto err;
210 }
211
212 if ( (lseek(fd, 0, SEEK_SET) == -1) ||
213 ((offset = lseek(fd, 0, SEEK_END)) == -1) ) {
214 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
215 "failed to seek on file '%s': %s",
216 filename, strerror(errno));
217 goto err;
218 }
219
220 *size = offset;
221
222 if ( max_size && *size > max_size )
223 {
224 xc_dom_panic(dom->xch, XC_OUT_OF_MEMORY,
225 "tried to map file which is too large");
226 goto err;
227 }
228
229 if ( !*size )
230 {
231 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
232 "'%s': zero length file", filename);
233 goto err;
234 }
235
236 block = malloc(sizeof(*block));
237 if ( block == NULL ) {
238 xc_dom_panic(dom->xch, XC_OUT_OF_MEMORY,
239 "failed to allocate block (%zu bytes)",
240 sizeof(*block));
241 goto err;
242 }
243
244 memset(block, 0, sizeof(*block));
245 block->len = *size;
246 block->ptr = mmap(NULL, block->len, PROT_READ,
247 MAP_SHARED, fd, 0);
248 if ( block->ptr == MAP_FAILED ) {
249 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
250 "failed to mmap file '%s': %s",
251 filename, strerror(errno));
252 goto err;
253 }
254
255 block->type = XC_DOM_MEM_TYPE_MMAP;
256 block->next = dom->memblocks;
257 dom->memblocks = block;
258 dom->alloc_malloc += sizeof(*block);
259 dom->alloc_file_map += block->len;
260 close(fd);
261 if ( *size > (100 * 1024) )
262 print_mem(dom, __FUNCTION__, *size);
263 return block->ptr;
264
265 err:
266 if ( fd != -1 )
267 close(fd);
268 free(block);
269 DOMPRINTF("%s: failed (on file `%s')", __FUNCTION__, filename);
270 return NULL;
271 }
272
xc_dom_free_all(struct xc_dom_image * dom)273 static void xc_dom_free_all(struct xc_dom_image *dom)
274 {
275 struct xc_dom_mem *block;
276
277 while ( (block = dom->memblocks) != NULL )
278 {
279 dom->memblocks = block->next;
280 switch ( block->type )
281 {
282 case XC_DOM_MEM_TYPE_MALLOC_INTERNAL:
283 break;
284 case XC_DOM_MEM_TYPE_MALLOC_EXTERNAL:
285 free(block->ptr);
286 break;
287 case XC_DOM_MEM_TYPE_MMAP:
288 munmap(block->ptr, block->len);
289 break;
290 }
291 free(block);
292 }
293 }
294
xc_dom_strdup(struct xc_dom_image * dom,const char * str)295 char *xc_dom_strdup(struct xc_dom_image *dom, const char *str)
296 {
297 size_t len = strlen(str) + 1;
298 char *nstr = xc_dom_malloc(dom, len);
299
300 if ( nstr == NULL )
301 return NULL;
302 memcpy(nstr, str, len);
303 return nstr;
304 }
305
306 /* ------------------------------------------------------------------------ */
307 /* decompression buffer sizing */
xc_dom_kernel_check_size(struct xc_dom_image * dom,size_t sz)308 int xc_dom_kernel_check_size(struct xc_dom_image *dom, size_t sz)
309 {
310 /* No limit */
311 if ( !dom->max_kernel_size )
312 return 0;
313
314 if ( sz > dom->max_kernel_size )
315 {
316 xc_dom_panic(dom->xch, XC_INVALID_KERNEL,
317 "kernel image too large");
318 return 1;
319 }
320
321 return 0;
322 }
323
324 /* ------------------------------------------------------------------------ */
325 /* read files, copy memory blocks, with transparent gunzip */
326
xc_dom_check_gzip(xc_interface * xch,void * blob,size_t ziplen)327 size_t xc_dom_check_gzip(xc_interface *xch, void *blob, size_t ziplen)
328 {
329 unsigned char *gzlen;
330 size_t unziplen;
331
332 if ( ziplen < 6 )
333 /* Too small. We need (i.e. the subsequent code relies on)
334 * 2 bytes for the magic number plus 4 bytes length. */
335 return 0;
336
337 if ( strncmp(blob, "\037\213", 2) )
338 /* not gzipped */
339 return 0;
340
341 gzlen = blob + ziplen - 4;
342 unziplen = (size_t)gzlen[3] << 24 | gzlen[2] << 16 | gzlen[1] << 8 | gzlen[0];
343 if ( unziplen > XC_DOM_DECOMPRESS_MAX )
344 {
345 xc_dom_printf
346 (xch,
347 "%s: size (zip %zd, unzip %zd) looks insane, skip gunzip",
348 __FUNCTION__, ziplen, unziplen);
349 return 0;
350 }
351
352 return unziplen + 16;
353 }
354
xc_dom_do_gunzip(xc_interface * xch,void * src,size_t srclen,void * dst,size_t dstlen)355 int xc_dom_do_gunzip(xc_interface *xch,
356 void *src, size_t srclen, void *dst, size_t dstlen)
357 {
358 z_stream zStream;
359 int rc;
360
361 memset(&zStream, 0, sizeof(zStream));
362 zStream.next_in = src;
363 zStream.avail_in = srclen;
364 zStream.next_out = dst;
365 zStream.avail_out = dstlen;
366 rc = inflateInit2(&zStream, (MAX_WBITS + 32)); /* +32 means "handle gzip" */
367 if ( rc != Z_OK )
368 {
369 xc_dom_panic(xch, XC_INTERNAL_ERROR,
370 "%s: inflateInit2 failed (rc=%d)", __FUNCTION__, rc);
371 return -1;
372 }
373 rc = inflate(&zStream, Z_FINISH);
374 inflateEnd(&zStream);
375 if ( rc != Z_STREAM_END )
376 {
377 xc_dom_panic(xch, XC_INTERNAL_ERROR,
378 "%s: inflate failed (rc=%d)", __FUNCTION__, rc);
379 return -1;
380 }
381
382 xc_dom_printf(xch, "%s: unzip ok, 0x%zx -> 0x%zx",
383 __FUNCTION__, srclen, dstlen);
384 return 0;
385 }
386
xc_dom_try_gunzip(struct xc_dom_image * dom,void ** blob,size_t * size)387 int xc_dom_try_gunzip(struct xc_dom_image *dom, void **blob, size_t * size)
388 {
389 void *unzip;
390 size_t unziplen;
391
392 unziplen = xc_dom_check_gzip(dom->xch, *blob, *size);
393 if ( unziplen == 0 )
394 return 0;
395
396 if ( xc_dom_kernel_check_size(dom, unziplen) )
397 return 0;
398
399 unzip = xc_dom_malloc(dom, unziplen);
400 if ( unzip == NULL )
401 return -1;
402
403 if ( xc_dom_do_gunzip(dom->xch, *blob, *size, unzip, unziplen) == -1 )
404 return -1;
405
406 *blob = unzip;
407 *size = unziplen;
408 return 0;
409 }
410
411 /* ------------------------------------------------------------------------ */
412 /* domain memory */
413
xc_dom_pfn_to_ptr(struct xc_dom_image * dom,xen_pfn_t pfn,xen_pfn_t count)414 void *xc_dom_pfn_to_ptr(struct xc_dom_image *dom, xen_pfn_t pfn,
415 xen_pfn_t count)
416 {
417 xen_pfn_t count_out_dummy;
418 return xc_dom_pfn_to_ptr_retcount(dom, pfn, count, &count_out_dummy);
419 }
420
xc_dom_pfn_to_ptr_retcount(struct xc_dom_image * dom,xen_pfn_t pfn,xen_pfn_t count,xen_pfn_t * count_out)421 void *xc_dom_pfn_to_ptr_retcount(struct xc_dom_image *dom, xen_pfn_t pfn,
422 xen_pfn_t count, xen_pfn_t *count_out)
423 {
424 struct xc_dom_phys *phys;
425 xen_pfn_t offset;
426 unsigned int page_shift = XC_DOM_PAGE_SHIFT(dom);
427 char *mode = "unset";
428
429 *count_out = 0;
430
431 offset = pfn - dom->rambase_pfn;
432 if ( offset > dom->total_pages || /* multiple checks to avoid overflows */
433 count > dom->total_pages ||
434 offset > dom->total_pages - count )
435 {
436 DOMPRINTF("%s: pfn %"PRI_xen_pfn" out of range (0x%" PRIpfn " > 0x%" PRIpfn ")",
437 __FUNCTION__, pfn, offset, dom->total_pages);
438 return NULL;
439 }
440
441 /* already allocated? */
442 for ( phys = dom->phys_pages; phys != NULL; phys = phys->next )
443 {
444 if ( pfn >= (phys->first + phys->count) )
445 continue;
446 if ( count )
447 {
448 /* size given: must be completely within the already allocated block */
449 if ( (pfn + count) <= phys->first )
450 continue;
451 if ( (pfn < phys->first) ||
452 ((pfn + count) > (phys->first + phys->count)) )
453 {
454 DOMPRINTF("%s: request overlaps allocated block"
455 " (req 0x%" PRIpfn "+0x%" PRIpfn ","
456 " blk 0x%" PRIpfn "+0x%" PRIpfn ")",
457 __FUNCTION__, pfn, count, phys->first,
458 phys->count);
459 return NULL;
460 }
461 *count_out = count;
462 }
463 else
464 {
465 /* no size given: block must be allocated already,
466 just hand out a pointer to it */
467 if ( pfn < phys->first )
468 continue;
469 if ( pfn >= phys->first + phys->count )
470 continue;
471 *count_out = phys->count - (pfn - phys->first);
472 }
473 return phys->ptr + ((pfn - phys->first) << page_shift);
474 }
475
476 /* allocating is allowed with size specified only */
477 if ( count == 0 )
478 {
479 DOMPRINTF("%s: no block found, no size given,"
480 " can't malloc (pfn 0x%" PRIpfn ")",
481 __FUNCTION__, pfn);
482 return NULL;
483 }
484
485 /* not found, no overlap => allocate */
486 phys = xc_dom_malloc(dom, sizeof(*phys));
487 if ( phys == NULL )
488 return NULL;
489 memset(phys, 0, sizeof(*phys));
490 phys->first = pfn;
491 phys->count = count;
492
493 if ( dom->guest_domid )
494 {
495 mode = "domU mapping";
496 phys->ptr = xc_dom_boot_domU_map(dom, phys->first, phys->count);
497 if ( phys->ptr == NULL )
498 return NULL;
499 dom->alloc_domU_map += phys->count << page_shift;
500 }
501 else
502 {
503 int err;
504
505 mode = "anonymous memory";
506 phys->ptr = mmap(NULL, phys->count << page_shift,
507 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
508 -1, 0);
509 if ( phys->ptr == MAP_FAILED )
510 {
511 err = errno;
512 xc_dom_panic(dom->xch, XC_OUT_OF_MEMORY,
513 "%s: oom: can't allocate 0x%" PRIpfn " pages"
514 " [mmap, errno=%i (%s)]",
515 __FUNCTION__, count, err, strerror(err));
516 return NULL;
517 }
518 dom->alloc_mem_map += phys->count << page_shift;
519 }
520
521 #if 1
522 DOMPRINTF("%s: %s: pfn 0x%" PRIpfn "+0x%" PRIpfn " at %p",
523 __FUNCTION__, mode, phys->first, phys->count, phys->ptr);
524 #endif
525 phys->next = dom->phys_pages;
526 dom->phys_pages = phys;
527 return phys->ptr;
528 }
529
xc_dom_chk_alloc_pages(struct xc_dom_image * dom,char * name,xen_pfn_t pages)530 static int xc_dom_chk_alloc_pages(struct xc_dom_image *dom, char *name,
531 xen_pfn_t pages)
532 {
533 unsigned int page_size = XC_DOM_PAGE_SIZE(dom);
534
535 if ( pages > dom->total_pages || /* multiple test avoids overflow probs */
536 dom->pfn_alloc_end - dom->rambase_pfn > dom->total_pages ||
537 pages > dom->total_pages - dom->pfn_alloc_end + dom->rambase_pfn )
538 {
539 xc_dom_panic(dom->xch, XC_OUT_OF_MEMORY,
540 "%s: segment %s too large (0x%"PRIpfn" > "
541 "0x%"PRIpfn" - 0x%"PRIpfn" pages)", __FUNCTION__, name,
542 pages, dom->total_pages,
543 dom->pfn_alloc_end - dom->rambase_pfn);
544 return -1;
545 }
546
547 dom->pfn_alloc_end += pages;
548 dom->virt_alloc_end += pages * page_size;
549
550 if ( dom->allocate )
551 dom->allocate(dom);
552
553 return 0;
554 }
555
xc_dom_alloc_pad(struct xc_dom_image * dom,xen_vaddr_t boundary)556 static int xc_dom_alloc_pad(struct xc_dom_image *dom, xen_vaddr_t boundary)
557 {
558 unsigned int page_size = XC_DOM_PAGE_SIZE(dom);
559 xen_pfn_t pages;
560
561 if ( boundary & (page_size - 1) )
562 {
563 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
564 "%s: segment boundary isn't page aligned (0x%" PRIx64 ")",
565 __FUNCTION__, boundary);
566 return -1;
567 }
568 if ( boundary < dom->virt_alloc_end )
569 {
570 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
571 "%s: segment boundary too low (0x%" PRIx64 " < 0x%" PRIx64
572 ")", __FUNCTION__, boundary, dom->virt_alloc_end);
573 return -1;
574 }
575 pages = (boundary - dom->virt_alloc_end) / page_size;
576
577 return xc_dom_chk_alloc_pages(dom, "padding", pages);
578 }
579
xc_dom_alloc_segment(struct xc_dom_image * dom,struct xc_dom_seg * seg,char * name,xen_vaddr_t start,xen_vaddr_t size)580 int xc_dom_alloc_segment(struct xc_dom_image *dom,
581 struct xc_dom_seg *seg, char *name,
582 xen_vaddr_t start, xen_vaddr_t size)
583 {
584 unsigned int page_size = XC_DOM_PAGE_SIZE(dom);
585 xen_pfn_t pages;
586 void *ptr;
587
588 if ( start && xc_dom_alloc_pad(dom, start) )
589 return -1;
590
591 pages = (size + page_size - 1) / page_size;
592 start = dom->virt_alloc_end;
593
594 seg->pfn = dom->pfn_alloc_end;
595 seg->pages = pages;
596
597 if ( xc_dom_chk_alloc_pages(dom, name, pages) )
598 return -1;
599
600 /* map and clear pages */
601 ptr = xc_dom_seg_to_ptr(dom, seg);
602 if ( ptr == NULL )
603 return -1;
604 memset(ptr, 0, pages * page_size);
605
606 seg->vstart = start;
607 seg->vend = dom->virt_alloc_end;
608
609 DOMPRINTF("%-20s: %-12s : 0x%" PRIx64 " -> 0x%" PRIx64
610 " (pfn 0x%" PRIpfn " + 0x%" PRIpfn " pages)",
611 __FUNCTION__, name, seg->vstart, seg->vend, seg->pfn, pages);
612
613 return 0;
614 }
615
xc_dom_alloc_page(struct xc_dom_image * dom,char * name)616 xen_pfn_t xc_dom_alloc_page(struct xc_dom_image *dom, char *name)
617 {
618 xen_vaddr_t start;
619 xen_pfn_t pfn;
620
621 start = dom->virt_alloc_end;
622 pfn = dom->pfn_alloc_end - dom->rambase_pfn;
623
624 if ( xc_dom_chk_alloc_pages(dom, name, 1) )
625 return INVALID_PFN;
626
627 DOMPRINTF("%-20s: %-12s : 0x%" PRIx64 " (pfn 0x%" PRIpfn ")",
628 __FUNCTION__, name, start, pfn);
629 return pfn;
630 }
631
xc_dom_unmap_one(struct xc_dom_image * dom,xen_pfn_t pfn)632 void xc_dom_unmap_one(struct xc_dom_image *dom, xen_pfn_t pfn)
633 {
634 unsigned int page_shift = XC_DOM_PAGE_SHIFT(dom);
635 struct xc_dom_phys *phys, *prev = NULL;
636
637 for ( phys = dom->phys_pages; phys != NULL; phys = phys->next )
638 {
639 if ( (pfn >= phys->first) && (pfn < (phys->first + phys->count)) )
640 break;
641 prev = phys;
642 }
643 if ( !phys )
644 {
645 DOMPRINTF("%s: Huh? no mapping with pfn 0x%" PRIpfn "",
646 __FUNCTION__, pfn);
647 return;
648 }
649
650 munmap(phys->ptr, phys->count << page_shift);
651 if ( prev )
652 prev->next = phys->next;
653 else
654 dom->phys_pages = phys->next;
655
656 xc_domain_cacheflush(dom->xch, dom->guest_domid, phys->first, phys->count);
657 }
658
xc_dom_unmap_all(struct xc_dom_image * dom)659 void xc_dom_unmap_all(struct xc_dom_image *dom)
660 {
661 while ( dom->phys_pages )
662 xc_dom_unmap_one(dom, dom->phys_pages->first);
663 }
664
665 /* ------------------------------------------------------------------------ */
666 /* pluggable kernel loaders */
667
668 static struct xc_dom_loader *first_loader = NULL;
669 static struct xc_dom_arch *first_hook = NULL;
670
xc_dom_register_loader(struct xc_dom_loader * loader)671 void xc_dom_register_loader(struct xc_dom_loader *loader)
672 {
673 loader->next = first_loader;
674 first_loader = loader;
675 }
676
xc_dom_find_loader(struct xc_dom_image * dom)677 static struct xc_dom_loader *xc_dom_find_loader(struct xc_dom_image *dom)
678 {
679 struct xc_dom_loader *loader = first_loader;
680
681 while ( loader != NULL )
682 {
683 DOMPRINTF("%s: trying %s loader ... ", __FUNCTION__, loader->name);
684 if ( loader->probe(dom) == 0 )
685 {
686 DOMPRINTF("loader probe OK");
687 return loader;
688 }
689 DOMPRINTF("loader probe failed");
690 loader = loader->next;
691 }
692 xc_dom_panic(dom->xch,
693 XC_INVALID_KERNEL, "%s: no loader found", __FUNCTION__);
694 return NULL;
695 }
696
xc_dom_register_arch_hooks(struct xc_dom_arch * hooks)697 void xc_dom_register_arch_hooks(struct xc_dom_arch *hooks)
698 {
699 hooks->next = first_hook;
700 first_hook = hooks;
701 }
702
xc_dom_set_arch_hooks(struct xc_dom_image * dom)703 int xc_dom_set_arch_hooks(struct xc_dom_image *dom)
704 {
705 struct xc_dom_arch *hooks = first_hook;
706
707 while ( hooks != NULL )
708 {
709 if ( !strcmp(hooks->guest_type, dom->guest_type) )
710 {
711 if ( hooks->arch_private_size )
712 {
713 dom->arch_private = malloc(hooks->arch_private_size);
714 if ( dom->arch_private == NULL )
715 return -1;
716 memset(dom->arch_private, 0, hooks->arch_private_size);
717 dom->alloc_malloc += hooks->arch_private_size;
718 }
719 dom->arch_hooks = hooks;
720 return 0;
721 }
722 hooks = hooks->next;
723 }
724 xc_dom_panic(dom->xch, XC_INVALID_KERNEL,
725 "%s: not found (type %s)", __FUNCTION__, dom->guest_type);
726 return -1;
727 }
728
729 /* ------------------------------------------------------------------------ */
730 /* public interface */
731
xc_dom_release(struct xc_dom_image * dom)732 void xc_dom_release(struct xc_dom_image *dom)
733 {
734 DOMPRINTF_CALLED(dom->xch);
735 if ( dom->phys_pages )
736 xc_dom_unmap_all(dom);
737 xc_dom_free_all(dom);
738 free(dom->arch_private);
739 free(dom);
740 }
741
xc_dom_allocate(xc_interface * xch,const char * cmdline,const char * features)742 struct xc_dom_image *xc_dom_allocate(xc_interface *xch,
743 const char *cmdline, const char *features)
744 {
745 struct xc_dom_image *dom;
746
747 xc_dom_printf(xch, "%s: cmdline=\"%s\", features=\"%s\"",
748 __FUNCTION__, cmdline ? cmdline : "",
749 features ? features : "");
750 dom = malloc(sizeof(*dom));
751 if ( !dom )
752 goto err;
753
754 memset(dom, 0, sizeof(*dom));
755 dom->xch = xch;
756
757 dom->max_kernel_size = XC_DOM_DECOMPRESS_MAX;
758 dom->max_module_size = XC_DOM_DECOMPRESS_MAX;
759 dom->max_devicetree_size = XC_DOM_DECOMPRESS_MAX;
760
761 if ( cmdline )
762 dom->cmdline = xc_dom_strdup(dom, cmdline);
763 if ( features )
764 elf_xen_parse_features(features, dom->f_requested, NULL);
765
766 dom->parms.virt_base = UNSET_ADDR;
767 dom->parms.virt_entry = UNSET_ADDR;
768 dom->parms.virt_hypercall = UNSET_ADDR;
769 dom->parms.virt_hv_start_low = UNSET_ADDR;
770 dom->parms.elf_paddr_offset = UNSET_ADDR;
771 dom->parms.p2m_base = UNSET_ADDR;
772
773 dom->flags = SIF_VIRT_P2M_4TOOLS;
774
775 dom->alloc_malloc += sizeof(*dom);
776 return dom;
777
778 err:
779 if ( dom )
780 xc_dom_release(dom);
781 return NULL;
782 }
783
xc_dom_kernel_max_size(struct xc_dom_image * dom,size_t sz)784 int xc_dom_kernel_max_size(struct xc_dom_image *dom, size_t sz)
785 {
786 DOMPRINTF("%s: kernel_max_size=%zx", __FUNCTION__, sz);
787 dom->max_kernel_size = sz;
788 return 0;
789 }
790
xc_dom_module_max_size(struct xc_dom_image * dom,size_t sz)791 int xc_dom_module_max_size(struct xc_dom_image *dom, size_t sz)
792 {
793 DOMPRINTF("%s: module_max_size=%zx", __FUNCTION__, sz);
794 dom->max_module_size = sz;
795 return 0;
796 }
797
xc_dom_devicetree_max_size(struct xc_dom_image * dom,size_t sz)798 int xc_dom_devicetree_max_size(struct xc_dom_image *dom, size_t sz)
799 {
800 DOMPRINTF("%s: devicetree_max_size=%zx", __FUNCTION__, sz);
801 dom->max_devicetree_size = sz;
802 return 0;
803 }
804
xc_dom_kernel_file(struct xc_dom_image * dom,const char * filename)805 int xc_dom_kernel_file(struct xc_dom_image *dom, const char *filename)
806 {
807 DOMPRINTF("%s: filename=\"%s\"", __FUNCTION__, filename);
808 dom->kernel_blob = xc_dom_malloc_filemap(dom, filename, &dom->kernel_size,
809 dom->max_kernel_size);
810 if ( dom->kernel_blob == NULL )
811 return -1;
812 return xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size);
813 }
814
xc_dom_module_file(struct xc_dom_image * dom,const char * filename,const char * cmdline)815 int xc_dom_module_file(struct xc_dom_image *dom, const char *filename, const char *cmdline)
816 {
817 unsigned int mod = dom->num_modules++;
818
819 DOMPRINTF("%s: filename=\"%s\"", __FUNCTION__, filename);
820 dom->modules[mod].blob =
821 xc_dom_malloc_filemap(dom, filename, &dom->modules[mod].size,
822 dom->max_module_size);
823
824 if ( dom->modules[mod].blob == NULL )
825 return -1;
826
827 if ( cmdline )
828 {
829 dom->modules[mod].cmdline = xc_dom_strdup(dom, cmdline);
830
831 if ( dom->modules[mod].cmdline == NULL )
832 return -1;
833 }
834 else
835 {
836 dom->modules[mod].cmdline = NULL;
837 }
838
839 return 0;
840 }
841
xc_dom_devicetree_file(struct xc_dom_image * dom,const char * filename)842 int xc_dom_devicetree_file(struct xc_dom_image *dom, const char *filename)
843 {
844 #if defined (__arm__) || defined(__aarch64__)
845 DOMPRINTF("%s: filename=\"%s\"", __FUNCTION__, filename);
846 dom->devicetree_blob =
847 xc_dom_malloc_filemap(dom, filename, &dom->devicetree_size,
848 dom->max_devicetree_size);
849
850 if ( dom->devicetree_blob == NULL )
851 return -1;
852 return 0;
853 #else
854 errno = -EINVAL;
855 return -1;
856 #endif
857 }
858
xc_dom_kernel_mem(struct xc_dom_image * dom,const void * mem,size_t memsize)859 int xc_dom_kernel_mem(struct xc_dom_image *dom, const void *mem, size_t memsize)
860 {
861 DOMPRINTF_CALLED(dom->xch);
862 dom->kernel_blob = (void *)mem;
863 dom->kernel_size = memsize;
864 return xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size);
865 }
866
xc_dom_module_mem(struct xc_dom_image * dom,const void * mem,size_t memsize,const char * cmdline)867 int xc_dom_module_mem(struct xc_dom_image *dom, const void *mem,
868 size_t memsize, const char *cmdline)
869 {
870 unsigned int mod = dom->num_modules++;
871
872 DOMPRINTF_CALLED(dom->xch);
873
874 dom->modules[mod].blob = (void *)mem;
875 dom->modules[mod].size = memsize;
876
877 if ( cmdline )
878 {
879 dom->modules[mod].cmdline = xc_dom_strdup(dom, cmdline);
880
881 if ( dom->modules[mod].cmdline == NULL )
882 return -1;
883 }
884 else
885 {
886 dom->modules[mod].cmdline = NULL;
887 }
888
889 return 0;
890 }
891
xc_dom_devicetree_mem(struct xc_dom_image * dom,const void * mem,size_t memsize)892 int xc_dom_devicetree_mem(struct xc_dom_image *dom, const void *mem,
893 size_t memsize)
894 {
895 DOMPRINTF_CALLED(dom->xch);
896 dom->devicetree_blob = (void *)mem;
897 dom->devicetree_size = memsize;
898 return 0;
899 }
900
xc_dom_parse_image(struct xc_dom_image * dom)901 int xc_dom_parse_image(struct xc_dom_image *dom)
902 {
903 int i;
904
905 DOMPRINTF_CALLED(dom->xch);
906
907 /* parse kernel image */
908 dom->kernel_loader = xc_dom_find_loader(dom);
909 if ( dom->kernel_loader == NULL )
910 goto err;
911 if ( dom->kernel_loader->parser(dom) != 0 )
912 goto err;
913 if ( dom->guest_type == NULL )
914 {
915 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
916 "%s: guest_type not set", __FUNCTION__);
917 goto err;
918 }
919
920 /* check features */
921 for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ )
922 {
923 dom->f_active[i] |= dom->f_requested[i]; /* cmd line */
924 dom->f_active[i] |= dom->parms.f_required[i]; /* kernel */
925 if ( (dom->f_active[i] & dom->parms.f_supported[i]) !=
926 dom->f_active[i] )
927 {
928 xc_dom_panic(dom->xch, XC_INVALID_PARAM,
929 "%s: unsupported feature requested", __FUNCTION__);
930 goto err;
931 }
932 }
933 return 0;
934
935 err:
936 return -1;
937 }
938
xc_dom_rambase_init(struct xc_dom_image * dom,uint64_t rambase)939 int xc_dom_rambase_init(struct xc_dom_image *dom, uint64_t rambase)
940 {
941 dom->rambase_pfn = rambase >> XC_PAGE_SHIFT;
942 dom->pfn_alloc_end = dom->rambase_pfn;
943 DOMPRINTF("%s: RAM starts at %"PRI_xen_pfn,
944 __FUNCTION__, dom->rambase_pfn);
945 return 0;
946 }
947
xc_dom_mem_init(struct xc_dom_image * dom,unsigned int mem_mb)948 int xc_dom_mem_init(struct xc_dom_image *dom, unsigned int mem_mb)
949 {
950 unsigned int page_shift;
951 xen_pfn_t nr_pages;
952
953 if ( xc_dom_set_arch_hooks(dom) )
954 {
955 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: arch hooks not set",
956 __FUNCTION__);
957 return -1;
958 }
959
960 page_shift = XC_DOM_PAGE_SHIFT(dom);
961 nr_pages = mem_mb << (20 - page_shift);
962
963 DOMPRINTF("%s: mem %d MB, pages 0x%" PRIpfn " pages, %dk each",
964 __FUNCTION__, mem_mb, nr_pages, 1 << (page_shift-10));
965 dom->total_pages = nr_pages;
966
967 DOMPRINTF("%s: 0x%" PRIpfn " pages",
968 __FUNCTION__, dom->total_pages);
969
970 return 0;
971 }
972
xc_dom_build_module(struct xc_dom_image * dom,unsigned int mod)973 static int xc_dom_build_module(struct xc_dom_image *dom, unsigned int mod)
974 {
975 size_t unziplen, modulelen;
976 void *modulemap;
977 char name[10];
978
979 if ( !dom->modules[mod].seg.vstart )
980 unziplen = xc_dom_check_gzip(dom->xch,
981 dom->modules[mod].blob, dom->modules[mod].size);
982 else
983 unziplen = 0;
984
985 modulelen = max(unziplen, dom->modules[mod].size);
986 if ( dom->max_module_size )
987 {
988 if ( unziplen && modulelen > dom->max_module_size )
989 {
990 modulelen = min(unziplen, dom->modules[mod].size);
991 if ( unziplen > modulelen )
992 unziplen = 0;
993 }
994 if ( modulelen > dom->max_module_size )
995 {
996 xc_dom_panic(dom->xch, XC_INVALID_KERNEL,
997 "module %u image too large", mod);
998 goto err;
999 }
1000 }
1001
1002 snprintf(name, sizeof(name), "module%u", mod);
1003 if ( xc_dom_alloc_segment(dom, &dom->modules[mod].seg, name,
1004 dom->modules[mod].seg.vstart, modulelen) != 0 )
1005 goto err;
1006 modulemap = xc_dom_seg_to_ptr(dom, &dom->modules[mod].seg);
1007 if ( modulemap == NULL )
1008 {
1009 DOMPRINTF("%s: xc_dom_seg_to_ptr(dom, &dom->modules[%u].seg) => NULL",
1010 __FUNCTION__, mod);
1011 goto err;
1012 }
1013 if ( unziplen )
1014 {
1015 if ( xc_dom_do_gunzip(dom->xch, dom->modules[mod].blob, dom->modules[mod].size,
1016 modulemap, unziplen) != -1 )
1017 return 0;
1018 if ( dom->modules[mod].size > modulelen )
1019 goto err;
1020 }
1021
1022 /* Fall back to handing over the raw blob. */
1023 memcpy(modulemap, dom->modules[mod].blob, dom->modules[mod].size);
1024 /* If an unzip attempt was made, the buffer may no longer be all zero. */
1025 if ( unziplen > dom->modules[mod].size )
1026 memset(modulemap + dom->modules[mod].size, 0,
1027 unziplen - dom->modules[mod].size);
1028
1029 return 0;
1030
1031 err:
1032 return -1;
1033 }
1034
populate_acpi_pages(struct xc_dom_image * dom,xen_pfn_t * extents,unsigned int num_pages)1035 static int populate_acpi_pages(struct xc_dom_image *dom,
1036 xen_pfn_t *extents,
1037 unsigned int num_pages)
1038 {
1039 int rc;
1040 xc_interface *xch = dom->xch;
1041 uint32_t domid = dom->guest_domid;
1042 unsigned long idx;
1043 unsigned long first_high_idx = 4UL << (30 - PAGE_SHIFT); /* 4GB */
1044
1045 for ( ; num_pages; num_pages--, extents++ )
1046 {
1047
1048 if ( xc_domain_populate_physmap(xch, domid, 1, 0, 0, extents) == 1 )
1049 continue;
1050
1051 if ( dom->highmem_end )
1052 {
1053 idx = --dom->highmem_end;
1054 if ( idx == first_high_idx )
1055 dom->highmem_end = 0;
1056 }
1057 else
1058 {
1059 idx = --dom->lowmem_end;
1060 }
1061
1062 rc = xc_domain_add_to_physmap(xch, domid,
1063 XENMAPSPACE_gmfn,
1064 idx, *extents);
1065 if ( rc )
1066 return rc;
1067 }
1068
1069 return 0;
1070 }
1071
xc_dom_load_acpi(struct xc_dom_image * dom)1072 static int xc_dom_load_acpi(struct xc_dom_image *dom)
1073 {
1074 int j, i = 0;
1075 unsigned num_pages;
1076 xen_pfn_t *extents, base;
1077 void *ptr;
1078
1079 while ( (i < MAX_ACPI_MODULES) && dom->acpi_modules[i].length )
1080 {
1081 DOMPRINTF("%s: %d bytes at address %" PRIx64, __FUNCTION__,
1082 dom->acpi_modules[i].length,
1083 dom->acpi_modules[i].guest_addr_out);
1084
1085 num_pages = (dom->acpi_modules[i].length +
1086 (dom->acpi_modules[i].guest_addr_out & ~XC_PAGE_MASK) +
1087 (XC_PAGE_SIZE - 1)) >> XC_PAGE_SHIFT;
1088 extents = malloc(num_pages * sizeof(*extents));
1089 if ( !extents )
1090 {
1091 DOMPRINTF("%s: Out of memory", __FUNCTION__);
1092 goto err;
1093 }
1094
1095 base = dom->acpi_modules[i].guest_addr_out >> XC_PAGE_SHIFT;
1096 for ( j = 0; j < num_pages; j++ )
1097 extents[j] = base + j;
1098 if ( populate_acpi_pages(dom, extents, num_pages) )
1099 {
1100 DOMPRINTF("%s: Can populate ACPI pages", __FUNCTION__);
1101 goto err;
1102 }
1103
1104 ptr = xc_map_foreign_range(dom->xch, dom->guest_domid,
1105 XC_PAGE_SIZE * num_pages,
1106 PROT_READ | PROT_WRITE, base);
1107 if ( !ptr )
1108 {
1109 DOMPRINTF("%s: Can't map %d pages at 0x%"PRI_xen_pfn,
1110 __FUNCTION__, num_pages, base);
1111 goto err;
1112 }
1113
1114 memcpy((uint8_t *)ptr +
1115 (dom->acpi_modules[i].guest_addr_out & ~XC_PAGE_MASK),
1116 dom->acpi_modules[i].data, dom->acpi_modules[i].length);
1117 munmap(ptr, XC_PAGE_SIZE * num_pages);
1118
1119 free(extents);
1120 i++;
1121 }
1122
1123 return 0;
1124
1125 err:
1126 free(extents);
1127 return -1;
1128 }
1129
xc_dom_build_image(struct xc_dom_image * dom)1130 int xc_dom_build_image(struct xc_dom_image *dom)
1131 {
1132 unsigned int page_size;
1133 bool unmapped_initrd;
1134 unsigned int mod;
1135
1136 DOMPRINTF_CALLED(dom->xch);
1137
1138 /* check for arch hooks */
1139 if ( dom->arch_hooks == NULL )
1140 {
1141 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: arch hooks not set",
1142 __FUNCTION__);
1143 goto err;
1144 }
1145 page_size = XC_DOM_PAGE_SIZE(dom);
1146 if ( dom->parms.virt_base != UNSET_ADDR )
1147 dom->virt_alloc_end = dom->parms.virt_base;
1148
1149 /* load kernel */
1150 if ( xc_dom_alloc_segment(dom, &dom->kernel_seg, "kernel",
1151 dom->kernel_seg.vstart,
1152 dom->kernel_seg.vend -
1153 dom->kernel_seg.vstart) != 0 )
1154 goto err;
1155 if ( dom->kernel_loader->loader(dom) != 0 )
1156 goto err;
1157
1158 /* Don't load ramdisk / other modules now if no initial mapping required. */
1159 for ( mod = 0; mod < dom->num_modules; mod++ )
1160 {
1161 unmapped_initrd = (dom->parms.unmapped_initrd &&
1162 !dom->modules[mod].seg.vstart);
1163
1164 if ( dom->modules[mod].blob && !unmapped_initrd )
1165 {
1166 if ( xc_dom_build_module(dom, mod) != 0 )
1167 goto err;
1168
1169 if ( mod == 0 )
1170 {
1171 dom->initrd_start = dom->modules[mod].seg.vstart;
1172 dom->initrd_len =
1173 dom->modules[mod].seg.vend - dom->modules[mod].seg.vstart;
1174 }
1175 }
1176 }
1177
1178 /* load devicetree */
1179 if ( dom->devicetree_blob )
1180 {
1181 void *devicetreemap;
1182
1183 if ( xc_dom_alloc_segment(dom, &dom->devicetree_seg, "devicetree",
1184 dom->devicetree_seg.vstart,
1185 dom->devicetree_size) != 0 )
1186 goto err;
1187 devicetreemap = xc_dom_seg_to_ptr(dom, &dom->devicetree_seg);
1188 if ( devicetreemap == NULL )
1189 {
1190 DOMPRINTF("%s: xc_dom_seg_to_ptr(dom, &dom->devicetree_seg) => NULL",
1191 __FUNCTION__);
1192 goto err;
1193 }
1194 memcpy(devicetreemap, dom->devicetree_blob, dom->devicetree_size);
1195 }
1196
1197 /* load ACPI tables */
1198 if ( xc_dom_load_acpi(dom) != 0 )
1199 goto err;
1200
1201 /* allocate other pages */
1202 if ( !dom->arch_hooks->p2m_base_supported ||
1203 dom->parms.p2m_base >= dom->parms.virt_base ||
1204 (dom->parms.p2m_base & (XC_DOM_PAGE_SIZE(dom) - 1)) )
1205 dom->parms.p2m_base = UNSET_ADDR;
1206 if ( dom->arch_hooks->alloc_p2m_list && dom->parms.p2m_base == UNSET_ADDR &&
1207 dom->arch_hooks->alloc_p2m_list(dom) != 0 )
1208 goto err;
1209 if ( dom->arch_hooks->alloc_magic_pages(dom) != 0 )
1210 goto err;
1211 if ( dom->arch_hooks->alloc_pgtables &&
1212 dom->arch_hooks->alloc_pgtables(dom) != 0 )
1213 goto err;
1214 if ( dom->alloc_bootstack )
1215 {
1216 dom->bootstack_pfn = xc_dom_alloc_page(dom, "boot stack");
1217 if ( dom->bootstack_pfn == INVALID_PFN )
1218 goto err;
1219 }
1220
1221 DOMPRINTF("%-20s: virt_alloc_end : 0x%" PRIx64 "",
1222 __FUNCTION__, dom->virt_alloc_end);
1223 DOMPRINTF("%-20s: virt_pgtab_end : 0x%" PRIx64 "",
1224 __FUNCTION__, dom->virt_pgtab_end);
1225
1226 /* Make sure all memory mapped by initial page tables is available */
1227 if ( dom->virt_pgtab_end && xc_dom_alloc_pad(dom, dom->virt_pgtab_end) )
1228 return -1;
1229
1230 for ( mod = 0; mod < dom->num_modules; mod++ )
1231 {
1232 unmapped_initrd = (dom->parms.unmapped_initrd &&
1233 !dom->modules[mod].seg.vstart);
1234
1235 /* Load ramdisk / other modules if no initial mapping required. */
1236 if ( dom->modules[mod].blob && unmapped_initrd )
1237 {
1238 if ( xc_dom_build_module(dom, mod) != 0 )
1239 goto err;
1240
1241 if ( mod == 0 )
1242 {
1243 dom->flags |= SIF_MOD_START_PFN;
1244 dom->initrd_start = dom->modules[mod].seg.pfn;
1245 dom->initrd_len = page_size * dom->modules[mod].seg.pages;
1246 }
1247 }
1248 }
1249
1250 /* Allocate p2m list if outside of initial kernel mapping. */
1251 if ( dom->arch_hooks->alloc_p2m_list && dom->parms.p2m_base != UNSET_ADDR )
1252 {
1253 if ( dom->arch_hooks->alloc_p2m_list(dom) != 0 )
1254 goto err;
1255 dom->p2m_seg.vstart = dom->parms.p2m_base;
1256 }
1257
1258 return 0;
1259
1260 err:
1261 return -1;
1262 }
1263
1264 /*
1265 * Local variables:
1266 * mode: C
1267 * c-file-style: "BSD"
1268 * c-basic-offset: 4
1269 * tab-width: 4
1270 * indent-tabs-mode: nil
1271 * End:
1272 */
1273