KVM 特定的 MSR

作者:

Glauber Costa <glommer@redhat.com>, 红帽公司, 2010

KVM 使用一些自定义 MSR 来处理一些请求。

自定义 MSR 有一个保留的范围,从 0x4b564d00 到 0x4b564dff。这个区域之外也有 MSR,但它们已被弃用,不鼓励使用。

自定义 MSR 列表

当前支持的自定义 MSR 列表是

MSR_KVM_WALL_CLOCK_NEW

0x4b564d00

数据

必须在客户机 RAM 中的内存区域的 4 字节对齐物理地址。此内存应保存以下结构的副本

struct pvclock_wall_clock {
       u32   version;
       u32   sec;
       u32   nsec;
 } __attribute__((__packed__));

其数据将由 hypervisor 填充。hypervisor 仅保证在 MSR 写入时更新此数据。希望可靠地多次查询此信息的用户必须多次写入此 MSR。字段具有以下含义

版本

客户机必须在获取时间信息之前和之后检查版本,并检查它们是否都相等且为偶数。奇数版本表示正在进行的更新。

启动时墙钟的秒数。

纳秒

启动时墙钟的纳秒数。

为了获得当前的墙钟时间,需要添加 MSR_KVM_SYSTEM_TIME_NEW 中的 system_time。

请注意,虽然 MSR 是每个 CPU 的实体,但此特定 MSR 的影响是全局的。

必须在使用前通过 0x4000001 cpuid 叶中的位 3 来检查此 MSR 的可用性。

MSR_KVM_SYSTEM_TIME_NEW

0x4b564d01

数据

必须在客户机 RAM 中的内存区域的 4 字节对齐物理地址,以及位 0 中的使能位。此内存应保存以下结构的副本

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];
} __attribute__((__packed__)); /* 32 bytes */

其数据将由 hypervisor 定期填充。每个 VCPU 只需要一次写入或注册。此结构的更新间隔是任意的,并且取决于实现。hypervisor 可以随时更新此结构,直到写入任何 bit0 == 0 的值为止。

字段具有以下含义

版本

客户机必须在获取时间信息之前和之后检查版本,并检查它们是否都相等且为偶数。奇数版本表示正在进行的更新。

tsc_timestamp

在更新此结构时,当前 VCPU 的 tsc 值。客户机可以从此结构中减去此值,以得出自结构更新以来经过的时间的概念。

system_time

主机单调时间的表示,包括上次更新此结构时的睡眠时间。单位为纳秒。

tsc_to_system_mul

将 tsc 相关量转换为纳秒时要使用的乘数

tsc_shift

将 tsc 相关量转换为纳秒时要使用的移位。此移位将确保与 tsc_to_system_mul 的乘法不会溢出。正值表示左移,负值表示右移。

从 tsc 到纳秒的转换涉及额外的右移 32 位。有了此信息,客户机可以通过执行以下操作来得出每个 CPU 的时间

time = (current_tsc - tsc_timestamp)
if (tsc_shift >= 0)
        time <<= tsc_shift;
else
        time >>= -tsc_shift;
time = (time * tsc_to_system_mul) >> 32
time = time + system_time
标志

此字段中的位表示客户机和 hypervisor 之间协调的扩展功能。必须在 0x40000001 cpuid 叶中检查特定标志的可用性。当前标志是

标志位

cpuid 位

含义

0

24

保证跨多个 cpu 进行的时间测量是单调的

1

N/A

客户机 vcpu 已被主机暂停。请参阅 api.txt 中的 4.70

必须在使用前通过 0x4000001 cpuid 叶中的位 3 来检查此 MSR 的可用性。

MSR_KVM_WALL_CLOCK

0x11

数据和功能

与 MSR_KVM_WALL_CLOCK_NEW 相同。请改用它。

此 MSR 不在 KVM 保留范围内,将来可能会被删除。它的使用已被弃用。

必须在使用前通过 0x4000001 cpuid 叶中的位 0 来检查此 MSR 的可用性。

MSR_KVM_SYSTEM_TIME

0x12

数据和功能

与 MSR_KVM_SYSTEM_TIME_NEW 相同。请改用它。

此 MSR 不在 KVM 保留范围内,将来可能会被删除。它的使用已被弃用。

