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