KVM內核文檔閱讀筆記


KVM在內核中有豐富的文檔,位置在Documentation/virtual/kvm/

00-INDEX:整個目錄的索引及介紹文檔。

api.txt:KVM用戶空間API,所謂的API主要是通過ioctl來實現的。

cpuid.txt:KVM的cpuid相關API。

devices/:各種平台相關設備API。

hypercalls.txt:KVM的hypercall介紹,介紹了X86和S390的支持的hypercall詳細信息。

locking.txt:介紹了KVM用到的鎖、互斥量。

mmu.txt:介紹了Guest X86 MMU功能。

msr.txt:X86架構下的MSR用途。

nested-vmx.txt:使用X86特有的VMX來更簡潔高效的運行Guest OS。

ppc-pv.txt和說90-diag.txt:針對PPC和S390架構的特殊用途,忽略。

review-checklist.txt:KVM相關patch的review檢查列表。

timekeeping.txt:X86架構下時間虛擬化設備。

 

關於KVM API定義的文檔(api.txt)

1.概述

KVM API是一系列用來控制VM各方面的ioctl。它包括三個方面:

System ioctls:這些ioctl用來查詢或者設置影響整個KVM子系統的屬性。並且有一個system ioctl用來創建VM。

VM ioctls:這些ioctl用來查詢或者設置影響整個VM的屬性,其中一個VM ioctl用來創建vcpu。這些VM ioctl只能在用來創建此VM的進程中使用。

vcpu ioctls:這些ioctl用來查詢或者設置能夠控制單個vcpu的屬性。這些vcpu ioctl只能在創建此vcpu的線程中使用。

從上面描述,可以清晰看出三者的層級關系:System ioctls(整個KVM子系統) > VM ioctls(單個VM實體) > vcpu ioctls(單個vcpu)

2.文件描述符

KVM API是圍繞文件描述符展開的。從打開/dev/kvm開始,獲得操作整個KVM子系統的句柄,這個句柄用來執行System ioctls。基於此System句柄執行KVM_CREATE_VM可以創建一個VM的文件句柄,VM句柄用來執行VM ioctls。基於VM句柄的KVM_CREATE_VCPU用來創建一個vcpu句柄。vcpu句柄執行系列vcpu ioctls用來控制vcpu。

常見的文件句柄的特性在KVM並不適用,比如fork操作等。KVM里面只支持一個VM一個進程,一個vcpu一個線程。

3.API描述

每個API,即ioctl都包含一些信息,比如能力、所屬架構、類型(System、VM、vcpu)、參數和返回值。這些ioctl非常多,並且龐雜,根據類型分為3類。有一些特殊架構專有的ioctl活在Architecture中列出,如果通用則是all。

下面重點分析Architecture為all或者x86,Capability為basic類型的ioctl。

System ioctls

API值 說明
KVM_GET_API_VERSION 目前情況下返回值,只有12。如果返回12,表示所有能力為basic的ioctl都能否使用。其他值是不被允許的。
KVM_CREATE_VM 創建一個VM,返回的句柄可以用來控制創建的VM。但此時VM還沒有vcpu和memory。
KVM_GET_MSR_INDEX_LIST 返回Guest支持的MSRs
KVM_CHECK_EXTENSION  
KVM_GET_VCPU_MMAP_SIZE 返回運行vcpu的KVM_RUN使用的共享Memory Region大小。
   

VM ioctls

API值 說明
KVM_CAP_CHECK_EXTENSION_VM  
KVM_CREATE_VCPU 在VM里添加一個vcpu,但是總數不會超過max_cpus。vcpu的id在[0, max_vcpu_id)之間。
KVM_GET_DIRTY_LOG  
KVM_SET_MEMORY_ALIAS  
KVM_CREATE_IRQCHIP  
KVM_GET_IRQCHIP  
KVM_SET_IRQCHIP  
KVM_GET_CLOCK  
KVM_SET_CLOCK  
KVM_GET_VCPU_EVENTS  
KVM_SET_VCPU_EVENTS  
KVM_SET_USER_MEMORY_REGION  
KVM_CAP_ENABLE_CAP_VM 不是所有的能力都被默認打開,可以使用此ioctl來擴展。
   

vcpu ioctls

API值 說明
KVM_RUN 用於運行一個Guest的vcpu。
KVM_GET_REGS 返回vcpu的通用寄存器值,通過struct kvm_regs結構體返回,根據不同架構有所不同。
KVM_SET_REGS 設置vcpu的通用寄存器。
KVM_GET_SREGS 讀取不同架構vcpu的特殊寄存器。
KVM_SET_SREGS 設置不同架構vcpu的特殊寄存器。
KVM_TRANSLATE  
KVM_INTERRUPT  
KVM_DEBUG_GUEST  
KVM_GET_MSRS  
KVM_SET_MSRS  
KVM_SET_CPUID  
KVM_SET_SIGNAL_MASK  
KVM_GET_FPU 獲取vcpu的FPU狀態。
KVM_SET_FPU 設置vcpu的FPU狀態。
KVM_ENABLE_CAP 不是所有的能力都被默認打開,可以使用此ioctl來擴展。
   

 

