Timekeeping in virtual machines

From OSDev.wiki
Revision as of 19:33, 27 August 2022 by osdev>Demindiro (Created page with "{{stub}} {{In Progress}} There are several ways to keep track of time in a VM, but they're either very slow (e.g. HPET) or do not work correctly if the VM is migrated (e.g. T...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
This page is a stub.
You can help the wiki by accurately adding more contents to it.
This page is a work in progress.
This page may thus be incomplete. Its content may be changed in the near future.

There are several ways to keep track of time in a VM, but they're either very slow (e.g. HPET) or do not work correctly if the VM is migrated (e.g. TSC).

To work around this, VMs suck as QEMU/KVM provide several ways keep track of time whilst sacrificing little performance.

KVM_HC_CLOCK_PAIRING

This hypercall is used to get the parameters to calculate a host's clock (KVM_CLOCK_PAIRING_WALLCLOCK for CLOCK_REALTIME).

The host copies the following structure to a physical address given by the guest:

struct kvm_clock_pairing {
    s64 sec;
    s64 nsec;
    u64 tsc;
    u32 flags;
    u32 pad[9];
};

A hypercall is performed with the `vmcall` instruction. On KVM, RBX, RCX, RDX and RSI are used for arguments, RAX as the hypercall number and as the return value. No other registers are clobbered (unless explicitly noted).

For example, calling KVM_HC_CLOCK_PAIRING can be done as follows on x86_64:

; rdi: physical address to copy structure to
; rsi: clock type (KVM_CLOCK_PAIRING_WALLCLOCK = 0)
kvm_hc_clock_pairing:
    mov eax, 9   ; KVM_HC_CLOCK_PAIRING
    mov rbx, rdi
    mov rcx, rsi
    vmcall
    ret

pvclock

struct pvclock_vcpu_time_info {
    u32 version;
    u32 pad0;
    u64 tsc_timestamp;
    u64 system_time;
    u32 tsc_to_system_mul;
    s8 tsc_shift;
    u8 flags;
    u8 pad[2];
};

Hyper-V TSC page

struct ms_hyperv_tsc_page {
    volatile u32 tsc_sequence;
    u32 reserved1;
    volatile u64 tsc_scale;
    volatile s64 tsc_offset;
    u64 reserved2[509];
};

See also

References