int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t);
 int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t);
 int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt);
-int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt);
+int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
+                   int fake);
 int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
-                          unsigned long *pgt, int *dat_protection);
+                          unsigned long *pgt, int *dat_protection, int *fake);
 int gmap_shadow_page(struct gmap *sg, unsigned long saddr, pte_t pte);
 
 void gmap_register_pte_notifier(struct gmap_notifier *);
 
  * @sg: pointer to the shadow guest address space structure
  * @saddr: faulting address in the shadow gmap
  * @pgt: pointer to the page table address result
+ * @fake: pgt references contiguous guest memory block, not a pgtable
  */
 static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
-                                 unsigned long *pgt, int *dat_protection)
+                                 unsigned long *pgt, int *dat_protection,
+                                 int *fake)
 {
        struct gmap *parent;
        union asce asce;
        unsigned long ptr;
        int rc;
 
+       *fake = 0;
        parent = sg->parent;
        vaddr.addr = saddr;
        asce.val = sg->orig_asce;
                if (ste.cs && asce.p)
                        return PGM_TRANSLATION_SPEC;
                *dat_protection = ste.fc0.p;
-               rc = gmap_shadow_pgt(sg, saddr, ste.val);
+               if (ste.fc && sg->edat_level >= 1) {
+                       bool prot = ste.fc1.p;
+
+                       *fake = 1;
+                       ptr = ste.fc1.sfaa << 20UL;
+                       ste.val = ptr;
+                       ste.fc0.p = prot;
+                       goto shadow_pgt;
+               }
+               ptr = ste.fc0.pto << 11UL;
+shadow_pgt:
+               rc = gmap_shadow_pgt(sg, saddr, ste.val, *fake);
                if (rc)
                        return rc;
-               ptr = ste.fc0.pto * 2048;
        }
        }
        /* Return the parent address of the page table */
        union vaddress vaddr;
        union page_table_entry pte;
        unsigned long pgt;
-       int dat_protection;
+       int dat_protection, fake;
        int rc;
 
        down_read(&sg->mm->mmap_sem);
         */
        ipte_lock(vcpu);
 
-       rc = gmap_shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection);
+       rc = gmap_shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection, &fake);
        if (rc)
-               rc = kvm_s390_shadow_tables(sg, saddr, &pgt, &dat_protection);
+               rc = kvm_s390_shadow_tables(sg, saddr, &pgt, &dat_protection,
+                                           &fake);
 
        vaddr.addr = saddr;
+       if (fake) {
+               /* offset in 1MB guest memory block */
+               pte.val = pgt + ((unsigned long) vaddr.px << 12UL);
+               goto shadow_page;
+       }
        if (!rc)
                rc = gmap_read_table(sg->parent, pgt + vaddr.px * 8, &pte.val);
        if (!rc && pte.i)
                rc = PGM_PAGE_TRANSLATION;
-       if (!rc && (pte.z || pte.co))
+       if (!rc && (pte.z || (pte.co && sg->edat_level < 1)))
                rc = PGM_TRANSLATION_SPEC;
+shadow_page:
        pte.p |= dat_protection;
        if (!rc)
                rc = gmap_shadow_page(sg, saddr, __pte(pte.val));
 
 #include <asm/gmap.h>
 #include <asm/tlb.h>
 
+#define GMAP_SHADOW_FAKE_TABLE 1ULL
+
 /**
  * gmap_alloc - allocate and initialize a guest address space
  * @mm: pointer to the parent mm_struct
        /* mark as invalid as long as the parent table is not protected */
        *table = (unsigned long) s_r2t | _REGION_ENTRY_LENGTH |
                 _REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INVALID;
+       if (sg->edat_level >= 1)
+               *table |= (r2t & _REGION_ENTRY_PROTECT);
        list_add(&page->lru, &sg->crst_list);
        spin_unlock(&sg->guest_table_lock);
        /* Make r2t read-only in parent gmap page table */
        /* mark as invalid as long as the parent table is not protected */
        *table = (unsigned long) s_r3t | _REGION_ENTRY_LENGTH |
                 _REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INVALID;
+       if (sg->edat_level >= 1)
+               *table |= (r3t & _REGION_ENTRY_PROTECT);
        list_add(&page->lru, &sg->crst_list);
        spin_unlock(&sg->guest_table_lock);
        /* Make r3t read-only in parent gmap page table */
        /* mark as invalid as long as the parent table is not protected */
        *table = (unsigned long) s_sgt | _REGION_ENTRY_LENGTH |
                 _REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID;
+       if (sg->edat_level >= 1)
+               *table |= sgt & _REGION_ENTRY_PROTECT;
        list_add(&page->lru, &sg->crst_list);
        spin_unlock(&sg->guest_table_lock);
        /* Make sgt read-only in parent gmap page table */
  * @saddr: the address in the shadow aguest address space
  * @pgt: parent gmap address of the page table to get shadowed
  * @dat_protection: if the pgtable is marked as protected by dat
+ * @fake: pgt references contiguous guest memory block, not a pgtable
  *
  * Returns 0 if the shadow page table was found and -EAGAIN if the page
  * table was not found.
  * Called with sg->mm->mmap_sem in read.
  */
 int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
-                          unsigned long *pgt, int *dat_protection)
+                          unsigned long *pgt, int *dat_protection,
+                          int *fake)
 {
        unsigned long *table;
        struct page *page;
        if (table && !(*table & _SEGMENT_ENTRY_INVALID)) {
                /* Shadow page tables are full pages (pte+pgste) */
                page = pfn_to_page(*table >> PAGE_SHIFT);
-               *pgt = page->index;
+               *pgt = page->index & ~GMAP_SHADOW_FAKE_TABLE;
                *dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT);
+               *fake = !!(page->index & GMAP_SHADOW_FAKE_TABLE);
                rc = 0;
        } else  {
                rc = -EAGAIN;
  * @sg: pointer to the shadow guest address space structure
  * @saddr: faulting address in the shadow gmap
  * @pgt: parent gmap address of the page table to get shadowed
+ * @fake: pgt references contiguous guest memory block, not a pgtable
  *
  * Returns 0 if successfully shadowed or already shadowed, -EAGAIN if the
  * shadow table structure is incomplete, -ENOMEM if out of memory,
  *
  * Called with gmap->mm->mmap_sem in read
  */
-int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt)
+int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
+                   int fake)
 {
        unsigned long raddr, origin;
        unsigned long *s_pgt, *table;
        struct page *page;
        int rc;
 
-       BUG_ON(!gmap_is_shadow(sg));
+       BUG_ON(!gmap_is_shadow(sg) || (pgt & _SEGMENT_ENTRY_LARGE));
        /* Allocate a shadow page table */
        page = page_table_alloc_pgste(sg->mm);
        if (!page)
                return -ENOMEM;
        page->index = pgt & _SEGMENT_ENTRY_ORIGIN;
+       if (fake)
+               page->index |= GMAP_SHADOW_FAKE_TABLE;
        s_pgt = (unsigned long *) page_to_phys(page);
        /* Install shadow page table */
        spin_lock(&sg->guest_table_lock);
        *table = (unsigned long) s_pgt | _SEGMENT_ENTRY |
                 (pgt & _SEGMENT_ENTRY_PROTECT) | _SEGMENT_ENTRY_INVALID;
        list_add(&page->lru, &sg->pt_list);
+       if (fake) {
+               /* nothing to protect for fake tables */
+               *table &= ~_SEGMENT_ENTRY_INVALID;
+               spin_unlock(&sg->guest_table_lock);
+               return 0;
+       }
        spin_unlock(&sg->guest_table_lock);
        /* Make pgt read-only in parent gmap page table (not the pgste) */
        raddr = (saddr & 0xfffffffffff00000UL) | _SHADOW_RMAP_SEGMENT;