diff options
Diffstat (limited to 'drivers/kvm/mmu.c')
-rw-r--r-- | drivers/kvm/mmu.c | 151 |
1 files changed, 120 insertions, 31 deletions
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 0bd2a19709ce..e96362aa7947 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c | |||
@@ -166,6 +166,84 @@ static int is_rmap_pte(u64 pte) | |||
166 | == (PT_WRITABLE_MASK | PT_PRESENT_MASK); | 166 | == (PT_WRITABLE_MASK | PT_PRESENT_MASK); |
167 | } | 167 | } |
168 | 168 | ||
169 | static void mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, | ||
170 | size_t objsize, int min) | ||
171 | { | ||
172 | void *obj; | ||
173 | |||
174 | if (cache->nobjs >= min) | ||
175 | return; | ||
176 | while (cache->nobjs < ARRAY_SIZE(cache->objects)) { | ||
177 | obj = kzalloc(objsize, GFP_NOWAIT); | ||
178 | if (!obj) | ||
179 | BUG(); | ||
180 | cache->objects[cache->nobjs++] = obj; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) | ||
185 | { | ||
186 | while (mc->nobjs) | ||
187 | kfree(mc->objects[--mc->nobjs]); | ||
188 | } | ||
189 | |||
190 | static void mmu_topup_memory_caches(struct kvm_vcpu *vcpu) | ||
191 | { | ||
192 | mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache, | ||
193 | sizeof(struct kvm_pte_chain), 4); | ||
194 | mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache, | ||
195 | sizeof(struct kvm_rmap_desc), 1); | ||
196 | } | ||
197 | |||
198 | static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) | ||
199 | { | ||
200 | mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache); | ||
201 | mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache); | ||
202 | } | ||
203 | |||
204 | static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc, | ||
205 | size_t size) | ||
206 | { | ||
207 | void *p; | ||
208 | |||
209 | BUG_ON(!mc->nobjs); | ||
210 | p = mc->objects[--mc->nobjs]; | ||
211 | memset(p, 0, size); | ||
212 | return p; | ||
213 | } | ||
214 | |||
215 | static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj) | ||
216 | { | ||
217 | if (mc->nobjs < KVM_NR_MEM_OBJS) | ||
218 | mc->objects[mc->nobjs++] = obj; | ||
219 | else | ||
220 | kfree(obj); | ||
221 | } | ||
222 | |||
223 | static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu) | ||
224 | { | ||
225 | return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache, | ||
226 | sizeof(struct kvm_pte_chain)); | ||
227 | } | ||
228 | |||
229 | static void mmu_free_pte_chain(struct kvm_vcpu *vcpu, | ||
230 | struct kvm_pte_chain *pc) | ||
231 | { | ||
232 | mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc); | ||
233 | } | ||
234 | |||
235 | static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu) | ||
236 | { | ||
237 | return mmu_memory_cache_alloc(&vcpu->mmu_rmap_desc_cache, | ||
238 | sizeof(struct kvm_rmap_desc)); | ||
239 | } | ||
240 | |||
241 | static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu, | ||
242 | struct kvm_rmap_desc *rd) | ||
243 | { | ||
244 | mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd); | ||
245 | } | ||
246 | |||
169 | /* | 247 | /* |
170 | * Reverse mapping data structures: | 248 | * Reverse mapping data structures: |
171 | * | 249 | * |
@@ -175,7 +253,7 @@ static int is_rmap_pte(u64 pte) | |||
175 | * If page->private bit zero is one, (then page->private & ~1) points | 253 | * If page->private bit zero is one, (then page->private & ~1) points |
176 | * to a struct kvm_rmap_desc containing more mappings. | 254 | * to a struct kvm_rmap_desc containing more mappings. |
177 | */ | 255 | */ |
178 | static void rmap_add(struct kvm *kvm, u64 *spte) | 256 | static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte) |
179 | { | 257 | { |
180 | struct page *page; | 258 | struct page *page; |
181 | struct kvm_rmap_desc *desc; | 259 | struct kvm_rmap_desc *desc; |
@@ -189,9 +267,7 @@ static void rmap_add(struct kvm *kvm, u64 *spte) | |||
189 | page->private = (unsigned long)spte; | 267 | page->private = (unsigned long)spte; |
190 | } else if (!(page->private & 1)) { | 268 | } else if (!(page->private & 1)) { |
191 | rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte); | 269 | rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte); |
192 | desc = kzalloc(sizeof *desc, GFP_NOWAIT); | 270 | desc = mmu_alloc_rmap_desc(vcpu); |
193 | if (!desc) | ||
194 | BUG(); /* FIXME: return error */ | ||
195 | desc->shadow_ptes[0] = (u64 *)page->private; | 271 | desc->shadow_ptes[0] = (u64 *)page->private; |
196 | desc->shadow_ptes[1] = spte; | 272 | desc->shadow_ptes[1] = spte; |
197 | page->private = (unsigned long)desc | 1; | 273 | page->private = (unsigned long)desc | 1; |
@@ -201,9 +277,7 @@ static void rmap_add(struct kvm *kvm, u64 *spte) | |||
201 | while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) | 277 | while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) |
202 | desc = desc->more; | 278 | desc = desc->more; |
203 | if (desc->shadow_ptes[RMAP_EXT-1]) { | 279 | if (desc->shadow_ptes[RMAP_EXT-1]) { |
204 | desc->more = kzalloc(sizeof *desc->more, GFP_NOWAIT); | 280 | desc->more = mmu_alloc_rmap_desc(vcpu); |
205 | if (!desc->more) | ||
206 | BUG(); /* FIXME: return error */ | ||
207 | desc = desc->more; | 281 | desc = desc->more; |
208 | } | 282 | } |
209 | for (i = 0; desc->shadow_ptes[i]; ++i) | 283 | for (i = 0; desc->shadow_ptes[i]; ++i) |
@@ -212,7 +286,8 @@ static void rmap_add(struct kvm *kvm, u64 *spte) | |||
212 | } | 286 | } |
213 | } | 287 | } |
214 | 288 | ||
215 | static void rmap_desc_remove_entry(struct page *page, | 289 | static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu, |
290 | struct page *page, | ||
216 | struct kvm_rmap_desc *desc, | 291 | struct kvm_rmap_desc *desc, |
217 | int i, | 292 | int i, |
218 | struct kvm_rmap_desc *prev_desc) | 293 | struct kvm_rmap_desc *prev_desc) |
@@ -232,10 +307,10 @@ static void rmap_desc_remove_entry(struct page *page, | |||
232 | prev_desc->more = desc->more; | 307 | prev_desc->more = desc->more; |
233 | else | 308 | else |
234 | page->private = (unsigned long)desc->more | 1; | 309 | page->private = (unsigned long)desc->more | 1; |
235 | kfree(desc); | 310 | mmu_free_rmap_desc(vcpu, desc); |
236 | } | 311 | } |
237 | 312 | ||
238 | static void rmap_remove(struct kvm *kvm, u64 *spte) | 313 | static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte) |
239 | { | 314 | { |
240 | struct page *page; | 315 | struct page *page; |
241 | struct kvm_rmap_desc *desc; | 316 | struct kvm_rmap_desc *desc; |
@@ -263,7 +338,8 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) | |||
263 | while (desc) { | 338 | while (desc) { |
264 | for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i) | 339 | for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i) |
265 | if (desc->shadow_ptes[i] == spte) { | 340 | if (desc->shadow_ptes[i] == spte) { |
266 | rmap_desc_remove_entry(page, desc, i, | 341 | rmap_desc_remove_entry(vcpu, page, |
342 | desc, i, | ||
267 | prev_desc); | 343 | prev_desc); |
268 | return; | 344 | return; |
269 | } | 345 | } |
@@ -274,8 +350,9 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) | |||
274 | } | 350 | } |
275 | } | 351 | } |
276 | 352 | ||
277 | static void rmap_write_protect(struct kvm *kvm, u64 gfn) | 353 | static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) |
278 | { | 354 | { |
355 | struct kvm *kvm = vcpu->kvm; | ||
279 | struct page *page; | 356 | struct page *page; |
280 | struct kvm_memory_slot *slot; | 357 | struct kvm_memory_slot *slot; |
281 | struct kvm_rmap_desc *desc; | 358 | struct kvm_rmap_desc *desc; |
@@ -298,7 +375,7 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn) | |||
298 | BUG_ON(!(*spte & PT_PRESENT_MASK)); | 375 | BUG_ON(!(*spte & PT_PRESENT_MASK)); |
299 | BUG_ON(!(*spte & PT_WRITABLE_MASK)); | 376 | BUG_ON(!(*spte & PT_WRITABLE_MASK)); |
300 | rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte); | 377 | rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte); |
301 | rmap_remove(kvm, spte); | 378 | rmap_remove(vcpu, spte); |
302 | *spte &= ~(u64)PT_WRITABLE_MASK; | 379 | *spte &= ~(u64)PT_WRITABLE_MASK; |
303 | } | 380 | } |
304 | } | 381 | } |
@@ -354,7 +431,8 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, | |||
354 | return page; | 431 | return page; |
355 | } | 432 | } |
356 | 433 | ||
357 | static void mmu_page_add_parent_pte(struct kvm_mmu_page *page, u64 *parent_pte) | 434 | static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu, |
435 | struct kvm_mmu_page *page, u64 *parent_pte) | ||
358 | { | 436 | { |
359 | struct kvm_pte_chain *pte_chain; | 437 | struct kvm_pte_chain *pte_chain; |
360 | struct hlist_node *node; | 438 | struct hlist_node *node; |
@@ -370,8 +448,7 @@ static void mmu_page_add_parent_pte(struct kvm_mmu_page *page, u64 *parent_pte) | |||
370 | return; | 448 | return; |
371 | } | 449 | } |
372 | page->multimapped = 1; | 450 | page->multimapped = 1; |
373 | pte_chain = kzalloc(sizeof(struct kvm_pte_chain), GFP_NOWAIT); | 451 | pte_chain = mmu_alloc_pte_chain(vcpu); |
374 | BUG_ON(!pte_chain); | ||
375 | INIT_HLIST_HEAD(&page->parent_ptes); | 452 | INIT_HLIST_HEAD(&page->parent_ptes); |
376 | hlist_add_head(&pte_chain->link, &page->parent_ptes); | 453 | hlist_add_head(&pte_chain->link, &page->parent_ptes); |
377 | pte_chain->parent_ptes[0] = old; | 454 | pte_chain->parent_ptes[0] = old; |
@@ -385,13 +462,14 @@ static void mmu_page_add_parent_pte(struct kvm_mmu_page *page, u64 *parent_pte) | |||
385 | return; | 462 | return; |
386 | } | 463 | } |
387 | } | 464 | } |
388 | pte_chain = kzalloc(sizeof(struct kvm_pte_chain), GFP_NOWAIT); | 465 | pte_chain = mmu_alloc_pte_chain(vcpu); |
389 | BUG_ON(!pte_chain); | 466 | BUG_ON(!pte_chain); |
390 | hlist_add_head(&pte_chain->link, &page->parent_ptes); | 467 | hlist_add_head(&pte_chain->link, &page->parent_ptes); |
391 | pte_chain->parent_ptes[0] = parent_pte; | 468 | pte_chain->parent_ptes[0] = parent_pte; |
392 | } | 469 | } |
393 | 470 | ||
394 | static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page, | 471 | static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu, |
472 | struct kvm_mmu_page *page, | ||
395 | u64 *parent_pte) | 473 | u64 *parent_pte) |
396 | { | 474 | { |
397 | struct kvm_pte_chain *pte_chain; | 475 | struct kvm_pte_chain *pte_chain; |
@@ -418,7 +496,7 @@ static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page, | |||
418 | pte_chain->parent_ptes[i] = NULL; | 496 | pte_chain->parent_ptes[i] = NULL; |
419 | if (i == 0) { | 497 | if (i == 0) { |
420 | hlist_del(&pte_chain->link); | 498 | hlist_del(&pte_chain->link); |
421 | kfree(pte_chain); | 499 | mmu_free_pte_chain(vcpu, pte_chain); |
422 | if (hlist_empty(&page->parent_ptes)) { | 500 | if (hlist_empty(&page->parent_ptes)) { |
423 | page->multimapped = 0; | 501 | page->multimapped = 0; |
424 | page->parent_pte = NULL; | 502 | page->parent_pte = NULL; |
@@ -478,7 +556,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, | |||
478 | bucket = &vcpu->kvm->mmu_page_hash[index]; | 556 | bucket = &vcpu->kvm->mmu_page_hash[index]; |
479 | hlist_for_each_entry(page, node, bucket, hash_link) | 557 | hlist_for_each_entry(page, node, bucket, hash_link) |
480 | if (page->gfn == gfn && page->role.word == role.word) { | 558 | if (page->gfn == gfn && page->role.word == role.word) { |
481 | mmu_page_add_parent_pte(page, parent_pte); | 559 | mmu_page_add_parent_pte(vcpu, page, parent_pte); |
482 | pgprintk("%s: found\n", __FUNCTION__); | 560 | pgprintk("%s: found\n", __FUNCTION__); |
483 | return page; | 561 | return page; |
484 | } | 562 | } |
@@ -490,7 +568,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, | |||
490 | page->role = role; | 568 | page->role = role; |
491 | hlist_add_head(&page->hash_link, bucket); | 569 | hlist_add_head(&page->hash_link, bucket); |
492 | if (!metaphysical) | 570 | if (!metaphysical) |
493 | rmap_write_protect(vcpu->kvm, gfn); | 571 | rmap_write_protect(vcpu, gfn); |
494 | return page; | 572 | return page; |
495 | } | 573 | } |
496 | 574 | ||
@@ -506,7 +584,7 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu, | |||
506 | if (page->role.level == PT_PAGE_TABLE_LEVEL) { | 584 | if (page->role.level == PT_PAGE_TABLE_LEVEL) { |
507 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { | 585 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { |
508 | if (pt[i] & PT_PRESENT_MASK) | 586 | if (pt[i] & PT_PRESENT_MASK) |
509 | rmap_remove(vcpu->kvm, &pt[i]); | 587 | rmap_remove(vcpu, &pt[i]); |
510 | pt[i] = 0; | 588 | pt[i] = 0; |
511 | } | 589 | } |
512 | return; | 590 | return; |
@@ -519,7 +597,7 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu, | |||
519 | if (!(ent & PT_PRESENT_MASK)) | 597 | if (!(ent & PT_PRESENT_MASK)) |
520 | continue; | 598 | continue; |
521 | ent &= PT64_BASE_ADDR_MASK; | 599 | ent &= PT64_BASE_ADDR_MASK; |
522 | mmu_page_remove_parent_pte(page_header(ent), &pt[i]); | 600 | mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]); |
523 | } | 601 | } |
524 | } | 602 | } |
525 | 603 | ||
@@ -527,7 +605,7 @@ static void kvm_mmu_put_page(struct kvm_vcpu *vcpu, | |||
527 | struct kvm_mmu_page *page, | 605 | struct kvm_mmu_page *page, |
528 | u64 *parent_pte) | 606 | u64 *parent_pte) |
529 | { | 607 | { |
530 | mmu_page_remove_parent_pte(page, parent_pte); | 608 | mmu_page_remove_parent_pte(vcpu, page, parent_pte); |
531 | } | 609 | } |
532 | 610 | ||
533 | static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu, | 611 | static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu, |
@@ -644,7 +722,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p) | |||
644 | page_header_update_slot(vcpu->kvm, table, v); | 722 | page_header_update_slot(vcpu->kvm, table, v); |
645 | table[index] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK | | 723 | table[index] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK | |
646 | PT_USER_MASK; | 724 | PT_USER_MASK; |
647 | rmap_add(vcpu->kvm, &table[index]); | 725 | rmap_add(vcpu, &table[index]); |
648 | return 0; | 726 | return 0; |
649 | } | 727 | } |
650 | 728 | ||
@@ -747,6 +825,8 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, | |||
747 | gpa_t addr = gva; | 825 | gpa_t addr = gva; |
748 | hpa_t paddr; | 826 | hpa_t paddr; |
749 | 827 | ||
828 | mmu_topup_memory_caches(vcpu); | ||
829 | |||
750 | ASSERT(vcpu); | 830 | ASSERT(vcpu); |
751 | ASSERT(VALID_PAGE(vcpu->mmu.root_hpa)); | 831 | ASSERT(VALID_PAGE(vcpu->mmu.root_hpa)); |
752 | 832 | ||
@@ -845,7 +925,7 @@ static inline void set_pte_common(struct kvm_vcpu *vcpu, | |||
845 | mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT); | 925 | mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT); |
846 | 926 | ||
847 | page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); | 927 | page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); |
848 | rmap_add(vcpu->kvm, shadow_pte); | 928 | rmap_add(vcpu, shadow_pte); |
849 | } | 929 | } |
850 | 930 | ||
851 | static void inject_page_fault(struct kvm_vcpu *vcpu, | 931 | static void inject_page_fault(struct kvm_vcpu *vcpu, |
@@ -966,8 +1046,15 @@ static void destroy_kvm_mmu(struct kvm_vcpu *vcpu) | |||
966 | 1046 | ||
967 | int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) | 1047 | int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) |
968 | { | 1048 | { |
1049 | int r; | ||
1050 | |||
969 | destroy_kvm_mmu(vcpu); | 1051 | destroy_kvm_mmu(vcpu); |
970 | return init_kvm_mmu(vcpu); | 1052 | r = init_kvm_mmu(vcpu); |
1053 | if (r < 0) | ||
1054 | goto out; | ||
1055 | mmu_topup_memory_caches(vcpu); | ||
1056 | out: | ||
1057 | return r; | ||
971 | } | 1058 | } |
972 | 1059 | ||
973 | void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) | 1060 | void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) |
@@ -1030,10 +1117,10 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) | |||
1030 | pte = *spte; | 1117 | pte = *spte; |
1031 | if (is_present_pte(pte)) { | 1118 | if (is_present_pte(pte)) { |
1032 | if (level == PT_PAGE_TABLE_LEVEL) | 1119 | if (level == PT_PAGE_TABLE_LEVEL) |
1033 | rmap_remove(vcpu->kvm, spte); | 1120 | rmap_remove(vcpu, spte); |
1034 | else { | 1121 | else { |
1035 | child = page_header(pte & PT64_BASE_ADDR_MASK); | 1122 | child = page_header(pte & PT64_BASE_ADDR_MASK); |
1036 | mmu_page_remove_parent_pte(child, spte); | 1123 | mmu_page_remove_parent_pte(vcpu, child, spte); |
1037 | } | 1124 | } |
1038 | } | 1125 | } |
1039 | *spte = 0; | 1126 | *spte = 0; |
@@ -1145,10 +1232,12 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu) | |||
1145 | 1232 | ||
1146 | destroy_kvm_mmu(vcpu); | 1233 | destroy_kvm_mmu(vcpu); |
1147 | free_mmu_pages(vcpu); | 1234 | free_mmu_pages(vcpu); |
1235 | mmu_free_memory_caches(vcpu); | ||
1148 | } | 1236 | } |
1149 | 1237 | ||
1150 | void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) | 1238 | void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot) |
1151 | { | 1239 | { |
1240 | struct kvm *kvm = vcpu->kvm; | ||
1152 | struct kvm_mmu_page *page; | 1241 | struct kvm_mmu_page *page; |
1153 | 1242 | ||
1154 | list_for_each_entry(page, &kvm->active_mmu_pages, link) { | 1243 | list_for_each_entry(page, &kvm->active_mmu_pages, link) { |
@@ -1162,7 +1251,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) | |||
1162 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i) | 1251 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i) |
1163 | /* avoid RMW */ | 1252 | /* avoid RMW */ |
1164 | if (pt[i] & PT_WRITABLE_MASK) { | 1253 | if (pt[i] & PT_WRITABLE_MASK) { |
1165 | rmap_remove(kvm, &pt[i]); | 1254 | rmap_remove(vcpu, &pt[i]); |
1166 | pt[i] &= ~PT_WRITABLE_MASK; | 1255 | pt[i] &= ~PT_WRITABLE_MASK; |
1167 | } | 1256 | } |
1168 | } | 1257 | } |