1 /*
2  * Xen domain builder -- ARM
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation;
7  * version 2.1 of the License.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Copyright (c) 2011, Citrix Systems
18  */
19 #include <inttypes.h>
20 #include <assert.h>
21 
22 #include <xen/xen.h>
23 #include <xen/io/protocols.h>
24 #include <xen-tools/libs.h>
25 
26 #include "xg_private.h"
27 #include "xc_dom.h"
28 
29 #define NR_MAGIC_PAGES 4
30 #define CONSOLE_PFN_OFFSET 0
31 #define XENSTORE_PFN_OFFSET 1
32 #define MEMACCESS_PFN_OFFSET 2
33 #define VUART_PFN_OFFSET 3
34 
35 #define LPAE_SHIFT 9
36 
37 #define PFN_4K_SHIFT  (0)
38 #define PFN_2M_SHIFT  (PFN_4K_SHIFT+LPAE_SHIFT)
39 #define PFN_1G_SHIFT  (PFN_2M_SHIFT+LPAE_SHIFT)
40 #define PFN_512G_SHIFT (PFN_1G_SHIFT+LPAE_SHIFT)
41 
42 /* get guest IO ABI protocol */
xc_domain_get_native_protocol(xc_interface * xch,uint32_t domid)43 const char *xc_domain_get_native_protocol(xc_interface *xch,
44                                           uint32_t domid)
45 {
46     return XEN_IO_PROTO_ABI_ARM;
47 }
48 
49 /* ------------------------------------------------------------------------ */
50 /*
51  * arm guests are hybrid and start off with paging disabled, therefore no
52  * pagetables and nothing to do here.
53  */
alloc_pgtables_arm(struct xc_dom_image * dom)54 static int alloc_pgtables_arm(struct xc_dom_image *dom)
55 {
56     DOMPRINTF_CALLED(dom->xch);
57     return 0;
58 }
59 
setup_pgtables_arm(struct xc_dom_image * dom)60 static int setup_pgtables_arm(struct xc_dom_image *dom)
61 {
62     DOMPRINTF_CALLED(dom->xch);
63     return 0;
64 }
65 
66 /* ------------------------------------------------------------------------ */
67 
alloc_magic_pages(struct xc_dom_image * dom)68 static int alloc_magic_pages(struct xc_dom_image *dom)
69 {
70     int rc, i;
71     const xen_pfn_t base = GUEST_MAGIC_BASE >> XC_PAGE_SHIFT;
72     xen_pfn_t p2m[NR_MAGIC_PAGES];
73 
74     BUILD_BUG_ON(NR_MAGIC_PAGES > GUEST_MAGIC_SIZE >> XC_PAGE_SHIFT);
75 
76     DOMPRINTF_CALLED(dom->xch);
77 
78     for (i = 0; i < NR_MAGIC_PAGES; i++)
79         p2m[i] = base + i;
80 
81     rc = xc_domain_populate_physmap_exact(
82             dom->xch, dom->guest_domid, NR_MAGIC_PAGES,
83             0, 0, p2m);
84     if ( rc < 0 )
85         return rc;
86 
87     dom->console_pfn = base + CONSOLE_PFN_OFFSET;
88     dom->xenstore_pfn = base + XENSTORE_PFN_OFFSET;
89     dom->vuart_gfn = base + VUART_PFN_OFFSET;
90 
91     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->console_pfn);
92     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->xenstore_pfn);
93     xc_clear_domain_page(dom->xch, dom->guest_domid, base + MEMACCESS_PFN_OFFSET);
94     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->vuart_gfn);
95 
96     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CONSOLE_PFN,
97             dom->console_pfn);
98     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_STORE_PFN,
99             dom->xenstore_pfn);
100     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_MONITOR_RING_PFN,
101             base + MEMACCESS_PFN_OFFSET);
102     /* allocated by toolstack */
103     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CONSOLE_EVTCHN,
104             dom->console_evtchn);
105     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_STORE_EVTCHN,
106             dom->xenstore_evtchn);
107 
108     return 0;
109 }
110 
111 /* ------------------------------------------------------------------------ */
112 
start_info_arm(struct xc_dom_image * dom)113 static int start_info_arm(struct xc_dom_image *dom)
114 {
115     DOMPRINTF_CALLED(dom->xch);
116     return 0;
117 }
118 
shared_info_arm(struct xc_dom_image * dom,void * ptr)119 static int shared_info_arm(struct xc_dom_image *dom, void *ptr)
120 {
121     DOMPRINTF_CALLED(dom->xch);
122     return 0;
123 }
124 
125 /* ------------------------------------------------------------------------ */
126 
vcpu_arm32(struct xc_dom_image * dom)127 static int vcpu_arm32(struct xc_dom_image *dom)
128 {
129     vcpu_guest_context_any_t any_ctx;
130     vcpu_guest_context_t *ctxt = &any_ctx.c;
131     int rc;
132 
133     DOMPRINTF_CALLED(dom->xch);
134 
135     /* clear everything */
136     memset(ctxt, 0, sizeof(*ctxt));
137 
138     ctxt->user_regs.pc32 = dom->parms.virt_entry;
139 
140     /* Linux boot protocol. See linux.Documentation/arm/Booting. */
141     ctxt->user_regs.r0_usr = 0; /* SBZ */
142     /* Machine ID: We use DTB therefore no machine id */
143     ctxt->user_regs.r1_usr = 0xffffffff;
144     /* ATAGS/DTB: We currently require that the guest kernel to be
145      * using CONFIG_ARM_APPENDED_DTB. Ensure that r2 does not look
146      * like a valid pointer to a set of ATAGS or a DTB.
147      */
148     ctxt->user_regs.r2_usr = dom->devicetree_blob ?
149         dom->devicetree_seg.vstart : 0xffffffff;
150 
151     ctxt->sctlr = SCTLR_GUEST_INIT;
152 
153     ctxt->ttbr0 = 0;
154     ctxt->ttbr1 = 0;
155     ctxt->ttbcr = 0; /* Defined Reset Value */
156 
157     ctxt->user_regs.cpsr = PSR_GUEST32_INIT;
158 
159     ctxt->flags = VGCF_online;
160 
161     DOMPRINTF("Initial state CPSR %#"PRIx32" PC %#"PRIx32,
162            ctxt->user_regs.cpsr, ctxt->user_regs.pc32);
163 
164     rc = xc_vcpu_setcontext(dom->xch, dom->guest_domid, 0, &any_ctx);
165     if ( rc != 0 )
166         xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
167                      "%s: SETVCPUCONTEXT failed (rc=%d)", __func__, rc);
168 
169     return rc;
170 }
171 
vcpu_arm64(struct xc_dom_image * dom)172 static int vcpu_arm64(struct xc_dom_image *dom)
173 {
174     vcpu_guest_context_any_t any_ctx;
175     vcpu_guest_context_t *ctxt = &any_ctx.c;
176     int rc;
177 
178     DOMPRINTF_CALLED(dom->xch);
179     /* clear everything */
180     memset(ctxt, 0, sizeof(*ctxt));
181 
182     ctxt->user_regs.pc64 = dom->parms.virt_entry;
183 
184     /* Linux boot protocol. See linux.Documentation/arm64/booting.txt. */
185     ctxt->user_regs.x0 = dom->devicetree_blob ?
186         dom->devicetree_seg.vstart : 0xffffffff;
187     ctxt->user_regs.x1 = 0;
188     ctxt->user_regs.x2 = 0;
189     ctxt->user_regs.x3 = 0;
190 
191     DOMPRINTF("DTB %"PRIx64, ctxt->user_regs.x0);
192 
193     ctxt->sctlr = SCTLR_GUEST_INIT;
194 
195     ctxt->ttbr0 = 0;
196     ctxt->ttbr1 = 0;
197     ctxt->ttbcr = 0; /* Defined Reset Value */
198 
199     ctxt->user_regs.cpsr = PSR_GUEST64_INIT;
200 
201     ctxt->flags = VGCF_online;
202 
203     DOMPRINTF("Initial state CPSR %#"PRIx32" PC %#"PRIx64,
204            ctxt->user_regs.cpsr, ctxt->user_regs.pc64);
205 
206     rc = xc_vcpu_setcontext(dom->xch, dom->guest_domid, 0, &any_ctx);
207     if ( rc != 0 )
208         xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
209                      "%s: SETVCPUCONTEXT failed (rc=%d)", __func__, rc);
210 
211     return rc;
212 }
213 
214 /* ------------------------------------------------------------------------ */
215 
set_mode(xc_interface * xch,uint32_t domid,char * guest_type)216 static int set_mode(xc_interface *xch, uint32_t domid, char *guest_type)
217 {
218     static const struct {
219         char           *guest;
220         uint32_t        size;
221     } types[] = {
222         { "xen-3.0-aarch64", 64 },
223         { "xen-3.0-armv7l",  32 },
224     };
225     DECLARE_DOMCTL;
226     int i,rc;
227 
228     domctl.domain = domid;
229     domctl.cmd    = XEN_DOMCTL_set_address_size;
230     domctl.u.address_size.size = 0;
231 
232     for ( i = 0; i < ARRAY_SIZE(types); i++ )
233         if ( !strcmp(types[i].guest, guest_type) )
234             domctl.u.address_size.size = types[i].size;
235     if ( domctl.u.address_size.size == 0 )
236     {
237         xc_dom_printf(xch, "%s: warning: unknown guest type %s",
238                       __FUNCTION__, guest_type);
239         return -EINVAL;
240     }
241 
242     xc_dom_printf(xch, "%s: guest %s, address size %" PRId32 "", __FUNCTION__,
243                   guest_type, domctl.u.address_size.size);
244     rc = do_domctl(xch, &domctl);
245     if ( rc != 0 )
246         xc_dom_printf(xch, "%s: warning: failed (rc=%d)",
247                       __FUNCTION__, rc);
248     return rc;
249 }
250 
251 /*  >0: success, *nr_pfns set to number actually populated
252  *   0: didn't try with this pfn shift (e.g. misaligned base etc)
253  *  <0: ERROR
254  */
populate_one_size(struct xc_dom_image * dom,int pfn_shift,xen_pfn_t base_pfn,xen_pfn_t * nr_pfns,xen_pfn_t * extents)255 static int populate_one_size(struct xc_dom_image *dom, int pfn_shift,
256                              xen_pfn_t base_pfn, xen_pfn_t *nr_pfns,
257                              xen_pfn_t *extents)
258 {
259     /* The mask for this level */
260     const uint64_t mask = ((uint64_t)1<<(pfn_shift))-1;
261     /* The shift, mask and next boundary for the level above this one */
262     const int next_shift = pfn_shift + LPAE_SHIFT;
263     const uint64_t next_mask = ((uint64_t)1<<next_shift)-1;
264     const xen_pfn_t next_boundary
265         = (base_pfn + ((uint64_t)1<<next_shift)) & ~next_mask;
266 
267     int nr, i, count;
268     xen_pfn_t end_pfn = base_pfn + *nr_pfns;
269 
270     /* No level zero super pages with current hardware */
271     if ( pfn_shift == PFN_512G_SHIFT )
272         return 0;
273 
274     /* base is misaligned for this level */
275     if ( mask & base_pfn )
276         return 0;
277 
278     /*
279      * If base is not aligned at the next level up then try and make
280      * it so for next time around.
281      */
282     if ( (base_pfn & next_mask) && end_pfn > next_boundary )
283         end_pfn = next_boundary;
284 
285     count = ( end_pfn - base_pfn ) >> pfn_shift;
286 
287     /* Nothing to allocate */
288     if ( !count )
289         return 0;
290 
291     for ( i = 0 ; i < count ; i ++ )
292         extents[i] = base_pfn + (i<<pfn_shift);
293 
294     nr = xc_domain_populate_physmap(dom->xch, dom->guest_domid, count,
295                                     pfn_shift, 0, extents);
296     if ( nr <= 0 ) return nr;
297     DOMPRINTF("%s: populated %#x/%#x entries with shift %d",
298               __FUNCTION__, nr, count, pfn_shift);
299 
300     *nr_pfns = nr << pfn_shift;
301 
302     return 1;
303 }
304 
populate_guest_memory(struct xc_dom_image * dom,xen_pfn_t base_pfn,xen_pfn_t nr_pfns)305 static int populate_guest_memory(struct xc_dom_image *dom,
306                                  xen_pfn_t base_pfn, xen_pfn_t nr_pfns)
307 {
308     int rc = 0;
309     xen_pfn_t allocsz, pfn, *extents;
310 
311     extents = calloc(1024*1024,sizeof(xen_pfn_t));
312     if ( extents == NULL )
313     {
314         DOMPRINTF("%s: Unable to allocate extent array", __FUNCTION__);
315         return -1;
316     }
317 
318     DOMPRINTF("%s: populating RAM @ %016"PRIx64"-%016"PRIx64" (%"PRId64"MB)",
319               __FUNCTION__,
320               (uint64_t)base_pfn << XC_PAGE_SHIFT,
321               (uint64_t)(base_pfn + nr_pfns) << XC_PAGE_SHIFT,
322               (uint64_t)nr_pfns >> (20-XC_PAGE_SHIFT));
323 
324     for ( pfn = 0; pfn < nr_pfns; pfn += allocsz )
325     {
326         allocsz = min_t(int, 1024*1024, nr_pfns - pfn);
327 #if 0 /* Enable this to exercise/debug the code which tries to realign
328        * to a superpage boundary, by misaligning at the start. */
329         if ( pfn == 0 )
330         {
331             allocsz = 1;
332             rc = populate_one_size(dom, PFN_4K_SHIFT,
333                                    base_pfn + pfn, &allocsz, extents);
334             if (rc < 0) break;
335             if (rc > 0) continue;
336             /* Failed to allocate a single page? */
337             break;
338         }
339 #endif
340 
341         rc = populate_one_size(dom, PFN_512G_SHIFT,
342                                base_pfn + pfn, &allocsz, extents);
343         if ( rc < 0 ) break;
344         if ( rc > 0 ) continue;
345 
346         rc = populate_one_size(dom, PFN_1G_SHIFT,
347                                base_pfn + pfn, &allocsz, extents);
348         if ( rc < 0 ) break;
349         if ( rc > 0 ) continue;
350 
351         rc = populate_one_size(dom, PFN_2M_SHIFT,
352                                base_pfn + pfn, &allocsz, extents);
353         if ( rc < 0 ) break;
354         if ( rc > 0 ) continue;
355 
356         rc = populate_one_size(dom, PFN_4K_SHIFT,
357                                base_pfn + pfn, &allocsz, extents);
358         if ( rc < 0 ) break;
359         if ( rc == 0 )
360         {
361             DOMPRINTF("%s: Not enough RAM", __FUNCTION__);
362             errno = ENOMEM;
363             rc = -1;
364             goto out;
365         }
366     }
367 
368     for ( pfn = 0; pfn < nr_pfns; pfn++ )
369         dom->p2m_host[pfn] = base_pfn + pfn;
370 
371 out:
372     free(extents);
373     return rc < 0 ? rc : 0;
374 }
375 
meminit(struct xc_dom_image * dom)376 static int meminit(struct xc_dom_image *dom)
377 {
378     int i, rc;
379     xen_pfn_t pfn;
380     uint64_t modbase;
381 
382     uint64_t ramsize = (uint64_t)dom->total_pages << XC_PAGE_SHIFT;
383 
384     const uint64_t bankbase[] = GUEST_RAM_BANK_BASES;
385     const uint64_t bankmax[] = GUEST_RAM_BANK_SIZES;
386 
387     /* Convenient */
388     const uint64_t kernbase = dom->kernel_seg.vstart;
389     const uint64_t kernend = ROUNDUP(dom->kernel_seg.vend, 21/*2MB*/);
390     const uint64_t kernsize = kernend - kernbase;
391     const uint64_t dtb_size = dom->devicetree_blob ?
392         ROUNDUP(dom->devicetree_size, XC_PAGE_SHIFT) : 0;
393     const uint64_t ramdisk_size = dom->ramdisk_blob ?
394         ROUNDUP(dom->ramdisk_size, XC_PAGE_SHIFT) : 0;
395     const uint64_t modsize = dtb_size + ramdisk_size;
396     const uint64_t ram128mb = bankbase[0] + (128<<20);
397 
398     xen_pfn_t p2m_size;
399     uint64_t bank0end;
400 
401     assert(dom->rambase_pfn << XC_PAGE_SHIFT == bankbase[0]);
402 
403     if ( modsize + kernsize > bankmax[0] )
404     {
405         DOMPRINTF("%s: Not enough memory for the kernel+dtb+initrd",
406                   __FUNCTION__);
407         return -1;
408     }
409 
410     if ( ramsize == 0 )
411     {
412         DOMPRINTF("%s: ram size is 0", __FUNCTION__);
413         return -1;
414     }
415 
416     if ( ramsize > GUEST_RAM_MAX )
417     {
418         DOMPRINTF("%s: ram size is too large for guest address space: "
419                   "%"PRIx64" > %llx",
420                   __FUNCTION__, ramsize, GUEST_RAM_MAX);
421         return -1;
422     }
423 
424     rc = set_mode(dom->xch, dom->guest_domid, dom->guest_type);
425     if ( rc )
426         return rc;
427 
428     for ( i = 0; ramsize && i < GUEST_RAM_BANKS; i++ )
429     {
430         uint64_t banksize = ramsize > bankmax[i] ? bankmax[i] : ramsize;
431 
432         ramsize -= banksize;
433 
434         p2m_size = ( bankbase[i] + banksize - bankbase[0] ) >> XC_PAGE_SHIFT;
435 
436         dom->rambank_size[i] = banksize >> XC_PAGE_SHIFT;
437     }
438 
439     assert(dom->rambank_size[0] != 0);
440     assert(ramsize == 0); /* Too much RAM is rejected above */
441 
442     dom->p2m_size = p2m_size;
443     dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * p2m_size);
444     if ( dom->p2m_host == NULL )
445         return -EINVAL;
446     for ( pfn = 0; pfn < p2m_size; pfn++ )
447         dom->p2m_host[pfn] = INVALID_PFN;
448 
449     /* setup initial p2m and allocate guest memory */
450     for ( i = 0; i < GUEST_RAM_BANKS && dom->rambank_size[i]; i++ )
451     {
452         if ((rc = populate_guest_memory(dom,
453                                         bankbase[i] >> XC_PAGE_SHIFT,
454                                         dom->rambank_size[i])))
455             return rc;
456     }
457 
458     /*
459      * We try to place dtb+initrd at 128MB or if we have less RAM
460      * as high as possible. If there is no space then fallback to
461      * just before the kernel.
462      *
463      * If changing this then consider
464      * xen/arch/arm/kernel.c:place_modules as well.
465      */
466     bank0end = bankbase[0] + ((uint64_t)dom->rambank_size[0] << XC_PAGE_SHIFT);
467 
468     if ( bank0end >= ram128mb + modsize && kernend < ram128mb )
469         modbase = ram128mb;
470     else if ( bank0end - modsize > kernend )
471         modbase = bank0end - modsize;
472     else if (kernbase - bankbase[0] > modsize )
473         modbase = kernbase - modsize;
474     else
475         return -1;
476 
477     DOMPRINTF("%s: placing boot modules at 0x%" PRIx64, __FUNCTION__, modbase);
478 
479     /*
480      * Must map DTB *after* initrd, to satisfy order of calls to
481      * xc_dom_alloc_segment in xc_dom_build_image, which must map
482      * things at monotonolically increasing addresses.
483      */
484     if ( ramdisk_size )
485     {
486         dom->ramdisk_seg.vstart = modbase;
487         dom->ramdisk_seg.vend = modbase + ramdisk_size;
488 
489         DOMPRINTF("%s: ramdisk: 0x%" PRIx64 " -> 0x%" PRIx64 "",
490                   __FUNCTION__,
491                   dom->ramdisk_seg.vstart, dom->ramdisk_seg.vend);
492 
493         modbase += ramdisk_size;
494     }
495 
496     if ( dtb_size )
497     {
498         dom->devicetree_seg.vstart = modbase;
499         dom->devicetree_seg.vend = modbase + dtb_size;
500 
501         DOMPRINTF("%s: devicetree: 0x%" PRIx64 " -> 0x%" PRIx64 "",
502                   __FUNCTION__,
503                   dom->devicetree_seg.vstart, dom->devicetree_seg.vend);
504 
505         modbase += dtb_size;
506     }
507 
508     return 0;
509 }
510 
xc_dom_translated(const struct xc_dom_image * dom)511 bool xc_dom_translated(const struct xc_dom_image *dom)
512 {
513     return true;
514 }
515 
516 /* ------------------------------------------------------------------------ */
517 
bootearly(struct xc_dom_image * dom)518 static int bootearly(struct xc_dom_image *dom)
519 {
520     DOMPRINTF("%s: doing nothing", __FUNCTION__);
521     return 0;
522 }
523 
bootlate(struct xc_dom_image * dom)524 static int bootlate(struct xc_dom_image *dom)
525 {
526     /* XXX
527      *   map shared info
528      *   map grant tables
529      *   setup shared info
530      */
531     return 0;
532 }
533 
534 /* ------------------------------------------------------------------------ */
535 
536 static struct xc_dom_arch xc_dom_32 = {
537     .guest_type = "xen-3.0-armv7l",
538     .native_protocol = XEN_IO_PROTO_ABI_ARM,
539     .page_shift = PAGE_SHIFT_ARM,
540     .sizeof_pfn = 8,
541     .alloc_magic_pages = alloc_magic_pages,
542     .alloc_pgtables = alloc_pgtables_arm,
543     .setup_pgtables = setup_pgtables_arm,
544     .start_info = start_info_arm,
545     .shared_info = shared_info_arm,
546     .vcpu = vcpu_arm32,
547     .meminit = meminit,
548     .bootearly = bootearly,
549     .bootlate = bootlate,
550 };
551 
552 static struct xc_dom_arch xc_dom_64 = {
553     .guest_type = "xen-3.0-aarch64",
554     .native_protocol = XEN_IO_PROTO_ABI_ARM,
555     .page_shift = PAGE_SHIFT_ARM,
556     .sizeof_pfn = 8,
557     .alloc_magic_pages = alloc_magic_pages,
558     .alloc_pgtables = alloc_pgtables_arm,
559     .setup_pgtables = setup_pgtables_arm,
560     .start_info = start_info_arm,
561     .shared_info = shared_info_arm,
562     .vcpu = vcpu_arm64,
563     .meminit = meminit,
564     .bootearly = bootearly,
565     .bootlate = bootlate,
566 };
567 
register_arch_hooks(void)568 static void __init register_arch_hooks(void)
569 {
570     xc_dom_register_arch_hooks(&xc_dom_32);
571     xc_dom_register_arch_hooks(&xc_dom_64);
572 }
573 
574 /*
575  * Local variables:
576  * mode: C
577  * c-file-style: "BSD"
578  * c-basic-offset: 4
579  * tab-width: 4
580  * indent-tabs-mode: nil
581  * End:
582  */
583