1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Nested HVM
4  * Copyright (c) 2011, Advanced Micro Devices, Inc.
5  * Author: Christoph Egger <Christoph.Egger@amd.com>
6  */
7 
8 #ifndef _HVM_NESTEDHVM_H
9 #define _HVM_NESTEDHVM_H
10 
11 #include <xen/types.h>         /* for uintNN_t */
12 #include <xen/sched.h>         /* for struct vcpu, struct domain */
13 #include <asm/hvm/vcpu.h>      /* for vcpu_nestedhvm */
14 #include <public/hvm/params.h>
15 
16 enum nestedhvm_vmexits {
17     NESTEDHVM_VMEXIT_ERROR = 0, /* inject VMEXIT w/ invalid VMCB */
18     NESTEDHVM_VMEXIT_FATALERROR = 1, /* crash first level guest */
19     NESTEDHVM_VMEXIT_HOST = 2,  /* exit handled on host level */
20     NESTEDHVM_VMEXIT_CONTINUE = 3, /* further handling */
21     NESTEDHVM_VMEXIT_INJECT = 4, /* inject VMEXIT */
22     NESTEDHVM_VMEXIT_DONE = 5, /* VMEXIT handled */
23 };
24 
25 /* Nested HVM on/off per domain */
nestedhvm_enabled(const struct domain * d)26 static inline bool nestedhvm_enabled(const struct domain *d)
27 {
28     return IS_ENABLED(CONFIG_HVM) && (d->options & XEN_DOMCTL_CDF_nested_virt);
29 }
30 
31 /* Nested VCPU */
32 int nestedhvm_vcpu_initialise(struct vcpu *v);
33 void nestedhvm_vcpu_destroy(struct vcpu *v);
34 void nestedhvm_vcpu_reset(struct vcpu *v);
35 bool nestedhvm_vcpu_in_guestmode(struct vcpu *v);
36 #define nestedhvm_vcpu_enter_guestmode(v) \
37     vcpu_nestedhvm(v).nv_guestmode = 1
38 #define nestedhvm_vcpu_exit_guestmode(v)  \
39     vcpu_nestedhvm(v).nv_guestmode = 0
40 
41 /* Nested paging */
42 #define NESTEDHVM_PAGEFAULT_DONE       0
43 #define NESTEDHVM_PAGEFAULT_INJECT     1
44 #define NESTEDHVM_PAGEFAULT_L1_ERROR   2
45 #define NESTEDHVM_PAGEFAULT_L0_ERROR   3
46 #define NESTEDHVM_PAGEFAULT_MMIO       4
47 #define NESTEDHVM_PAGEFAULT_RETRY      5
48 #define NESTEDHVM_PAGEFAULT_DIRECT_MMIO 6
49 int nestedhvm_hap_nested_page_fault(struct vcpu *v, paddr_t *L2_gpa,
50                                     struct npfec npfec);
51 
52 /* IO permission map */
53 unsigned long *nestedhvm_vcpu_iomap_get(bool ioport_80, bool ioport_ed);
54 
55 /* Misc */
56 #define nestedhvm_paging_mode_hap(v) (!!nhvm_vmcx_hap_enabled(v))
57 #define nestedhvm_vmswitch_in_progress(v)   \
58     (!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress)
59 
60 void nestedhvm_vmcx_flushtlb(struct p2m_domain *p2m);
61 
nestedhvm_is_n2(struct vcpu * v)62 static inline bool nestedhvm_is_n2(struct vcpu *v)
63 {
64     if ( !nestedhvm_enabled(v->domain) ||
65         nestedhvm_vmswitch_in_progress(v) ||
66         !nestedhvm_paging_mode_hap(v) )
67         return false;
68 
69     return nestedhvm_vcpu_in_guestmode(v);
70 }
71 
nestedhvm_set_cr(struct vcpu * v,unsigned int cr,unsigned long value)72 static inline void nestedhvm_set_cr(struct vcpu *v, unsigned int cr,
73                                     unsigned long value)
74 {
75     if ( !nestedhvm_vmswitch_in_progress(v) &&
76          nestedhvm_vcpu_in_guestmode(v) )
77         v->arch.hvm.nvcpu.guest_cr[cr] = value;
78 }
79 
vvmcx_valid(const struct vcpu * v)80 static inline bool vvmcx_valid(const struct vcpu *v)
81 {
82     return vcpu_nestedhvm(v).nv_vvmcxaddr != INVALID_PADDR;
83 }
84 
85 
86 void start_nested_svm(struct hvm_function_table *hvm_function_table);
87 void start_nested_vmx(struct hvm_function_table *hvm_function_table);
88 
89 #endif /* _HVM_NESTEDHVM_H */
90