之前介紹了CCA設(shè)計的一個目的是讓hypervisor可以創(chuàng)建和調(diào)度RME虛擬機和vCPU,并且給它分配內(nèi)存等資源,但是一旦這些資源分配給RME虛擬機之后,hypervisor就失去了訪問這些RME所有的內(nèi)存內(nèi)容的權(quán)限。這是通過EL3的monitor軟件修改GPT表項實現(xiàn)的。從而實現(xiàn)虛擬機的機密計算。
Arm和開源社區(qū)提供一個參考設(shè)計,其中包括包括:
1. Linux kernel KVM模塊的支持:
- 支持由RME通過RMI接口創(chuàng)建,運行虛擬機vCPU,可以服務(wù)RME虛擬的RIS host call
- 增加了KVM UABI用于管理Realms
- 增加了Linux kernel作為CCA的Host, 也可以做為CCA的Guest(運行于RME虛擬機,支持RSI接口)
目前運行hypervisor的host Linux運行在non secure EL2, 并且運行于VHE模式。
2. 開源的RMM實現(xiàn):TF-RMM,主要是服務(wù)host hypervisor發(fā)過來的RMI請求,創(chuàng)建在Realm狀態(tài)下對應(yīng)host Linux KVM里struct kvm的虛擬機的描述和狀態(tài),和對應(yīng)host Linux vCPU的虛擬CPU狀態(tài)和上下文的結(jié)構(gòu),并且負責(zé)Realm中vCPU的context的save/restore. RMM還負責(zé)通過Realm的stage 2實現(xiàn)多個Realm虛擬機間的隔離。
3. 擴展現(xiàn)有的 Arm Trusted Firmware,使它支持RME引入的4個secure狀態(tài)和它們間切換時的context swithing,增加了RMI調(diào)用的支持和GPT頁表的管理。
TF-RMM采用了類似Hafnium, OPTEE的工作方式,主要目的是將原來在host Linux kernel做的部分事情(如和vCPU context,stage 2頁表配置相關(guān)的)通過RMI調(diào)用轉(zhuǎn)到Realm world實現(xiàn),這部分事情放在host Linux中的話,可以導(dǎo)致host可以獲得修改VM的信息和控制VM的執(zhí)行。但是TF-RMM和Hafnium, OPTEE一樣沒有調(diào)度和復(fù)雜的內(nèi)存管理功能,TF-RMM的執(zhí)行主要是服務(wù)Host Linux的RMI調(diào)用和Guest Linux的RSI調(diào)用。
概況
Host Linux支持創(chuàng)建普通的虛擬機和Realm虛擬機,現(xiàn)有的KVM API還是可以使用。Host Linux通過KVM_CAP_ARM_RME告訴user space的VMM,平臺是否支持RME的KVM。如果要創(chuàng)建Realm虛擬機,VMM可以通過kvm module的ioctl KVM_ENABLE_CAP調(diào)用并傳入.cap = KVM_CAP_ARM_RME參數(shù)。Host Linux kernel為之創(chuàng)建的struct kvm結(jié)構(gòu)中的kvm->arch.is_realm記錄,后面kernel通過kvm_is_realm(kvm)檢查是否為Realm VM. KVM_CAP_ARM_RME會導(dǎo)致KVM調(diào)用kvm_create_realm->realm_create_rd->rmi_realm_create 這會引起RMI Realm.Create的SMC調(diào)用,ATF會將這個調(diào)用dispatch給TF-RMM處理,TF-RMM會為之創(chuàng)建Realm Descriptor (RD,struct rd)的結(jié)構(gòu),對應(yīng)于host Linux kernel的struct kvm結(jié)構(gòu)。TF-RMM的rmm_handler通過一下handler來服務(wù)這些RMI調(diào)用:
static const struct smc_handler smc_handlers[] = {
HANDLER(VERSION, 0, 0, smc_version, true, true),
HANDLER(FEATURES, 1, 1, smc_read_feature_register, true, true),
HANDLER(GRANULE_DELEGATE, 1, 0, smc_granule_delegate, false, true),
HANDLER(GRANULE_UNDELEGATE, 1, 0, smc_granule_undelegate, false, true),
HANDLER(REALM_CREATE, 2, 0, smc_realm_create, true, true),
HANDLER(REALM_DESTROY, 1, 0, smc_realm_destroy, true, true),
HANDLER(REALM_ACTIVATE, 1, 0, smc_realm_activate, true, true),
HANDLER(REC_CREATE, 3, 0, smc_rec_create, true, true),
HANDLER(REC_DESTROY, 1, 0, smc_rec_destroy, true, true),
HANDLER(REC_ENTER, 2, 0, smc_rec_enter, false, true),
HANDLER(DATA_CREATE, 5, 0, smc_data_create, false, false),
HANDLER(DATA_CREATE_UNKNOWN, 3, 0, smc_data_create_unknown, false, false),
HANDLER(DATA_DESTROY, 2, 0, smc_data_destroy, false, true),
HANDLER(RTT_CREATE, 4, 0, smc_rtt_create, false, true),
HANDLER(RTT_DESTROY, 4, 0, smc_rtt_destroy, false, true),
HANDLER(RTT_FOLD, 4, 0, smc_rtt_fold, false, true),
HANDLER(RTT_MAP_UNPROTECTED, 4, 0, smc_rtt_map_unprotected, false, false),
HANDLER(RTT_UNMAP_UNPROTECTED, 3, 0, smc_rtt_unmap_unprotected, false, false),
HANDLER(RTT_READ_ENTRY, 3, 4, smc_rtt_read_entry, false, true),
HANDLER(PSCI_COMPLETE, 2, 0, smc_psci_complete, true, true),
HANDLER(REC_AUX_COUNT, 1, 1, smc_rec_aux_count, true, true),
HANDLER(RTT_INIT_RIPAS, 3, 0, smc_rtt_init_ripas, false, true),
HANDLER(RTT_SET_RIPAS, 5, 0, smc_rtt_set_ripas, false, true)
然后VMM通過KVM_CREATE_VCPU的kvm ioctl調(diào)用kvm_vm_ioctl_create_vcpu ->kvm_arch_vcpu_create創(chuàng)建了vCPU之后,對于Realm VMh還需要通過KVM_ARM_VCPU_FINALIZE kvm_arch_vcpu_ioctl系統(tǒng)調(diào)用, kvm_arm_vcpu_finalize kvm_create_rec->rmi_rec_create, 通過RMI REC_CREATE調(diào)用(通過SMC指令)到ATF,ATF再將此調(diào)用dispatch到TF-RMM,TF-RMM通過smc_rec_create在Realm狀態(tài)創(chuàng)建對應(yīng)于host Linux KVM struct kvm_vcpu的struct rec結(jié)構(gòu)體。Host kernel KVM通過vcpu_is_rec()檢查vCPU是否運行在Realm中。
struct rec {
struct granule *g_rec; /* the granule in which this REC lives */
unsigned long rec_idx; /* which REC is this */
bool runnable;
unsigned long regs[31];
/*
* PAuth state of Realm.
* Note that we do not need to save NS state as EL3 will save this as part of world switch.
*/
struct pauth_state pauth;
unsigned long pc;
unsigned long pstate;
struct sysreg_state sysregs;
struct common_sysreg_state common_sysregs;
struct {
unsigned long start;
unsigned long end;
unsigned long addr;
enum ripas ripas;
} set_ripas;
/*
* Common values across all RECs in a Realm.
*/
struct {
unsigned long ipa_bits;
int s2_starting_level;
struct granule *g_rtt;
struct granule *g_rd;
bool pmu_enabled;
unsigned int pmu_num_cnts;
bool sve_enabled;
uint8_t sve_vq;
} realm_info;
struct {
/*
* The contents of the *_EL2 system registers at the last time
* the REC exited to the host due to a synchronous exception.
* These are the unsanitized register values which may differ
* from the value returned to the host in rec_exit structure.
*/
unsigned long esr;
unsigned long hpfar;
unsigned long far;
} last_run_info;
/* Pointer to per-cpu non-secure state */
struct ns_state *ns;
struct {
/*
* Set to 'true' when there is a pending PSCI
* command that must be resolved by the host.
* The command is encoded in rec- >regs[0].
*
* A REC with pending PSCI is not schedulable.
*/
bool pending;
} psci_info;
/* Number of auxiliary granules */
unsigned int num_rec_aux;
/* Addresses of auxiliary granules */
struct granule *g_aux[MAX_REC_AUX_GRANULES];
struct rec_aux_data aux_data;
unsigned char rmm_realm_token_buf[SZ_1K];
size_t rmm_realm_token_len;
struct token_sign_ctx token_sign_ctx;
/* Buffer allocation info used for heap init and management */
struct {
struct buffer_alloc_ctx ctx;
bool ctx_initialised;
} alloc_info;
struct {
unsigned long vsesr_el2;
bool inject;
} serror_info;
/* True if host call is pending */
bool host_call;
};
然后VMM通過KVM_RUN 的ioctl運行vCPU,對于Realm VM, 這是通過kvm_arch_vcpu_ioctl_run ->kvm_rec_enter->rmi_rec_enter,rmi_rec_enter通過RMI REC_ENTER的調(diào)用(通過SMC指令)到ATF,ATF將它dispatch到TF-RMM,TF-RMM調(diào)用smc_rec_enter,然后通過rec_run_loop將物理CPU的執(zhí)行轉(zhuǎn)交給Realm EL0&EL1的Realm VM。
完整的vCPU運轉(zhuǎn)圖如下:
由此看出,對于host Linux KVM, 與正常的KVM VM, pKVM VM類似,Realm虛擬機的vCPU的創(chuàng)建是由host Linux上的VMM管理的,每個Realm vCPU對于host Linux來說也只是VM進程的一個線程,也是由host Linux負責(zé)調(diào)度的。只是Realm vCPU運行于Realm EL0&EL1狀態(tài)。但是Realm VM和Realm vCPU的信息host Linux是看不到的,這點與正常的KVM VM不同。
從上圖也可以看出,Realm vCPU執(zhí)行的進入和退出需要經(jīng)過更長的路徑,如進入vCPU的執(zhí)行需要經(jīng)過host Linux KVM->ATF->TF-RMM->Realm VM,每個步驟都涉及到context save/restore. 但根據(jù)初步的研究發(fā)現(xiàn),這個過程中帶來的overhead并不是很明顯。
Stage 2 table的管理
RMM的stage 2用于Realm VM之間的隔離。在TF-RMM中維護一個RTT,相當(dāng)于Normal KVM VM中的stage 2頁表,對于Realm VM, 這是由TF-RMM管理的RTT.
Realm VM的IPA空間包括一個受保護的地址范圍(PAR),RMM確保只能將其映射到Realm PAS。
對于在PAR內(nèi)的訪問,RMM保證給Realm的機密性和完整性;在PAR之外,hypervisor可以自由地映射NS PAS內(nèi)存頁或模擬訪問。這為在Realm VM上運行的OS提供了一個可靠的機制來確定它是訪問自己的私有內(nèi)存,還是可以與不受信任的其他部分共享的內(nèi)存。
在Realm創(chuàng)建期間,hypervisor可以將一個內(nèi)存頁分配給Realm,在PAR內(nèi)的特定IPA處,并從NS內(nèi)存頁復(fù)制數(shù)據(jù)到它。IPA和數(shù)據(jù)經(jīng)過加密哈希,哈希包含在Realm的認證令牌中。認證令牌允許Realm的所有者推理其初始狀態(tài)和內(nèi)容。一旦Realm被激活,只能將內(nèi)存添加到其他未使用的IPA。
hypervisor可以隨時從Realm回收內(nèi)存。RMM在回收內(nèi)存頁并將其返回給hypervisor之前將此內(nèi)存頁清零。后續(xù)訪問Realm回收內(nèi)存的IPA會導(dǎo)致RMM的stage 2異常,這會阻止Realm進一步執(zhí)行并保持Arm CCA的完整性保證。
在Host Linux KVM中它可以請求map或是unmap Realm VM的stage 2映射,讓RMM管理Realm stage 2頁表,但它不能獲取修改到Realm RMM的stage 2頁表內(nèi)容。例如Host Linux KVM可以通過unmap_stage2_range來請求unmap一些stage 2映射,這個過程是:
unmap_stage2_range- >__unmap_stage2_range- >kvm_realm_unmap_range- >realm_tear_down_rtt_range,
在這里會通過RMI的RTT_DESTROY,RTT_CREAT調(diào)用(通過SMC指令)到ATF, ATF再將它dispatch到TF-RMM的smc_rtt_create,smc_rtt_create進行RMM RTT頁表操作。
中斷處理
目前沒有GIC沒有專門對Realm VM的虛擬中斷支持,因此Realm VM的中斷需要在host Linux kernel中通過其vgic中斷產(chǎn)生虛擬中斷。
由代碼可知,RMM在rec_run_loop中準備運行Realm時(參見前面Realm vCPU運行流程圖),它調(diào)用restore_realm_state
static void restore_realm_state(struct rec *rec)
{
write_cnthctl_el2(rec- >sysregs.cnthctl_el2);
isb();
restore_sysreg_state(&rec- >sysregs);
write_elr_el2(rec- >pc);
write_spsr_el2(rec- >pstate);
write_hcr_el2(rec- >sysregs.hcr_el2);
設(shè)置Realm EL2的HCR_EL2寄存器的值為
HCR_FLAGS (HCR_FWB | HCR_E2H | HCR_RW | HCR_TSC | HCR_AMO |HCR_BSU_IS | HCR_IMO | HCR_FMO | HCR_PTW | HCR_SWIO | HCR_VM | HCR_TID3 | HCR_TEA | HCR_API | HCR_APK)
這個設(shè)置中HCR_IMO, HCR_FMO讓當(dāng)運行在Realm EL0&EL1 (Realm VM)時產(chǎn)生的IRQ和FIQ會route到Realm EL2 (RMM)中處理。
RMM對于這些route到Realm EL2的處理為
el2_irq_lel:
stp x0, x1, [sp, #-16]!
mov x0, #ARM_EXCEPTION_IRQ_LEL
b realm_exit
ENDPROC(el2_sync_lel)
el2_fiq_lel:
stp x0, x1, [sp, #-16]!
mov x0, #ARM_EXCEPTION_FIQ_LEL
b realm_exit
ENDPROC(el2_sync_lel)
realm_exit使執(zhí)行回到handle_realm_exit,然后繼續(xù)退回到ATF,ATF繼續(xù)退回到Host Linux KVM, 再在host Linux kernel里進行這個物理中斷的處理,如果要產(chǎn)生一個虛擬中斷給Realm VM,host Linux kernel利用其GIC driver的vGIC產(chǎn)生一個虛擬中斷,然后通過ATF進入到RMM,RMM再回到Realm VM的執(zhí)行,這是Realm VM就能處理這個pending的虛擬中斷。
ATF的支持
ATF對CCA支持主要包括:
1. 加載RMM Image和啟動RMM
2. 負責(zé)Root,Non Secure,Secure和Realm四個secure world的切換,增加了RMM的dispatcher
3. 管理GPT頁表
Host Linux KVM可以通過alloc_delegated_page ,free_delegated_page 等函數(shù)來請求ATF改變一個物理內(nèi)存頁在GPT頁表中的PAS, 這是通過host Linux kvm調(diào)用rmi_granule_delegate, rmi_granule_undelegate也就是RMI GRANULE_UNDELEGATE ,RMI GRANULE_UNDELEGATE的RMI調(diào)用(通過SMC指令),這會進入到ATF的rmmd_rmi_handler進行處理,它將這個RMI請求forward到RMM中處理,RMM處理之后,RMM可以調(diào)用RMM_GTSI_DELEGATE或SMC_RMM_GTSI_UNDELEGATE調(diào)用(通過SMC)回到ATF,在ATF中的rmmd_rmm_el3_handler中調(diào)用gpt_delegate_pas或是gpt_undelegate_pas來修改GPT頁表,最終修改了此物理頁對應(yīng)的PAS。
不受信任的hypervisor總能停止調(diào)度一個Realm,并總是可以回收分配給Realm的內(nèi)存,但在任何情況下,它都不能訪問Realm的CPU或內(nèi)存狀態(tài)。這是通過一個簡單但功能強大delegate(分批/委托)來實現(xiàn)的。hypervisor將內(nèi)存delegate給Realm world,和回收到non secure world。所有由Realms使用的內(nèi)存首先必須由hypervisor delegate;RMM本身不管理Realm的內(nèi)存池。
一旦內(nèi)存被delegate給Realm world,hypervisor可以請求RMM將其用于各種目的,例如保存Realm的元數(shù)據(jù)或數(shù)據(jù)。當(dāng)一個內(nèi)存頁被delegate給Realm world但未被RMM使用時,RMM確保該內(nèi)存頁清零,從而降低了內(nèi)存頁被重用或回收時意外信息泄露風(fēng)險。
RMM為hypervisor提供了一個Realm管理接口(RMI),要求RMM delegate內(nèi)存、創(chuàng)建Realms、執(zhí)行Realms和為Realms分配內(nèi)存。每一個RMI命令都是作為一個SMC實現(xiàn)的,所以當(dāng)hypervisor調(diào)用該命令時,它會陷入到EL3 Monitor,然后切換執(zhí)行到Realm world的RMM來處理命令。在RMI命令完成后,RMM向EL3 Monitor發(fā)出一個SMC,將執(zhí)行切換回NS world的hypervisor。
為了維護Realms的安全保證,RMM必須知道系統(tǒng)上每個內(nèi)存頁的狀態(tài),它通過維護自己的內(nèi)存頁狀態(tài)表(GST)來實現(xiàn),以跟蹤每個內(nèi)存頁的delegate狀態(tài)和使用情況。當(dāng)hypervisor delegate一個內(nèi)存頁時,RMM檢查其GST,以確認內(nèi)存頁尚未被delegate,RMM然后向EL3 Monitor發(fā)出一個SMC請求更改Realm PAS。
EL3 Monitor檢查該內(nèi)存頁當(dāng)前是否位于NS PAS,然后更新GPT將其移至Realm PAS。最后,RMM更新其GST以記錄該內(nèi)存頁已被delegate。如果hypervisor試圖delegate已被delegate的內(nèi)存頁,或回收RMM正在使用的內(nèi)存頁,RMM會返回一個錯誤代碼給不受信任的hypervisor。與GPT不同,GST不是由硬件檢查的,而只是一個軟件記錄機制。
目前的限制
- 目前沒有GIC沒有專門對Realm VM的虛擬中斷支持,因此Realm VM的中斷需要在host Linux kernel中通過其vgic中斷產(chǎn)生虛擬中斷。未來的GIC會支持Realm虛擬中斷的注入
- 暫時沒有 Device Assignment的支持,隨著SMMU的進化和軟件的開放,后面會支持
- 目前在arm構(gòu)架上的KVM有四種不同的支持方式:armv7-a/armv8.0-a的KVM支持方式,自armv8.1-a開始支持的VHE方式,Google推的pKVM方式,Realm支持的方式。軟件構(gòu)架上需要提供更clear的實現(xiàn)。
-
寄存器
+關(guān)注
關(guān)注
31文章
5343瀏覽量
120385 -
ARM處理器
+關(guān)注
關(guān)注
6文章
360瀏覽量
41750 -
虛擬機
+關(guān)注
關(guān)注
1文章
917瀏覽量
28209 -
LINUX內(nèi)核
+關(guān)注
關(guān)注
1文章
316瀏覽量
21651 -
RTThread
+關(guān)注
關(guān)注
8文章
132瀏覽量
40878
發(fā)布評論請先 登錄
相關(guān)推薦
評論