天天看點

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

背景

Read the fucking source code!  --By 魯迅

A picture is worth a thousand words. --By 高爾基

說明:

KVM版本:5.9.1

QEMU版本:5.0.0

工具:Source Insight 3.5, Visio

文章同步在部落格園:https://www.cnblogs.com/LoyenWang/

1. 概述

本文圍繞ARMv8 CPU的虛拟化展開;

本文會結合Qemu + KVM的代碼分析,捋清楚上層到底層的脈絡;

本文會提供一個Sample Code,用于類比Qemu和KVM的關系,總而言之,大同小異,大題小做,大道至簡,大功告成,大恩不言謝;

先來兩段前戲。

AI的世界,程式的執行不再冰冷,CPU對a.out說,hello啊,world已經ok啦,下來return吧!

既然要說CPU的虛拟化,那就先簡要介紹一下CPU的工作原理:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

CPU的根本任務是執行指令,我們常說的取指-譯碼-執行-訪存-寫回,就是典型的指令Pipeline操作;

從CPU的功能出發,可以簡要分成三個邏輯子產品:

Control Unit:CPU的指揮中心,協調資料的移動;

ALU:運算單元,執行CPU内部所有的計算;

Register:寄存器和Cache,都算是CPU内部的存儲單元,其中寄存器可用于存儲需要被譯碼和執行的指令、資料、位址等;

CPU從記憶體中讀取指令進行譯碼并執行,執行的過程中需要去通路記憶體中的資料,CPU内部的寄存器可以暫存中間的指令和資料等資訊,通常說的CPU的context指的就是CPU寄存器值;

在硬體支援虛拟化之前,Qemu純軟體虛拟化方案,是通過tcg(tiny code generator)的方式來進行指令翻譯,翻譯成Host處理器架構的指令來執行。硬體虛拟化技術,是讓虛拟機能直接執行在Host CPU上,讓Host CPU直接來執行虛拟機,結合CPU的實際工作原理,應該怎麼來了解呢?來張圖:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

CPU通過pc寄存器擷取下一條執行指令,進行取指譯碼執行等操作,是以給定CPU一個Context,自然就能控制其執行某些代碼;

CPU的虛拟化,最終目标讓虛拟機執行在CPU上,無非也是要進行CPU的Context切換,控制CPU去執行對應的代碼,下文會進一步闡述;

既然都講CPU了,那就捎帶介紹下ARMv8的寄存器吧:

通用寄存器:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

圖中描述的是EL3以下,AArch32與AArch64寄存器對應關系;

AArch64中,總共31個通用寄存器,64bit的為X0-X30,32bit的為W0-W30;

特殊用途寄存器:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

這些特殊用途的寄存器,主要分為三種:1)存放異常傳回位址的ELR_ELx;2)各個EL的棧指針SP_ELx;3)CPU的狀态相關寄存器;

CPU的狀态PSTATE:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

CPU的狀态在AArch32時是通過CPSR來擷取,在AArch64中,使用PSTATE,PSTATE不是一個寄存器,它表示的是儲存目前CPU狀态資訊的一組寄存器或一些标志資訊的統稱;

好了,ARMv8的介紹該打住了,否則要跑偏了。。。

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

Linux系統有兩種執行模式:kernel模式與user模式,為了支援虛拟化功能的CPU,KVM向Linux核心提供了guest模式,用于執行虛拟機系統非I/O的代碼;

user模式,對應的是使用者态執行,Qemu程式就執行在user模式下,并循環監聽是否有I/O需要模拟處理;

kernel模式,運作kvm子產品代碼,負責将CPU切換到VM的執行,其中包含了上下文的load/restore;

guest模式,本地運作VM的非I/O代碼,在某些異常情況下會退出該模式,Host OS開始接管;

好了啦,前戲結束,開始直奔主題吧。

2. 流程分析

不管你說啥,我上來就是一句中國萬歲,對不起,跑題了。我上來就是一張Qemu初始化流程圖:

看過Qemu源代碼的人可能都有種感覺,一開始看好像摸不到門框,這圖簡要畫了下關鍵子產品的流程;

Qemu的源代碼,後續的文章會詳細介紹,本文隻focus在vcpu相關部分;