下面一段代碼很好的詮釋了KVM->VM->vcpu之間的關系:

image

int ret, kvmfd = -1, vmfd = -1, cpufd = -1;

kvmfd = qemu_open("/dev/kvm", O_RDWR);
if (kvmfd < 0) {
    goto err;
}
vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
if (vmfd < 0) {
    goto err;
}
cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
if (cpufd < 0) {
    goto err;
}

 

4.kvm_run結構體

KVM Hypercall(hypercalls.txt)

這里重點關注x86架構下的Hypercall。

KVM hypercall最多支持四個參數,通過rbx、rcx、rdx、rsi。Hypercall調用號通過rax傳遞,返回時rax存放返回值。

一般情況下,其他寄存器不參與Hypercall。

適用於X86架構的Hypercall有三個:KVM_HC_VAPIC_POLL_IRQ、KVM_HC_MMU_OP、KVM_HC_KICK_CPU。

Hypercall的定義在include/uapi/linux/kvm_para.h中:

#define KVM_HC_VAPIC_POLL_IRQ        1
#define KVM_HC_MMU_OP            2
#define KVM_HC_FEATURES            3
#define KVM_HC_PPC_MAP_MAGIC_PAGE    4
#define KVM_HC_KICK_CPU            5
#define KVM_HC_MIPS_GET_CLOCK_FREQ    6
#define KVM_HC_MIPS_EXIT_VM        7
#define KVM_HC_MIPS_CONSOLE_OUTPUT    8

KVM_HC_VAPIC_POLL_IRQ:Host檢查關起的中斷。

KVM_HC_MMU_OP:支持MMU操作,比如PTE、flushing TLB、release PT。

KVM_HC_KICK_CPU:喚醒HLT狀態下的vcpu。如果Guest內核模式下一個vcpu等待時間超時而執行HLT指令,另一個同Guest下vcpu可以通過觸發KVM_HC_KICK_CPU來喚醒。

這些Hypercall都在kvm_emulate_hypercall中處理:

int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
{
    unsigned long nr, a0, a1, a2, a3, ret;
    int op_64_bit, r = 1;

    kvm_x86_ops->skip_emulated_instruction(vcpu);

    if (kvm_hv_hypercall_enabled(vcpu->kvm))
        return kvm_hv_hypercall(vcpu);

    nr = kvm_register_read(vcpu, VCPU_REGS_RAX);  Hypercall調用號
    a0 = kvm_register_read(vcpu, VCPU_REGS_RBX);  依次是四個參數
    a1 = kvm_register_read(vcpu, VCPU_REGS_RCX);
    a2 = kvm_register_read(vcpu, VCPU_REGS_RDX);
    a3 = kvm_register_read(vcpu, VCPU_REGS_RSI);

    switch (nr) {
    case KVM_HC_VAPIC_POLL_IRQ:
        ret = 0;
        break;
    case KVM_HC_KICK_CPU:
        kvm_pv_kick_cpu_op(vcpu->kvm, a0, a1);  真正用到的也就是喚醒vcpu,a1表示vcpu的apicid。
        ret = 0;
        break;
    default:
        ret = -KVM_ENOSYS;
        break;
    }
out:
    if (!op_64_bit)
        ret = (u32)ret;
    kvm_register_write(vcpu, VCPU_REGS_RAX, ret);  返回值放在RAX中。
    ++vcpu->stat.hypercalls;
    return r;
}

 

支持Guest的MMU功能(mmu.txt)

X86 KVM的shadow MMU功能提供一個標准的MMU功能給Guest,將Guest的物理地址轉換成Host物理地址。

關於Nested VMX是一種嵌套式虛擬功能,能夠使一台虛擬機具有物理機CPU特性,支持VMX/SVM硬件虛擬化。參考《Nested VMX》。這樣虛擬機可以使自己成為一個Hypervisors,並在其上安裝虛擬機。

所謂Nested就是運行在Guest上的嵌套Guest,Guest作為Hypervisor。

術語

解釋

PFN

Host page frame number

HPA

Host physical address

HVA

Host virtual address

GFN

Guest page frame number

GPA

Guest physical address

GVA

Guest virtual address

NGPA

Nested guest physical address

NGVA

Nested guest virtual address

PTE

Page table entry

GPTE

Guest page table entry

SPTE

Shadow page table entry

TDP

Two dimensional paging

此處KVM MMU功能主要工作就是配置處理器的MMU以達到將Guest地址轉變到Host。有下面三種不同的轉變需求:

-當Guest關閉分頁功能時,將Guest物理地址轉變成Host物理地址。GPA->HPA

-當Guesst使能分頁功能時,將Guest虛擬地址,轉變成Guest物理地址,進而Host物理地址。GVA->GPA->HPA

-當Guest又虛擬化一個嵌套Guest時,將嵌套的Guest虛擬地址轉變成嵌套的物理地址,進而Guest物理地址,最后是Host物理地址。NGVA->NGPA->GPA-HPA

GPA是運行KVM進程的用戶地址空間的一部分。用戶空間定義了Guest地址到用戶空間地址的轉變(GPA->HVA)。兩個不同的GPA可以映射到一個HVA,但反之不成立。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM