@@ -451,6 +451,69 @@ int kvm_pgtable_hyp_map(struct kvm_pgtable *pgt, u64 addr, u64 size, u64 phys,
451
451
return ret ;
452
452
}
453
453
454
+ struct hyp_unmap_data {
455
+ u64 unmapped ;
456
+ struct kvm_pgtable_mm_ops * mm_ops ;
457
+ };
458
+
459
+ static int hyp_unmap_walker (u64 addr , u64 end , u32 level , kvm_pte_t * ptep ,
460
+ enum kvm_pgtable_walk_flags flag , void * const arg )
461
+ {
462
+ kvm_pte_t pte = * ptep , * childp = NULL ;
463
+ u64 granule = kvm_granule_size (level );
464
+ struct hyp_unmap_data * data = arg ;
465
+ struct kvm_pgtable_mm_ops * mm_ops = data -> mm_ops ;
466
+
467
+ if (!kvm_pte_valid (pte ))
468
+ return - EINVAL ;
469
+
470
+ if (kvm_pte_table (pte , level )) {
471
+ childp = kvm_pte_follow (pte , mm_ops );
472
+
473
+ if (mm_ops -> page_count (childp ) != 1 )
474
+ return 0 ;
475
+
476
+ kvm_clear_pte (ptep );
477
+ dsb (ishst );
478
+ __tlbi_level (vae2is , __TLBI_VADDR (addr , 0 ), level );
479
+ } else {
480
+ if (end - addr < granule )
481
+ return - EINVAL ;
482
+
483
+ kvm_clear_pte (ptep );
484
+ dsb (ishst );
485
+ __tlbi_level (vale2is , __TLBI_VADDR (addr , 0 ), level );
486
+ data -> unmapped += granule ;
487
+ }
488
+
489
+ dsb (ish );
490
+ isb ();
491
+ mm_ops -> put_page (ptep );
492
+
493
+ if (childp )
494
+ mm_ops -> put_page (childp );
495
+
496
+ return 0 ;
497
+ }
498
+
499
+ u64 kvm_pgtable_hyp_unmap (struct kvm_pgtable * pgt , u64 addr , u64 size )
500
+ {
501
+ struct hyp_unmap_data unmap_data = {
502
+ .mm_ops = pgt -> mm_ops ,
503
+ };
504
+ struct kvm_pgtable_walker walker = {
505
+ .cb = hyp_unmap_walker ,
506
+ .arg = & unmap_data ,
507
+ .flags = KVM_PGTABLE_WALK_LEAF | KVM_PGTABLE_WALK_TABLE_POST ,
508
+ };
509
+
510
+ if (!pgt -> mm_ops -> page_count )
511
+ return 0 ;
512
+
513
+ kvm_pgtable_walk (pgt , addr , size , & walker );
514
+ return unmap_data .unmapped ;
515
+ }
516
+
454
517
int kvm_pgtable_hyp_init (struct kvm_pgtable * pgt , u32 va_bits ,
455
518
struct kvm_pgtable_mm_ops * mm_ops )
456
519
{
0 commit comments