|
[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 |