HVM save restore: guest memory handling
PATCH 6/8 HVM save restore: guest memory handling
[PATCH 6/8] HVM save restore: guest memory handling
Signed-off-by Zhai Edwin <[email protected]>
add support for save/restore HVM guest memory
tools/libxc/xc_hvm_restore.c +319 -1
@@ -31,6 +31,40 @@#include <xen/hvm/ioreq.h> #include <xen/hvm/params.h> #include <xen/hvm/e820.h> + +/* max mfn of the whole machine */ +static unsigned long max_mfn; + +/* virtual starting address of the hypervisor */ +static unsigned long hvirt_start; + +/* #levels of page tables used by the currrent guest */ +static unsigned int pt_levels; + +/* total number of pages used by the current guest */ +static unsigned long max_pfn; + +/* A table mapping each PFN to its new MFN. */ +static xen_pfn_t *p2m =NULL ; + +static ssize_t +read_exact (int fd,void *buf,size_t count) +{ +int r =0 , s; +unsigned char *b = buf; + +while (r < count) { + s =read (fd, &b[r], count - r); +if ((s ==-1 ) && (errno ==EINTR )) +continue ; +if (s <=0 ) { +break ; + } + r += s; + } + +return (r == count) ?1 :0 ; +} int xc_hvm_restore(int xc_handle, int io_fd, uint32_t dom, unsigned long nr_pfns,
@@ -38,5 +72,289 @@ int xc_hvm_restore(int xc_handle, int io unsigned int console_evtchn, unsigned long *console_mfn, unsigned int pae, unsigned int apic) { - return 0; +DECLARE_DOMCTL ; + +/* The new domain's shared-info frame number. */ +unsigned long shared_info_frame; + +/* A copy of the CPU context of the guest. */ +vcpu_guest_context_t ctxt; + +char *region_base; + +unsigned long buf[PAGE_SIZE /sizeof (unsigned long )]; + +xc_dominfo_t info; +unsigned int rc =1 , n, i; +uint32_t rec_len, nr_vcpus; +hvm_domain_context_t hvm_ctxt; +unsigned long long v_end, memsize; +unsigned long shared_page_nr; + +unsigned long mfn, pfn; +unsigned int prev_pc, this_pc; +int verify =0 ; + +/* Types of the pfns in the current region */ +unsigned long region_pfn_type[MAX_BATCH_SIZE ]; + +/* hvm guest mem size (Mb) */ + memsize = (unsigned long long )*store_mfn; + v_end = memsize <<20 ; + +DPRINTF ("xc_hvm_restore:dom=%d, nr_pfns=0x%lx, store_evtchn=%d, *store_mfn=%ld, console_evtchn=%d, *console_mfn=%ld, pae=%u, apic=%u.\n" , + dom, nr_pfns, store_evtchn, *store_mfn, console_evtchn, *console_mfn, pae, apic); + + max_pfn = nr_pfns; + +if (!get_platform_info (xc_handle, dom, + &max_mfn, &hvirt_start, &pt_levels)) { +ERROR ("Unable to get platform info." ); +return 1 ; + } + +DPRINTF ("xc_hvm_restore start: max_pfn = %lx, max_mfn = %lx, hvirt_start=%lx, pt_levels=%d\n" , + max_pfn, + max_mfn, + hvirt_start, + pt_levels); + +if (mlock (&ctxt,sizeof (ctxt))) { +/* needed for build dom0 op, but might as well do early */ +ERROR ("Unable to mlock ctxt" ); +return 1 ; + } + + + p2m =malloc (max_pfn *sizeof (xen_pfn_t)); + +if (p2m ==NULL ) { +ERROR ("memory alloc failed" ); + errno =ENOMEM ; + goto out; + } + +/* Get the domain's shared-info frame. */ + domctl.cmd = XEN_DOMCTL_getdomaininfo; + domctl.domain = (domid_t )dom; +if (xc_domctl (xc_handle, &domctl) <0 ) { +ERROR ("Could not get information on new domain" ); + goto out; + } + shared_info_frame = domctl.u.getdomaininfo.shared_info_frame; + +if (xc_domain_setmaxmem (xc_handle, dom,PFN_TO_KB (max_pfn)) !=0 ) { + errno =ENOMEM ; + goto out; + } + +for ( i =0 ; i < max_pfn; i++ ) + p2m[i] = i; +for ( i =HVM_BELOW_4G_RAM_END >>PAGE_SHIFT ; i < max_pfn; i++ ) + p2m[i] +=HVM_BELOW_4G_MMIO_LENGTH >>PAGE_SHIFT ; + +/* Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000. */ + rc =xc_domain_memory_populate_physmap ( + xc_handle, dom, (max_pfn >0xa0 ) ?0xa0 : max_pfn, +0 ,0 , &p2m[0x00 ]); +if ( (rc ==0 ) && (max_pfn >0xc0 ) ) + rc =xc_domain_memory_populate_physmap ( + xc_handle, dom, max_pfn -0xc0 ,0 ,0 , &p2m[0xc0 ]); +if ( rc !=0 ) + { +PERROR ("Could not allocate memory for HVM guest.\n" ); + goto out; + } + + +/**********XXXXXXXXXXXXXXXX******************/ +if (xc_domain_getinfo (xc_handle, dom,1 , &info) !=1 ) { +ERROR ("Could not get domain info" ); +return 1 ; + } + + domctl.cmd = XEN_DOMCTL_getdomaininfo; + domctl.domain = (domid_t )dom; +if (xc_domctl (xc_handle, &domctl) <0 ) { +ERROR ("Could not get information on new domain" ); + goto out; + } + +for ( i =0 ; i < max_pfn; i++) + p2m[i] = i; + + prev_pc =0 ; + + n =0 ; +while (1 ) { + +int j; + + this_pc = (n *100 ) / max_pfn; +if ( (this_pc - prev_pc) >=5 ) + { +PPRINTF ("\b\b\b\b%3d%%" , this_pc); + prev_pc = this_pc; + } + +if (!read_exact (io_fd, &j,sizeof (int ))) { +ERROR ("HVM restore Error when reading batch size" ); + goto out; + } + +PPRINTF ("batch %d\n" ,j); + +if (j ==-1 ) { + verify =1 ; +DPRINTF ("Entering page verify mode\n" ); +continue ; + } + +if (j ==0 ) +break ;/* our work here is done */ + +if (j >MAX_BATCH_SIZE ) { +ERROR ("Max batch size exceeded. Giving up." ); + goto out; + } + +if (!read_exact (io_fd, region_pfn_type, j*sizeof (unsigned long ))) { +ERROR ("Error when reading region pfn types" ); + goto out; + } + + region_base =xc_map_foreign_batch ( + xc_handle, dom,PROT_WRITE , region_pfn_type, j); + +for ( i =0 ; i < j; i++ ) + { +void *page; + + pfn = region_pfn_type[i]; +if ( pfn > max_pfn ) + { +ERROR ("pfn out of range" ); + goto out; + } + +if ( pfn >=0xa0 && pfn <0xc0 ) { +ERROR ("hvm restore:pfn in vga hole" ); + goto out; + } + + + mfn = p2m[pfn]; + +/* In verify mode, we use a copy; otherwise we work in place */ + page = verify ? (void *)buf : (region_base + i*PAGE_SIZE ); + +if (!read_exact (io_fd, page,PAGE_SIZE )) { +ERROR ("Error when reading page (%x)" , i); + goto out; + } + +if (verify) { + +int res =memcmp (buf, (region_base + i*PAGE_SIZE ),PAGE_SIZE ); + +if (res) { + +int v; + +DPRINTF ("************** pfn=%lx mfn=%lx gotcs=%08lx " +"actualcs=%08lx\n" , pfn, p2m[pfn], +csum_page (region_base + i*PAGE_SIZE ), +csum_page (buf)); + +for (v =0 ; v <4 ; v++) { + +unsigned long *p = (unsigned long *) + (region_base + i*PAGE_SIZE ); +if (buf[v] != p[v]) +DPRINTF (" %d: %08lx %08lx\n" , v, buf[v], p[v]); + } + } + } + + }/* end of 'batch' for loop */ +munmap (region_base, j*PAGE_SIZE ); + n+= j;/* crude stats */ + + }/*while 1*/ + +/* xc_set_hvm_param(xc_handle, dom, HVM_PARAM_APIC_ENABLED, apic);*/ +xc_set_hvm_param (xc_handle, dom,HVM_PARAM_PAE_ENABLED , pae); +xc_set_hvm_param (xc_handle, dom,HVM_PARAM_STORE_EVTCHN , store_evtchn); + +if ( v_end >HVM_BELOW_4G_RAM_END ) + shared_page_nr = (HVM_BELOW_4G_RAM_END >>PAGE_SHIFT ) -1 ; +else + shared_page_nr = (v_end >>PAGE_SHIFT ) -1 ; + +xc_set_hvm_param (xc_handle, dom,HVM_PARAM_STORE_PFN , shared_page_nr-1 ); +xc_set_hvm_param (xc_handle, dom,HVM_PARAM_BUFIOREQ_PFN , shared_page_nr-2 ); +xc_set_hvm_param (xc_handle, dom,HVM_PARAM_IOREQ_PFN , shared_page_nr); + +/* caculate the store_mfn , wrong val cause hang when introduceDomain */ + *store_mfn = (v_end >>PAGE_SHIFT ) -2 ; +DPRINTF ("hvm restore:calculate new store_mfn=0x%lx,v_end=0x%llx..\n" , *store_mfn, v_end); + +/* restore hvm context including pic/pit/shpage */ +if (!read_exact (io_fd, &rec_len,sizeof (uint32_t ))) { +ERROR ("error read hvm context size!\n" ); + goto out; + } +if (rec_len !=sizeof (hvm_ctxt)) { +ERROR ("hvm context size dismatch!\n" ); + goto out; + } + +if (!read_exact (io_fd, &hvm_ctxt,sizeof (hvm_ctxt))) { +ERROR ("error read hvm context!\n" ); + goto out; + } + +if (( rc =xc_domain_hvm_setcontext (xc_handle, dom, &hvm_ctxt))) { +ERROR ("error set hvm context!\n" ); + goto out; + } + +if (!read_exact (io_fd, &nr_vcpus,sizeof (uint32_t ))) { +ERROR ("error read nr vcpu !\n" ); + goto out; + } +DPRINTF ("hvm restore:get nr_vcpus=%d.\n" , nr_vcpus); + +for (i =0 ; i < nr_vcpus; i++) { +if (!read_exact (io_fd, &rec_len,sizeof (uint32_t ))) { +ERROR ("error read vcpu context size!\n" ); + goto out; + } +if (rec_len !=sizeof (ctxt)) { +ERROR ("vcpu context size dismatch!\n" ); + goto out; + } + +if (!read_exact (io_fd, &(ctxt),sizeof (ctxt))) { +ERROR ("error read vcpu context.\n" ); + goto out; + } + +if ( (rc =xc_vcpu_setcontext (xc_handle, dom, i, &ctxt)) ) { +ERROR ("Could not set vcpu context, rc=%d" , rc); + goto out; + } + } + + rc =0 ; + goto out; + + out: +if ( (rc !=0 ) && (dom !=0 ) ) +xc_domain_destroy (xc_handle, dom); +free (p2m); + +DPRINTF ("Restore exit with rc=%d\n" , rc); + +return rc; }
tools/libxc/xc_hvm_save.c +690 -3
699 lines not on this page · raw message