Post

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.