1 /******************************************************************************
2 * arch/x86/mm/mm-locks.h
3 *
4 * Spinlocks used by the code in arch/x86/mm.
5 *
6 * Copyright (c) 2011 Citrix Systems, inc.
7 * Copyright (c) 2007 Advanced Micro Devices (Wei Huang)
8 * Copyright (c) 2006-2007 XenSource Inc.
9 * Copyright (c) 2006 Michael A Fetterman
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #ifndef _MM_LOCKS_H
26 #define _MM_LOCKS_H
27
28 #include <asm/mem_sharing.h>
29
30 /* Per-CPU variable for enforcing the lock ordering */
31 DECLARE_PER_CPU(int, mm_lock_level);
32
33 DECLARE_PERCPU_RWLOCK_GLOBAL(p2m_percpu_rwlock);
34
mm_lock_init(mm_lock_t * l)35 static inline void mm_lock_init(mm_lock_t *l)
36 {
37 spin_lock_init(&l->lock);
38 l->locker = -1;
39 l->locker_function = "nobody";
40 l->unlock_level = 0;
41 }
42
mm_locked_by_me(mm_lock_t * l)43 static inline int mm_locked_by_me(mm_lock_t *l)
44 {
45 return (l->lock.recurse_cpu == current->processor);
46 }
47
_get_lock_level(void)48 static inline int _get_lock_level(void)
49 {
50 return this_cpu(mm_lock_level);
51 }
52
53 #define MM_LOCK_ORDER_MAX 64
54 /*
55 * Return the lock level taking the domain bias into account. If the domain is
56 * privileged a bias of MM_LOCK_ORDER_MAX is applied to the lock level, so that
57 * mm locks that belong to a control domain can be acquired after having
58 * acquired mm locks of an unprivileged domain.
59 *
60 * This is required in order to use some hypercalls from a paging domain that
61 * take locks of a subject domain and then attempt to copy data to/from the
62 * caller domain.
63 */
_lock_level(const struct domain * d,int l)64 static inline int _lock_level(const struct domain *d, int l)
65 {
66 ASSERT(l <= MM_LOCK_ORDER_MAX);
67
68 return l + (d && is_control_domain(d) ? MM_LOCK_ORDER_MAX : 0);
69 }
70
71 /*
72 * If you see this crash, the numbers printed are order levels defined
73 * in this file.
74 */
_check_lock_level(const struct domain * d,int l)75 static inline void _check_lock_level(const struct domain *d, int l)
76 {
77 int lvl = _lock_level(d, l);
78
79 if ( unlikely(_get_lock_level() > lvl) )
80 {
81 printk("mm locking order violation: %i > %i\n", _get_lock_level(), lvl);
82 BUG();
83 }
84 }
85
_set_lock_level(int l)86 static inline void _set_lock_level(int l)
87 {
88 this_cpu(mm_lock_level) = l;
89 }
90
_mm_lock(const struct domain * d,mm_lock_t * l,const char * func,int level,int rec)91 static inline void _mm_lock(const struct domain *d, mm_lock_t *l,
92 const char *func, int level, int rec)
93 {
94 if ( !((mm_locked_by_me(l)) && rec) )
95 _check_lock_level(d, level);
96 spin_lock_recursive(&l->lock);
97 if ( l->lock.recurse_cnt == 1 )
98 {
99 l->locker_function = func;
100 l->unlock_level = _get_lock_level();
101 }
102 else if ( (unlikely(!rec)) )
103 panic("mm lock already held by %s\n", l->locker_function);
104 _set_lock_level(_lock_level(d, level));
105 }
106
_mm_enforce_order_lock_pre(const struct domain * d,int level)107 static inline void _mm_enforce_order_lock_pre(const struct domain *d, int level)
108 {
109 _check_lock_level(d, level);
110 }
111
_mm_enforce_order_lock_post(const struct domain * d,int level,int * unlock_level,unsigned short * recurse_count)112 static inline void _mm_enforce_order_lock_post(const struct domain *d, int level,
113 int *unlock_level,
114 unsigned short *recurse_count)
115 {
116 if ( recurse_count )
117 {
118 if ( (*recurse_count)++ == 0 )
119 {
120 *unlock_level = _get_lock_level();
121 }
122 } else {
123 *unlock_level = _get_lock_level();
124 }
125 _set_lock_level(_lock_level(d, level));
126 }
127
128
mm_rwlock_init(mm_rwlock_t * l)129 static inline void mm_rwlock_init(mm_rwlock_t *l)
130 {
131 percpu_rwlock_resource_init(&l->lock, p2m_percpu_rwlock);
132 l->locker = -1;
133 l->locker_function = "nobody";
134 l->unlock_level = 0;
135 }
136
mm_write_locked_by_me(mm_rwlock_t * l)137 static inline int mm_write_locked_by_me(mm_rwlock_t *l)
138 {
139 return (l->locker == get_processor_id());
140 }
141
_mm_write_lock(const struct domain * d,mm_rwlock_t * l,const char * func,int level)142 static inline void _mm_write_lock(const struct domain *d, mm_rwlock_t *l,
143 const char *func, int level)
144 {
145 if ( !mm_write_locked_by_me(l) )
146 {
147 _check_lock_level(d, level);
148 percpu_write_lock(p2m_percpu_rwlock, &l->lock);
149 l->locker = get_processor_id();
150 l->locker_function = func;
151 l->unlock_level = _get_lock_level();
152 _set_lock_level(_lock_level(d, level));
153 }
154 l->recurse_count++;
155 }
156
mm_write_unlock(mm_rwlock_t * l)157 static inline void mm_write_unlock(mm_rwlock_t *l)
158 {
159 if ( --(l->recurse_count) != 0 )
160 return;
161 l->locker = -1;
162 l->locker_function = "nobody";
163 _set_lock_level(l->unlock_level);
164 percpu_write_unlock(p2m_percpu_rwlock, &l->lock);
165 }
166
_mm_read_lock(const struct domain * d,mm_rwlock_t * l,int level)167 static inline void _mm_read_lock(const struct domain *d, mm_rwlock_t *l,
168 int level)
169 {
170 _check_lock_level(d, level);
171 percpu_read_lock(p2m_percpu_rwlock, &l->lock);
172 /* There's nowhere to store the per-CPU unlock level so we can't
173 * set the lock level. */
174 }
175
mm_read_unlock(mm_rwlock_t * l)176 static inline void mm_read_unlock(mm_rwlock_t *l)
177 {
178 percpu_read_unlock(p2m_percpu_rwlock, &l->lock);
179 }
180
181 /* This wrapper uses the line number to express the locking order below */
182 #define declare_mm_lock(name) \
183 static inline void mm_lock_##name(const struct domain *d, mm_lock_t *l, \
184 const char *func, int rec) \
185 { _mm_lock(d, l, func, MM_LOCK_ORDER_##name, rec); }
186 #define declare_mm_rwlock(name) \
187 static inline void mm_write_lock_##name(const struct domain *d, \
188 mm_rwlock_t *l, const char *func) \
189 { _mm_write_lock(d, l, func, MM_LOCK_ORDER_##name); } \
190 static inline void mm_read_lock_##name(const struct domain *d, \
191 mm_rwlock_t *l) \
192 { _mm_read_lock(d, l, MM_LOCK_ORDER_##name); }
193 /* These capture the name of the calling function */
194 #define mm_lock(name, d, l) mm_lock_##name(d, l, __func__, 0)
195 #define mm_lock_recursive(name, d, l) mm_lock_##name(d, l, __func__, 1)
196 #define mm_write_lock(name, d, l) mm_write_lock_##name(d, l, __func__)
197 #define mm_read_lock(name, d, l) mm_read_lock_##name(d, l)
198
199 /* This wrapper is intended for "external" locks which do not use
200 * the mm_lock_t types. Such locks inside the mm code are also subject
201 * to ordering constraints. */
202 #define declare_mm_order_constraint(name) \
203 static inline void mm_enforce_order_lock_pre_##name(const struct domain *d) \
204 { _mm_enforce_order_lock_pre(d, MM_LOCK_ORDER_##name); } \
205 static inline void mm_enforce_order_lock_post_##name(const struct domain *d,\
206 int *unlock_level, unsigned short *recurse_count) \
207 { _mm_enforce_order_lock_post(d, MM_LOCK_ORDER_##name, unlock_level, \
208 recurse_count); }
209
mm_unlock(mm_lock_t * l)210 static inline void mm_unlock(mm_lock_t *l)
211 {
212 if ( l->lock.recurse_cnt == 1 )
213 {
214 l->locker_function = "nobody";
215 _set_lock_level(l->unlock_level);
216 }
217 spin_unlock_recursive(&l->lock);
218 }
219
mm_enforce_order_unlock(int unlock_level,unsigned short * recurse_count)220 static inline void mm_enforce_order_unlock(int unlock_level,
221 unsigned short *recurse_count)
222 {
223 if ( recurse_count )
224 {
225 BUG_ON(*recurse_count == 0);
226 if ( (*recurse_count)-- == 1 )
227 {
228 _set_lock_level(unlock_level);
229 }
230 } else {
231 _set_lock_level(unlock_level);
232 }
233 }
234
235 /************************************************************************
236 * *
237 * To avoid deadlocks, these locks _MUST_ be taken in the order listed *
238 * below. The locking functions will enforce this. *
239 * *
240 ************************************************************************/
241
242 /* Nested P2M lock (per-domain)
243 *
244 * A per-domain lock that protects the mapping from nested-CR3 to
245 * nested-p2m. In particular it covers:
246 * - the array of nested-p2m tables, and all LRU activity therein; and
247 * - setting the "cr3" field of any p2m table to a non-P2M_BASE_EAADR value.
248 * (i.e. assigning a p2m table to be the shadow of that cr3 */
249
250 #define MM_LOCK_ORDER_nestedp2m 8
251 declare_mm_lock(nestedp2m)
252 #define nestedp2m_lock(d) mm_lock(nestedp2m, d, &(d)->arch.nested_p2m_lock)
253 #define nestedp2m_unlock(d) mm_unlock(&(d)->arch.nested_p2m_lock)
254
255 /* P2M lock (per-non-alt-p2m-table)
256 *
257 * This protects all queries and updates to the p2m table.
258 * Queries may be made under the read lock but all modifications
259 * need the main (write) lock.
260 *
261 * The write lock is recursive as it is common for a code path to look
262 * up a gfn and later mutate it.
263 *
264 * Note that this lock shares its implementation with the altp2m
265 * lock (not the altp2m list lock), so the implementation
266 * is found there.
267 *
268 * Changes made to the host p2m when in altp2m mode are propagated to the
269 * altp2ms synchronously in ept_set_entry(). At that point, we will hold
270 * the host p2m lock; propagating this change involves grabbing the
271 * altp2m_list lock, and the locks of the individual alternate p2ms. In
272 * order to allow us to maintain locking order discipline, we split the p2m
273 * lock into p2m (for host p2ms) and altp2m (for alternate p2ms), putting
274 * the altp2mlist lock in the middle.
275 */
276
277 #define MM_LOCK_ORDER_p2m 16
278 declare_mm_rwlock(p2m);
279
280 /* Sharing per page lock
281 *
282 * This is an external lock, not represented by an mm_lock_t. The memory
283 * sharing lock uses it to protect addition and removal of (gfn,domain)
284 * tuples to a shared page. We enforce order here against the p2m lock,
285 * which is taken after the page_lock to change the gfn's p2m entry.
286 *
287 * The lock is recursive because during share we lock two pages. */
288
289 #define MM_LOCK_ORDER_per_page_sharing 24
290 declare_mm_order_constraint(per_page_sharing)
291 #define page_sharing_mm_pre_lock() \
292 mm_enforce_order_lock_pre_per_page_sharing(NULL)
293 #define page_sharing_mm_post_lock(l, r) \
294 mm_enforce_order_lock_post_per_page_sharing(NULL, (l), (r))
295 #define page_sharing_mm_unlock(l, r) mm_enforce_order_unlock((l), (r))
296
297 /* Alternate P2M list lock (per-domain)
298 *
299 * A per-domain lock that protects the list of alternate p2m's.
300 * Any operation that walks the list needs to acquire this lock.
301 * Additionally, before destroying an alternate p2m all VCPU's
302 * in the target domain must be paused.
303 */
304
305 #define MM_LOCK_ORDER_altp2mlist 32
306 declare_mm_lock(altp2mlist)
307 #define altp2m_list_lock(d) mm_lock(altp2mlist, d, \
308 &(d)->arch.altp2m_list_lock)
309 #define altp2m_list_unlock(d) mm_unlock(&(d)->arch.altp2m_list_lock)
310
311 /* P2M lock (per-altp2m-table)
312 *
313 * This protects all queries and updates to the p2m table.
314 * Queries may be made under the read lock but all modifications
315 * need the main (write) lock.
316 *
317 * The write lock is recursive as it is common for a code path to look
318 * up a gfn and later mutate it.
319 */
320
321 #define MM_LOCK_ORDER_altp2m 40
322 declare_mm_rwlock(altp2m);
323
p2m_lock(struct p2m_domain * p)324 static inline void p2m_lock(struct p2m_domain *p)
325 {
326 if ( p2m_is_altp2m(p) )
327 mm_write_lock(altp2m, p->domain, &p->lock);
328 else
329 mm_write_lock(p2m, p->domain, &p->lock);
330 p->defer_flush++;
331 }
332
p2m_unlock(struct p2m_domain * p)333 static inline void p2m_unlock(struct p2m_domain *p)
334 {
335 if ( --p->defer_flush == 0 )
336 p2m_unlock_and_tlb_flush(p);
337 else
338 mm_write_unlock(&p->lock);
339 }
340
341 #define gfn_lock(p,g,o) p2m_lock(p)
342 #define gfn_unlock(p,g,o) p2m_unlock(p)
343 #define p2m_read_lock(p) mm_read_lock(p2m, (p)->domain, &(p)->lock)
344 #define p2m_read_unlock(p) mm_read_unlock(&(p)->lock)
345 #define p2m_locked_by_me(p) mm_write_locked_by_me(&(p)->lock)
346 #define gfn_locked_by_me(p,g) p2m_locked_by_me(p)
347
348 /* PoD lock (per-p2m-table)
349 *
350 * Protects private PoD data structs: entry and cache
351 * counts, page lists, sweep parameters. */
352
353 #define MM_LOCK_ORDER_pod 48
354 declare_mm_lock(pod)
355 #define pod_lock(p) mm_lock(pod, (p)->domain, &(p)->pod.lock)
356 #define pod_unlock(p) mm_unlock(&(p)->pod.lock)
357 #define pod_locked_by_me(p) mm_locked_by_me(&(p)->pod.lock)
358
359 /* Page alloc lock (per-domain)
360 *
361 * This is an external lock, not represented by an mm_lock_t. However,
362 * pod code uses it in conjunction with the p2m lock, and expecting
363 * the ordering which we enforce here.
364 * The lock is not recursive. */
365
366 #define MM_LOCK_ORDER_page_alloc 56
367 declare_mm_order_constraint(page_alloc)
368 #define page_alloc_mm_pre_lock(d) mm_enforce_order_lock_pre_page_alloc(d)
369 #define page_alloc_mm_post_lock(d, l) \
370 mm_enforce_order_lock_post_page_alloc(d, &(l), NULL)
371 #define page_alloc_mm_unlock(l) mm_enforce_order_unlock((l), NULL)
372
373 /* Paging lock (per-domain)
374 *
375 * For shadow pagetables, this lock protects
376 * - all changes to shadow page table pages
377 * - the shadow hash table
378 * - the shadow page allocator
379 * - all changes to guest page table pages
380 * - all changes to the page_info->tlbflush_timestamp
381 * - the page_info->count fields on shadow pages
382 *
383 * For HAP, it protects the NPT/EPT tables and mode changes.
384 *
385 * It also protects the log-dirty bitmap from concurrent accesses (and
386 * teardowns, etc). */
387
388 #define MM_LOCK_ORDER_paging 64
389 declare_mm_lock(paging)
390 #define paging_lock(d) mm_lock(paging, d, &(d)->arch.paging.lock)
391 #define paging_lock_recursive(d) \
392 mm_lock_recursive(paging, d, &(d)->arch.paging.lock)
393 #define paging_unlock(d) mm_unlock(&(d)->arch.paging.lock)
394 #define paging_locked_by_me(d) mm_locked_by_me(&(d)->arch.paging.lock)
395
396 #endif /* _MM_LOCKS_H */
397