@@ -379,45 +379,108 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
379
379
}
380
380
EXPORT_SYMBOL_GPL (gmap_map_segment );
381
381
382
+ static unsigned long * gmap_table_walk (unsigned long address , struct gmap * gmap )
383
+ {
384
+ unsigned long * table ;
385
+
386
+ table = gmap -> table + ((address >> 53 ) & 0x7ff );
387
+ if (unlikely (* table & _REGION_ENTRY_INV ))
388
+ return ERR_PTR (- EFAULT );
389
+ table = (unsigned long * )(* table & _REGION_ENTRY_ORIGIN );
390
+ table = table + ((address >> 42 ) & 0x7ff );
391
+ if (unlikely (* table & _REGION_ENTRY_INV ))
392
+ return ERR_PTR (- EFAULT );
393
+ table = (unsigned long * )(* table & _REGION_ENTRY_ORIGIN );
394
+ table = table + ((address >> 31 ) & 0x7ff );
395
+ if (unlikely (* table & _REGION_ENTRY_INV ))
396
+ return ERR_PTR (- EFAULT );
397
+ table = (unsigned long * )(* table & _REGION_ENTRY_ORIGIN );
398
+ table = table + ((address >> 20 ) & 0x7ff );
399
+ return table ;
400
+ }
401
+
402
+ /**
403
+ * __gmap_translate - translate a guest address to a user space address
404
+ * @address: guest address
405
+ * @gmap: pointer to guest mapping meta data structure
406
+ *
407
+ * Returns user space address which corresponds to the guest address or
408
+ * -EFAULT if no such mapping exists.
409
+ * This function does not establish potentially missing page table entries.
410
+ * The mmap_sem of the mm that belongs to the address space must be held
411
+ * when this function gets called.
412
+ */
413
+ unsigned long __gmap_translate (unsigned long address , struct gmap * gmap )
414
+ {
415
+ unsigned long * segment_ptr , vmaddr , segment ;
416
+ struct gmap_pgtable * mp ;
417
+ struct page * page ;
418
+
419
+ current -> thread .gmap_addr = address ;
420
+ segment_ptr = gmap_table_walk (address , gmap );
421
+ if (IS_ERR (segment_ptr ))
422
+ return PTR_ERR (segment_ptr );
423
+ /* Convert the gmap address to an mm address. */
424
+ segment = * segment_ptr ;
425
+ if (!(segment & _SEGMENT_ENTRY_INV )) {
426
+ page = pfn_to_page (segment >> PAGE_SHIFT );
427
+ mp = (struct gmap_pgtable * ) page -> index ;
428
+ return mp -> vmaddr | (address & ~PMD_MASK );
429
+ } else if (segment & _SEGMENT_ENTRY_RO ) {
430
+ vmaddr = segment & _SEGMENT_ENTRY_ORIGIN ;
431
+ return vmaddr | (address & ~PMD_MASK );
432
+ }
433
+ return - EFAULT ;
434
+ }
435
+ EXPORT_SYMBOL_GPL (__gmap_translate );
436
+
437
+ /**
438
+ * gmap_translate - translate a guest address to a user space address
439
+ * @address: guest address
440
+ * @gmap: pointer to guest mapping meta data structure
441
+ *
442
+ * Returns user space address which corresponds to the guest address or
443
+ * -EFAULT if no such mapping exists.
444
+ * This function does not establish potentially missing page table entries.
445
+ */
446
+ unsigned long gmap_translate (unsigned long address , struct gmap * gmap )
447
+ {
448
+ unsigned long rc ;
449
+
450
+ down_read (& gmap -> mm -> mmap_sem );
451
+ rc = __gmap_translate (address , gmap );
452
+ up_read (& gmap -> mm -> mmap_sem );
453
+ return rc ;
454
+ }
455
+ EXPORT_SYMBOL_GPL (gmap_translate );
456
+
382
457
/*
383
458
* this function is assumed to be called with mmap_sem held
384
459
*/
385
460
unsigned long __gmap_fault (unsigned long address , struct gmap * gmap )
386
461
{
387
- unsigned long * table , vmaddr , segment ;
388
- struct mm_struct * mm ;
462
+ unsigned long * segment_ptr , vmaddr , segment ;
463
+ struct vm_area_struct * vma ;
389
464
struct gmap_pgtable * mp ;
390
465
struct gmap_rmap * rmap ;
391
- struct vm_area_struct * vma ;
466
+ struct mm_struct * mm ;
392
467
struct page * page ;
393
468
pgd_t * pgd ;
394
469
pud_t * pud ;
395
470
pmd_t * pmd ;
396
471
397
472
current -> thread .gmap_addr = address ;
398
- mm = gmap -> mm ;
399
- /* Walk the gmap address space page table */
400
- table = gmap -> table + ((address >> 53 ) & 0x7ff );
401
- if (unlikely (* table & _REGION_ENTRY_INV ))
402
- return - EFAULT ;
403
- table = (unsigned long * )(* table & _REGION_ENTRY_ORIGIN );
404
- table = table + ((address >> 42 ) & 0x7ff );
405
- if (unlikely (* table & _REGION_ENTRY_INV ))
473
+ segment_ptr = gmap_table_walk (address , gmap );
474
+ if (IS_ERR (segment_ptr ))
406
475
return - EFAULT ;
407
- table = (unsigned long * )(* table & _REGION_ENTRY_ORIGIN );
408
- table = table + ((address >> 31 ) & 0x7ff );
409
- if (unlikely (* table & _REGION_ENTRY_INV ))
410
- return - EFAULT ;
411
- table = (unsigned long * )(* table & _REGION_ENTRY_ORIGIN );
412
- table = table + ((address >> 20 ) & 0x7ff );
413
-
414
476
/* Convert the gmap address to an mm address. */
415
- segment = * table ;
416
- if (likely ( !(segment & _SEGMENT_ENTRY_INV ) )) {
477
+ segment = * segment_ptr ;
478
+ if (!(segment & _SEGMENT_ENTRY_INV )) {
417
479
page = pfn_to_page (segment >> PAGE_SHIFT );
418
480
mp = (struct gmap_pgtable * ) page -> index ;
419
481
return mp -> vmaddr | (address & ~PMD_MASK );
420
482
} else if (segment & _SEGMENT_ENTRY_RO ) {
483
+ mm = gmap -> mm ;
421
484
vmaddr = segment & _SEGMENT_ENTRY_ORIGIN ;
422
485
vma = find_vma (mm , vmaddr );
423
486
if (!vma || vma -> vm_start > vmaddr )
@@ -441,12 +504,12 @@ unsigned long __gmap_fault(unsigned long address, struct gmap *gmap)
441
504
/* Link gmap segment table entry location to page table. */
442
505
page = pmd_page (* pmd );
443
506
mp = (struct gmap_pgtable * ) page -> index ;
444
- rmap -> entry = table ;
507
+ rmap -> entry = segment_ptr ;
445
508
spin_lock (& mm -> page_table_lock );
446
509
list_add (& rmap -> list , & mp -> mapper );
447
510
spin_unlock (& mm -> page_table_lock );
448
511
/* Set gmap segment table entry to page table. */
449
- * table = pmd_val (* pmd ) & PAGE_MASK ;
512
+ * segment_ptr = pmd_val (* pmd ) & PAGE_MASK ;
450
513
return vmaddr | (address & ~PMD_MASK );
451
514
}
452
515
return - EFAULT ;
0 commit comments