Merge QEMU v9.2.1

This commit is contained in:
Matt Borgerson
2025-02-15 13:59:10 -07:00
89 changed files with 495 additions and 176 deletions
+103 -39
View File
@@ -65,6 +65,9 @@ class MigrationFile(object):
def tell(self):
return self.file.tell()
def seek(self, a, b):
return self.file.seek(a, b)
# The VMSD description is at the end of the file, after EOF. Look for
# the last NULL byte, then for the beginning brace of JSON.
def read_migration_debug_json(self):
@@ -272,11 +275,24 @@ class S390StorageAttributes(object):
self.section_key = section_key
def read(self):
pos = 0
while True:
addr_flags = self.file.read64()
flags = addr_flags & 0xfff
if (flags & (self.STATTR_FLAG_DONE | self.STATTR_FLAG_EOS)):
if flags & self.STATTR_FLAG_DONE:
pos = self.file.tell()
continue
elif flags & self.STATTR_FLAG_EOS:
return
else:
# No EOS came after DONE, that's OK, but rewind the
# stream because this is not our data.
if pos:
self.file.seek(pos, os.SEEK_SET)
return
raise Exception("Unknown flags %x", flags)
if (flags & self.STATTR_FLAG_ERROR):
raise Exception("Error in migration stream")
count = self.file.read64()
@@ -401,6 +417,28 @@ class VMSDFieldIntLE(VMSDFieldInt):
super(VMSDFieldIntLE, self).__init__(desc, file)
self.dtype = '<i%d' % self.size
class VMSDFieldNull(VMSDFieldGeneric):
NULL_PTR_MARKER = b'0'
def __init__(self, desc, file):
super(VMSDFieldNull, self).__init__(desc, file)
def __repr__(self):
# A NULL pointer is encoded in the stream as a '0' to
# disambiguate from a mere 0x0 value and avoid consumers
# trying to follow the NULL pointer. Displaying '0', 0x30 or
# 0x0 when analyzing the JSON debug stream could become
# confusing, so use an explicit term instead.
return "nullptr"
def __str__(self):
return self.__repr__()
def read(self):
super(VMSDFieldNull, self).read()
assert(self.data == self.NULL_PTR_MARKER)
return self.data
class VMSDFieldBool(VMSDFieldGeneric):
def __init__(self, desc, file):
super(VMSDFieldBool, self).__init__(desc, file)
@@ -429,6 +467,9 @@ class VMSDFieldStruct(VMSDFieldGeneric):
super(VMSDFieldStruct, self).__init__(desc, file)
self.data = collections.OrderedDict()
if 'fields' not in self.desc['struct']:
raise Exception("No fields in struct. VMSD:\n%s" % self.desc)
# When we see compressed array elements, unfold them here
new_fields = []
for field in self.desc['struct']['fields']:
@@ -461,15 +502,25 @@ class VMSDFieldStruct(VMSDFieldGeneric):
field['data'] = reader(field, self.file)
field['data'].read()
if 'index' in field:
if field['name'] not in self.data:
self.data[field['name']] = []
a = self.data[field['name']]
if len(a) != int(field['index']):
raise Exception("internal index of data field unmatched (%d/%d)" % (len(a), int(field['index'])))
a.append(field['data'])
fname = field['name']
fdata = field['data']
# The field could be:
# i) a single data entry, e.g. uint64
# ii) an array, indicated by it containing the 'index' key
#
# However, the overall data after parsing the whole
# stream, could be a mix of arrays and single data fields,
# all sharing the same field name due to how QEMU breaks
# up arrays with NULL pointers into multiple compressed
# array segments.
if fname not in self.data:
self.data[fname] = fdata
elif type(self.data[fname]) == list:
self.data[fname].append(fdata)
else:
self.data[field['name']] = field['data']
tmp = self.data[fname]
self.data[fname] = [tmp, fdata]
if 'subsections' in self.desc['struct']:
for subsection in self.desc['struct']['subsections']:
@@ -477,6 +528,10 @@ class VMSDFieldStruct(VMSDFieldGeneric):
raise Exception("Subsection %s not found at offset %x" % ( subsection['vmsd_name'], self.file.tell()))
name = self.file.readstr()
version_id = self.file.read32()
if not subsection:
raise Exception("Empty description for subsection: %s" % name)
self.data[name] = VMSDSection(self.file, version_id, subsection, (name, 0))
self.data[name].read()
@@ -535,6 +590,7 @@ vmsd_field_readers = {
"bitmap" : VMSDFieldGeneric,
"struct" : VMSDFieldStruct,
"capability": VMSDFieldCap,
"nullptr": VMSDFieldNull,
"unknown" : VMSDFieldGeneric,
}
@@ -574,10 +630,13 @@ class MigrationDump(object):
}
self.filename = filename
self.vmsd_desc = None
self.vmsd_json = ""
def read(self, desc_only = False, dump_memory = False, write_memory = False):
def read(self, desc_only = False, dump_memory = False,
write_memory = False):
# Read in the whole file
file = MigrationFile(self.filename)
self.vmsd_json = file.read_migration_debug_json()
# File magic
data = file.read32()
@@ -635,9 +694,11 @@ class MigrationDump(object):
file.close()
def load_vmsd_json(self, file):
vmsd_json = file.read_migration_debug_json()
self.vmsd_desc = json.loads(vmsd_json, object_pairs_hook=collections.OrderedDict)
self.vmsd_desc = json.loads(self.vmsd_json,
object_pairs_hook=collections.OrderedDict)
for device in self.vmsd_desc['devices']:
if 'fields' not in device:
raise Exception("vmstate for device %s has no fields" % device['name'])
key = (device['name'], device['instance_id'])
value = ( VMSDSection, device )
self.section_classes[key] = value
@@ -666,31 +727,34 @@ args = parser.parse_args()
jsonenc = JSONEncoder(indent=4, separators=(',', ': '))
if args.extract:
dump = MigrationDump(args.file)
dump.read(desc_only = True)
print("desc.json")
f = open("desc.json", "w")
f.truncate()
f.write(jsonenc.encode(dump.vmsd_desc))
f.close()
dump.read(write_memory = True)
dict = dump.getDict()
print("state.json")
f = open("state.json", "w")
f.truncate()
f.write(jsonenc.encode(dict))
f.close()
elif args.dump == "state":
dump = MigrationDump(args.file)
dump.read(dump_memory = args.memory)
dict = dump.getDict()
print(jsonenc.encode(dict))
elif args.dump == "desc":
dump = MigrationDump(args.file)
dump.read(desc_only = True)
print(jsonenc.encode(dump.vmsd_desc))
else:
if not any([args.extract, args.dump == "state", args.dump == "desc"]):
raise Exception("Please specify either -x, -d state or -d desc")
try:
dump = MigrationDump(args.file)
if args.extract:
dump.read(desc_only = True)
print("desc.json")
f = open("desc.json", "w")
f.truncate()
f.write(jsonenc.encode(dump.vmsd_desc))
f.close()
dump.read(write_memory = True)
dict = dump.getDict()
print("state.json")
f = open("state.json", "w")
f.truncate()
f.write(jsonenc.encode(dict))
f.close()
elif args.dump == "state":
dump.read(dump_memory = args.memory)
dict = dump.getDict()
print(jsonenc.encode(dict))
elif args.dump == "desc":
dump.read(desc_only = True)
print(jsonenc.encode(dump.vmsd_desc))
except Exception:
raise Exception("Full JSON dump:\n%s", dump.vmsd_json)
+30 -1
View File
@@ -10,6 +10,27 @@
# This work is licensed under the terms of the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
function subproject_dir() {
if test ! -f "subprojects/$1.wrap"; then
error "scripts/archive-source.sh should only process wrap subprojects"
fi
# Print the directory key of the wrap file, defaulting to the
# subproject name. The wrap file is in ini format and should
# have a single section only. There should be only one section
# named "[wrap-*]", which helps keeping the script simple.
local dir
dir=$(sed -n \
-e '/^\[wrap-[a-z][a-z]*\]$/,/^\[/{' \
-e '/^directory *= */!b' \
-e 's///p' \
-e 'q' \
-e '}' \
"subprojects/$1.wrap")
echo "${dir:-$1}"
}
if [ $# -ne 2 ]; then
echo "Usage:"
echo " $0 gitrepo version"
@@ -51,5 +72,13 @@ meson subprojects download $SUBPROJECTS
CryptoPkg/Library/OpensslLib/openssl \
MdeModulePkg/Library/BrotliCustomDecompressLib/brotli)
popd
tar --exclude=.git -cJf ${destination}.tar.xz ${destination}
exclude=(--exclude=.git)
# include the tarballs in subprojects/packagecache but not their expansion
for sp in $SUBPROJECTS; do
if grep -xqF "[wrap-file]" subprojects/$sp.wrap; then
exclude+=(--exclude=subprojects/"$(subproject_dir $sp)")
fi
done
tar "${exclude[@]}" -cJf ${destination}.tar.xz ${destination}
rm -rf ${destination}