sev-snp
调用栈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
snp_set_memory_private
set_memory_encrypted
=> __set_memory_enc_dec(addr, numpages, true)
=> __set_memory_enc_pgtable
=> cpa_flush()
=> x86_platform.guest.enc_status_change_prepare
(amd_enc_status_change_prepare)
=> if (!enc)
=> snp_set_memory_shared
=> set_pages_state
=> __set_pages_state
## 修改页表c-bit
=> ret = __change_page_attr_set_clr(&cpa, 1);
=> cpa_flush(&cpa, 0);
=> x86_platform.guest.enc_status_change_finish(addr, numpages, enc);
=> if (enc)
=> snp_set_memory_private(vaddr, npages);
=> set_pages_state(vaddr, npages, SNP_PAGE_STATE_PRIVATE)
=> enc_dec_hypercall(vaddr, npages << PAGE_SHIFT, enc)
set_memory_decrypted
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
set_memory_decrypted
=> __set_memory_enc_dec(addr, numpages, false)
__set_pages_state
=> if op == SNP_PAGE_STATE_SHARED:
## set rmp validate_pages => 0
## 这个地方必须重新做验证。否则这个page可以会被host利用。
=> pvalidate_pages()
## 只考虑sev_cfg.ghcbs_inititalized 情况
=> ghcb = __sev_get_ghcb(&state);
=> vmgexit_psc(ghcb, data) ## data: desc
=> memcpy(ghcb->shared_buffer, desc, min_t(int, GHCB_SHARED_BUF_SIZE, sizeof(*desc)));
=> foreach_entry
=> sev_es_ghcb_hv_call(ghcb, &ctxt, SVM_VMGEXIT_PSC, 0, 0)
## 初始化exit_code 和 exit_info
=> ghcb_set_sw_exit_code(ghcb, exit_code)
=> ghcb_set_sw_exit_info_1(ghcb, exit_info_1)
=> ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
## 设置ghcb pa 到msr
=> sev_es_wr_ghcb_msr(__pa(ghcb))
=> native_wrmsr(MSR_AMD64_SEV_ES_GHCB, low, high);
=> VMGEXIT()
### ???? 实际上是VMGEXIT指令 rep + vmmcall 编码
=> asm volatile("rep; vmmcall\n\r")
=> __set_put_ghcb(&state)
=> if op == SNP_PAGE_STATE_PRIVATE:
## 如果是要变为private, 需要对新映射的page,重新做验证
=> pvalidate_pages()
enc_dec_hypercall
1
2
3
4
5
6
7
enc_dec_hypercall
=> foreach pfn (may be huge)
=> notify_page_enc_status_changed
=> kvm_sev_hc_page_enc_status
=> kvm_sev_hypercall3(KVM_HC_MAP_GPA_RANGE, pfn << PAGE_SHIFT, npages,
KVM_MAP_GPA_RANGE_ENC_STAT(enc) | KVM_MAP_GPA_RANGE_PAGE_SZ_4K)
=> vmmcall
sev_handle_vmgexit(kvm)
1
2
3
4
5
6
7
8
sev_handle_vmgexit
=> case SVM_VMGEXIT_PSC:
=> setup_vmgexit_scratch()
=> snp_begin_psc()
=> switch(entry_state.operation)
=> case VMGEXIT_PSC_OP_PRIVATE, VMGEXIT_PSC_OP_SHARED
=> vcpu->run->exit_reason = KVM_EXIT_HYPERCALL;
=> vcpu->run->hypercall.nr = KVM_HC_MAP_GPA_RANGE;
参考commit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[PATCH 0/4] x86: Cleanup and extend computing computing API
https://lore.kernel.org/all/20220222185740.26228-1-kirill.shutemov@linux.intel.com/
Add AMD Secure Nested Paging (SEV-SNP) Guest Support
https://lore.kernel.org/all/20220307213356.2797205-1-brijesh.singh@amd.com/
commit dc3f3d2474b80eaee8be89f4c5eb344f10648f42
Author: Brijesh Singh <brijesh.singh@amd.com>
Date: Thu Feb 24 10:56:01 2022 -0600
x86/mm: Validate memory when changing the C-bit
Add the needed functionality to change pages state from shared
to private and vice-versa using the Page State Change VMGEXIT as
documented in the GHCB spec.
This post is licensed under CC BY 4.0 by the author.