direct-io.hg

annotate tools/libxc/xc_hvm_restore.c @ 14099:aa1be6f5150e

x86 hvm domain builder, restore: set shared_info.arch.max_pfn for
dump-core to know the area to dump

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir@xensource.com>
date Sat Feb 24 14:19:05 2007 +0000 (2007-02-24)
parents e21834bc78f2
children eedbddf55e51
rev   line source
Tim@13413 1 /******************************************************************************
Tim@13413 2 * xc_hvm_restore.c
Tim@13413 3 *
Tim@13413 4 * Restore the state of a HVM guest.
Tim@13413 5 *
Tim@13413 6 * Copyright (c) 2003, K A Fraser.
Tim@13413 7 * Copyright (c) 2006 Intel Corperation
Tim@13413 8 * rewriten for hvm guest by Zhai Edwin <edwin.zhai@intel.com>
Tim@13413 9 *
Tim@13413 10 * This program is free software; you can redistribute it and/or modify it
Tim@13413 11 * under the terms and conditions of the GNU General Public License,
Tim@13413 12 * version 2, as published by the Free Software Foundation.
Tim@13413 13 *
Tim@13413 14 * This program is distributed in the hope it will be useful, but WITHOUT
Tim@13413 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Tim@13413 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
Tim@13413 17 * more details.
Tim@13413 18 *
Tim@13413 19 * You should have received a copy of the GNU General Public License along with
Tim@13413 20 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Tim@13413 21 * Place - Suite 330, Boston, MA 02111-1307 USA.
Tim@13413 22 *
Tim@13413 23 */
Tim@13413 24
Tim@13413 25 #include <stdlib.h>
Tim@13413 26 #include <unistd.h>
Tim@13413 27
Tim@13413 28 #include "xg_private.h"
Tim@13413 29 #include "xg_save_restore.h"
Tim@13413 30
Tim@13413 31 #include <xen/hvm/ioreq.h>
Tim@13413 32 #include <xen/hvm/params.h>
Tim@13413 33 #include <xen/hvm/e820.h>
Tim@13413 34
Tim@13418 35 /* max mfn of the whole machine */
Tim@13418 36 static unsigned long max_mfn;
Tim@13418 37
Tim@13418 38 /* virtual starting address of the hypervisor */
Tim@13418 39 static unsigned long hvirt_start;
Tim@13418 40
Tim@13418 41 /* #levels of page tables used by the currrent guest */
Tim@13418 42 static unsigned int pt_levels;
Tim@13418 43
Tim@13896 44 /* A list of PFNs that exist, used when allocating memory to the guest */
Tim@13896 45 static xen_pfn_t *pfns = NULL;
Tim@13418 46
Tim@13418 47 static ssize_t
Tim@13418 48 read_exact(int fd, void *buf, size_t count)
Tim@13418 49 {
Tim@13418 50 int r = 0, s;
Tim@13418 51 unsigned char *b = buf;
Tim@13418 52
Tim@13418 53 while (r < count) {
Tim@13418 54 s = read(fd, &b[r], count - r);
Tim@13418 55 if ((s == -1) && (errno == EINTR))
Tim@13418 56 continue;
Tim@13418 57 if (s <= 0) {
Tim@13418 58 break;
Tim@13418 59 }
Tim@13418 60 r += s;
Tim@13418 61 }
Tim@13418 62
Tim@13418 63 return (r == count) ? 1 : 0;
Tim@13418 64 }
Tim@13418 65
Tim@13413 66 int xc_hvm_restore(int xc_handle, int io_fd,
Tim@13896 67 uint32_t dom, unsigned long max_pfn,
Tim@13413 68 unsigned int store_evtchn, unsigned long *store_mfn,
Tim@13413 69 unsigned int pae, unsigned int apic)
Tim@13413 70 {
Tim@13418 71 DECLARE_DOMCTL;
Tim@13418 72
Tim@13418 73 /* The new domain's shared-info frame number. */
Tim@13418 74 unsigned long shared_info_frame;
Tim@13418 75
Tim@13418 76 /* A copy of the CPU context of the guest. */
Tim@13418 77 vcpu_guest_context_t ctxt;
Tim@13418 78
Tim@13418 79 char *region_base;
Tim@13418 80
Tim@13418 81 unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
Tim@13418 82
Tim@13418 83 xc_dominfo_t info;
Tim@13418 84 unsigned int rc = 1, n, i;
Tim@13418 85 uint32_t rec_len, nr_vcpus;
Tim@13757 86 uint8_t *hvm_buf = NULL;
Tim@13418 87 unsigned long long v_end, memsize;
Tim@13418 88 unsigned long shared_page_nr;
keir@14099 89 shared_info_t *shared_info = NULL;
keir@14099 90 xen_pfn_t arch_max_pfn;
Tim@13418 91
Tim@13896 92 unsigned long pfn;
Tim@13418 93 unsigned int prev_pc, this_pc;
Tim@13418 94 int verify = 0;
Tim@13418 95
Tim@13418 96 /* Types of the pfns in the current region */
Tim@13418 97 unsigned long region_pfn_type[MAX_BATCH_SIZE];
Tim@13418 98
Tim@13743 99 struct xen_add_to_physmap xatp;
Tim@13743 100
Tim@13896 101 /* Number of pages of memory the guest has. *Not* the same as max_pfn. */
Tim@13896 102 unsigned long nr_pages;
Tim@13896 103
Tim@13418 104 /* hvm guest mem size (Mb) */
Tim@13418 105 memsize = (unsigned long long)*store_mfn;
Tim@13418 106 v_end = memsize << 20;
Tim@13896 107 nr_pages = (unsigned long) memsize << (20 - PAGE_SHIFT);
Tim@13418 108
kfraser@14085 109 DPRINTF("xc_hvm_restore:dom=%d, nr_pages=0x%lx, store_evtchn=%d, "
kfraser@14085 110 "*store_mfn=%ld, pae=%u, apic=%u.\n",
Tim@13896 111 dom, nr_pages, store_evtchn, *store_mfn, pae, apic);
Tim@13418 112
Tim@13418 113 if(!get_platform_info(xc_handle, dom,
Tim@13418 114 &max_mfn, &hvirt_start, &pt_levels)) {
Tim@13418 115 ERROR("Unable to get platform info.");
Tim@13418 116 return 1;
Tim@13418 117 }
Tim@13418 118
kfraser@14085 119 DPRINTF("xc_hvm_restore start: nr_pages = %lx, max_pfn = %lx, "
kfraser@14085 120 "max_mfn = %lx, hvirt_start=%lx, pt_levels=%d\n",
kfraser@14085 121 nr_pages, max_pfn, max_mfn, hvirt_start, pt_levels);
Tim@13418 122
Tim@13418 123 if (mlock(&ctxt, sizeof(ctxt))) {
Tim@13418 124 /* needed for build dom0 op, but might as well do early */
Tim@13418 125 ERROR("Unable to mlock ctxt");
Tim@13418 126 return 1;
Tim@13418 127 }
Tim@13418 128
Tim@13418 129
Tim@13896 130 pfns = malloc(max_pfn * sizeof(xen_pfn_t));
Tim@13896 131 if (pfns == NULL) {
Tim@13418 132 ERROR("memory alloc failed");
Tim@13418 133 errno = ENOMEM;
Tim@13418 134 goto out;
Tim@13418 135 }
Tim@13418 136
Tim@13896 137 if(xc_domain_setmaxmem(xc_handle, dom, PFN_TO_KB(nr_pages)) != 0) {
Tim@13418 138 errno = ENOMEM;
Tim@13418 139 goto out;
Tim@13418 140 }
Tim@13418 141
Tim@13418 142 for ( i = 0; i < max_pfn; i++ )
Tim@13896 143 pfns[i] = i;
Tim@13418 144 for ( i = HVM_BELOW_4G_RAM_END >> PAGE_SHIFT; i < max_pfn; i++ )
Tim@13896 145 pfns[i] += HVM_BELOW_4G_MMIO_LENGTH >> PAGE_SHIFT;
keir@14099 146 arch_max_pfn = pfns[max_pfn - 1];/* used later */
Tim@13418 147
Tim@13418 148 /* Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000. */
Tim@13418 149 rc = xc_domain_memory_populate_physmap(
Tim@13896 150 xc_handle, dom, (nr_pages > 0xa0) ? 0xa0 : nr_pages,
Tim@13896 151 0, 0, &pfns[0x00]);
Tim@13896 152 if ( (rc == 0) && (nr_pages > 0xc0) )
Tim@13418 153 rc = xc_domain_memory_populate_physmap(
Tim@13896 154 xc_handle, dom, nr_pages - 0xc0, 0, 0, &pfns[0xc0]);
Tim@13418 155 if ( rc != 0 )
Tim@13418 156 {
Tim@13418 157 PERROR("Could not allocate memory for HVM guest.\n");
Tim@13418 158 goto out;
Tim@13418 159 }
Tim@13418 160
Tim@13418 161
Tim@13418 162 /**********XXXXXXXXXXXXXXXX******************/
Tim@13418 163 if (xc_domain_getinfo(xc_handle, dom, 1, &info) != 1) {
Tim@13418 164 ERROR("Could not get domain info");
Tim@13418 165 return 1;
Tim@13418 166 }
Tim@13418 167
Tim@13418 168 domctl.cmd = XEN_DOMCTL_getdomaininfo;
Tim@13418 169 domctl.domain = (domid_t)dom;
Tim@13418 170 if (xc_domctl(xc_handle, &domctl) < 0) {
Tim@13418 171 ERROR("Could not get information on new domain");
Tim@13418 172 goto out;
Tim@13418 173 }
Tim@13418 174
Tim@13418 175 prev_pc = 0;
Tim@13418 176
Tim@13418 177 n = 0;
Tim@13418 178 while (1) {
Tim@13418 179
Tim@13418 180 int j;
Tim@13418 181
Tim@13896 182 this_pc = (n * 100) / nr_pages;
Tim@13418 183 if ( (this_pc - prev_pc) >= 5 )
Tim@13418 184 {
Tim@13418 185 PPRINTF("\b\b\b\b%3d%%", this_pc);
Tim@13418 186 prev_pc = this_pc;
Tim@13418 187 }
Tim@13418 188
Tim@13418 189 if (!read_exact(io_fd, &j, sizeof(int))) {
Tim@13418 190 ERROR("HVM restore Error when reading batch size");
Tim@13418 191 goto out;
Tim@13418 192 }
Tim@13418 193
Tim@13418 194 PPRINTF("batch %d\n",j);
Tim@13418 195
Tim@13418 196 if (j == -1) {
Tim@13418 197 verify = 1;
Tim@13418 198 DPRINTF("Entering page verify mode\n");
Tim@13418 199 continue;
Tim@13418 200 }
Tim@13418 201
Tim@13418 202 if (j == 0)
Tim@13418 203 break; /* our work here is done */
Tim@13418 204
Tim@13418 205 if (j > MAX_BATCH_SIZE) {
Tim@13418 206 ERROR("Max batch size exceeded. Giving up.");
Tim@13418 207 goto out;
Tim@13418 208 }
Tim@13418 209
Tim@13418 210 if (!read_exact(io_fd, region_pfn_type, j*sizeof(unsigned long))) {
Tim@13418 211 ERROR("Error when reading region pfn types");
Tim@13418 212 goto out;
Tim@13418 213 }
Tim@13418 214
Tim@13418 215 region_base = xc_map_foreign_batch(
Tim@13418 216 xc_handle, dom, PROT_WRITE, region_pfn_type, j);
Tim@13418 217
Tim@13418 218 for ( i = 0; i < j; i++ )
Tim@13418 219 {
Tim@13418 220 void *page;
Tim@13418 221
Tim@13418 222 pfn = region_pfn_type[i];
kfraser@14085 223 if ( pfn & XEN_DOMCTL_PFINFO_LTAB_MASK )
kfraser@14085 224 continue;
kfraser@14085 225
Tim@13418 226 if ( pfn > max_pfn )
Tim@13418 227 {
Tim@13418 228 ERROR("pfn out of range");
Tim@13418 229 goto out;
Tim@13418 230 }
Tim@13418 231
Tim@13418 232 if ( pfn >= 0xa0 && pfn < 0xc0) {
Tim@13418 233 ERROR("hvm restore:pfn in vga hole");
Tim@13418 234 goto out;
Tim@13418 235 }
Tim@13418 236
Tim@13418 237
Tim@13418 238 /* In verify mode, we use a copy; otherwise we work in place */
Tim@13418 239 page = verify ? (void *)buf : (region_base + i*PAGE_SIZE);
Tim@13418 240
Tim@13418 241 if (!read_exact(io_fd, page, PAGE_SIZE)) {
Tim@13418 242 ERROR("Error when reading page (%x)", i);
Tim@13418 243 goto out;
Tim@13418 244 }
Tim@13418 245
Tim@13418 246 if (verify) {
Tim@13418 247
Tim@13418 248 int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE);
Tim@13418 249
Tim@13418 250 if (res) {
Tim@13418 251
Tim@13418 252 int v;
Tim@13418 253
Tim@13896 254 DPRINTF("************** pfn=%lx gotcs=%08lx "
Tim@13896 255 "actualcs=%08lx\n", pfn,
Tim@13418 256 csum_page(region_base + i*PAGE_SIZE),
Tim@13418 257 csum_page(buf));
Tim@13418 258
Tim@13418 259 for (v = 0; v < 4; v++) {
Tim@13418 260
Tim@13418 261 unsigned long *p = (unsigned long *)
Tim@13418 262 (region_base + i*PAGE_SIZE);
Tim@13418 263 if (buf[v] != p[v])
Tim@13418 264 DPRINTF(" %d: %08lx %08lx\n", v, buf[v], p[v]);
Tim@13418 265 }
Tim@13418 266 }
Tim@13418 267 }
Tim@13418 268
Tim@13418 269 } /* end of 'batch' for loop */
Tim@13418 270 munmap(region_base, j*PAGE_SIZE);
Tim@13418 271 n+= j; /* crude stats */
Tim@13418 272
Tim@13418 273 }/*while 1*/
Tim@13418 274
Tim@13418 275 /* xc_set_hvm_param(xc_handle, dom, HVM_PARAM_APIC_ENABLED, apic);*/
Tim@13418 276 xc_set_hvm_param(xc_handle, dom, HVM_PARAM_PAE_ENABLED, pae);
Tim@13418 277 xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn);
Tim@13418 278
Tim@13418 279 if ( v_end > HVM_BELOW_4G_RAM_END )
Tim@13418 280 shared_page_nr = (HVM_BELOW_4G_RAM_END >> PAGE_SHIFT) - 1;
Tim@13418 281 else
Tim@13418 282 shared_page_nr = (v_end >> PAGE_SHIFT) - 1;
Tim@13418 283
Tim@13418 284 xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, shared_page_nr-1);
Tim@13418 285 xc_set_hvm_param(xc_handle, dom, HVM_PARAM_BUFIOREQ_PFN, shared_page_nr-2);
Tim@13418 286 xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, shared_page_nr);
Tim@13418 287
Tim@13418 288 /* caculate the store_mfn , wrong val cause hang when introduceDomain */
Tim@13418 289 *store_mfn = (v_end >> PAGE_SHIFT) - 2;
Tim@13418 290 DPRINTF("hvm restore:calculate new store_mfn=0x%lx,v_end=0x%llx..\n", *store_mfn, v_end);
Tim@13418 291
Tim@13418 292 /* restore hvm context including pic/pit/shpage */
Tim@13418 293 if (!read_exact(io_fd, &rec_len, sizeof(uint32_t))) {
Tim@13418 294 ERROR("error read hvm context size!\n");
Tim@13418 295 goto out;
Tim@13418 296 }
Tim@13757 297
Tim@13757 298 hvm_buf = malloc(rec_len);
Tim@13757 299 if (hvm_buf == NULL) {
Tim@13757 300 ERROR("memory alloc for hvm context buffer failed");
Tim@13757 301 errno = ENOMEM;
Tim@13418 302 goto out;
Tim@13418 303 }
Tim@13418 304
Tim@13757 305 if (!read_exact(io_fd, hvm_buf, rec_len)) {
Tim@13757 306 ERROR("error read hvm buffer!\n");
Tim@13418 307 goto out;
Tim@13418 308 }
Tim@13418 309
Tim@13757 310 if (( rc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf, rec_len))) {
Tim@13757 311 ERROR("error set hvm buffer!\n");
Tim@13418 312 goto out;
Tim@13418 313 }
Tim@13418 314
Tim@13418 315 if (!read_exact(io_fd, &nr_vcpus, sizeof(uint32_t))) {
Tim@13418 316 ERROR("error read nr vcpu !\n");
Tim@13418 317 goto out;
Tim@13418 318 }
Tim@13418 319 DPRINTF("hvm restore:get nr_vcpus=%d.\n", nr_vcpus);
Tim@13418 320
Tim@13418 321 for (i =0; i < nr_vcpus; i++) {
Tim@13418 322 if (!read_exact(io_fd, &rec_len, sizeof(uint32_t))) {
Tim@13418 323 ERROR("error read vcpu context size!\n");
Tim@13418 324 goto out;
Tim@13418 325 }
Tim@13418 326 if (rec_len != sizeof(ctxt)) {
Tim@13418 327 ERROR("vcpu context size dismatch!\n");
Tim@13418 328 goto out;
Tim@13418 329 }
Tim@13418 330
Tim@13418 331 if (!read_exact(io_fd, &(ctxt), sizeof(ctxt))) {
Tim@13418 332 ERROR("error read vcpu context.\n");
Tim@13418 333 goto out;
Tim@13418 334 }
Tim@13418 335
Tim@13418 336 if ( (rc = xc_vcpu_setcontext(xc_handle, dom, i, &ctxt)) ) {
Tim@13418 337 ERROR("Could not set vcpu context, rc=%d", rc);
Tim@13418 338 goto out;
Tim@13418 339 }
Tim@13418 340 }
Tim@13418 341
Tim@13743 342 /* Shared-info pfn */
Tim@13743 343 if (!read_exact(io_fd, &(shared_info_frame), sizeof(uint32_t)) ) {
Tim@13743 344 ERROR("reading the shared-info pfn failed!\n");
Tim@13743 345 goto out;
Tim@13743 346 }
Tim@13743 347 /* Map the shared-info frame where it was before */
Tim@13743 348 xatp.domid = dom;
Tim@13743 349 xatp.space = XENMAPSPACE_shared_info;
Tim@13743 350 xatp.idx = 0;
Tim@13743 351 xatp.gpfn = shared_info_frame;
Tim@13743 352 if ( (rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp)) != 0 ) {
Tim@13743 353 ERROR("setting the shared-info pfn failed!\n");
Tim@13743 354 goto out;
Tim@13743 355 }
keir@14099 356 if ( (xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp) != 0) ||
keir@14099 357 ((shared_info = xc_map_foreign_range(
keir@14099 358 xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
keir@14099 359 shared_info_frame)) == NULL) )
keir@14099 360 goto out;
keir@14099 361 /* shared_info.arch.max_pfn is used by dump-core */
keir@14099 362 shared_info->arch.max_pfn = arch_max_pfn;
keir@14099 363 munmap(shared_info, PAGE_SIZE);
Tim@13743 364
Tim@13418 365 rc = 0;
Tim@13418 366 goto out;
Tim@13418 367
Tim@13418 368 out:
Tim@13418 369 if ( (rc != 0) && (dom != 0) )
Tim@13418 370 xc_domain_destroy(xc_handle, dom);
Tim@13896 371 free(pfns);
Tim@13757 372 free(hvm_buf);
Tim@13418 373
Tim@13418 374 DPRINTF("Restore exit with rc=%d\n", rc);
Tim@13418 375
Tim@13418 376 return rc;
Tim@13413 377 }