aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm
diff options
context:
space:
mode:
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>2016-04-18 07:24:52 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2016-06-20 03:54:51 -0400
commitfd8d4e3ab6993e194287a59c4d3a6a43da86b8dc (patch)
tree7b604322fdb22cda63e86edf7a81775df321b2e9 /arch/s390/mm
parent5b062bd4940f81e0bd26b0d75f56d7abebf0309f (diff)
s390/mm: support EDAT1 for gmap shadows
If the guest is enabled for EDAT1, we can easily create shadows for guest2 -> guest3 provided tables that make use of EDAT1. If guest2 references a 1MB page, this memory looks consecutive for guest2, but it might not be so for us. Therefore we have to create fake page tables. We can easily add that to our existing infrastructure. The invalidation mechanism will make sure that fake page tables are removed when the parent table (sgt table entry) is changed. As EDAT1 also introduced protection on all page table levels, we have to also shadow these correctly. We don't have to care about: - ACCF-Validity Control in STE - Access-Control Bits in STE - Fetch-Protection Bit in STE - Common-Segment Bit in STE As all bits might be dropped and there is no guaranteed that they are active ("unpredictable whether the CPU uses these bits", "may be used"). Without using EDAT1 in the shadow ourselfes (STE-format control == 0), simply shadowing these bits would not be enough. They would be ignored. Please note that we are using the "fake" flag to make this look consistent with further changes (EDAT2, real-space designation support) and don't let the shadow functions handle fc=1 stes. In the future, with huge pages in the host, gmap_shadow_pgt() could simply try to map a huge host page if "fake" is set to one and indicate via return value that no lower fake tables / shadow ptes are required. 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.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index f0b2a531c599..de7ad7bd4a48 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -20,6 +20,8 @@
20#include <asm/gmap.h> 20#include <asm/gmap.h>
21#include <asm/tlb.h> 21#include <asm/tlb.h>
22 22
23#define GMAP_SHADOW_FAKE_TABLE 1ULL
24
23/** 25/**
24 * gmap_alloc - allocate and initialize a guest address space 26 * gmap_alloc - allocate and initialize a guest address space
25 * @mm: pointer to the parent mm_struct 27 * @mm: pointer to the parent mm_struct
@@ -1521,6 +1523,8 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t)
1521 /* mark as invalid as long as the parent table is not protected */ 1523 /* mark as invalid as long as the parent table is not protected */
1522 *table = (unsigned long) s_r2t | _REGION_ENTRY_LENGTH | 1524 *table = (unsigned long) s_r2t | _REGION_ENTRY_LENGTH |
1523 _REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INVALID; 1525 _REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INVALID;
1526 if (sg->edat_level >= 1)
1527 *table |= (r2t & _REGION_ENTRY_PROTECT);
1524 list_add(&page->lru, &sg->crst_list); 1528 list_add(&page->lru, &sg->crst_list);
1525 spin_unlock(&sg->guest_table_lock); 1529 spin_unlock(&sg->guest_table_lock);
1526 /* Make r2t read-only in parent gmap page table */ 1530 /* Make r2t read-only in parent gmap page table */
@@ -1592,6 +1596,8 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t)
1592 /* mark as invalid as long as the parent table is not protected */ 1596 /* mark as invalid as long as the parent table is not protected */
1593 *table = (unsigned long) s_r3t | _REGION_ENTRY_LENGTH | 1597 *table = (unsigned long) s_r3t | _REGION_ENTRY_LENGTH |
1594 _REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INVALID; 1598 _REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INVALID;
1599 if (sg->edat_level >= 1)
1600 *table |= (r3t & _REGION_ENTRY_PROTECT);
1595 list_add(&page->lru, &sg->crst_list); 1601 list_add(&page->lru, &sg->crst_list);
1596 spin_unlock(&sg->guest_table_lock); 1602 spin_unlock(&sg->guest_table_lock);
1597 /* Make r3t read-only in parent gmap page table */ 1603 /* Make r3t read-only in parent gmap page table */
@@ -1664,6 +1670,8 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt)
1664 /* mark as invalid as long as the parent table is not protected */ 1670 /* mark as invalid as long as the parent table is not protected */
1665 *table = (unsigned long) s_sgt | _REGION_ENTRY_LENGTH | 1671 *table = (unsigned long) s_sgt | _REGION_ENTRY_LENGTH |
1666 _REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID; 1672 _REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID;
1673 if (sg->edat_level >= 1)
1674 *table |= sgt & _REGION_ENTRY_PROTECT;
1667 list_add(&page->lru, &sg->crst_list); 1675 list_add(&page->lru, &sg->crst_list);
1668 spin_unlock(&sg->guest_table_lock); 1676 spin_unlock(&sg->guest_table_lock);
1669 /* Make sgt read-only in parent gmap page table */ 1677 /* Make sgt read-only in parent gmap page table */
@@ -1698,6 +1706,7 @@ EXPORT_SYMBOL_GPL(gmap_shadow_sgt);
1698 * @saddr: the address in the shadow aguest address space 1706 * @saddr: the address in the shadow aguest address space
1699 * @pgt: parent gmap address of the page table to get shadowed 1707 * @pgt: parent gmap address of the page table to get shadowed
1700 * @dat_protection: if the pgtable is marked as protected by dat 1708 * @dat_protection: if the pgtable is marked as protected by dat
1709 * @fake: pgt references contiguous guest memory block, not a pgtable
1701 * 1710 *
1702 * Returns 0 if the shadow page table was found and -EAGAIN if the page 1711 * Returns 0 if the shadow page table was found and -EAGAIN if the page
1703 * table was not found. 1712 * table was not found.
@@ -1705,7 +1714,8 @@ EXPORT_SYMBOL_GPL(gmap_shadow_sgt);
1705 * Called with sg->mm->mmap_sem in read. 1714 * Called with sg->mm->mmap_sem in read.
1706 */ 1715 */
1707int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr, 1716int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
1708 unsigned long *pgt, int *dat_protection) 1717 unsigned long *pgt, int *dat_protection,
1718 int *fake)
1709{ 1719{
1710 unsigned long *table; 1720 unsigned long *table;
1711 struct page *page; 1721 struct page *page;
@@ -1717,8 +1727,9 @@ int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
1717 if (table && !(*table & _SEGMENT_ENTRY_INVALID)) { 1727 if (table && !(*table & _SEGMENT_ENTRY_INVALID)) {
1718 /* Shadow page tables are full pages (pte+pgste) */ 1728 /* Shadow page tables are full pages (pte+pgste) */
1719 page = pfn_to_page(*table >> PAGE_SHIFT); 1729 page = pfn_to_page(*table >> PAGE_SHIFT);
1720 *pgt = page->index; 1730 *pgt = page->index & ~GMAP_SHADOW_FAKE_TABLE;
1721 *dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT); 1731 *dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT);
1732 *fake = !!(page->index & GMAP_SHADOW_FAKE_TABLE);
1722 rc = 0; 1733 rc = 0;
1723 } else { 1734 } else {
1724 rc = -EAGAIN; 1735 rc = -EAGAIN;
@@ -1734,6 +1745,7 @@ EXPORT_SYMBOL_GPL(gmap_shadow_pgt_lookup);
1734 * @sg: pointer to the shadow guest address space structure 1745 * @sg: pointer to the shadow guest address space structure
1735 * @saddr: faulting address in the shadow gmap 1746 * @saddr: faulting address in the shadow gmap
1736 * @pgt: parent gmap address of the page table to get shadowed 1747 * @pgt: parent gmap address of the page table to get shadowed
1748 * @fake: pgt references contiguous guest memory block, not a pgtable
1737 * 1749 *
1738 * Returns 0 if successfully shadowed or already shadowed, -EAGAIN if the 1750 * Returns 0 if successfully shadowed or already shadowed, -EAGAIN if the
1739 * shadow table structure is incomplete, -ENOMEM if out of memory, 1751 * shadow table structure is incomplete, -ENOMEM if out of memory,
@@ -1741,19 +1753,22 @@ EXPORT_SYMBOL_GPL(gmap_shadow_pgt_lookup);
1741 * 1753 *
1742 * Called with gmap->mm->mmap_sem in read 1754 * Called with gmap->mm->mmap_sem in read
1743 */ 1755 */
1744int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt) 1756int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
1757 int fake)
1745{ 1758{
1746 unsigned long raddr, origin; 1759 unsigned long raddr, origin;
1747 unsigned long *s_pgt, *table; 1760 unsigned long *s_pgt, *table;
1748 struct page *page; 1761 struct page *page;
1749 int rc; 1762 int rc;
1750 1763
1751 BUG_ON(!gmap_is_shadow(sg)); 1764 BUG_ON(!gmap_is_shadow(sg) || (pgt & _SEGMENT_ENTRY_LARGE));
1752 /* Allocate a shadow page table */ 1765 /* Allocate a shadow page table */
1753 page = page_table_alloc_pgste(sg->mm); 1766 page = page_table_alloc_pgste(sg->mm);
1754 if (!page) 1767 if (!page)
1755 return -ENOMEM; 1768 return -ENOMEM;
1756 page->index = pgt & _SEGMENT_ENTRY_ORIGIN; 1769 page->index = pgt & _SEGMENT_ENTRY_ORIGIN;
1770 if (fake)
1771 page->index |= GMAP_SHADOW_FAKE_TABLE;
1757 s_pgt = (unsigned long *) page_to_phys(page); 1772 s_pgt = (unsigned long *) page_to_phys(page);
1758 /* Install shadow page table */ 1773 /* Install shadow page table */
1759 spin_lock(&sg->guest_table_lock); 1774 spin_lock(&sg->guest_table_lock);
@@ -1773,6 +1788,12 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt)
1773 *table = (unsigned long) s_pgt | _SEGMENT_ENTRY | 1788 *table = (unsigned long) s_pgt | _SEGMENT_ENTRY |
1774 (pgt & _SEGMENT_ENTRY_PROTECT) | _SEGMENT_ENTRY_INVALID; 1789 (pgt & _SEGMENT_ENTRY_PROTECT) | _SEGMENT_ENTRY_INVALID;
1775 list_add(&page->lru, &sg->pt_list); 1790 list_add(&page->lru, &sg->pt_list);
1791 if (fake) {
1792 /* nothing to protect for fake tables */
1793 *table &= ~_SEGMENT_ENTRY_INVALID;
1794 spin_unlock(&sg->guest_table_lock);
1795 return 0;
1796 }
1776 spin_unlock(&sg->guest_table_lock); 1797 spin_unlock(&sg->guest_table_lock);
1777 /* Make pgt read-only in parent gmap page table (not the pgste) */ 1798 /* Make pgt read-only in parent gmap page table (not the pgste) */
1778 raddr = (saddr & 0xfffffffffff00000UL) | _SHADOW_RMAP_SEGMENT; 1799 raddr = (saddr & 0xfffffffffff00000UL) | _SHADOW_RMAP_SEGMENT;