diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index a12ea9fc8f..e81deab8f9 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -19,6 +19,7 @@ import json import os +import math import argparse import collections import struct @@ -127,6 +128,7 @@ class RamSection(object): self.dump_memory = ramargs['dump_memory'] self.write_memory = ramargs['write_memory'] self.ignore_shared = ramargs['ignore_shared'] + self.mapped_ram = ramargs['mapped_ram'] self.sizeinfo = collections.OrderedDict() self.data = collections.OrderedDict() self.data['section sizes'] = self.sizeinfo @@ -146,6 +148,57 @@ class RamSection(object): def getDict(self): return self.data + def parseMappedRamBlob(self, len): + version = self.file.read32() + if version != 1: + raise Exception("Unsupported MappedRamHeader version %s" % version) + + page_size = self.file.read64() + if page_size != self.TARGET_PAGE_SIZE: + raise Exception("Page size mismatch in MappedRamHeader") + + bitmap_offset = self.file.read64() + pages_offset = self.file.read64() + + if self.ignore_shared and bitmap_offset == 0 and pages_offset == 0: + # This is a shared ramblock, x-ignore-share must have been + # enabled, and mapped-ram didn't allocate bitmap or page blob + # for it. + return + + if self.dump_memory or self.write_memory: + num_pages = len // page_size + + self.file.seek(bitmap_offset, os.SEEK_SET) + bitmap_len = int(math.ceil(num_pages / 8)) + bitmap = self.file.readvar(size=bitmap_len) + + self.file.seek(pages_offset, os.SEEK_SET) + for page_num in range(num_pages): + page_addr = page_num * page_size + + is_filled = (bitmap[page_num // 8] >> page_num % 8) & 1 + if is_filled: + data = self.file.readvar(size=self.TARGET_PAGE_SIZE) + if self.write_memory: + self.files[self.name].seek(page_addr, os.SEEK_SET) + self.files[self.name].write(data) + if self.dump_memory: + hexdata = " ".join("{0:02x}".format(c) for c in data) + self.memory['%s (0x%016x)' % + (self.name, page_addr)] = hexdata + else: + self.file.seek(self.TARGET_PAGE_SIZE, os.SEEK_CUR) + if self.write_memory: + self.files[self.name].seek(page_addr, os.SEEK_SET) + self.files[self.name].write( + b'\x00' * self.TARGET_PAGE_SIZE) + if self.dump_memory: + self.memory['%s (0x%016x)' % + (self.name, page_addr)] = 'Filled with 0x00' + + self.file.seek(pages_offset + len, os.SEEK_SET) + def read(self): # Read all RAM sections while True: @@ -170,6 +223,8 @@ class RamSection(object): self.files[self.name] = f if self.ignore_shared: mr_addr = self.file.read64() + if self.mapped_ram: + self.parseMappedRamBlob(len) flags &= ~self.RAM_SAVE_FLAG_MEM_SIZE if flags & self.RAM_SAVE_FLAG_ZERO: @@ -660,6 +715,7 @@ class MigrationDump(object): ramargs['dump_memory'] = dump_memory ramargs['write_memory'] = write_memory ramargs['ignore_shared'] = False + ramargs['mapped_ram'] = False self.section_classes[('ram',0)][1] = ramargs while True: @@ -671,6 +727,7 @@ class MigrationDump(object): section = ConfigurationSection(file, config_desc) section.read() ramargs['ignore_shared'] = section.has_capability('x-ignore-shared') + ramargs['mapped_ram'] = section.has_capability('mapped-ram') elif section_type == self.QEMU_VM_SECTION_START or section_type == self.QEMU_VM_SECTION_FULL: section_id = file.read32() name = file.readstr()