1 #ifndef __PV_MM_H__
2 #define __PV_MM_H__
3
4 l1_pgentry_t *map_guest_l1e(unsigned long linear, mfn_t *gl1mfn);
5
6 int new_guest_cr3(mfn_t mfn);
7
8 /* Read a PV guest's l1e that maps this linear address. */
guest_get_eff_l1e(unsigned long linear)9 static inline l1_pgentry_t guest_get_eff_l1e(unsigned long linear)
10 {
11 l1_pgentry_t l1e;
12
13 ASSERT(!paging_mode_translate(current->domain));
14 ASSERT(!paging_mode_external(current->domain));
15
16 if ( unlikely(!__addr_ok(linear)) ||
17 __copy_from_user(&l1e,
18 &__linear_l1_table[l1_linear_offset(linear)],
19 sizeof(l1_pgentry_t)) )
20 l1e = l1e_empty();
21
22 return l1e;
23 }
24
25 /*
26 * PTE updates can be done with ordinary writes except:
27 * 1. Debug builds get extra checking by using CMPXCHG[8B].
28 */
29 #ifndef NDEBUG
30 #define PTE_UPDATE_WITH_CMPXCHG
31 #else
32 #undef PTE_UPDATE_WITH_CMPXCHG
33 #endif
34
35 /*
36 * How to write an entry to the guest pagetables.
37 * Returns false for failure (pointer not valid), true for success.
38 */
update_intpte(intpte_t * p,intpte_t old,intpte_t new,unsigned long mfn,struct vcpu * v,bool preserve_ad)39 static inline bool update_intpte(intpte_t *p, intpte_t old, intpte_t new,
40 unsigned long mfn, struct vcpu *v,
41 bool preserve_ad)
42 {
43 bool rv = true;
44
45 #ifndef PTE_UPDATE_WITH_CMPXCHG
46 if ( !preserve_ad )
47 {
48 rv = paging_write_guest_entry(v, p, new, _mfn(mfn));
49 }
50 else
51 #endif
52 {
53 intpte_t t = old;
54
55 for ( ; ; )
56 {
57 intpte_t _new = new;
58
59 if ( preserve_ad )
60 _new |= old & (_PAGE_ACCESSED | _PAGE_DIRTY);
61
62 rv = paging_cmpxchg_guest_entry(v, p, &t, _new, _mfn(mfn));
63 if ( unlikely(rv == 0) )
64 {
65 gdprintk(XENLOG_WARNING,
66 "Failed to update %" PRIpte " -> %" PRIpte
67 ": saw %" PRIpte "\n", old, _new, t);
68 break;
69 }
70
71 if ( t == old )
72 break;
73
74 /* Allowed to change in Accessed/Dirty flags only. */
75 BUG_ON((t ^ old) & ~(intpte_t)(_PAGE_ACCESSED|_PAGE_DIRTY));
76
77 old = t;
78 }
79 }
80 return rv;
81 }
82
83 /*
84 * Macro that wraps the appropriate type-changes around update_intpte().
85 * Arguments are: type, ptr, old, new, mfn, vcpu
86 */
87 #define UPDATE_ENTRY(_t,_p,_o,_n,_m,_v,_ad) \
88 update_intpte(&_t ## e_get_intpte(*(_p)), \
89 _t ## e_get_intpte(_o), _t ## e_get_intpte(_n), \
90 (_m), (_v), (_ad))
91
adjust_guest_l1e(l1_pgentry_t l1e,const struct domain * d)92 static inline l1_pgentry_t adjust_guest_l1e(l1_pgentry_t l1e,
93 const struct domain *d)
94 {
95 if ( likely(l1e_get_flags(l1e) & _PAGE_PRESENT) &&
96 likely(!is_pv_32bit_domain(d)) )
97 {
98 /* _PAGE_GUEST_KERNEL page cannot have the Global bit set. */
99 if ( (l1e_get_flags(l1e) & (_PAGE_GUEST_KERNEL | _PAGE_GLOBAL)) ==
100 (_PAGE_GUEST_KERNEL | _PAGE_GLOBAL) )
101 gdprintk(XENLOG_WARNING, "Global bit is set in kernel page %lx\n",
102 l1e_get_pfn(l1e));
103
104 if ( !(l1e_get_flags(l1e) & _PAGE_USER) )
105 l1e_add_flags(l1e, (_PAGE_GUEST_KERNEL | _PAGE_USER));
106
107 if ( !(l1e_get_flags(l1e) & _PAGE_GUEST_KERNEL) )
108 l1e_add_flags(l1e, (_PAGE_GLOBAL | _PAGE_USER));
109 }
110
111 return l1e;
112 }
113
adjust_guest_l2e(l2_pgentry_t l2e,const struct domain * d)114 static inline l2_pgentry_t adjust_guest_l2e(l2_pgentry_t l2e,
115 const struct domain *d)
116 {
117 if ( likely(l2e_get_flags(l2e) & _PAGE_PRESENT) &&
118 likely(!is_pv_32bit_domain(d)) )
119 l2e_add_flags(l2e, _PAGE_USER);
120
121 return l2e;
122 }
123
adjust_guest_l3e(l3_pgentry_t l3e,const struct domain * d)124 static inline l3_pgentry_t adjust_guest_l3e(l3_pgentry_t l3e,
125 const struct domain *d)
126 {
127 if ( likely(l3e_get_flags(l3e) & _PAGE_PRESENT) )
128 l3e_add_flags(l3e, (likely(!is_pv_32bit_domain(d))
129 ? _PAGE_USER : _PAGE_USER | _PAGE_RW));
130
131 return l3e;
132 }
133
unadjust_guest_l3e(l3_pgentry_t l3e,const struct domain * d)134 static inline l3_pgentry_t unadjust_guest_l3e(l3_pgentry_t l3e,
135 const struct domain *d)
136 {
137 if ( unlikely(is_pv_32bit_domain(d)) &&
138 likely(l3e_get_flags(l3e) & _PAGE_PRESENT) )
139 l3e_remove_flags(l3e, _PAGE_USER | _PAGE_RW | _PAGE_ACCESSED);
140
141 return l3e;
142 }
143
adjust_guest_l4e(l4_pgentry_t l4e,const struct domain * d)144 static inline l4_pgentry_t adjust_guest_l4e(l4_pgentry_t l4e,
145 const struct domain *d)
146 {
147 if ( likely(l4e_get_flags(l4e) & _PAGE_PRESENT) &&
148 likely(!is_pv_32bit_domain(d)) )
149 l4e_add_flags(l4e, _PAGE_USER);
150
151 return l4e;
152 }
153
154 #endif /* __PV_MM_H__ */
155