aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm
diff options
context:
space:
mode:
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>2016-04-18 07:42:05 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2016-06-20 03:54:56 -0400
commit18b89809881834cecd2977e6048a30c4c8f140fe (patch)
tree7542079e9cbb1b59df833981ddd005a3524178bc /arch/s390/mm
parentfd8d4e3ab6993e194287a59c4d3a6a43da86b8dc (diff)
s390/mm: support EDAT2 for gmap shadows
If the guest is enabled for EDAT2, we can easily create shadows for guest2 -> guest3 provided tables that make use of EDAT2. If guest2 references a 2GB page, this memory looks consecutive for guest2, but it does not have to be so for us. Therefore we have to create fake segment and page tables. This works just like EDAT1 support, so page tables are removed when the parent table (r3t table entry) is changed. We don't hve to care about: - ACCF-Validity Control in RTTE - Access-Control Bits in RTTE - Fetch-Protection Bit in RTTE - Common-Region Bit in RTTE Just like for EDAT1, all bits might be dropped and there is no guaranteed that they are active. Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r--arch/s390/mm/gmap.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index de7ad7bd4a48..c96bf30245c0 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -1631,6 +1631,7 @@ EXPORT_SYMBOL_GPL(gmap_shadow_r3t);
1631 * @sg: pointer to the shadow guest address space structure 1631 * @sg: pointer to the shadow guest address space structure
1632 * @saddr: faulting address in the shadow gmap 1632 * @saddr: faulting address in the shadow gmap
1633 * @sgt: parent gmap address of the segment table to get shadowed 1633 * @sgt: parent gmap address of the segment table to get shadowed
1634 * @fake: sgt references contiguous guest memory block, not a sgt
1634 * 1635 *
1635 * Returns: 0 if successfully shadowed or already shadowed, -EAGAIN if the 1636 * Returns: 0 if successfully shadowed or already shadowed, -EAGAIN if the
1636 * shadow table structure is incomplete, -ENOMEM if out of memory and 1637 * shadow table structure is incomplete, -ENOMEM if out of memory and
@@ -1638,19 +1639,22 @@ EXPORT_SYMBOL_GPL(gmap_shadow_r3t);
1638 * 1639 *
1639 * Called with sg->mm->mmap_sem in read. 1640 * Called with sg->mm->mmap_sem in read.
1640 */ 1641 */
1641int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt) 1642int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
1643 int fake)
1642{ 1644{
1643 unsigned long raddr, origin, offset, len; 1645 unsigned long raddr, origin, offset, len;
1644 unsigned long *s_sgt, *table; 1646 unsigned long *s_sgt, *table;
1645 struct page *page; 1647 struct page *page;
1646 int rc; 1648 int rc;
1647 1649
1648 BUG_ON(!gmap_is_shadow(sg)); 1650 BUG_ON(!gmap_is_shadow(sg) || (sgt & _REGION3_ENTRY_LARGE));
1649 /* Allocate a shadow segment table */ 1651 /* Allocate a shadow segment table */
1650 page = alloc_pages(GFP_KERNEL, 2); 1652 page = alloc_pages(GFP_KERNEL, 2);
1651 if (!page) 1653 if (!page)
1652 return -ENOMEM; 1654 return -ENOMEM;
1653 page->index = sgt & _REGION_ENTRY_ORIGIN; 1655 page->index = sgt & _REGION_ENTRY_ORIGIN;
1656 if (fake)
1657 page->index |= GMAP_SHADOW_FAKE_TABLE;
1654 s_sgt = (unsigned long *) page_to_phys(page); 1658 s_sgt = (unsigned long *) page_to_phys(page);
1655 /* Install shadow region second table */ 1659 /* Install shadow region second table */
1656 spin_lock(&sg->guest_table_lock); 1660 spin_lock(&sg->guest_table_lock);
@@ -1673,6 +1677,12 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt)
1673 if (sg->edat_level >= 1) 1677 if (sg->edat_level >= 1)
1674 *table |= sgt & _REGION_ENTRY_PROTECT; 1678 *table |= sgt & _REGION_ENTRY_PROTECT;
1675 list_add(&page->lru, &sg->crst_list); 1679 list_add(&page->lru, &sg->crst_list);
1680 if (fake) {
1681 /* nothing to protect for fake tables */
1682 *table &= ~_REGION_ENTRY_INVALID;
1683 spin_unlock(&sg->guest_table_lock);
1684 return 0;
1685 }
1676 spin_unlock(&sg->guest_table_lock); 1686 spin_unlock(&sg->guest_table_lock);
1677 /* Make sgt read-only in parent gmap page table */ 1687 /* Make sgt read-only in parent gmap page table */
1678 raddr = (saddr & 0xffffffff80000000UL) | _SHADOW_RMAP_REGION3; 1688 raddr = (saddr & 0xffffffff80000000UL) | _SHADOW_RMAP_REGION3;