27
27
#include "kvm.h"
28
28
29
29
#define pgprintk (x ...) do { } while (0)
30
+ #define rmap_printk (x ...) do { } while (0)
30
31
31
32
#define ASSERT (x ) \
32
33
if (!(x)) { \
125
126
#define PT_DIRECTORY_LEVEL 2
126
127
#define PT_PAGE_TABLE_LEVEL 1
127
128
129
+ #define RMAP_EXT 4
130
+
131
+ struct kvm_rmap_desc {
132
+ u64 * shadow_ptes [RMAP_EXT ];
133
+ struct kvm_rmap_desc * more ;
134
+ };
135
+
128
136
static int is_write_protection (struct kvm_vcpu * vcpu )
129
137
{
130
138
return vcpu -> cr0 & CR0_WP_MASK ;
@@ -150,6 +158,120 @@ static int is_io_pte(unsigned long pte)
150
158
return pte & PT_SHADOW_IO_MARK ;
151
159
}
152
160
161
+ static int is_rmap_pte (u64 pte )
162
+ {
163
+ return (pte & (PT_WRITABLE_MASK | PT_PRESENT_MASK ))
164
+ == (PT_WRITABLE_MASK | PT_PRESENT_MASK );
165
+ }
166
+
167
+ /*
168
+ * Reverse mapping data structures:
169
+ *
170
+ * If page->private bit zero is zero, then page->private points to the
171
+ * shadow page table entry that points to page_address(page).
172
+ *
173
+ * If page->private bit zero is one, (then page->private & ~1) points
174
+ * to a struct kvm_rmap_desc containing more mappings.
175
+ */
176
+ static void rmap_add (struct kvm * kvm , u64 * spte )
177
+ {
178
+ struct page * page ;
179
+ struct kvm_rmap_desc * desc ;
180
+ int i ;
181
+
182
+ if (!is_rmap_pte (* spte ))
183
+ return ;
184
+ page = pfn_to_page ((* spte & PT64_BASE_ADDR_MASK ) >> PAGE_SHIFT );
185
+ if (!page -> private ) {
186
+ rmap_printk ("rmap_add: %p %llx 0->1\n" , spte , * spte );
187
+ page -> private = (unsigned long )spte ;
188
+ } else if (!(page -> private & 1 )) {
189
+ rmap_printk ("rmap_add: %p %llx 1->many\n" , spte , * spte );
190
+ desc = kzalloc (sizeof * desc , GFP_NOWAIT );
191
+ if (!desc )
192
+ BUG (); /* FIXME: return error */
193
+ desc -> shadow_ptes [0 ] = (u64 * )page -> private ;
194
+ desc -> shadow_ptes [1 ] = spte ;
195
+ page -> private = (unsigned long )desc | 1 ;
196
+ } else {
197
+ rmap_printk ("rmap_add: %p %llx many->many\n" , spte , * spte );
198
+ desc = (struct kvm_rmap_desc * )(page -> private & ~1ul );
199
+ while (desc -> shadow_ptes [RMAP_EXT - 1 ] && desc -> more )
200
+ desc = desc -> more ;
201
+ if (desc -> shadow_ptes [RMAP_EXT - 1 ]) {
202
+ desc -> more = kzalloc (sizeof * desc -> more , GFP_NOWAIT );
203
+ if (!desc -> more )
204
+ BUG (); /* FIXME: return error */
205
+ desc = desc -> more ;
206
+ }
207
+ for (i = 0 ; desc -> shadow_ptes [i ]; ++ i )
208
+ ;
209
+ desc -> shadow_ptes [i ] = spte ;
210
+ }
211
+ }
212
+
213
+ static void rmap_desc_remove_entry (struct page * page ,
214
+ struct kvm_rmap_desc * desc ,
215
+ int i ,
216
+ struct kvm_rmap_desc * prev_desc )
217
+ {
218
+ int j ;
219
+
220
+ for (j = RMAP_EXT - 1 ; !desc -> shadow_ptes [j ] && j > i ; -- j )
221
+ ;
222
+ desc -> shadow_ptes [i ] = desc -> shadow_ptes [j ];
223
+ desc -> shadow_ptes [j ] = 0 ;
224
+ if (j != 0 )
225
+ return ;
226
+ if (!prev_desc && !desc -> more )
227
+ page -> private = (unsigned long )desc -> shadow_ptes [0 ];
228
+ else
229
+ if (prev_desc )
230
+ prev_desc -> more = desc -> more ;
231
+ else
232
+ page -> private = (unsigned long )desc -> more | 1 ;
233
+ kfree (desc );
234
+ }
235
+
236
+ static void rmap_remove (struct kvm * kvm , u64 * spte )
237
+ {
238
+ struct page * page ;
239
+ struct kvm_rmap_desc * desc ;
240
+ struct kvm_rmap_desc * prev_desc ;
241
+ int i ;
242
+
243
+ if (!is_rmap_pte (* spte ))
244
+ return ;
245
+ page = pfn_to_page ((* spte & PT64_BASE_ADDR_MASK ) >> PAGE_SHIFT );
246
+ if (!page -> private ) {
247
+ printk (KERN_ERR "rmap_remove: %p %llx 0->BUG\n" , spte , * spte );
248
+ BUG ();
249
+ } else if (!(page -> private & 1 )) {
250
+ rmap_printk ("rmap_remove: %p %llx 1->0\n" , spte , * spte );
251
+ if ((u64 * )page -> private != spte ) {
252
+ printk (KERN_ERR "rmap_remove: %p %llx 1->BUG\n" ,
253
+ spte , * spte );
254
+ BUG ();
255
+ }
256
+ page -> private = 0 ;
257
+ } else {
258
+ rmap_printk ("rmap_remove: %p %llx many->many\n" , spte , * spte );
259
+ desc = (struct kvm_rmap_desc * )(page -> private & ~1ul );
260
+ prev_desc = NULL ;
261
+ while (desc ) {
262
+ for (i = 0 ; i < RMAP_EXT && desc -> shadow_ptes [i ]; ++ i )
263
+ if (desc -> shadow_ptes [i ] == spte ) {
264
+ rmap_desc_remove_entry (page , desc , i ,
265
+ prev_desc );
266
+ return ;
267
+ }
268
+ prev_desc = desc ;
269
+ desc = desc -> more ;
270
+ }
271
+ BUG ();
272
+ }
273
+ }
274
+
153
275
static void kvm_mmu_free_page (struct kvm_vcpu * vcpu , hpa_t page_hpa )
154
276
{
155
277
struct kvm_mmu_page * page_head = page_header (page_hpa );
@@ -229,27 +351,27 @@ hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva)
229
351
static void release_pt_page_64 (struct kvm_vcpu * vcpu , hpa_t page_hpa ,
230
352
int level )
231
353
{
354
+ u64 * pos ;
355
+ u64 * end ;
356
+
232
357
ASSERT (vcpu );
233
358
ASSERT (VALID_PAGE (page_hpa ));
234
359
ASSERT (level <= PT64_ROOT_LEVEL && level > 0 );
235
360
236
- if (level == 1 )
237
- memset (__va (page_hpa ), 0 , PAGE_SIZE );
238
- else {
239
- u64 * pos ;
240
- u64 * end ;
361
+ for (pos = __va (page_hpa ), end = pos + PT64_ENT_PER_PAGE ;
362
+ pos != end ; pos ++ ) {
363
+ u64 current_ent = * pos ;
241
364
242
- for (pos = __va (page_hpa ), end = pos + PT64_ENT_PER_PAGE ;
243
- pos != end ; pos ++ ) {
244
- u64 current_ent = * pos ;
245
-
246
- * pos = 0 ;
247
- if (is_present_pte (current_ent ))
365
+ if (is_present_pte (current_ent )) {
366
+ if (level != 1 )
248
367
release_pt_page_64 (vcpu ,
249
368
current_ent &
250
369
PT64_BASE_ADDR_MASK ,
251
370
level - 1 );
371
+ else
372
+ rmap_remove (vcpu -> kvm , pos );
252
373
}
374
+ * pos = 0 ;
253
375
}
254
376
kvm_mmu_free_page (vcpu , page_hpa );
255
377
}
@@ -275,6 +397,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p)
275
397
page_header_update_slot (vcpu -> kvm , table , v );
276
398
table [index ] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK |
277
399
PT_USER_MASK ;
400
+ rmap_add (vcpu -> kvm , & table [index ]);
278
401
return 0 ;
279
402
}
280
403
@@ -437,6 +560,7 @@ static inline void set_pte_common(struct kvm_vcpu *vcpu,
437
560
} else {
438
561
* shadow_pte |= paddr ;
439
562
page_header_update_slot (vcpu -> kvm , shadow_pte , gaddr );
563
+ rmap_add (vcpu -> kvm , shadow_pte );
440
564
}
441
565
}
442
566
@@ -489,6 +613,7 @@ static void paging_inval_page(struct kvm_vcpu *vcpu, gva_t addr)
489
613
u64 * table = __va (page_addr );
490
614
491
615
if (level == PT_PAGE_TABLE_LEVEL ) {
616
+ rmap_remove (vcpu -> kvm , & table [index ]);
492
617
table [index ] = 0 ;
493
618
return ;
494
619
}
@@ -679,8 +804,9 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
679
804
pt = __va (page -> page_hpa );
680
805
for (i = 0 ; i < PT64_ENT_PER_PAGE ; ++ i )
681
806
/* avoid RMW */
682
- if (pt [i ] & PT_WRITABLE_MASK )
807
+ if (pt [i ] & PT_WRITABLE_MASK ) {
808
+ rmap_remove (kvm , & pt [i ]);
683
809
pt [i ] &= ~PT_WRITABLE_MASK ;
684
-
810
+ }
685
811
}
686
812
}
0 commit comments