diff options
author | Thomas Huth <thuth@linux.vnet.ibm.com> | 2014-04-25 15:37:19 +0200 |
---|---|---|
committer | Michael Roth <mdroth@linux.vnet.ibm.com> | 2014-06-25 16:39:52 -0500 |
commit | dd8f80b83c47ce6298a0a40a357d2ad738b0a0c2 (patch) | |
tree | fecbe09c5385d488dc141bad0d75cf4f357f45c1 | |
parent | b1a86eb532b4d32e4527a5373307873d95729aea (diff) |
s390x/helper: Added format control bit to MMU translation
With the EDAT-1 facility, the MMU translation can stop at the
segment table already, pointing to a 1 MB block. And while we're
at it, move the page table entry handling to a separate function,
too, as suggested by Alexander Graf.
Acked-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
(cherry picked from commit c4400206d43b6a235299c7047cca0af93269fc03)
Conflicts:
target-s390x/helper.c
*removed unecessary context
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
-rw-r--r-- | target-s390x/cpu.h | 4 | ||||
-rw-r--r-- | target-s390x/helper.c | 70 |
2 files changed, 56 insertions, 18 deletions
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 68b5ab7056..8c0d00a2ed 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -274,6 +274,9 @@ typedef struct CPUS390XState { #define FLAG_MASK_64 (PSW_MASK_64 >> 32) #define FLAG_MASK_32 0x00001000 +/* Control register 0 bits */ +#define CR0_EDAT 0x0000000000800000ULL + static inline int cpu_mmu_index (CPUS390XState *env) { if (env->psw.mask & PSW_MASK_PSTATE) { @@ -932,6 +935,7 @@ struct sysib_322 { #define _REGION_ENTRY_LENGTH 0x03 /* region third length */ #define _SEGMENT_ENTRY_ORIGIN ~0x7ffULL /* segment table origin */ +#define _SEGMENT_ENTRY_FC 0x400 /* format control */ #define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ diff --git a/target-s390x/helper.c b/target-s390x/helper.c index da33b38009..e8e92efa8d 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -164,6 +164,50 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, trigger_pgm_exception(env, type, ilen); } +/* Decode page table entry (normal 4KB page) */ +static int mmu_translate_pte(CPUS390XState *env, target_ulong vaddr, + uint64_t asc, uint64_t asce, + target_ulong *raddr, int *flags, int rw) +{ + if (asce & _PAGE_INVALID) { + DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, asce); + trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw); + return -1; + } + + if (asce & _PAGE_RO) { + *flags &= ~PAGE_WRITE; + } + + *raddr = asce & _ASCE_ORIGIN; + + PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, asce); + + return 0; +} + +/* Decode EDAT1 segment frame absolute address (1MB page) */ +static int mmu_translate_sfaa(CPUS390XState *env, target_ulong vaddr, + uint64_t asc, uint64_t asce, target_ulong *raddr, + int *flags, int rw) +{ + if (asce & _SEGMENT_ENTRY_INV) { + DPRINTF("%s: SEG=0x%" PRIx64 " invalid\n", __func__, asce); + trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw); + return -1; + } + + if (asce & _SEGMENT_ENTRY_RO) { + *flags &= ~PAGE_WRITE; + } + + *raddr = (asce & 0xfffffffffff00000ULL) | (vaddr & 0xfffff); + + PTE_DPRINTF("%s: SEG=0x%" PRIx64 "\n", __func__, asce); + + return 0; +} + static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t asc, uint64_t asce, int level, target_ulong *raddr, int *flags, int rw) @@ -222,28 +266,18 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n", __func__, origin, offs, new_asce); - if (level != _ASCE_TYPE_SEGMENT) { + if (level == _ASCE_TYPE_SEGMENT) { + /* 4KB page */ + return mmu_translate_pte(env, vaddr, asc, new_asce, raddr, flags, rw); + } else if (level - 4 == _ASCE_TYPE_SEGMENT && + (new_asce & _SEGMENT_ENTRY_FC) && (env->cregs[0] & CR0_EDAT)) { + /* 1MB page */ + return mmu_translate_sfaa(env, vaddr, asc, new_asce, raddr, flags, rw); + } else { /* yet another region */ return mmu_translate_asce(env, vaddr, asc, new_asce, level - 4, raddr, flags, rw); } - - /* PTE */ - if (new_asce & _PAGE_INVALID) { - DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, new_asce); - trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw); - return -1; - } - - if (new_asce & _PAGE_RO) { - *flags &= ~PAGE_WRITE; - } - - *raddr = new_asce & _ASCE_ORIGIN; - - PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, new_asce); - - return 0; } static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, |