1 /*
2  * Nested HVM
3  * Copyright (c) 2011, Advanced Micro Devices, Inc.
4  * Author: Christoph Egger <Christoph.Egger@amd.com>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef _HVM_NESTEDHVM_H
20 #define _HVM_NESTEDHVM_H
21 
22 #include <xen/types.h>         /* for uintNN_t */
23 #include <xen/sched.h>         /* for struct vcpu, struct domain */
24 #include <asm/hvm/vcpu.h>      /* for vcpu_nestedhvm */
25 #include <public/hvm/params.h>
26 
27 enum nestedhvm_vmexits {
28     NESTEDHVM_VMEXIT_ERROR = 0, /* inject VMEXIT w/ invalid VMCB */
29     NESTEDHVM_VMEXIT_FATALERROR = 1, /* crash first level guest */
30     NESTEDHVM_VMEXIT_HOST = 2,  /* exit handled on host level */
31     NESTEDHVM_VMEXIT_CONTINUE = 3, /* further handling */
32     NESTEDHVM_VMEXIT_INJECT = 4, /* inject VMEXIT */
33     NESTEDHVM_VMEXIT_DONE = 5, /* VMEXIT handled */
34 };
35 
36 /* Nested HVM on/off per domain */
nestedhvm_enabled(const struct domain * d)37 static always_inline bool nestedhvm_enabled(const struct domain *d)
38 {
39     return is_hvm_domain(d) && d->arch.hvm.params &&
40         d->arch.hvm.params[HVM_PARAM_NESTEDHVM];
41 }
42 
43 /* Nested VCPU */
44 int nestedhvm_vcpu_initialise(struct vcpu *v);
45 void nestedhvm_vcpu_destroy(struct vcpu *v);
46 void nestedhvm_vcpu_reset(struct vcpu *v);
47 bool_t nestedhvm_vcpu_in_guestmode(struct vcpu *v);
48 #define nestedhvm_vcpu_enter_guestmode(v) \
49     vcpu_nestedhvm(v).nv_guestmode = 1
50 #define nestedhvm_vcpu_exit_guestmode(v)  \
51     vcpu_nestedhvm(v).nv_guestmode = 0
52 
53 /* Nested paging */
54 #define NESTEDHVM_PAGEFAULT_DONE       0
55 #define NESTEDHVM_PAGEFAULT_INJECT     1
56 #define NESTEDHVM_PAGEFAULT_L1_ERROR   2
57 #define NESTEDHVM_PAGEFAULT_L0_ERROR   3
58 #define NESTEDHVM_PAGEFAULT_MMIO       4
59 #define NESTEDHVM_PAGEFAULT_RETRY      5
60 #define NESTEDHVM_PAGEFAULT_DIRECT_MMIO 6
61 int nestedhvm_hap_nested_page_fault(struct vcpu *v, paddr_t *L2_gpa,
62     bool_t access_r, bool_t access_w, bool_t access_x);
63 
64 int nestedhap_walk_L1_p2m(struct vcpu *v, paddr_t L2_gpa, paddr_t *L1_gpa,
65                           unsigned int *page_order, uint8_t *p2m_acc,
66                           bool_t access_r, bool_t access_w, bool_t access_x);
67 
68 /* IO permission map */
69 unsigned long *nestedhvm_vcpu_iomap_get(bool_t ioport_80, bool_t ioport_ed);
70 
71 /* Misc */
72 #define nestedhvm_paging_mode_hap(v) (!!nhvm_vmcx_hap_enabled(v))
73 #define nestedhvm_vmswitch_in_progress(v)   \
74     (!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress)
75 
76 void nestedhvm_vmcx_flushtlb(struct p2m_domain *p2m);
77 
nestedhvm_is_n2(struct vcpu * v)78 static inline bool nestedhvm_is_n2(struct vcpu *v)
79 {
80     if ( !nestedhvm_enabled(v->domain) ||
81         nestedhvm_vmswitch_in_progress(v) ||
82         !nestedhvm_paging_mode_hap(v) )
83         return false;
84 
85     return nestedhvm_vcpu_in_guestmode(v);
86 }
87 
nestedhvm_set_cr(struct vcpu * v,unsigned int cr,unsigned long value)88 static inline void nestedhvm_set_cr(struct vcpu *v, unsigned int cr,
89                                     unsigned long value)
90 {
91     if ( !nestedhvm_vmswitch_in_progress(v) &&
92          nestedhvm_vcpu_in_guestmode(v) )
93         v->arch.hvm.nvcpu.guest_cr[cr] = value;
94 }
95 
vvmcx_valid(const struct vcpu * v)96 static inline bool vvmcx_valid(const struct vcpu *v)
97 {
98     return vcpu_nestedhvm(v).nv_vvmcxaddr != INVALID_PADDR;
99 }
100 
101 #endif /* _HVM_NESTEDHVM_H */
102