@ -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 ( )