ia64/xen-unstable

view tools/libxc/xc_dom_boot.c @ 19639:205b1badbcfd

Add support for superpages (hugepages) in PV domain

This patch adds the option "superpages" to the domain configuration
file. If it is set, the domain is populated using 2M pages.

This code does not support fallback to small pages. If the domain can
not be created with 2M pages, the create will fail.

The patch also includes support for saving and restoring domains with
the superpage flag set. However, if a domain has freed small pages
within its physical page array and then extended the array, the
restore will fill in those freed pages. It will then attempt to
allocate more than its memory limit and will fail. This is
significant because apparently Linux does this during boot, thus a
freshly booted Linux image can not be saved and restored successfully.

Signed-off-by: Dave McCracken <dcm@mccr.org>
author Keir Fraser <keir.fraser@citrix.com>
date Tue May 26 09:58:38 2009 +0100 (2009-05-26)
parents b4bde79b7ba0
children
line source
1 /*
2 * Xen domain builder -- xen booter.
3 *
4 * This is the code which actually boots a fresh
5 * prepared domain image as xen guest domain.
6 *
7 * ==> this is the only domain builder code piece
8 * where xen hypercalls are allowed <==
9 *
10 * This code is licenced under the GPL.
11 * written 2006 by Gerd Hoffmann <kraxel@suse.de>.
12 *
13 */
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <inttypes.h>
18 #include <zlib.h>
20 #include "xg_private.h"
21 #include "xc_dom.h"
22 #include <xen/hvm/params.h>
24 /* ------------------------------------------------------------------------ */
26 static int setup_hypercall_page(struct xc_dom_image *dom)
27 {
28 DECLARE_DOMCTL;
29 xen_pfn_t pfn;
30 int rc;
32 if ( dom->parms.virt_hypercall == -1 )
33 return 0;
34 pfn = (dom->parms.virt_hypercall - dom->parms.virt_base)
35 >> XC_DOM_PAGE_SHIFT(dom);
37 xc_dom_printf("%s: vaddr=0x%" PRIx64 " pfn=0x%" PRIpfn "\n", __FUNCTION__,
38 dom->parms.virt_hypercall, pfn);
39 domctl.cmd = XEN_DOMCTL_hypercall_init;
40 domctl.domain = dom->guest_domid;
41 domctl.u.hypercall_init.gmfn = xc_dom_p2m_guest(dom, pfn);
42 rc = do_domctl(dom->guest_xc, &domctl);
43 if ( rc != 0 )
44 xc_dom_panic(XC_INTERNAL_ERROR, "%s: HYPERCALL_INIT failed (rc=%d)\n",
45 __FUNCTION__, rc);
46 return rc;
47 }
49 static int launch_vm(int xc, domid_t domid, void *ctxt)
50 {
51 DECLARE_DOMCTL;
52 int rc;
54 xc_dom_printf("%s: called, ctxt=%p\n", __FUNCTION__, ctxt);
55 memset(&domctl, 0, sizeof(domctl));
56 domctl.cmd = XEN_DOMCTL_setvcpucontext;
57 domctl.domain = domid;
58 domctl.u.vcpucontext.vcpu = 0;
59 set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
60 rc = do_domctl(xc, &domctl);
61 if ( rc != 0 )
62 xc_dom_panic(XC_INTERNAL_ERROR,
63 "%s: SETVCPUCONTEXT failed (rc=%d)\n", __FUNCTION__, rc);
64 return rc;
65 }
67 static int clear_page(struct xc_dom_image *dom, xen_pfn_t pfn)
68 {
69 xen_pfn_t dst;
70 int rc;
72 if ( pfn == 0 )
73 return 0;
75 dst = xc_dom_p2m_host(dom, pfn);
76 xc_dom_printf("%s: pfn 0x%" PRIpfn ", mfn 0x%" PRIpfn "\n",
77 __FUNCTION__, pfn, dst);
78 rc = xc_clear_domain_page(dom->guest_xc, dom->guest_domid, dst);
79 if ( rc != 0 )
80 xc_dom_panic(XC_INTERNAL_ERROR,
81 "%s: xc_clear_domain_page failed (pfn 0x%" PRIpfn
82 ", rc=%d)\n", __FUNCTION__, pfn, rc);
83 return rc;
84 }
87 /* ------------------------------------------------------------------------ */
89 int xc_dom_compat_check(struct xc_dom_image *dom)
90 {
91 xen_capabilities_info_t xen_caps;
92 char *item, *ptr;
93 int match, found = 0;
95 strncpy(xen_caps, dom->xen_caps, XEN_CAPABILITIES_INFO_LEN - 1);
96 xen_caps[XEN_CAPABILITIES_INFO_LEN - 1] = '\0';
98 for ( item = strtok_r(xen_caps, " ", &ptr);
99 item != NULL ; item = strtok_r(NULL, " ", &ptr) )
100 {
101 match = !strcmp(dom->guest_type, item);
102 xc_dom_printf("%s: supported guest type: %s%s\n", __FUNCTION__,
103 item, match ? " <= matches" : "");
104 if ( match )
105 found++;
106 }
107 if ( !found )
108 xc_dom_panic(XC_INVALID_KERNEL,
109 "%s: guest type %s not supported by xen kernel, sorry\n",
110 __FUNCTION__, dom->guest_type);
112 return found;
113 }
115 int xc_dom_boot_xen_init(struct xc_dom_image *dom, int xc, domid_t domid)
116 {
117 dom->guest_xc = xc;
118 dom->guest_domid = domid;
120 dom->xen_version = xc_version(dom->guest_xc, XENVER_version, NULL);
121 if ( xc_version(xc, XENVER_capabilities, &dom->xen_caps) < 0 )
122 {
123 xc_dom_panic(XC_INTERNAL_ERROR, "can't get xen capabilities");
124 return -1;
125 }
126 xc_dom_printf("%s: ver %d.%d, caps %s\n", __FUNCTION__,
127 dom->xen_version >> 16, dom->xen_version & 0xff,
128 dom->xen_caps);
129 return 0;
130 }
132 int xc_dom_boot_mem_init(struct xc_dom_image *dom, int superpages)
133 {
134 long rc;
136 xc_dom_printf("%s: called\n", __FUNCTION__);
138 rc = arch_setup_meminit(dom, superpages);
139 if ( rc != 0 )
140 {
141 xc_dom_panic(XC_OUT_OF_MEMORY,
142 "%s: can't allocate low memory for domain\n",
143 __FUNCTION__);
144 return rc;
145 }
147 return 0;
148 }
150 void *xc_dom_boot_domU_map(struct xc_dom_image *dom, xen_pfn_t pfn,
151 xen_pfn_t count)
152 {
153 int page_shift = XC_DOM_PAGE_SHIFT(dom);
154 privcmd_mmap_entry_t *entries;
155 void *ptr;
156 int i;
157 int err;
159 entries = xc_dom_malloc(dom, count * sizeof(privcmd_mmap_entry_t));
160 if ( entries == NULL )
161 {
162 xc_dom_panic(XC_INTERNAL_ERROR,
163 "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn
164 " [malloc]\n", __FUNCTION__, pfn, count);
165 return NULL;
166 }
168 for ( i = 0; i < count; i++ )
169 entries[i].mfn = xc_dom_p2m_host(dom, pfn + i);
171 ptr = xc_map_foreign_ranges(dom->guest_xc, dom->guest_domid,
172 count << page_shift, PROT_READ | PROT_WRITE, 1 << page_shift,
173 entries, count);
174 if ( ptr == NULL )
175 {
176 err = errno;
177 xc_dom_panic(XC_INTERNAL_ERROR,
178 "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn
179 " [mmap, errno=%i (%s)]\n", __FUNCTION__, pfn, count,
180 err, strerror(err));
181 return NULL;
182 }
184 return ptr;
185 }
187 int xc_dom_boot_image(struct xc_dom_image *dom)
188 {
189 DECLARE_DOMCTL;
190 vcpu_guest_context_any_t ctxt;
191 int rc;
193 xc_dom_printf("%s: called\n", __FUNCTION__);
195 /* misc ia64 stuff*/
196 if ( (rc = arch_setup_bootearly(dom)) != 0 )
197 return rc;
199 /* collect some info */
200 domctl.cmd = XEN_DOMCTL_getdomaininfo;
201 domctl.domain = dom->guest_domid;
202 rc = do_domctl(dom->guest_xc, &domctl);
203 if ( rc != 0 )
204 {
205 xc_dom_panic(XC_INTERNAL_ERROR,
206 "%s: getdomaininfo failed (rc=%d)\n", __FUNCTION__, rc);
207 return rc;
208 }
209 if ( domctl.domain != dom->guest_domid )
210 {
211 xc_dom_panic(XC_INTERNAL_ERROR,
212 "%s: Huh? domid mismatch (%d != %d)\n", __FUNCTION__,
213 domctl.domain, dom->guest_domid);
214 return -1;
215 }
216 dom->shared_info_mfn = domctl.u.getdomaininfo.shared_info_frame;
218 /* sanity checks */
219 if ( !xc_dom_compat_check(dom) )
220 return -1;
222 /* initial mm setup */
223 if ( (rc = xc_dom_update_guest_p2m(dom)) != 0 )
224 return rc;
225 if ( dom->arch_hooks->setup_pgtables )
226 if ( (rc = dom->arch_hooks->setup_pgtables(dom)) != 0 )
227 return rc;
229 if ( (rc = clear_page(dom, dom->console_pfn)) != 0 )
230 return rc;
231 if ( (rc = clear_page(dom, dom->xenstore_pfn)) != 0 )
232 return rc;
234 /* start info page */
235 if ( dom->arch_hooks->start_info )
236 dom->arch_hooks->start_info(dom);
238 /* hypercall page */
239 if ( (rc = setup_hypercall_page(dom)) != 0 )
240 return rc;
241 xc_dom_log_memory_footprint(dom);
243 /* misc x86 stuff */
244 if ( (rc = arch_setup_bootlate(dom)) != 0 )
245 return rc;
247 /* let the vm run */
248 memset(&ctxt, 0, sizeof(ctxt));
249 if ( (rc = dom->arch_hooks->vcpu(dom, &ctxt)) != 0 )
250 return rc;
251 xc_dom_unmap_all(dom);
252 rc = launch_vm(dom->guest_xc, dom->guest_domid, &ctxt);
254 return rc;
255 }
257 /*
258 * Local variables:
259 * mode: C
260 * c-set-style: "BSD"
261 * c-basic-offset: 4
262 * tab-width: 4
263 * indent-tabs-mode: nil
264 * End:
265 */