除了找到了qemu_init_vcpu的入口,這張圖好像跟本文的vcpu的虛拟化關系不是很大,不管了,就算是給後續的Qemu分析打個廣告吧。

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

Qemu初始化流程圖中,找到了qemu_init_vcpu的入口,順着這個qemu_init_vcpu就能找到與底層KVM子產品互動的過程;

Qemu中為每個vcpu建立了一個線程,操作裝置節點來建立和初始化vcpu;

是以,接力棒甩到了KVM核心子產品。

來一張前文的圖:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

前文中分析過,系統在初始化的時候會注冊字元裝置驅動,設定好了各類操作函數集,等待使用者層的ioctl來進行控制;

Qemu中設定KVM_CREATE_VCPU,将觸發kvm_vm_ioctl_create_vcpu的執行,完成vcpu的建立工作;

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

在底層中進行vcpu的建立工作,主要是配置設定一個kvm_vcpu結構,并且對該結構中的字段進行初始化;

其中有一個用于與應用層進行通信的資料結構struct kvm_run,配置設定一頁記憶體,應用層會調用mmap來進行映射,并且會從該結構中擷取到虛拟機的退出原因;

kvm_arch_vcpu_create主要完成體系架構相關的初始化,包括timer,pmu,vgic等;

create_hyp_mappings将kvm_vcpu結構體建立映射,以便在Hypervisor模式下能通路該結構;

create_vcpu_fd注冊了kvm_vcpu_fops操作函數集,針對vcpu進行操作,Qemu中設定KVM_ARM_VCPU_INIT,将觸發kvm_arch_vcpu_ioctl_vcpu_init的執行,完成的工作主要是vcpu的核心寄存器,系統寄存器等的reset操作,此外還包含了上層設定下來的值,放置在struct kvm_vcpu_init中;

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

Qemu中為每一個vcpu建立一個使用者線程,完成了vcpu的初始化後,便進入了vcpu的運作,而這是通過kvm_cpu_exec函數來完成的;

kvm_cpu_exec函數中,調用kvm_vcpu_ioctl(,KVM_RUN,)來讓底層的實體CPU進行運作,并且監測VM的退出,而這個退出原因就是存在放在kvm_run->exit_reason中,也就是上文中提到過的應用層與底層互動的機制;

使用者層通過KVM_RUN指令,将觸發KVM子產品中kvm_arch_vcpu_ioctl_run函數的執行:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

vcpu最終是要放置在實體CPU上執行的,很顯然,我們需要進行context的切換:儲存好Host的Context,并切換到Guest的Context去執行,最終在退出時再恢複回Host的Context;

__guest_enter函數完成最終的context切換,進入Guest的執行,當Guest退出時,fixup_guest_exit将會處理exit_code,判斷是否繼續傳回Guest執行;

當最終Guest退出到Host時,Host調用handle_exit來處理異常退出,根據kvm_get_exit_handler去查詢異常處理函數表對應的處理函數,最終進行執行處理;

3. Sample Code

上文已經将Qemu+KVM的CPU的虛拟化大概的輪廓已經介紹了,方方面面,問題不大;

來一段Sample Code類比Qemu和KVM的關系,在Ubuntu16.04系統上進行測試;

簡要介紹一下:

tiny_kernel.S,相當于Qemu中運作的Guest OS,完成的功能很簡單,沒錯,就是Hello, world列印;

tiny_qemu.c,相當于Qemu,用于加載Guest到vCPU上運作,最終通過kvm放到實體CPU上運作;

魯迅在1921年的時候,說過這麼一句話:Talk is cheap, show me the code。

tiny_kernel.S:

tiny_qemu.c:

為了表明我沒有騙人,上一張在Ubuntu16.04的虛拟機上運作的結果圖吧:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

草草收工吧。

4. 參考

ARMv8-A Architecture Overview

ARMv8 Techinology Preview

Arm Architecture Reference Manual, Armv8, for Armv8-A architecture profile

 Virtual lockstep for fault tolerance and architectural vulnerability analysis

歡迎關注個人公衆号,不定期分享技術文章:

【原創】Linux虛拟化KVM-Qemu分析(四)之CPU虛拟化(2)

繼續閱讀