必须在使用前通过 0x4000001 cpuid 叶中的位 0 来检查此 MSR 的可用性。

然后,检测 kvmclock 存在的建议算法是

if (!kvm_para_available())    /* refer to cpuid.txt */
        return NON_PRESENT;

flags = cpuid_eax(0x40000001);
if (flags & 3) {
        msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW;
        msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW;
        return PRESENT;
} else if (flags & 0) {
        msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
        msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
        return PRESENT;
} else
        return NON_PRESENT;
MSR_KVM_ASYNC_PF_EN

0x4b564d02

数据

异步页面错误 (APF) 控制 MSR。

位 63-6 保存必须在客户机 RAM 中的 64 字节内存区域的 64 字节对齐物理地址。此内存应保存以下结构

struct kvm_vcpu_pv_apf_data {
      /* Used for 'page not present' events delivered via #PF */
      __u32 flags;

      /* Used for 'page ready' events delivered via interrupt notification */
      __u32 token;

      __u8 pad[56];
};

MSR 的位 5-4 是保留的,应为零。当 vcpu 上启用异步页面错误时,位 0 设置为 1,禁用时设置为 0。如果当 vcpu 处于 cpl == 0 时可以注入异步页面错误,则位 1 为 1。如果异步页面错误作为 #PF vmexit 传递到 L1,则位 2 为 1。只有当 CPUID 中存在 KVM_FEATURE_ASYNC_PF_VMEXIT 时,才能设置位 2。如果 CPUID 中存在 KVM_FEATURE_ASYNC_PF_INT,则位 3 启用基于中断的“页面就绪”事件传递。只有当 CPUID 中存在 KVM_FEATURE_ASYNC_PF_INT 时才能设置位 3。

“页面不存在”事件当前始终作为合成 #PF 异常传递。在传递这些事件期间,APF CR2 寄存器包含一个令牌,该令牌将在丢失的页面可用时用于通知客户机。此外,为了能够区分真实 #PF 和 APF,hypervisor 将在注入时将 64 字节内存位置(“标志”)的前 4 个字节写入。当前仅支持“标志”的第一个位,当设置时,它表示客户机正在处理异步“页面不存在”事件。如果在页面错误期间 APF “标志”为“0”,则表示这是一个常规页面错误。客户机应该在处理 #PF 异常后清除“标志”,以便可以传递下一个事件。

请注意,由于 APF “页面不存在”事件使用与常规页面错误相同的异常向量,因此客户机必须在执行可能生成正常页面错误的操作之前将“标志”重置为“0”。

hypervisor 将在 APF “页面就绪”事件注入时将 64 字节内存位置(“令牌”)的字节 4-7 写入。这些字节的内容是在 CR2 中作为“页面不存在”事件先前传递的令牌。该事件指示页面现在可用。客户机应在处理“页面就绪”事件后将“0”写入“令牌”,并在清除该位置后将“1”写入 MSR_KVM_ASYNC_PF_ACK;写入 MSR 会强制 KVM 重新扫描其队列并传递下一个挂起的通知。

请注意,在 MSR_KVM_ASYNC_PF_EN 中启用 APF 机制之前,需要写入指定“页面就绪”APF 传递的中断向量的 MSR_KVM_ASYNC_PF_INT MSR,否则可能会注入中断 #0。如果 CPUID 中存在 KVM_FEATURE_ASYNC_PF_INT,则 MSR 可用。

请注意,以前,“页面就绪”事件通过与“页面不存在”事件相同的 #PF 异常传递,但这现在已被弃用。如果未设置位 3(基于中断的传递),则不会传递 APF 事件。

如果在存在未完成的 APF 时禁用 APF,则不会传递它们。

目前,“页面就绪”APF 事件将始终在与“页面不存在”事件相同的 vcpu 上传递,但客户机不应依赖这一点。

MSR_KVM_STEAL_TIME

0x4b564d03

数据

必须在客户机 RAM 中的内存区域的 64 字节对齐物理地址,以及位 0 中的使能位。此内存应保存以下结构的副本

struct kvm_steal_time {
      __u64 steal;
      __u32 version;
      __u32 flags;
      __u8  preempted;
      __u8  u8_pad[3];
      __u32 pad[11];
}

其数据将由 hypervisor 定期填充。每个 VCPU 只需要一次写入或注册。此结构的更新间隔是任意的,并且取决于实现。hypervisor 可以随时更新此结构,直到写入任何 bit0 == 0 的值为止。客户机需要确保此结构初始化为零。

字段具有以下含义

版本

一个序列计数器。换句话说,客户机必须在获取时间信息之前和之后检查此字段,并确保它们都相等且为偶数。奇数版本表示正在进行的更新。

标志

此时,始终为零。将来可能会用于指示此结构中的更改。

偷取

此 vCPU 未运行的时间量,单位为纳秒。vcpu 空闲期间的时间不会报告为偷取时间。

抢占

指示拥有此结构的 vCPU 是否正在运行。非零值表示 vCPU 已被抢占。零表示 vCPU 未被抢占。请注意,如果 hypervisor 不支持此字段,则始终为零。

MSR_KVM_EOI_EN

0x4b564d04

数据

当在 vcpu 上启用 PV 中断结束时,位 0 为 1;禁用时为 0。位 1 是保留的,必须为零。当启用 PV 中断结束时(位 0 设置),位 63-2 保存必须在客户机 RAM 中且必须为零的 4 字节内存区域的 4 字节对齐物理地址。

超管理器通常在中断注入时,会将 4 字节内存位置的最低有效位写入。值为 1 表示客户机可以跳过向 APIC 写入 EOI(使用 MSR 或 MMIO 写入);相反,通过清除客户机内存中的该位来发出 EOI 信号就足够了 - 此位置稍后将由超管理器轮询。值为 0 表示需要进行 EOI 写入。

客户机始终可以安全地忽略优化并执行 APIC EOI 写入。

超管理器保证仅在当前 VCPU 上下文中修改此最低有效位,这意味着客户机无需使用锁前缀或内存排序原语与超管理器同步。

但是,超管理器可以随时设置和清除此内存位:因此,为了确保超管理器不会中断客户机,并且不会在客户机测试该位以检测是否可以跳过 EOI apic 写入以及客户机清除该位以向超管理器发出 EOI 信号之间的窗口中清除内存区域中的最低有效位,客户机必须使用单个 CPU 指令(例如测试并清除,或比较并交换)读取内存区域中的最低有效位并清除它。

MSR_KVM_POLL_CONTROL

0x4b564d05

控制主机端轮询。

数据

位 0 启用 (1) 或禁用 (0) 主机端 HLT 轮询逻辑。

例如,如果 KVM 客户机正在自行执行轮询,则它们可以请求主机不轮询 HLT。

MSR_KVM_ASYNC_PF_INT

0x4b564d06

数据

第二个异步页错误 (APF) 控制 MSR。

位 0-7:用于传递“页面就绪”APF 事件的 APIC 向量。位 8-63:保留

用于异步“页面就绪”通知传递的中断向量。在 MSR_KVM_ASYNC_PF_EN 中启用异步页错误机制之前,必须设置向量。仅当 CPUID 中存在 KVM_FEATURE_ASYNC_PF_INT 时,MSR 才可用。

MSR_KVM_ASYNC_PF_ACK

0x4b564d07

数据

异步页错误 (APF) 确认。

当客户机完成处理“页面就绪”APF 事件,并且“struct kvm_vcpu_pv_apf_data”中的“token”字段被清除后,它应该向 MSR 的位 0 写入“1”,这会导致主机重新扫描其队列并检查是否有更多通知待处理。如果 CPUID 中存在 KVM_FEATURE_ASYNC_PF_INT,则 MSR 可用。

MSR_KVM_MIGRATION_CONTROL

0x4b564d08

数据

如果 CPUID 中存在 KVM_FEATURE_MIGRATION_CONTROL,则此 MSR 可用。位 0 表示是否允许客户机的实时迁移。

当启动客户机时,如果客户机具有加密内存,则位 0 将为 0;如果客户机没有加密内存,则位 0 将为 1。如果客户机使用 KVM_HC_MAP_GPA_RANGE 超调用将页面加密状态通信给主机,它可以设置此 MSR 中的位 0 以允许客户机的实时迁移。