[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Fwd: [BUG] Windows is frozen after restore from snapshot
# Abstract After `xl save win win.mem` and then `xl restore win.hvm win.mem` the Windows 10 VM remain frozen for about a minute. After the minute it becomes responsive. During the freeze the OS remains semi-responsive: on `Ctrl+Shift+Esc` press the wait cursor appears (blue circle indicator). This is an intermittent fault been reproduced only twice. # Technical notes It have been noticed that there were no timer interrupts during the freeze. zaytsevgu@xxxxxxxxx has debugged the received Xen state file and noticed that the flag HPET_TN_PERIODIC been set after unfreeze. Based on that he provided two Python scripts: one to check the value and one to patch it. Both "broken" state files we have been detected and patched successfully. # Other information ## Target machine ```bash $ uname -a Linux localhost 5.4.0-66-generic #74~18.04.2-Ubuntu SMP Fri Feb 5 11:17:31 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux ``` ## Xen version Build from source on tag RELEASE-4.12.4 ## OS version * Windows 10 build 1803 x64 * Hibernation, sleep and other disabled with powershell commands: ``` powercfg /hibernate off powercfg /change standby-timeout-ac 0 powercfg /change standby-timeout-dc 0 powercfg /change monitor-timeout-ac 0 powercfg /change monitor-timeout-dc 0 powercfg /change disk-timeout-ac 0 powercfg /change disk-timeout-dc 0 ``` ## Configuration file Build with envsubst from template: ``` name = "$VM_NAME" type = "hvm" vcpus = 2 maxvcpus = 2 memory = 2048 maxmem = 2048 on_poweroff = "destroy" on_reboot = "destroy" on_watchdog = "destroy" on_crash = "destroy" on_soft_reset = "soft-reset" nomigrate = 1 disk = [ "format=qcow2, vdev=hda, target=$VM_DISK_IMAGE_PATH" ] vif = [ "type=ioemu, model=e1000" ] hdtype = "ahci" shadow_memory = 16 altp2m = "external" viridian = [ "defaults" ] videoram = 128 vga = "stdvga" vnc = 1 vncunused = 1 soundhw = "hda" usb = 1 usbdevice = [ "usb-tablet" ] ``` ## Check script The script has been provided by zaytsevgu@xxxxxxxxx (with little refactoring). It checks that image is broken. ```python #!/usr/bin/env python3 import logging from pathlib import Path import sys import struct def check_snapshot_hpet(snapshot: Path) -> bool: def get_b32(file): data = file.read(4) return struct.unpack('>L', data)[0] def get_l32(file): data = file.read(4) return struct.unpack('<L', data)[0] def get_l64(file): data = file.read(8) return struct.unpack('<Q', data)[0] def get_hpet_loc_by_tag9(file): while True: tag = get_l32(file) tlen = get_l32(file) if tag == 12: break file.seek(tlen, 1) _ = get_l64(file) # caps _ = [get_l64(file) for i in range(31)] timer1_conf = get_l64(file) # Basic check if timer1_conf & 0xff == 0x34: return file.tell() - 8 return None def get_hpet(file): _ = get_l32(file) # x1 _ = get_l32(file) # x2 hdr = file.read(4) if hdr != b'XENF': return None _ = get_b32(file) # version get_b32(file) get_b32(file) _ = get_l32(file) # dmt _ = get_l32(file) # page_shift _ = get_l32(file) # xmj _ = get_l32(file) # xmn while True: tag_type = get_l32(file) rlen = get_l32(file) if tag_type == 9: break else: file.seek(rlen, 1) return get_hpet_loc_by_tag9(file) original = open(snapshot, 'rb') header = original.read(0x1000) xl_offset = header.index(b'LibxlFmt') original.seek(xl_offset) magic = original.read(8) if magic != b'LibxlFmt': logging.error('Invalid snapshot format') raise RuntimeError _ = get_b32(original) # version _ = get_b32(original) # options record_type = get_l32(original) _ = get_l32(original) # blen if record_type != 1: logging.error('Invalid snapshot record type') raise RuntimeError hpet_flag_byte_offset = get_hpet(original) if hpet_flag_byte_offset is not None: original.close() return False else: original.close() return True if check_snapshot_hpet(sys.argv[1]): print('The image is good! :)') sys.exit(0) else: print('The image is so bad... :(') sys.exit(1) ``` The image could be fixed with a little addition: ```python hpet_new = hpet[0] ^ 0x8 ``` , on `hpet_flag_byte_offset` ## Patch script ```python import sys import struct import io def get_b32(file): data = file.read(4) return struct.unpack(">L", data)[0] def get_l32(file): data = file.read(4) return struct.unpack("<L", data)[0] def get_l64(file): data = file.read(8) return struct.unpack("<Q", data)[0] def get_hpet_loc_by_tag9(file, rlen): while True: tag = get_l32(file) tlen = get_l32(file) if tag == 12: break file.seek(tlen, 1) caps = get_l64(file) [get_l64(file) for i in range(31)] timer1_conf = get_l64(file) print(hex(timer1_conf)) if timer1_conf & 0xff == 0x34: #VERY DUMMY CHECK return file.tell() - 8 return None def get_hpet(file): x1 = get_l32(file) x2 = get_l32(file) hdr = file.read(4) # print(hdr) if hdr != b"XENF": return None version = get_b32(file) get_b32(file) get_b32(file) dmt = get_l32(file) page_shift = get_l32(file) xmj = get_l32(file) xmn = get_l32(file) while True: tag_type = get_l32(file) # print(tag_type) rlen = get_l32(file) if tag_type == 9: break else: file.seek(rlen, 1) print("Found tag 9!") return get_hpet_loc_by_tag9(file, rlen) original = open(sys.argv[1], "rb") new = open(sys.argv[1]+".hpet_enable_periodic", "wb") header = original.read(0x1000) xl_offset = header.index(b"LibxlFmt") print("Found offset to xl data: {:x}".format(xl_offset)) original.seek(xl_offset) magic = original.read(8) if magic != b"LibxlFmt": print("ERROR INVALID FORMAT") else: version = get_b32(original) options = get_b32(original) record_type = get_l32(original) blen = get_l32(original) # print(record_type, blen) if record_type != 1: 0/0 hpet_flag_byte_offset = get_hpet(original) if hpet_flag_byte_offset != None: print("Got hpet timer flag!") file_size = 0 original.seek(0, 2) file_size = original.tell() original.seek(0,0) pos = 0 block_size = 4*1024*1024 print(hex(hpet_flag_byte_offset)) while pos != hpet_flag_byte_offset: if hpet_flag_byte_offset - pos < block_size: block_size = hpet_flag_byte_offset - pos data = original.read(block_size) new.write(data) pos += block_size hpet = original.read(8) # print(hpet) hpet_new = hpet[0] ^ 0x8 # print(hpet_new) new.write(bytes((hpet_new,))) new.write(hpet[1:]) pos = pos + 8 block_size = 4*1024*1024 while pos != file_size: if file_size - pos < block_size: block_size = file_size - pos data = original.read(block_size) new.write(data) pos += block_size else: print("can't find") original.close() new.close() ``` -- With best regards, Sergey Kovalev
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |