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