1 /*
2 * Alternate p2m HVM
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <asm/hvm/support.h>
19 #include <asm/hvm/hvm.h>
20 #include <asm/p2m.h>
21 #include <asm/altp2m.h>
22
23 void
altp2m_vcpu_initialise(struct vcpu * v)24 altp2m_vcpu_initialise(struct vcpu *v)
25 {
26 if ( v != current )
27 vcpu_pause(v);
28
29 vcpu_altp2m(v).p2midx = 0;
30 atomic_inc(&p2m_get_altp2m(v)->active_vcpus);
31
32 altp2m_vcpu_update_p2m(v);
33
34 if ( v != current )
35 vcpu_unpause(v);
36 }
37
38 void
altp2m_vcpu_destroy(struct vcpu * v)39 altp2m_vcpu_destroy(struct vcpu *v)
40 {
41 struct p2m_domain *p2m;
42
43 if ( v != current )
44 vcpu_pause(v);
45
46 if ( (p2m = p2m_get_altp2m(v)) )
47 atomic_dec(&p2m->active_vcpus);
48
49 altp2m_vcpu_disable_ve(v);
50
51 vcpu_altp2m(v).p2midx = INVALID_ALTP2M;
52 altp2m_vcpu_update_p2m(v);
53
54 if ( v != current )
55 vcpu_unpause(v);
56 }
57
altp2m_vcpu_enable_ve(struct vcpu * v,gfn_t gfn)58 int altp2m_vcpu_enable_ve(struct vcpu *v, gfn_t gfn)
59 {
60 struct domain *d = v->domain;
61 struct altp2mvcpu *a = &vcpu_altp2m(v);
62 p2m_type_t p2mt;
63 struct page_info *pg;
64 int rc;
65
66 /* Early exit path if #VE is already configured. */
67 if ( a->veinfo_pg )
68 return -EEXIST;
69
70 rc = check_get_page_from_gfn(d, gfn, false, &p2mt, &pg);
71 if ( rc )
72 return rc;
73
74 /*
75 * Looking for a plain piece of guest writeable RAM with isn't a magic
76 * frame such as a grant/ioreq/shared_info/etc mapping. We (ab)use the
77 * pageable() predicate for this, due to it having the same properties
78 * that we want.
79 */
80 if ( !p2m_is_pageable(p2mt) || is_special_page(pg) )
81 {
82 rc = -EINVAL;
83 goto err;
84 }
85
86 /*
87 * Update veinfo_pg, making sure to be safe with concurrent hypercalls.
88 * The first caller to make veinfo_pg become non-NULL will program its MFN
89 * into the VMCS, so must not be clobbered. Callers which lose the race
90 * back off with -EEXIST.
91 */
92 if ( cmpxchg(&a->veinfo_pg, NULL, pg) != NULL )
93 {
94 rc = -EEXIST;
95 goto err;
96 }
97
98 altp2m_vcpu_update_vmfunc_ve(v);
99
100 return 0;
101
102 err:
103 put_page(pg);
104
105 return rc;
106 }
107
altp2m_vcpu_disable_ve(struct vcpu * v)108 void altp2m_vcpu_disable_ve(struct vcpu *v)
109 {
110 struct altp2mvcpu *a = &vcpu_altp2m(v);
111 struct page_info *pg;
112
113 /*
114 * Update veinfo_pg, making sure to be safe with concurrent hypercalls.
115 * The winner of this race is responsible to update the VMCS to no longer
116 * point at the page, then drop the associated ref.
117 */
118 if ( (pg = xchg(&a->veinfo_pg, NULL)) )
119 {
120 altp2m_vcpu_update_vmfunc_ve(v);
121
122 put_page(pg);
123 }
124 }
125
126 /*
127 * Local variables:
128 * mode: C
129 * c-file-style: "BSD"
130 * c-basic-offset: 4
131 * tab-width: 4
132 * indent-tabs-mode: nil
133 * End:
134 */
135