@@ -131,9 +131,97 @@ static inline pud_t native_pudp_get_and_clear(pud_t *xp)
131
131
#endif
132
132
}
133
133
134
+ #ifdef CONFIG_PAGE_TABLE_ISOLATION
135
+ /*
136
+ * All top-level PAGE_TABLE_ISOLATION page tables are order-1 pages
137
+ * (8k-aligned and 8k in size). The kernel one is at the beginning 4k and
138
+ * the user one is in the last 4k. To switch between them, you
139
+ * just need to flip the 12th bit in their addresses.
140
+ */
141
+ #define PTI_PGTABLE_SWITCH_BIT PAGE_SHIFT
142
+
143
+ /*
144
+ * This generates better code than the inline assembly in
145
+ * __set_bit().
146
+ */
147
+ static inline void * ptr_set_bit (void * ptr , int bit )
148
+ {
149
+ unsigned long __ptr = (unsigned long )ptr ;
150
+
151
+ __ptr |= BIT (bit );
152
+ return (void * )__ptr ;
153
+ }
154
+ static inline void * ptr_clear_bit (void * ptr , int bit )
155
+ {
156
+ unsigned long __ptr = (unsigned long )ptr ;
157
+
158
+ __ptr &= ~BIT (bit );
159
+ return (void * )__ptr ;
160
+ }
161
+
162
+ static inline pgd_t * kernel_to_user_pgdp (pgd_t * pgdp )
163
+ {
164
+ return ptr_set_bit (pgdp , PTI_PGTABLE_SWITCH_BIT );
165
+ }
166
+
167
+ static inline pgd_t * user_to_kernel_pgdp (pgd_t * pgdp )
168
+ {
169
+ return ptr_clear_bit (pgdp , PTI_PGTABLE_SWITCH_BIT );
170
+ }
171
+
172
+ static inline p4d_t * kernel_to_user_p4dp (p4d_t * p4dp )
173
+ {
174
+ return ptr_set_bit (p4dp , PTI_PGTABLE_SWITCH_BIT );
175
+ }
176
+
177
+ static inline p4d_t * user_to_kernel_p4dp (p4d_t * p4dp )
178
+ {
179
+ return ptr_clear_bit (p4dp , PTI_PGTABLE_SWITCH_BIT );
180
+ }
181
+ #endif /* CONFIG_PAGE_TABLE_ISOLATION */
182
+
183
+ /*
184
+ * Page table pages are page-aligned. The lower half of the top
185
+ * level is used for userspace and the top half for the kernel.
186
+ *
187
+ * Returns true for parts of the PGD that map userspace and
188
+ * false for the parts that map the kernel.
189
+ */
190
+ static inline bool pgdp_maps_userspace (void * __ptr )
191
+ {
192
+ unsigned long ptr = (unsigned long )__ptr ;
193
+
194
+ return (ptr & ~PAGE_MASK ) < (PAGE_SIZE / 2 );
195
+ }
196
+
197
+ #ifdef CONFIG_PAGE_TABLE_ISOLATION
198
+ pgd_t __pti_set_user_pgd (pgd_t * pgdp , pgd_t pgd );
199
+
200
+ /*
201
+ * Take a PGD location (pgdp) and a pgd value that needs to be set there.
202
+ * Populates the user and returns the resulting PGD that must be set in
203
+ * the kernel copy of the page tables.
204
+ */
205
+ static inline pgd_t pti_set_user_pgd (pgd_t * pgdp , pgd_t pgd )
206
+ {
207
+ if (!static_cpu_has (X86_FEATURE_PTI ))
208
+ return pgd ;
209
+ return __pti_set_user_pgd (pgdp , pgd );
210
+ }
211
+ #else
212
+ static inline pgd_t pti_set_user_pgd (pgd_t * pgdp , pgd_t pgd )
213
+ {
214
+ return pgd ;
215
+ }
216
+ #endif
217
+
134
218
static inline void native_set_p4d (p4d_t * p4dp , p4d_t p4d )
135
219
{
220
+ #if defined(CONFIG_PAGE_TABLE_ISOLATION ) && !defined(CONFIG_X86_5LEVEL )
221
+ p4dp -> pgd = pti_set_user_pgd (& p4dp -> pgd , p4d .pgd );
222
+ #else
136
223
* p4dp = p4d ;
224
+ #endif
137
225
}
138
226
139
227
static inline void native_p4d_clear (p4d_t * p4d )
@@ -147,7 +235,11 @@ static inline void native_p4d_clear(p4d_t *p4d)
147
235
148
236
static inline void native_set_pgd (pgd_t * pgdp , pgd_t pgd )
149
237
{
238
+ #ifdef CONFIG_PAGE_TABLE_ISOLATION
239
+ * pgdp = pti_set_user_pgd (pgdp , pgd );
240
+ #else
150
241
* pgdp = pgd ;
242
+ #endif
151
243
}
152
244
153
245
static inline void native_pgd_clear (pgd_t * pgd )
0 commit comments