commit b22765ac59bff1661e08c748954b3a3138922b2a Author: Dyno (Hongjun) Fu Date: Tue Mar 24 13:47:46 2015 -0700 add vmss memory regions support There might be holes in the guest os memory address saved for PCI etc. The memory dump will be divided into regions to skip these holes. On vSphere 5.5, RHEL 6.5 memory dump larger than 3GB is such a case. diff --git a/vmware_vmss.c b/vmware_vmss.c index aeb1c1d..b961d09 100644 --- a/vmware_vmss.c +++ b/vmware_vmss.c @@ -21,6 +21,10 @@ #define LOGPRX "vmw: " +/* VMware only supports X86/X86_64 virtual machines. */ +#define VMW_PAGE_SIZE (4096) +#define VMW_PAGE_SHIFT (12) + static vmssdata vmss = { 0 }; int @@ -139,8 +143,7 @@ vmware_vmss_init(char *filename, FILE *ofp) break; } name[nameLen] = 0; - DEBUG_PARSE_PRINT((vmss.ofp, LOGPRX"\t Item %20s", - name)); + DEBUG_PARSE_PRINT((vmss.ofp, LOGPRX"\t Item %20s", name)); nindx = TAG_NINDX(tag); if (nindx > 3) { @@ -163,6 +166,8 @@ vmware_vmss_init(char *filename, FILE *ofp) int compressed = IS_BLOCK_COMPRESSED_TAG(tag); uint16_t padsize; + assert(strcmp(name, "Memory") == 0); + if (fread(&nbytes, sizeof(nbytes), 1, vmss.dfp) != 1) { fprintf(vmss.ofp, LOGPRX"Cannot read block size.\n"); break; @@ -188,46 +193,50 @@ vmware_vmss_init(char *filename, FILE *ofp) } /* The things that we really care about...*/ - if (strcmp(grps[i].name, "memory") == 0 && - strcmp(name, "Memory") == 0) { - vmss.memoffset = blockpos; - vmss.memsize = nbytesinmem; - } + vmss.memoffset = blockpos; + vmss.memsize = nbytesinmem; DEBUG_PARSE_PRINT((vmss.ofp, "\t=> %sBLOCK: position=%#llx size=%#llx memsize=%#llx\n", compressed ? "COMPRESSED " : "", (ulonglong)blockpos, (ulonglong)nbytes, (ulonglong)nbytesinmem)); + assert (!compressed); } else { - uint8_t val[TAG_VALSIZE_MASK]; + union { + uint8_t val[TAG_VALSIZE_MASK]; + uint32_t val32; + } u; unsigned k; unsigned valsize = TAG_VALSIZE(tag); uint64_t blockpos = ftell(vmss.dfp); DEBUG_PARSE_PRINT((vmss.ofp, "\t=> position=%#llx size=%#x: ", (ulonglong)blockpos, valsize)); - if (fread(val, sizeof(val[0]), valsize, vmss.dfp) != valsize) { + if (fread(u.val, sizeof(u.val[0]), valsize, vmss.dfp) != valsize) { fprintf(vmss.ofp, LOGPRX"Cannot read item.\n"); break; } for (k = 0; k < valsize; k++) { /* Assume Little Endian */ - DEBUG_PARSE_PRINT((vmss.ofp, "%02X", val[valsize - k - 1])); + DEBUG_PARSE_PRINT((vmss.ofp, "%02X", u.val[valsize - k - 1])); } if (strcmp(grps[i].name, "memory") == 0) { if (strcmp(name, "regionsCount") == 0) { - vmss.regionscount = (uint32_t) *val; - if (vmss.regionscount != 0) { - fprintf(vmss.ofp, LOGPRX"regionsCount=%d (!= 0) NOT TESTED!", - vmss.regionscount); - } + vmss.regionscount = u.val32; + assert(vmss.regionscount <= MAX_REGIONS); + } + if (strcmp(name, "regionPageNum") == 0) { + vmss.regions[idx[0]].startpagenum = u.val32; + } + if (strcmp(name, "regionPPN") == 0) { + vmss.regions[idx[0]].startppn = u.val32; + } + if (strcmp(name, "regionSize") == 0) { + vmss.regions[idx[0]].size = u.val32; } if (strcmp(name, "align_mask") == 0) { - vmss.alignmask = (uint32_t) *val; - if (vmss.alignmask != 0xff) { - fprintf(vmss.ofp, LOGPRX"align_mask=%d (!= 0xff) NOT TESTED!", - vmss.regionscount); - } + vmss.alignmask = u.val32; + assert(vmss.alignmask == 0xFFFF); } } @@ -272,26 +281,35 @@ vmware_vmss_init(char *filename, FILE *ofp) uint vmware_vmss_page_size(void) { - return 4096; + return VMW_PAGE_SIZE; } int read_vmware_vmss(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) { - uint64_t pos = vmss.memoffset + paddr; + uint64_t pos = paddr; + + if (vmss.regionscount > 0) { + /* Memory is divided into regions and there are holes between them. */ + uint32_t ppn = (uint32_t) (pos >> VMW_PAGE_SHIFT); + int i; + + for (i = 0; i < vmss.regionscount; i++) { + if (ppn < vmss.regions[i].startppn) + break; - if (pos + cnt > vmss.memoffset + vmss.memsize) { - cnt -= ((pos + cnt) - (vmss.memoffset + vmss.memsize)); - if (cnt < 0) { - error(INFO, LOGPRX"Read beyond the end of file! paddr=%#lx\n", - paddr); + /* skip holes. */ + pos -= ((vmss.regions[i].startppn - vmss.regions[i].startpagenum) + << VMW_PAGE_SHIFT); } } + assert(pos + cnt <= vmss.memsize); + pos += vmss.memoffset; if (fseek(vmss.dfp, pos, SEEK_SET) != 0) return SEEK_ERROR; - if (fread(bufptr, 1 , cnt, vmss.dfp) != cnt) + if (fread(bufptr, 1, cnt, vmss.dfp) != cnt) return READ_ERROR; return cnt; diff --git a/vmware_vmss.h b/vmware_vmss.h index dcbde2d..3f46188 100644 --- a/vmware_vmss.h +++ b/vmware_vmss.h @@ -82,6 +82,14 @@ struct cptgroupdesc { }; typedef struct cptgroupdesc cptgroupdesc; +struct memregion { + uint32_t startpagenum; + uint32_t startppn; + uint32_t size; +}; +typedef struct memregion memregion; + +#define MAX_REGIONS 3 struct vmssdata { int32_t cpt64bit; FILE *dfp; @@ -89,6 +97,7 @@ struct vmssdata { /* about the memory */ uint32_t alignmask; uint32_t regionscount; + memregion regions[MAX_REGIONS]; uint64_t memoffset; uint64_t memsize; };