qemu: hyperv: Add support for timer enlightenments

Add a new <timer> for the HyperV reference time counter enlightenment
and the iTSC reference page for Windows guests.

This feature provides a paravirtual approach to track timer events for
the guest (similar to kvmclock) with the option to use real hardware
clock on systems with a iTSC with compensation across various hosts.
This commit is contained in:
Peter Krempa 2014-01-21 18:50:12 +01:00
parent 8ffaa42d7b
commit 600bca592b
9 changed files with 66 additions and 17 deletions

View File

@ -1367,7 +1367,13 @@
being modified, and can be one of being modified, and can be one of
"platform" (currently unsupported), "platform" (currently unsupported),
"hpet" (libxl, xen, qemu), "kvmclock" (qemu), "hpet" (libxl, xen, qemu), "kvmclock" (qemu),
"pit" (qemu), "rtc" (qemu), or "tsc" (libxl). "pit" (qemu), "rtc" (qemu), "tsc" (libxl) or "hypervclock"
(qemu - <span class="since">since 1.2.2</span>).
The <code>hypervclock</code> timer adds support for the
reference time counter and the reference page for iTSC
feature for guests running the Microsoft Windows
operating system.
</dd> </dd>
<dt><code>track</code></dt> <dt><code>track</code></dt>
<dd> <dd>

View File

@ -915,7 +915,10 @@
</group> </group>
<group> <group>
<attribute name="name"> <attribute name="name">
<choice>
<value>kvmclock</value> <value>kvmclock</value>
<value>hypervclock</value>
</choice>
</attribute> </attribute>
</group> </group>
</choice> </choice>

View File

@ -726,7 +726,8 @@ VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
"rtc", "rtc",
"hpet", "hpet",
"tsc", "tsc",
"kvmclock"); "kvmclock",
"hypervclock");
VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST, VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST,
"boot", "boot",
@ -2929,7 +2930,8 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
for (i = 0; i < def->clock.ntimers; i++) { for (i = 0; i < def->clock.ntimers; i++) {
virDomainTimerDefPtr timer = def->clock.timers[i]; virDomainTimerDefPtr timer = def->clock.timers[i];
if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK) { if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK ||
timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK) {
if (timer->tickpolicy != -1) { if (timer->tickpolicy != -1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("timer %s doesn't support setting of " _("timer %s doesn't support setting of "

View File

@ -1750,6 +1750,7 @@ enum virDomainTimerNameType {
VIR_DOMAIN_TIMER_NAME_HPET, VIR_DOMAIN_TIMER_NAME_HPET,
VIR_DOMAIN_TIMER_NAME_TSC, VIR_DOMAIN_TIMER_NAME_TSC,
VIR_DOMAIN_TIMER_NAME_KVMCLOCK, VIR_DOMAIN_TIMER_NAME_KVMCLOCK,
VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK,
VIR_DOMAIN_TIMER_NAME_LAST VIR_DOMAIN_TIMER_NAME_LAST
}; };

View File

@ -6732,20 +6732,23 @@ qemuBuildCpuArgStr(virQEMUDriverPtr driver,
} }
} }
/* Now force kvmclock on/off based on the corresponding <timer> element. */ /* Handle paravirtual timers */
for (i = 0; i < def->clock.ntimers; i++) { for (i = 0; i < def->clock.ntimers; i++) {
if (def->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK && virDomainTimerDefPtr timer = def->clock.timers[i];
def->clock.timers[i]->present != -1) {
char sign; if (timer->present == -1)
if (def->clock.timers[i]->present) continue;
sign = '+';
else if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK) {
sign = '-';
virBufferAsprintf(&buf, "%s,%ckvmclock", virBufferAsprintf(&buf, "%s,%ckvmclock",
have_cpu ? "" : default_model, have_cpu ? "" : default_model,
sign); timer->present ? '+' : '-');
have_cpu = true;
} else if (timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK &&
timer->present) {
virBufferAsprintf(&buf, "%s,hv_time",
have_cpu ? "" : default_model);
have_cpu = true; have_cpu = true;
break;
} }
} }
@ -8007,8 +8010,7 @@ qemuBuildCommandLine(virConnectPtr conn,
} }
for (i = 0; i < def->clock.ntimers; i++) { for (i = 0; i < def->clock.ntimers; i++) {
switch (def->clock.timers[i]->name) { switch ((enum virDomainTimerNameType) def->clock.timers[i]->name) {
default:
case VIR_DOMAIN_TIMER_NAME_PLATFORM: case VIR_DOMAIN_TIMER_NAME_PLATFORM:
case VIR_DOMAIN_TIMER_NAME_TSC: case VIR_DOMAIN_TIMER_NAME_TSC:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@ -8017,7 +8019,9 @@ qemuBuildCommandLine(virConnectPtr conn,
goto error; goto error;
case VIR_DOMAIN_TIMER_NAME_KVMCLOCK: case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
/* This is handled when building -cpu. */ case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
/* Timers above are handled when building -cpu. */
case VIR_DOMAIN_TIMER_NAME_LAST:
break; break;
case VIR_DOMAIN_TIMER_NAME_RTC: case VIR_DOMAIN_TIMER_NAME_RTC:

View File

@ -0,0 +1,5 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
/usr/bin/kvm -S -M pc \
-cpu qemu32,hv_time -m 214 -smp 6 \
-nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot n -usb -net \
none -serial none -parallel none

View File

@ -0,0 +1,26 @@
<domain type='kvm'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
<vcpu placement='static'>6</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='network'/>
</os>
<features>
<pae/>
</features>
<clock offset='utc'>
<timer name='hypervclock' present='yes'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/kvm</emulator>
<controller type='usb' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -637,6 +637,7 @@ mymain(void)
DO_TEST("cpu-kvmclock", QEMU_CAPS_ENABLE_KVM); DO_TEST("cpu-kvmclock", QEMU_CAPS_ENABLE_KVM);
DO_TEST("cpu-host-kvmclock", QEMU_CAPS_ENABLE_KVM, QEMU_CAPS_CPU_HOST); DO_TEST("cpu-host-kvmclock", QEMU_CAPS_ENABLE_KVM, QEMU_CAPS_CPU_HOST);
DO_TEST("kvmclock", QEMU_CAPS_KVM); DO_TEST("kvmclock", QEMU_CAPS_KVM);
DO_TEST("clock-timer-hyperv-rtc", QEMU_CAPS_KVM);
DO_TEST("cpu-eoi-disabled", QEMU_CAPS_ENABLE_KVM); DO_TEST("cpu-eoi-disabled", QEMU_CAPS_ENABLE_KVM);
DO_TEST("cpu-eoi-enabled", QEMU_CAPS_ENABLE_KVM); DO_TEST("cpu-eoi-enabled", QEMU_CAPS_ENABLE_KVM);

View File

@ -160,6 +160,7 @@ mymain(void)
DO_TEST("cpu-host-kvmclock"); DO_TEST("cpu-host-kvmclock");
DO_TEST("clock-catchup"); DO_TEST("clock-catchup");
DO_TEST("kvmclock"); DO_TEST("kvmclock");
DO_TEST("clock-timer-hyperv-rtc");
DO_TEST("cpu-eoi-disabled"); DO_TEST("cpu-eoi-disabled");
DO_TEST("cpu-eoi-enabled"); DO_TEST("cpu-eoi-enabled");