浏览代码

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.9-20170303' into staging

ppc patch queuye for 2017-03-03

This will probably be my last pull request before the hard freeze.  It
has some new work, but that has all been posted in draft before the
soft freeze, so I think it's reasonable to include in qemu-2.9.

This batch has:
    * A substantial amount of POWER9 work
        * Implements the legacy (hash) MMU for POWER9
	* Some more preliminaries for implementing the POWER9 radix
          MMU
	* POWER9 has_work
	* Basic POWER9 compatibility mode handling
	* Removal of some premature tests
    * Some cleanups and fixes to the existing MMU code to make the
      POWER9 work simpler
    * A bugfix for TCG multiply adds on power
    * Allow pseries guests to access PCIe extended config space

This also includes a code-motion not strictly in ppc code - moving
getrampagesize() from ppc code to exec.c.  This will make some future
VFIO improvements easier, Paolo said it was ok to merge via my tree.

# gpg: Signature made Fri 03 Mar 2017 03:20:36 GMT
# gpg:                using RSA key 0x6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-2.9-20170303:
  target/ppc: rewrite f[n]m[add,sub] using float64_muladd
  spapr: Small cleanup of PPC MMU enums
  spapr_pci: Advertise access to PCIe extended config space
  target/ppc: Rework hash mmu page fault code and add defines for clarity
  target/ppc: Move no-execute and guarded page checking into new function
  target/ppc: Add execute permission checking to access authority check
  target/ppc: Add Instruction Authority Mask Register Check
  hw/ppc/spapr: Add POWER9 to pseries cpu models
  target/ppc/POWER9: Add cpu_has_work function for POWER9
  target/ppc/POWER9: Add POWER9 pa-features definition
  target/ppc/POWER9: Add POWER9 mmu fault handler
  target/ppc: Don't gen an SDR1 on POWER9 and rework register creation
  target/ppc: Add patb_entry to sPAPRMachineState
  target/ppc/POWER9: Add POWERPC_MMU_V3 bit
  powernv: Don't test POWER9 CPU yet
  exec, kvm, target-ppc: Move getrampagesize() to common code
  target/ppc: Add POWER9/ISAv3.00 to compat_table

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Peter Maydell 8 年之前
父节点
当前提交
17783ac828

+ 82 - 0
exec.c

@@ -42,6 +42,7 @@
 #include "exec/memory.h"
 #include "exec/memory.h"
 #include "exec/ioport.h"
 #include "exec/ioport.h"
 #include "sysemu/dma.h"
 #include "sysemu/dma.h"
+#include "sysemu/numa.h"
 #include "exec/address-spaces.h"
 #include "exec/address-spaces.h"
 #include "sysemu/xen-mapcache.h"
 #include "sysemu/xen-mapcache.h"
 #include "trace-root.h"
 #include "trace-root.h"
@@ -1256,6 +1257,87 @@ void qemu_mutex_unlock_ramlist(void)
     qemu_mutex_unlock(&ram_list.mutex);
     qemu_mutex_unlock(&ram_list.mutex);
 }
 }
 
 
+#ifdef __linux__
+/*
+ * FIXME TOCTTOU: this iterates over memory backends' mem-path, which
+ * may or may not name the same files / on the same filesystem now as
+ * when we actually open and map them.  Iterate over the file
+ * descriptors instead, and use qemu_fd_getpagesize().
+ */
+static int find_max_supported_pagesize(Object *obj, void *opaque)
+{
+    char *mem_path;
+    long *hpsize_min = opaque;
+
+    if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
+        mem_path = object_property_get_str(obj, "mem-path", NULL);
+        if (mem_path) {
+            long hpsize = qemu_mempath_getpagesize(mem_path);
+            if (hpsize < *hpsize_min) {
+                *hpsize_min = hpsize;
+            }
+        } else {
+            *hpsize_min = getpagesize();
+        }
+    }
+
+    return 0;
+}
+
+long qemu_getrampagesize(void)
+{
+    long hpsize = LONG_MAX;
+    long mainrampagesize;
+    Object *memdev_root;
+
+    if (mem_path) {
+        mainrampagesize = qemu_mempath_getpagesize(mem_path);
+    } else {
+        mainrampagesize = getpagesize();
+    }
+
+    /* it's possible we have memory-backend objects with
+     * hugepage-backed RAM. these may get mapped into system
+     * address space via -numa parameters or memory hotplug
+     * hooks. we want to take these into account, but we
+     * also want to make sure these supported hugepage
+     * sizes are applicable across the entire range of memory
+     * we may boot from, so we take the min across all
+     * backends, and assume normal pages in cases where a
+     * backend isn't backed by hugepages.
+     */
+    memdev_root = object_resolve_path("/objects", NULL);
+    if (memdev_root) {
+        object_child_foreach(memdev_root, find_max_supported_pagesize, &hpsize);
+    }
+    if (hpsize == LONG_MAX) {
+        /* No additional memory regions found ==> Report main RAM page size */
+        return mainrampagesize;
+    }
+
+    /* If NUMA is disabled or the NUMA nodes are not backed with a
+     * memory-backend, then there is at least one node using "normal" RAM,
+     * so if its page size is smaller we have got to report that size instead.
+     */
+    if (hpsize > mainrampagesize &&
+        (nb_numa_nodes == 0 || numa_info[0].node_memdev == NULL)) {
+        static bool warned;
+        if (!warned) {
+            error_report("Huge page support disabled (n/a for main memory).");
+            warned = true;
+        }
+        return mainrampagesize;
+    }
+
+    return hpsize;
+}
+#else
+long qemu_getrampagesize(void)
+{
+    return getpagesize();
+}
+#endif
+
 #ifdef __linux__
 #ifdef __linux__
 static int64_t get_file_size(int fd)
 static int64_t get_file_size(int fd)
 {
 {

+ 50 - 5
hw/ppc/spapr.c

@@ -390,20 +390,36 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset)
         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
+    /* Currently we don't advertise any of the "new" ISAv3.00 functionality */
+    uint8_t pa_features_300[] = { 64, 0,
+        0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /*  0 -  5 */
+        0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /*  6 - 11 */
+        0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
+        0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24 - 29 */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 - 35 */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 36 - 41 */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 - 47 */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 - 53 */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 54 - 59 */
+        0x00, 0x00, 0x00, 0x00           }; /* 60 - 63 */
+
     uint8_t *pa_features;
     uint8_t *pa_features;
     size_t pa_size;
     size_t pa_size;
 
 
-    switch (env->mmu_model) {
-    case POWERPC_MMU_2_06:
-    case POWERPC_MMU_2_06a:
+    switch (POWERPC_MMU_VER(env->mmu_model)) {
+    case POWERPC_MMU_VER_2_06:
         pa_features = pa_features_206;
         pa_features = pa_features_206;
         pa_size = sizeof(pa_features_206);
         pa_size = sizeof(pa_features_206);
         break;
         break;
-    case POWERPC_MMU_2_07:
-    case POWERPC_MMU_2_07a:
+    case POWERPC_MMU_VER_2_07:
         pa_features = pa_features_207;
         pa_features = pa_features_207;
         pa_size = sizeof(pa_features_207);
         pa_size = sizeof(pa_features_207);
         break;
         break;
+    case POWERPC_MMU_VER_3_00:
+        pa_features = pa_features_300;
+        pa_size = sizeof(pa_features_300);
+        break;
     default:
     default:
         return;
         return;
     }
     }
@@ -1055,6 +1071,13 @@ static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
     }
     }
 }
 }
 
 
+static uint64_t spapr_get_patbe(PPCVirtualHypervisor *vhyp)
+{
+    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+
+    return spapr->patb_entry;
+}
+
 #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
 #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
 #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
 #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
 #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
 #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
@@ -1234,6 +1257,8 @@ static void ppc_spapr_reset(void)
     /* Check for unknown sysbus devices */
     /* Check for unknown sysbus devices */
     foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
     foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
 
 
+    spapr->patb_entry = 0;
+
     /* Allocate and/or reset the hash page table */
     /* Allocate and/or reset the hash page table */
     spapr_reallocate_hpt(spapr,
     spapr_reallocate_hpt(spapr,
                          spapr_hpt_shift_for_ramsize(machine->maxram_size),
                          spapr_hpt_shift_for_ramsize(machine->maxram_size),
@@ -1427,6 +1452,24 @@ static const VMStateDescription vmstate_spapr_ov5_cas = {
     },
     },
 };
 };
 
 
+static bool spapr_patb_entry_needed(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    return !!spapr->patb_entry;
+}
+
+static const VMStateDescription vmstate_spapr_patb_entry = {
+    .name = "spapr_patb_entry",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = spapr_patb_entry_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(patb_entry, sPAPRMachineState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static const VMStateDescription vmstate_spapr = {
 static const VMStateDescription vmstate_spapr = {
     .name = "spapr",
     .name = "spapr",
     .version_id = 3,
     .version_id = 3,
@@ -1444,6 +1487,7 @@ static const VMStateDescription vmstate_spapr = {
     },
     },
     .subsections = (const VMStateDescription*[]) {
     .subsections = (const VMStateDescription*[]) {
         &vmstate_spapr_ov5_cas,
         &vmstate_spapr_ov5_cas,
+        &vmstate_spapr_patb_entry,
         NULL
         NULL
     }
     }
 };
 };
@@ -3049,6 +3093,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
     vhc->map_hptes = spapr_map_hptes;
     vhc->map_hptes = spapr_map_hptes;
     vhc->unmap_hptes = spapr_unmap_hptes;
     vhc->unmap_hptes = spapr_unmap_hptes;
     vhc->store_hpte = spapr_store_hpte;
     vhc->store_hpte = spapr_store_hpte;
+    vhc->get_patbe = spapr_get_patbe;
     xic->ics_get = spapr_ics_get;
     xic->ics_get = spapr_ics_get;
     xic->ics_resend = spapr_ics_resend;
     xic->ics_resend = spapr_ics_resend;
     xic->icp_get = spapr_icp_get;
     xic->icp_get = spapr_icp_get;

+ 3 - 0
hw/ppc/spapr_cpu_core.c

@@ -238,6 +238,9 @@ static const char *spapr_core_models[] = {
 
 
     /* POWER8NVL */
     /* POWER8NVL */
     "POWER8NVL_v1.0",
     "POWER8NVL_v1.0",
+
+    /* POWER9 */
+    "POWER9_v1.0",
 };
 };
 
 
 void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
 void spapr_cpu_core_class_init(ObjectClass *oc, void *data)

+ 4 - 0
hw/ppc/spapr_pci.c

@@ -1321,6 +1321,10 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
     _FDT(fdt_setprop(fdt, offset, "assigned-addresses",
     _FDT(fdt_setprop(fdt, offset, "assigned-addresses",
                      (uint8_t *)rp.assigned, rp.assigned_len));
                      (uint8_t *)rp.assigned, rp.assigned_len));
 
 
+    if (pci_is_express(dev)) {
+        _FDT(fdt_setprop_cell(fdt, offset, "ibm,pci-config-space-type", 0x1));
+    }
+
     return 0;
     return 0;
 }
 }
 
 

+ 1 - 0
include/exec/ram_addr.h

@@ -52,6 +52,7 @@ static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset)
     return (char *)block->host + offset;
     return (char *)block->host + offset;
 }
 }
 
 
+long qemu_getrampagesize(void);
 ram_addr_t last_ram_offset(void);
 ram_addr_t last_ram_offset(void);
 RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
 RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
                                    bool share, const char *mem_path,
                                    bool share, const char *mem_path,

+ 1 - 0
include/hw/ppc/spapr.h

@@ -62,6 +62,7 @@ struct sPAPRMachineState {
 
 
     void *htab;
     void *htab;
     uint32_t htab_shift;
     uint32_t htab_shift;
+    uint64_t patb_entry; /* Process tbl registed in H_REGISTER_PROCESS_TABLE */
     hwaddr rma_size;
     hwaddr rma_size;
     int vrma_adjust;
     int vrma_adjust;
     ssize_t rtas_size;
     ssize_t rtas_size;

+ 2 - 0
include/qemu/mmap-alloc.h

@@ -5,6 +5,8 @@
 
 
 size_t qemu_fd_getpagesize(int fd);
 size_t qemu_fd_getpagesize(int fd);
 
 
+size_t qemu_mempath_getpagesize(const char *mem_path);
+
 void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared);
 void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared);
 
 
 void qemu_ram_munmap(void *ptr, size_t size);
 void qemu_ram_munmap(void *ptr, size_t size);

+ 1 - 1
target/ppc/Makefile.objs

@@ -3,7 +3,7 @@ obj-y += cpu.o
 obj-y += translate.o
 obj-y += translate.o
 ifeq ($(CONFIG_SOFTMMU),y)
 ifeq ($(CONFIG_SOFTMMU),y)
 obj-y += machine.o mmu_helper.o mmu-hash32.o monitor.o arch_dump.o
 obj-y += machine.o mmu_helper.o mmu-hash32.o monitor.o arch_dump.o
-obj-$(TARGET_PPC64) += mmu-hash64.o compat.o
+obj-$(TARGET_PPC64) += mmu-hash64.o mmu-book3s-v3.o compat.o
 endif
 endif
 obj-$(CONFIG_KVM) += kvm.o
 obj-$(CONFIG_KVM) += kvm.o
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o

+ 11 - 5
target/ppc/compat.c

@@ -39,29 +39,35 @@ static const CompatInfo compat_table[] = {
      */
      */
     { /* POWER6, ISA2.05 */
     { /* POWER6, ISA2.05 */
         .pvr = CPU_POWERPC_LOGICAL_2_05,
         .pvr = CPU_POWERPC_LOGICAL_2_05,
-        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
-               | PCR_TM_DIS | PCR_VSX_DIS,
+        .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
+               PCR_COMPAT_2_05 | PCR_TM_DIS | PCR_VSX_DIS,
         .pcr_level = PCR_COMPAT_2_05,
         .pcr_level = PCR_COMPAT_2_05,
         .max_threads = 2,
         .max_threads = 2,
     },
     },
     { /* POWER7, ISA2.06 */
     { /* POWER7, ISA2.06 */
         .pvr = CPU_POWERPC_LOGICAL_2_06,
         .pvr = CPU_POWERPC_LOGICAL_2_06,
-        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+        .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
         .pcr_level = PCR_COMPAT_2_06,
         .pcr_level = PCR_COMPAT_2_06,
         .max_threads = 4,
         .max_threads = 4,
     },
     },
     {
     {
         .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
         .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
-        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+        .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
         .pcr_level = PCR_COMPAT_2_06,
         .pcr_level = PCR_COMPAT_2_06,
         .max_threads = 4,
         .max_threads = 4,
     },
     },
     { /* POWER8, ISA2.07 */
     { /* POWER8, ISA2.07 */
         .pvr = CPU_POWERPC_LOGICAL_2_07,
         .pvr = CPU_POWERPC_LOGICAL_2_07,
-        .pcr = PCR_COMPAT_2_07,
+        .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07,
         .pcr_level = PCR_COMPAT_2_07,
         .pcr_level = PCR_COMPAT_2_07,
         .max_threads = 8,
         .max_threads = 8,
     },
     },
+    { /* POWER9, ISA3.00 */
+        .pvr = CPU_POWERPC_LOGICAL_3_00,
+        .pcr = PCR_COMPAT_3_00,
+        .pcr_level = PCR_COMPAT_3_00,
+        .max_threads = 4,
+    },
 };
 };
 
 
 static const CompatInfo *compat_by_pvr(uint32_t pvr)
 static const CompatInfo *compat_by_pvr(uint32_t pvr)

+ 9 - 7
target/ppc/cpu-qom.h

@@ -71,6 +71,7 @@ enum powerpc_mmu_t {
 #define POWERPC_MMU_1TSEG    0x00020000
 #define POWERPC_MMU_1TSEG    0x00020000
 #define POWERPC_MMU_AMR      0x00040000
 #define POWERPC_MMU_AMR      0x00040000
 #define POWERPC_MMU_64K      0x00080000
 #define POWERPC_MMU_64K      0x00080000
+#define POWERPC_MMU_V3       0x00100000 /* ISA V3.00 MMU Support */
     /* 64 bits PowerPC MMU                                     */
     /* 64 bits PowerPC MMU                                     */
     POWERPC_MMU_64B        = POWERPC_MMU_64 | 0x00000001,
     POWERPC_MMU_64B        = POWERPC_MMU_64 | 0x00000001,
     /* Architecture 2.03 and later (has LPCR) */
     /* Architecture 2.03 and later (has LPCR) */
@@ -79,21 +80,22 @@ enum powerpc_mmu_t {
     POWERPC_MMU_2_06       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
     POWERPC_MMU_2_06       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
                              | POWERPC_MMU_64K
                              | POWERPC_MMU_64K
                              | POWERPC_MMU_AMR | 0x00000003,
                              | POWERPC_MMU_AMR | 0x00000003,
-    /* Architecture 2.06 "degraded" (no 1T segments)           */
-    POWERPC_MMU_2_06a      = POWERPC_MMU_64 | POWERPC_MMU_AMR
-                             | 0x00000003,
     /* Architecture 2.07 variant                               */
     /* Architecture 2.07 variant                               */
     POWERPC_MMU_2_07       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
     POWERPC_MMU_2_07       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
                              | POWERPC_MMU_64K
                              | POWERPC_MMU_64K
                              | POWERPC_MMU_AMR | 0x00000004,
                              | POWERPC_MMU_AMR | 0x00000004,
-    /* Architecture 2.07 "degraded" (no 1T segments)           */
-    POWERPC_MMU_2_07a      = POWERPC_MMU_64 | POWERPC_MMU_AMR
-                             | 0x00000004,
     /* Architecture 3.00 variant                               */
     /* Architecture 3.00 variant                               */
     POWERPC_MMU_3_00       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
     POWERPC_MMU_3_00       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
                              | POWERPC_MMU_64K
                              | POWERPC_MMU_64K
-                             | POWERPC_MMU_AMR | 0x00000005,
+                             | POWERPC_MMU_AMR | POWERPC_MMU_V3
+                             | 0x00000005,
 };
 };
+#define POWERPC_MMU_VER(x) ((x) & (POWERPC_MMU_64 | 0xFFFF))
+#define POWERPC_MMU_VER_64B POWERPC_MMU_VER(POWERPC_MMU_64B)
+#define POWERPC_MMU_VER_2_03 POWERPC_MMU_VER(POWERPC_MMU_2_03)
+#define POWERPC_MMU_VER_2_06 POWERPC_MMU_VER(POWERPC_MMU_2_06)
+#define POWERPC_MMU_VER_2_07 POWERPC_MMU_VER(POWERPC_MMU_2_07)
+#define POWERPC_MMU_VER_3_00 POWERPC_MMU_VER(POWERPC_MMU_3_00)
 
 
 /*****************************************************************************/
 /*****************************************************************************/
 /* Exception model                                                           */
 /* Exception model                                                           */

+ 17 - 0
target/ppc/cpu.h

@@ -473,6 +473,22 @@ struct ppc_slb_t {
 #endif
 #endif
 #endif
 #endif
 
 
+/* DSISR */
+#define DSISR_NOPTE              0x40000000
+/* Not permitted by access authority of encoded access authority */
+#define DSISR_PROTFAULT          0x08000000
+#define DSISR_ISSTORE            0x02000000
+/* Not permitted by virtual page class key protection */
+#define DSISR_AMR                0x00200000
+
+/* SRR1 error code fields */
+
+#define SRR1_NOPTE               DSISR_NOPTE
+/* Not permitted due to no-execute or guard bit set */
+#define SRR1_NOEXEC_GUARD        0x10000000
+#define SRR1_PROTFAULT           DSISR_PROTFAULT
+#define SRR1_IAMR                DSISR_AMR
+
 /* Facility Status and Control (FSCR) bits */
 /* Facility Status and Control (FSCR) bits */
 #define FSCR_EBB        (63 - 56) /* Event-Based Branch Facility */
 #define FSCR_EBB        (63 - 56) /* Event-Based Branch Facility */
 #define FSCR_TAR        (63 - 55) /* Target Address Register */
 #define FSCR_TAR        (63 - 55) /* Target Address Register */
@@ -1216,6 +1232,7 @@ struct PPCVirtualHypervisorClass {
                         hwaddr ptex, int n);
                         hwaddr ptex, int n);
     void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
     void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
                        uint64_t pte0, uint64_t pte1);
                        uint64_t pte0, uint64_t pte1);
+    uint64_t (*get_patbe)(PPCVirtualHypervisor *vhyp);
 };
 };
 
 
 #define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
 #define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"

+ 46 - 167
target/ppc/fpu_helper.c

@@ -743,178 +743,62 @@ uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
     return do_fri(env, arg, float_round_down);
     return do_fri(env, arg, float_round_down);
 }
 }
 
 
-/* fmadd - fmadd. */
-uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
-                      uint64_t arg3)
+static void float64_maddsub_update_excp(CPUPPCState *env, float64 arg1,
+                                        float64 arg2, float64 arg3,
+                                        unsigned int madd_flags)
 {
 {
-    CPU_DoubleU farg1, farg2, farg3;
-
-    farg1.ll = arg1;
-    farg2.ll = arg2;
-    farg3.ll = arg3;
-
-    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
-                 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
-        /* Multiplication of zero by infinity */
-        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
-    } else {
-        if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
-                     float64_is_signaling_nan(farg2.d, &env->fp_status) ||
-                     float64_is_signaling_nan(farg3.d, &env->fp_status))) {
-            /* sNaN operation */
-            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
-        }
-        /* This is the way the PowerPC specification defines it */
-        float128 ft0_128, ft1_128;
-
-        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
-        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
-        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
-        if (unlikely(float128_is_infinity(ft0_128) &&
-                     float64_is_infinity(farg3.d) &&
-                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
-            /* Magnitude subtraction of infinities */
-            farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
-        } else {
-            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
-            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
-            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
-        }
-    }
-
-    return farg1.ll;
-}
-
-/* fmsub - fmsub. */
-uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
-                      uint64_t arg3)
-{
-    CPU_DoubleU farg1, farg2, farg3;
-
-    farg1.ll = arg1;
-    farg2.ll = arg2;
-    farg3.ll = arg3;
-
-    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
-                 (float64_is_zero(farg1.d) &&
-                  float64_is_infinity(farg2.d)))) {
+    if (unlikely((float64_is_infinity(arg1) && float64_is_zero(arg2)) ||
+                 (float64_is_zero(arg1) && float64_is_infinity(arg2)))) {
         /* Multiplication of zero by infinity */
         /* Multiplication of zero by infinity */
-        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
-    } else {
-        if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
-                     float64_is_signaling_nan(farg2.d, &env->fp_status) ||
-                     float64_is_signaling_nan(farg3.d, &env->fp_status))) {
-            /* sNaN operation */
-            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        arg1 = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+    } else if (unlikely(float64_is_signaling_nan(arg1, &env->fp_status) ||
+                        float64_is_signaling_nan(arg2, &env->fp_status) ||
+                        float64_is_signaling_nan(arg3, &env->fp_status))) {
+        /* sNaN operation */
+        float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+    } else if ((float64_is_infinity(arg1) || float64_is_infinity(arg2)) &&
+               float64_is_infinity(arg3)) {
+        uint8_t aSign, bSign, cSign;
+
+        aSign = float64_is_neg(arg1);
+        bSign = float64_is_neg(arg2);
+        cSign = float64_is_neg(arg3);
+        if (madd_flags & float_muladd_negate_c) {
+            cSign ^= 1;
         }
         }
-        /* This is the way the PowerPC specification defines it */
-        float128 ft0_128, ft1_128;
-
-        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
-        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
-        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
-        if (unlikely(float128_is_infinity(ft0_128) &&
-                     float64_is_infinity(farg3.d) &&
-                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
-            /* Magnitude subtraction of infinities */
-            farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
-        } else {
-            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
-            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
-            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+        if (aSign ^ bSign ^ cSign) {
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
         }
         }
     }
     }
-    return farg1.ll;
 }
 }
 
 
-/* fnmadd - fnmadd. */
-uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
-                       uint64_t arg3)
-{
-    CPU_DoubleU farg1, farg2, farg3;
-
-    farg1.ll = arg1;
-    farg2.ll = arg2;
-    farg3.ll = arg3;
-
-    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
-                 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
-        /* Multiplication of zero by infinity */
-        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
-    } else {
-        if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
-                     float64_is_signaling_nan(farg2.d, &env->fp_status) ||
-                     float64_is_signaling_nan(farg3.d, &env->fp_status))) {
-            /* sNaN operation */
-            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
-        }
-        /* This is the way the PowerPC specification defines it */
-        float128 ft0_128, ft1_128;
-
-        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
-        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
-        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
-        if (unlikely(float128_is_infinity(ft0_128) &&
-                     float64_is_infinity(farg3.d) &&
-                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
-            /* Magnitude subtraction of infinities */
-            farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
-        } else {
-            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
-            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
-            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
-        }
-        if (likely(!float64_is_any_nan(farg1.d))) {
-            farg1.d = float64_chs(farg1.d);
-        }
-    }
-    return farg1.ll;
+#define FPU_FMADD(op, madd_flags)                                       \
+uint64_t helper_##op(CPUPPCState *env, uint64_t arg1,                   \
+                     uint64_t arg2, uint64_t arg3)                      \
+{                                                                       \
+    uint32_t flags;                                                     \
+    float64 ret = float64_muladd(arg1, arg2, arg3, madd_flags,          \
+                                 &env->fp_status);                      \
+    flags = get_float_exception_flags(&env->fp_status);                 \
+    if (flags) {                                                        \
+        if (flags & float_flag_invalid) {                               \
+            float64_maddsub_update_excp(env, arg1, arg2, arg3,          \
+                                        madd_flags);                    \
+        }                                                               \
+        float_check_status(env);                                        \
+    }                                                                   \
+    return ret;                                                         \
 }
 }
 
 
-/* fnmsub - fnmsub. */
-uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
-                       uint64_t arg3)
-{
-    CPU_DoubleU farg1, farg2, farg3;
-
-    farg1.ll = arg1;
-    farg2.ll = arg2;
-    farg3.ll = arg3;
+#define MADD_FLGS 0
+#define MSUB_FLGS float_muladd_negate_c
+#define NMADD_FLGS float_muladd_negate_result
+#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
 
 
-    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
-                 (float64_is_zero(farg1.d) &&
-                  float64_is_infinity(farg2.d)))) {
-        /* Multiplication of zero by infinity */
-        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
-    } else {
-        if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
-                     float64_is_signaling_nan(farg2.d, &env->fp_status) ||
-                     float64_is_signaling_nan(farg3.d, &env->fp_status))) {
-            /* sNaN operation */
-            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
-        }
-        /* This is the way the PowerPC specification defines it */
-        float128 ft0_128, ft1_128;
-
-        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
-        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
-        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
-        if (unlikely(float128_is_infinity(ft0_128) &&
-                     float64_is_infinity(farg3.d) &&
-                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
-            /* Magnitude subtraction of infinities */
-            farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
-        } else {
-            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
-            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
-            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
-        }
-        if (likely(!float64_is_any_nan(farg1.d))) {
-            farg1.d = float64_chs(farg1.d);
-        }
-    }
-    return farg1.ll;
-}
+FPU_FMADD(fmadd, MADD_FLGS)
+FPU_FMADD(fnmadd, NMADD_FLGS)
+FPU_FMADD(fmsub, MSUB_FLGS)
+FPU_FMADD(fnmsub, NMSUB_FLGS)
 
 
 /* frsp - frsp. */
 /* frsp - frsp. */
 uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
 uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
@@ -2384,11 +2268,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
     float_check_status(env);                                                  \
     float_check_status(env);                                                  \
 }
 }
 
 
-#define MADD_FLGS 0
-#define MSUB_FLGS float_muladd_negate_c
-#define NMADD_FLGS float_muladd_negate_result
-#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
-
 VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0)
 VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0)
 VSX_MADD(xsmaddmdp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 0)
 VSX_MADD(xsmaddmdp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 0)
 VSX_MADD(xsmsubadp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 0)
 VSX_MADD(xsmsubadp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 0)

+ 9 - 108
target/ppc/kvm.c

@@ -28,7 +28,6 @@
 #include "qemu/timer.h"
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/hw_accel.h"
 #include "sysemu/hw_accel.h"
-#include "sysemu/numa.h"
 #include "kvm_ppc.h"
 #include "kvm_ppc.h"
 #include "sysemu/cpus.h"
 #include "sysemu/cpus.h"
 #include "sysemu/device_tree.h"
 #include "sysemu/device_tree.h"
@@ -43,8 +42,10 @@
 #include "trace.h"
 #include "trace.h"
 #include "exec/gdbstub.h"
 #include "exec/gdbstub.h"
 #include "exec/memattrs.h"
 #include "exec/memattrs.h"
+#include "exec/ram_addr.h"
 #include "sysemu/hostmem.h"
 #include "sysemu/hostmem.h"
 #include "qemu/cutils.h"
 #include "qemu/cutils.h"
+#include "qemu/mmap-alloc.h"
 #if defined(TARGET_PPC64)
 #if defined(TARGET_PPC64)
 #include "hw/ppc/spapr_cpu_core.h"
 #include "hw/ppc/spapr_cpu_core.h"
 #endif
 #endif
@@ -282,8 +283,8 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu,
             info->flags |= KVM_PPC_1T_SEGMENTS;
             info->flags |= KVM_PPC_1T_SEGMENTS;
         }
         }
 
 
-        if (env->mmu_model == POWERPC_MMU_2_06 ||
-            env->mmu_model == POWERPC_MMU_2_07) {
+        if (POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_06 ||
+           POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_07) {
             info->slb_size = 32;
             info->slb_size = 32;
         } else {
         } else {
             info->slb_size = 64;
             info->slb_size = 64;
@@ -297,8 +298,8 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu,
         i++;
         i++;
 
 
         /* 64K on MMU 2.06 and later */
         /* 64K on MMU 2.06 and later */
-        if (env->mmu_model == POWERPC_MMU_2_06 ||
-            env->mmu_model == POWERPC_MMU_2_07) {
+        if (POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_06 ||
+            POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_07) {
             info->sps[i].page_shift = 16;
             info->sps[i].page_shift = 16;
             info->sps[i].slb_enc = 0x110;
             info->sps[i].slb_enc = 0x110;
             info->sps[i].enc[0].page_shift = 16;
             info->sps[i].enc[0].page_shift = 16;
@@ -329,106 +330,6 @@ static void kvm_get_smmu_info(PowerPCCPU *cpu, struct kvm_ppc_smmu_info *info)
     kvm_get_fallback_smmu_info(cpu, info);
     kvm_get_fallback_smmu_info(cpu, info);
 }
 }
 
 
-static long gethugepagesize(const char *mem_path)
-{
-    struct statfs fs;
-    int ret;
-
-    do {
-        ret = statfs(mem_path, &fs);
-    } while (ret != 0 && errno == EINTR);
-
-    if (ret != 0) {
-        fprintf(stderr, "Couldn't statfs() memory path: %s\n",
-                strerror(errno));
-        exit(1);
-    }
-
-#define HUGETLBFS_MAGIC       0x958458f6
-
-    if (fs.f_type != HUGETLBFS_MAGIC) {
-        /* Explicit mempath, but it's ordinary pages */
-        return getpagesize();
-    }
-
-    /* It's hugepage, return the huge page size */
-    return fs.f_bsize;
-}
-
-/*
- * FIXME TOCTTOU: this iterates over memory backends' mem-path, which
- * may or may not name the same files / on the same filesystem now as
- * when we actually open and map them.  Iterate over the file
- * descriptors instead, and use qemu_fd_getpagesize().
- */
-static int find_max_supported_pagesize(Object *obj, void *opaque)
-{
-    char *mem_path;
-    long *hpsize_min = opaque;
-
-    if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
-        mem_path = object_property_get_str(obj, "mem-path", NULL);
-        if (mem_path) {
-            long hpsize = gethugepagesize(mem_path);
-            if (hpsize < *hpsize_min) {
-                *hpsize_min = hpsize;
-            }
-        } else {
-            *hpsize_min = getpagesize();
-        }
-    }
-
-    return 0;
-}
-
-static long getrampagesize(void)
-{
-    long hpsize = LONG_MAX;
-    long mainrampagesize;
-    Object *memdev_root;
-
-    if (mem_path) {
-        mainrampagesize = gethugepagesize(mem_path);
-    } else {
-        mainrampagesize = getpagesize();
-    }
-
-    /* it's possible we have memory-backend objects with
-     * hugepage-backed RAM. these may get mapped into system
-     * address space via -numa parameters or memory hotplug
-     * hooks. we want to take these into account, but we
-     * also want to make sure these supported hugepage
-     * sizes are applicable across the entire range of memory
-     * we may boot from, so we take the min across all
-     * backends, and assume normal pages in cases where a
-     * backend isn't backed by hugepages.
-     */
-    memdev_root = object_resolve_path("/objects", NULL);
-    if (memdev_root) {
-        object_child_foreach(memdev_root, find_max_supported_pagesize, &hpsize);
-    }
-    if (hpsize == LONG_MAX) {
-        /* No additional memory regions found ==> Report main RAM page size */
-        return mainrampagesize;
-    }
-
-    /* If NUMA is disabled or the NUMA nodes are not backed with a
-     * memory-backend, then there is at least one node using "normal" RAM,
-     * so if its page size is smaller we have got to report that size instead.
-     */
-    if (hpsize > mainrampagesize &&
-        (nb_numa_nodes == 0 || numa_info[0].node_memdev == NULL)) {
-        static bool warned;
-        if (!warned) {
-            error_report("Huge page support disabled (n/a for main memory).");
-            warned = true;
-        }
-        return mainrampagesize;
-    }
-
-    return hpsize;
-}
-
 static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift)
 static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift)
 {
 {
     if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) {
     if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) {
@@ -460,7 +361,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
     }
     }
 
 
     if (!max_cpu_page_size) {
     if (!max_cpu_page_size) {
-        max_cpu_page_size = getrampagesize();
+        max_cpu_page_size = qemu_getrampagesize();
     }
     }
 
 
     /* Convert to QEMU form */
     /* Convert to QEMU form */
@@ -521,7 +422,7 @@ bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
     long pagesize;
     long pagesize;
 
 
     if (mempath) {
     if (mempath) {
-        pagesize = gethugepagesize(mempath);
+        pagesize = qemu_mempath_getpagesize(mempath);
     } else {
     } else {
         pagesize = getpagesize();
         pagesize = getpagesize();
     }
     }
@@ -2205,7 +2106,7 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
     /* Find the largest hardware supported page size that's less than
     /* Find the largest hardware supported page size that's less than
      * or equal to the (logical) backing page size of guest RAM */
      * or equal to the (logical) backing page size of guest RAM */
     kvm_get_smmu_info(POWERPC_CPU(first_cpu), &info);
     kvm_get_smmu_info(POWERPC_CPU(first_cpu), &info);
-    rampagesize = getrampagesize();
+    rampagesize = qemu_getrampagesize();
     best_page_shift = 0;
     best_page_shift = 0;
 
 
     for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
     for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {

+ 37 - 0
target/ppc/mmu-book3s-v3.c

@@ -0,0 +1,37 @@
+/*
+ *  PowerPC ISAV3 BookS emulation generic mmu helpers for qemu.
+ *
+ *  Copyright (c) 2017 Suraj Jitindar Singh, IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "mmu-hash64.h"
+#include "mmu-book3s-v3.h"
+#include "qemu/error-report.h"
+
+int ppc64_v3_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
+                              int mmu_idx)
+{
+    if (ppc64_radix_guest(cpu)) { /* Guest uses radix */
+        /* TODO - Unsupported */
+        error_report("Guest Radix Support Unimplemented");
+        exit(1);
+    } else { /* Guest uses hash */
+        return ppc_hash64_handle_mmu_fault(cpu, eaddr, rwx, mmu_idx);
+    }
+}

+ 50 - 0
target/ppc/mmu-book3s-v3.h

@@ -0,0 +1,50 @@
+/*
+ *  PowerPC ISAV3 BookS emulation generic mmu definitions for qemu.
+ *
+ *  Copyright (c) 2017 Suraj Jitindar Singh, IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MMU_H
+#define MMU_H
+
+#ifndef CONFIG_USER_ONLY
+
+/* Partition Table Entry Fields */
+#define PATBE1_GR 0x8000000000000000
+
+#ifdef TARGET_PPC64
+
+static inline bool ppc64_use_proc_tbl(PowerPCCPU *cpu)
+{
+    return !!(cpu->env.spr[SPR_LPCR] & LPCR_UPRT);
+}
+
+static inline bool ppc64_radix_guest(PowerPCCPU *cpu)
+{
+    PPCVirtualHypervisorClass *vhc =
+        PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+
+    return !!(vhc->get_patbe(cpu->vhyp) & PATBE1_GR);
+}
+
+int ppc64_v3_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
+                              int mmu_idx);
+
+#endif /* TARGET_PPC64 */
+
+#endif /* CONFIG_USER_ONLY */
+
+#endif /* MMU_H */

+ 85 - 32
target/ppc/mmu-hash64.c

@@ -28,6 +28,7 @@
 #include "mmu-hash64.h"
 #include "mmu-hash64.h"
 #include "exec/log.h"
 #include "exec/log.h"
 #include "hw/hw.h"
 #include "hw/hw.h"
+#include "mmu-book3s-v3.h"
 
 
 //#define DEBUG_SLB
 //#define DEBUG_SLB
 
 
@@ -289,6 +290,16 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
     return rt;
     return rt;
 }
 }
 
 
+/* Check No-Execute or Guarded Storage */
+static inline int ppc_hash64_pte_noexec_guard(PowerPCCPU *cpu,
+                                              ppc_hash_pte64_t pte)
+{
+    /* Exec permissions CANNOT take away read or write permissions */
+    return (pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G) ?
+            PAGE_READ | PAGE_WRITE : PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+}
+
+/* Check Basic Storage Protection */
 static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
 static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
                                ppc_slb_t *slb, ppc_hash_pte64_t pte)
                                ppc_slb_t *slb, ppc_hash_pte64_t pte)
 {
 {
@@ -307,41 +318,51 @@ static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
         case 0x0:
         case 0x0:
         case 0x1:
         case 0x1:
         case 0x2:
         case 0x2:
-            prot = PAGE_READ | PAGE_WRITE;
+            prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
             break;
             break;
 
 
         case 0x3:
         case 0x3:
         case 0x6:
         case 0x6:
-            prot = PAGE_READ;
+            prot = PAGE_READ | PAGE_EXEC;
             break;
             break;
         }
         }
     } else {
     } else {
         switch (pp) {
         switch (pp) {
         case 0x0:
         case 0x0:
         case 0x6:
         case 0x6:
-            prot = 0;
             break;
             break;
 
 
         case 0x1:
         case 0x1:
         case 0x3:
         case 0x3:
-            prot = PAGE_READ;
+            prot = PAGE_READ | PAGE_EXEC;
             break;
             break;
 
 
         case 0x2:
         case 0x2:
-            prot = PAGE_READ | PAGE_WRITE;
+            prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
             break;
             break;
         }
         }
     }
     }
 
 
-    /* No execute if either noexec or guarded bits set */
-    if (!(pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G)
-        || (slb->vsid & SLB_VSID_N)) {
-        prot |= PAGE_EXEC;
-    }
-
     return prot;
     return prot;
 }
 }
 
 
+/* Check the instruction access permissions specified in the IAMR */
+static int ppc_hash64_iamr_prot(PowerPCCPU *cpu, int key)
+{
+    CPUPPCState *env = &cpu->env;
+    int iamr_bits = (env->spr[SPR_IAMR] >> 2 * (31 - key)) & 0x3;
+
+    /*
+     * An instruction fetch is permitted if the IAMR bit is 0.
+     * If the bit is set, return PAGE_READ | PAGE_WRITE because this bit
+     * can only take away EXEC permissions not READ or WRITE permissions.
+     * If bit is cleared return PAGE_READ | PAGE_WRITE | PAGE_EXEC since
+     * EXEC permissions are allowed.
+     */
+    return (iamr_bits & 0x1) ? PAGE_READ | PAGE_WRITE :
+                               PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+}
+
 static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
 static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
 {
 {
     CPUPPCState *env = &cpu->env;
     CPUPPCState *env = &cpu->env;
@@ -374,6 +395,21 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
         prot &= ~PAGE_READ;
         prot &= ~PAGE_READ;
     }
     }
 
 
+    switch (env->mmu_model) {
+    /*
+     * MMU version 2.07 and later support IAMR
+     * Check if the IAMR allows the instruction access - it will return
+     * PAGE_EXEC if it doesn't (and thus that bit will be cleared) or 0
+     * if it does (and prot will be unchanged indicating execution support).
+     */
+    case POWERPC_MMU_2_07:
+    case POWERPC_MMU_3_00:
+        prot &= ppc_hash64_iamr_prot(cpu, key);
+        break;
+    default:
+        break;
+    }
+
     return prot;
     return prot;
 }
 }
 
 
@@ -664,8 +700,8 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
     unsigned apshift;
     unsigned apshift;
     hwaddr ptex;
     hwaddr ptex;
     ppc_hash_pte64_t pte;
     ppc_hash_pte64_t pte;
-    int pp_prot, amr_prot, prot;
-    uint64_t new_pte1, dsisr;
+    int exec_prot, pp_prot, amr_prot, prot;
+    uint64_t new_pte1;
     const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
     const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
     hwaddr raddr;
     hwaddr raddr;
 
 
@@ -706,11 +742,11 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
             } else {
             } else {
                 /* The access failed, generate the approriate interrupt */
                 /* The access failed, generate the approriate interrupt */
                 if (rwx == 2) {
                 if (rwx == 2) {
-                    ppc_hash64_set_isi(cs, env, 0x08000000);
+                    ppc_hash64_set_isi(cs, env, SRR1_PROTFAULT);
                 } else {
                 } else {
-                    dsisr = 0x08000000;
+                    int dsisr = DSISR_PROTFAULT;
                     if (rwx == 1) {
                     if (rwx == 1) {
-                        dsisr |= 0x02000000;
+                        dsisr |= DSISR_ISSTORE;
                     }
                     }
                     ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
                     ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
                 }
                 }
@@ -726,6 +762,13 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
     /* 2. Translation is on, so look up the SLB */
     /* 2. Translation is on, so look up the SLB */
     slb = slb_lookup(cpu, eaddr);
     slb = slb_lookup(cpu, eaddr);
     if (!slb) {
     if (!slb) {
+        /* No entry found, check if in-memory segment tables are in use */
+        if ((env->mmu_model & POWERPC_MMU_V3) && ppc64_use_proc_tbl(cpu)) {
+            /* TODO - Unsupported */
+            error_report("Segment Table Support Unimplemented");
+            exit(1);
+        }
+        /* Segment still not found, generate the appropriate interrupt */
         if (rwx == 2) {
         if (rwx == 2) {
             cs->exception_index = POWERPC_EXCP_ISEG;
             cs->exception_index = POWERPC_EXCP_ISEG;
             env->error_code = 0;
             env->error_code = 0;
@@ -741,19 +784,19 @@ skip_slb_search:
 
 
     /* 3. Check for segment level no-execute violation */
     /* 3. Check for segment level no-execute violation */
     if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
     if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
-        ppc_hash64_set_isi(cs, env, 0x10000000);
+        ppc_hash64_set_isi(cs, env, SRR1_NOEXEC_GUARD);
         return 1;
         return 1;
     }
     }
 
 
     /* 4. Locate the PTE in the hash table */
     /* 4. Locate the PTE in the hash table */
     ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
     ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
     if (ptex == -1) {
     if (ptex == -1) {
-        dsisr = 0x40000000;
         if (rwx == 2) {
         if (rwx == 2) {
-            ppc_hash64_set_isi(cs, env, dsisr);
+            ppc_hash64_set_isi(cs, env, SRR1_NOPTE);
         } else {
         } else {
+            int dsisr = DSISR_NOPTE;
             if (rwx == 1) {
             if (rwx == 1) {
-                dsisr |= 0x02000000;
+                dsisr |= DSISR_ISSTORE;
             }
             }
             ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
             ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
         }
         }
@@ -764,25 +807,35 @@ skip_slb_search:
 
 
     /* 5. Check access permissions */
     /* 5. Check access permissions */
 
 
+    exec_prot = ppc_hash64_pte_noexec_guard(cpu, pte);
     pp_prot = ppc_hash64_pte_prot(cpu, slb, pte);
     pp_prot = ppc_hash64_pte_prot(cpu, slb, pte);
     amr_prot = ppc_hash64_amr_prot(cpu, pte);
     amr_prot = ppc_hash64_amr_prot(cpu, pte);
-    prot = pp_prot & amr_prot;
+    prot = exec_prot & pp_prot & amr_prot;
 
 
     if ((need_prot[rwx] & ~prot) != 0) {
     if ((need_prot[rwx] & ~prot) != 0) {
         /* Access right violation */
         /* Access right violation */
         qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
         qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
         if (rwx == 2) {
         if (rwx == 2) {
-            ppc_hash64_set_isi(cs, env, 0x08000000);
+            int srr1 = 0;
+            if (PAGE_EXEC & ~exec_prot) {
+                srr1 |= SRR1_NOEXEC_GUARD; /* Access violates noexec or guard */
+            } else if (PAGE_EXEC & ~pp_prot) {
+                srr1 |= SRR1_PROTFAULT; /* Access violates access authority */
+            }
+            if (PAGE_EXEC & ~amr_prot) {
+                srr1 |= SRR1_IAMR; /* Access violates virt pg class key prot */
+            }
+            ppc_hash64_set_isi(cs, env, srr1);
         } else {
         } else {
-            dsisr = 0;
+            int dsisr = 0;
             if (need_prot[rwx] & ~pp_prot) {
             if (need_prot[rwx] & ~pp_prot) {
-                dsisr |= 0x08000000;
+                dsisr |= DSISR_PROTFAULT;
             }
             }
             if (rwx == 1) {
             if (rwx == 1) {
-                dsisr |= 0x02000000;
+                dsisr |= DSISR_ISSTORE;
             }
             }
             if (need_prot[rwx] & ~amr_prot) {
             if (need_prot[rwx] & ~amr_prot) {
-                dsisr |= 0x00200000;
+                dsisr |= DSISR_AMR;
             }
             }
             ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
             ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
         }
         }
@@ -979,8 +1032,8 @@ void helper_store_lpcr(CPUPPCState *env, target_ulong val)
     uint64_t lpcr = 0;
     uint64_t lpcr = 0;
 
 
     /* Filter out bits */
     /* Filter out bits */
-    switch (env->mmu_model) {
-    case POWERPC_MMU_64B: /* 970 */
+    switch (POWERPC_MMU_VER(env->mmu_model)) {
+    case POWERPC_MMU_VER_64B: /* 970 */
         if (val & 0x40) {
         if (val & 0x40) {
             lpcr |= LPCR_LPES0;
             lpcr |= LPCR_LPES0;
         }
         }
@@ -1006,26 +1059,26 @@ void helper_store_lpcr(CPUPPCState *env, target_ulong val)
          * to dig HRMOR out of HID5
          * to dig HRMOR out of HID5
          */
          */
         break;
         break;
-    case POWERPC_MMU_2_03: /* P5p */
+    case POWERPC_MMU_VER_2_03: /* P5p */
         lpcr = val & (LPCR_RMLS | LPCR_ILE |
         lpcr = val & (LPCR_RMLS | LPCR_ILE |
                       LPCR_LPES0 | LPCR_LPES1 |
                       LPCR_LPES0 | LPCR_LPES1 |
                       LPCR_RMI | LPCR_HDICE);
                       LPCR_RMI | LPCR_HDICE);
         break;
         break;
-    case POWERPC_MMU_2_06: /* P7 */
+    case POWERPC_MMU_VER_2_06: /* P7 */
         lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
         lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
                       LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
                       LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
                       LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
                       LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
                       LPCR_MER | LPCR_TC |
                       LPCR_MER | LPCR_TC |
                       LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE);
                       LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE);
         break;
         break;
-    case POWERPC_MMU_2_07: /* P8 */
+    case POWERPC_MMU_VER_2_07: /* P8 */
         lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
         lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
                       LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
                       LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
                       LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
                       LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
                       LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
                       LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
                       LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE);
                       LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE);
         break;
         break;
-    case POWERPC_MMU_3_00: /* P9 */
+    case POWERPC_MMU_VER_3_00: /* P9 */
         lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
         lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
                       (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
                       (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
                       LPCR_UPRT | LPCR_EVIRT | LPCR_ONL |
                       LPCR_UPRT | LPCR_EVIRT | LPCR_ONL |

+ 42 - 40
target/ppc/mmu_helper.c

@@ -29,6 +29,7 @@
 #include "exec/log.h"
 #include "exec/log.h"
 #include "helper_regs.h"
 #include "helper_regs.h"
 #include "qemu/error-report.h"
 #include "qemu/error-report.h"
+#include "mmu-book3s-v3.h"
 
 
 //#define DEBUG_MMU
 //#define DEBUG_MMU
 //#define DEBUG_BATS
 //#define DEBUG_BATS
@@ -1265,7 +1266,7 @@ static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
 
 
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
 {
 {
-    switch (env->mmu_model) {
+    switch (POWERPC_MMU_VER(env->mmu_model)) {
     case POWERPC_MMU_BOOKE:
     case POWERPC_MMU_BOOKE:
         mmubooke_dump_mmu(f, cpu_fprintf, env);
         mmubooke_dump_mmu(f, cpu_fprintf, env);
         break;
         break;
@@ -1277,14 +1278,19 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
         mmu6xx_dump_mmu(f, cpu_fprintf, env);
         mmu6xx_dump_mmu(f, cpu_fprintf, env);
         break;
         break;
 #if defined(TARGET_PPC64)
 #if defined(TARGET_PPC64)
-    case POWERPC_MMU_64B:
-    case POWERPC_MMU_2_03:
-    case POWERPC_MMU_2_06:
-    case POWERPC_MMU_2_06a:
-    case POWERPC_MMU_2_07:
-    case POWERPC_MMU_2_07a:
+    case POWERPC_MMU_VER_64B:
+    case POWERPC_MMU_VER_2_03:
+    case POWERPC_MMU_VER_2_06:
+    case POWERPC_MMU_VER_2_07:
         dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
         dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
         break;
         break;
+    case POWERPC_MMU_VER_3_00:
+        if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
+            /* TODO - Unsupported */
+        } else {
+            dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
+            break;
+        }
 #endif
 #endif
     default:
     default:
         qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
         qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
@@ -1417,15 +1423,20 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
     CPUPPCState *env = &cpu->env;
     CPUPPCState *env = &cpu->env;
     mmu_ctx_t ctx;
     mmu_ctx_t ctx;
 
 
-    switch (env->mmu_model) {
+    switch (POWERPC_MMU_VER(env->mmu_model)) {
 #if defined(TARGET_PPC64)
 #if defined(TARGET_PPC64)
-    case POWERPC_MMU_64B:
-    case POWERPC_MMU_2_03:
-    case POWERPC_MMU_2_06:
-    case POWERPC_MMU_2_06a:
-    case POWERPC_MMU_2_07:
-    case POWERPC_MMU_2_07a:
+    case POWERPC_MMU_VER_64B:
+    case POWERPC_MMU_VER_2_03:
+    case POWERPC_MMU_VER_2_06:
+    case POWERPC_MMU_VER_2_07:
         return ppc_hash64_get_phys_page_debug(cpu, addr);
         return ppc_hash64_get_phys_page_debug(cpu, addr);
+    case POWERPC_MMU_VER_3_00:
+        if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
+            /* TODO - Unsupported */
+        } else {
+            return ppc_hash64_get_phys_page_debug(cpu, addr);
+        }
+        break;
 #endif
 #endif
 
 
     case POWERPC_MMU_32B:
     case POWERPC_MMU_32B:
@@ -1909,6 +1920,12 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
 {
 {
     PowerPCCPU *cpu = ppc_env_get_cpu(env);
     PowerPCCPU *cpu = ppc_env_get_cpu(env);
 
 
+#if defined(TARGET_PPC64)
+    if (env->mmu_model & POWERPC_MMU_64) {
+        env->tlb_need_flush = 0;
+        tlb_flush(CPU(cpu));
+    } else
+#endif /* defined(TARGET_PPC64) */
     switch (env->mmu_model) {
     switch (env->mmu_model) {
     case POWERPC_MMU_SOFT_6xx:
     case POWERPC_MMU_SOFT_6xx:
     case POWERPC_MMU_SOFT_74xx:
     case POWERPC_MMU_SOFT_74xx:
@@ -1933,21 +1950,12 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
         break;
         break;
     case POWERPC_MMU_32B:
     case POWERPC_MMU_32B:
     case POWERPC_MMU_601:
     case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
-    case POWERPC_MMU_64B:
-    case POWERPC_MMU_2_03:
-    case POWERPC_MMU_2_06:
-    case POWERPC_MMU_2_06a:
-    case POWERPC_MMU_2_07:
-    case POWERPC_MMU_2_07a:
-    case POWERPC_MMU_3_00:
-#endif /* defined(TARGET_PPC64) */
         env->tlb_need_flush = 0;
         env->tlb_need_flush = 0;
         tlb_flush(CPU(cpu));
         tlb_flush(CPU(cpu));
         break;
         break;
     default:
     default:
         /* XXX: TODO */
         /* XXX: TODO */
-        cpu_abort(CPU(cpu), "Unknown MMU model %d\n", env->mmu_model);
+        cpu_abort(CPU(cpu), "Unknown MMU model %x\n", env->mmu_model);
         break;
         break;
     }
     }
 }
 }
@@ -1956,6 +1964,16 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
 {
 {
 #if !defined(FLUSH_ALL_TLBS)
 #if !defined(FLUSH_ALL_TLBS)
     addr &= TARGET_PAGE_MASK;
     addr &= TARGET_PAGE_MASK;
+#if defined(TARGET_PPC64)
+    if (env->mmu_model & POWERPC_MMU_64) {
+        /* tlbie invalidate TLBs for all segments */
+        /* XXX: given the fact that there are too many segments to invalidate,
+         *      and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
+         *      we just invalidate all TLBs
+         */
+        env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
+    } else
+#endif /* defined(TARGET_PPC64) */
     switch (env->mmu_model) {
     switch (env->mmu_model) {
     case POWERPC_MMU_SOFT_6xx:
     case POWERPC_MMU_SOFT_6xx:
     case POWERPC_MMU_SOFT_74xx:
     case POWERPC_MMU_SOFT_74xx:
@@ -1973,22 +1991,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
          */
          */
         env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
         env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
         break;
         break;
-#if defined(TARGET_PPC64)
-    case POWERPC_MMU_64B:
-    case POWERPC_MMU_2_03:
-    case POWERPC_MMU_2_06:
-    case POWERPC_MMU_2_06a:
-    case POWERPC_MMU_2_07:
-    case POWERPC_MMU_2_07a:
-    case POWERPC_MMU_3_00:
-        /* tlbie invalidate TLBs for all segments */
-        /* XXX: given the fact that there are too many segments to invalidate,
-         *      and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
-         *      we just invalidate all TLBs
-         */
-        env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
-        break;
-#endif /* defined(TARGET_PPC64) */
     default:
     default:
         /* Should never reach here with other MMU models */
         /* Should never reach here with other MMU models */
         assert(0);
         assert(0);

+ 10 - 9
target/ppc/translate.c

@@ -7078,21 +7078,22 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
     if (env->spr_cb[SPR_LPCR].name)
     if (env->spr_cb[SPR_LPCR].name)
         cpu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
         cpu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
 
 
-    switch (env->mmu_model) {
+    switch (POWERPC_MMU_VER(env->mmu_model)) {
     case POWERPC_MMU_32B:
     case POWERPC_MMU_32B:
     case POWERPC_MMU_601:
     case POWERPC_MMU_601:
     case POWERPC_MMU_SOFT_6xx:
     case POWERPC_MMU_SOFT_6xx:
     case POWERPC_MMU_SOFT_74xx:
     case POWERPC_MMU_SOFT_74xx:
 #if defined(TARGET_PPC64)
 #if defined(TARGET_PPC64)
-    case POWERPC_MMU_64B:
-    case POWERPC_MMU_2_03:
-    case POWERPC_MMU_2_06:
-    case POWERPC_MMU_2_06a:
-    case POWERPC_MMU_2_07:
-    case POWERPC_MMU_2_07a:
+    case POWERPC_MMU_VER_64B:
+    case POWERPC_MMU_VER_2_03:
+    case POWERPC_MMU_VER_2_06:
+    case POWERPC_MMU_VER_2_07:
+    case POWERPC_MMU_VER_3_00:
 #endif
 #endif
-        cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "   DAR " TARGET_FMT_lx
-                       "  DSISR " TARGET_FMT_lx "\n", env->spr[SPR_SDR1],
+        if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */
+            cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]);
+        }
+        cpu_fprintf(f, "  DAR " TARGET_FMT_lx "  DSISR " TARGET_FMT_lx "\n",
                     env->spr[SPR_DAR], env->spr[SPR_DSISR]);
                     env->spr[SPR_DAR], env->spr[SPR_DSISR]);
         break;
         break;
     case POWERPC_MMU_BOOKE206:
     case POWERPC_MMU_BOOKE206:

+ 245 - 119
target/ppc/translate_init.c

@@ -32,6 +32,7 @@
 #include "qapi/visitor.h"
 #include "qapi/visitor.h"
 #include "hw/qdev-properties.h"
 #include "hw/qdev-properties.h"
 #include "hw/ppc/ppc.h"
 #include "hw/ppc/ppc.h"
+#include "mmu-book3s-v3.h"
 
 
 //#define PPC_DUMP_CPU
 //#define PPC_DUMP_CPU
 //#define PPC_DEBUG_SPR
 //#define PPC_DEBUG_SPR
@@ -723,7 +724,7 @@ static void gen_spr_generic (CPUPPCState *env)
 }
 }
 
 
 /* SPR common to all non-embedded PowerPC, including 601 */
 /* SPR common to all non-embedded PowerPC, including 601 */
-static void gen_spr_ne_601 (CPUPPCState *env)
+static void gen_spr_ne_601(CPUPPCState *env)
 {
 {
     /* Exception processing */
     /* Exception processing */
     spr_register_kvm(env, SPR_DSISR, "DSISR",
     spr_register_kvm(env, SPR_DSISR, "DSISR",
@@ -739,7 +740,11 @@ static void gen_spr_ne_601 (CPUPPCState *env)
                  SPR_NOACCESS, SPR_NOACCESS,
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_decr, &spr_write_decr,
                  &spr_read_decr, &spr_write_decr,
                  0x00000000);
                  0x00000000);
-    /* Memory management */
+}
+
+/* Storage Description Register 1 */
+static void gen_spr_sdr1(CPUPPCState *env)
+{
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
     if (env->has_hv_mode) {
     if (env->has_hv_mode) {
         /* SDR1 is a hypervisor resource on CPUs which have a
         /* SDR1 is a hypervisor resource on CPUs which have a
@@ -1180,7 +1185,7 @@ static void spr_write_iamr(DisasContext *ctx, int sprn, int gprn)
 }
 }
 #endif /* CONFIG_USER_ONLY */
 #endif /* CONFIG_USER_ONLY */
 
 
-static void gen_spr_amr(CPUPPCState *env, bool has_iamr)
+static void gen_spr_amr(CPUPPCState *env)
 {
 {
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
     /* Virtual Page Class Key protection */
     /* Virtual Page Class Key protection */
@@ -1206,13 +1211,17 @@ static void gen_spr_amr(CPUPPCState *env, bool has_iamr)
                     SPR_NOACCESS, SPR_NOACCESS,
                     SPR_NOACCESS, SPR_NOACCESS,
                     &spr_read_generic, &spr_write_generic,
                     &spr_read_generic, &spr_write_generic,
                     0);
                     0);
-    if (has_iamr) {
-        spr_register_kvm_hv(env, SPR_IAMR, "IAMR",
-                            SPR_NOACCESS, SPR_NOACCESS,
-                            &spr_read_generic, &spr_write_iamr,
-                            &spr_read_generic, &spr_write_generic,
-                            KVM_REG_PPC_IAMR, 0);
-    }
+#endif /* !CONFIG_USER_ONLY */
+}
+
+static void gen_spr_iamr(CPUPPCState *env)
+{
+#ifndef CONFIG_USER_ONLY
+    spr_register_kvm_hv(env, SPR_IAMR, "IAMR",
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        &spr_read_generic, &spr_write_iamr,
+                        &spr_read_generic, &spr_write_generic,
+                        KVM_REG_PPC_IAMR, 0);
 #endif /* !CONFIG_USER_ONLY */
 #endif /* !CONFIG_USER_ONLY */
 }
 }
 #endif /* TARGET_PPC64 */
 #endif /* TARGET_PPC64 */
@@ -4422,6 +4431,7 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data)
 static void init_proc_G2 (CPUPPCState *env)
 static void init_proc_G2 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_G2_755(env);
     gen_spr_G2_755(env);
     gen_spr_G2(env);
     gen_spr_G2(env);
     /* Time base */
     /* Time base */
@@ -4500,6 +4510,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
 static void init_proc_G2LE (CPUPPCState *env)
 static void init_proc_G2LE (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_G2_755(env);
     gen_spr_G2_755(env);
     gen_spr_G2(env);
     gen_spr_G2(env);
     /* Time base */
     /* Time base */
@@ -4735,6 +4746,7 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data)
 static void init_proc_e300 (CPUPPCState *env)
 static void init_proc_e300 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_603(env);
     gen_spr_603(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -5234,6 +5246,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
 static void init_proc_601 (CPUPPCState *env)
 static void init_proc_601 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_601(env);
     gen_spr_601(env);
     /* Hardware implementation registers */
     /* Hardware implementation registers */
     /* XXX : not implemented */
     /* XXX : not implemented */
@@ -5348,6 +5361,7 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
 static void init_proc_602 (CPUPPCState *env)
 static void init_proc_602 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_602(env);
     gen_spr_602(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -5417,6 +5431,7 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data)
 static void init_proc_603 (CPUPPCState *env)
 static void init_proc_603 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_603(env);
     gen_spr_603(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -5483,6 +5498,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
 static void init_proc_603E (CPUPPCState *env)
 static void init_proc_603E (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_603(env);
     gen_spr_603(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -5549,6 +5565,7 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data)
 static void init_proc_604 (CPUPPCState *env)
 static void init_proc_604 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_604(env);
     gen_spr_604(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -5612,6 +5629,7 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
 static void init_proc_604E (CPUPPCState *env)
 static void init_proc_604E (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_604(env);
     gen_spr_604(env);
     /* XXX : not implemented */
     /* XXX : not implemented */
     spr_register(env, SPR_7XX_MMCR1, "MMCR1",
     spr_register(env, SPR_7XX_MMCR1, "MMCR1",
@@ -5695,6 +5713,7 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
 static void init_proc_740 (CPUPPCState *env)
 static void init_proc_740 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -5765,6 +5784,7 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
 static void init_proc_750 (CPUPPCState *env)
 static void init_proc_750 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* XXX : not implemented */
     /* XXX : not implemented */
     spr_register(env, SPR_L2CR, "L2CR",
     spr_register(env, SPR_L2CR, "L2CR",
@@ -5843,6 +5863,7 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
 static void init_proc_750cl (CPUPPCState *env)
 static void init_proc_750cl (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* XXX : not implemented */
     /* XXX : not implemented */
     spr_register(env, SPR_L2CR, "L2CR",
     spr_register(env, SPR_L2CR, "L2CR",
@@ -6044,6 +6065,7 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
 static void init_proc_750cx (CPUPPCState *env)
 static void init_proc_750cx (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* XXX : not implemented */
     /* XXX : not implemented */
     spr_register(env, SPR_L2CR, "L2CR",
     spr_register(env, SPR_L2CR, "L2CR",
@@ -6126,6 +6148,7 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
 static void init_proc_750fx (CPUPPCState *env)
 static void init_proc_750fx (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* XXX : not implemented */
     /* XXX : not implemented */
     spr_register(env, SPR_L2CR, "L2CR",
     spr_register(env, SPR_L2CR, "L2CR",
@@ -6213,6 +6236,7 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
 static void init_proc_750gx (CPUPPCState *env)
 static void init_proc_750gx (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* XXX : not implemented (XXX: different from 750fx) */
     /* XXX : not implemented (XXX: different from 750fx) */
     spr_register(env, SPR_L2CR, "L2CR",
     spr_register(env, SPR_L2CR, "L2CR",
@@ -6300,6 +6324,7 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
 static void init_proc_745 (CPUPPCState *env)
 static void init_proc_745 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     gen_spr_G2_755(env);
     gen_spr_G2_755(env);
     /* Time base */
     /* Time base */
@@ -6375,6 +6400,7 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data)
 static void init_proc_755 (CPUPPCState *env)
 static void init_proc_755 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     gen_spr_G2_755(env);
     gen_spr_G2_755(env);
     /* Time base */
     /* Time base */
@@ -6461,6 +6487,7 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data)
 static void init_proc_7400 (CPUPPCState *env)
 static void init_proc_7400 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -6539,6 +6566,7 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
 static void init_proc_7410 (CPUPPCState *env)
 static void init_proc_7410 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -6623,6 +6651,7 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
 static void init_proc_7440 (CPUPPCState *env)
 static void init_proc_7440 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -6730,6 +6759,7 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data)
 static void init_proc_7450 (CPUPPCState *env)
 static void init_proc_7450 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -6863,6 +6893,7 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data)
 static void init_proc_7445 (CPUPPCState *env)
 static void init_proc_7445 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -6999,6 +7030,7 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data)
 static void init_proc_7455 (CPUPPCState *env)
 static void init_proc_7455 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -7137,6 +7169,7 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data)
 static void init_proc_7457 (CPUPPCState *env)
 static void init_proc_7457 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -7299,6 +7332,7 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data)
 static void init_proc_e600 (CPUPPCState *env)
 static void init_proc_e600 (CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
+    gen_spr_sdr1(env);
     gen_spr_7xx(env);
     gen_spr_7xx(env);
     /* Time base */
     /* Time base */
     gen_tbl(env);
     gen_tbl(env);
@@ -7444,15 +7478,6 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void *data)
 #define POWERPC970_HID5_INIT 0x00000000
 #define POWERPC970_HID5_INIT 0x00000000
 #endif
 #endif
 
 
-enum BOOK3S_CPU_TYPE {
-    BOOK3S_CPU_970,
-    BOOK3S_CPU_POWER5PLUS,
-    BOOK3S_CPU_POWER6,
-    BOOK3S_CPU_POWER7,
-    BOOK3S_CPU_POWER8,
-    BOOK3S_CPU_POWER9
-};
-
 static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn,
 static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn,
                                     int bit, int sprn, int cause)
                                     int bit, int sprn, int cause)
 {
 {
@@ -7540,7 +7565,7 @@ static void gen_spr_970_hior(CPUPPCState *env)
                  0x00000000);
                  0x00000000);
 }
 }
 
 
-static void gen_spr_book3s_common(CPUPPCState *env)
+static void gen_spr_book3s_ctrl(CPUPPCState *env)
 {
 {
     spr_register(env, SPR_CTRL, "SPR_CTRL",
     spr_register(env, SPR_CTRL, "SPR_CTRL",
                  SPR_NOACCESS, SPR_NOACCESS,
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -8210,112 +8235,42 @@ static void gen_spr_power8_rpr(CPUPPCState *env)
 #endif
 #endif
 }
 }
 
 
-static void init_proc_book3s_64(CPUPPCState *env, int version)
+static void init_proc_book3s_common(CPUPPCState *env)
 {
 {
     gen_spr_ne_601(env);
     gen_spr_ne_601(env);
     gen_tbl(env);
     gen_tbl(env);
     gen_spr_book3s_altivec(env);
     gen_spr_book3s_altivec(env);
     gen_spr_book3s_pmu_sup(env);
     gen_spr_book3s_pmu_sup(env);
     gen_spr_book3s_pmu_user(env);
     gen_spr_book3s_pmu_user(env);
-    gen_spr_book3s_common(env);
+    gen_spr_book3s_ctrl(env);
+}
 
 
-    switch (version) {
-    case BOOK3S_CPU_970:
-    case BOOK3S_CPU_POWER5PLUS:
-        gen_spr_970_hid(env);
-        gen_spr_970_hior(env);
-        gen_low_BATs(env);
-        gen_spr_970_pmu_sup(env);
-        gen_spr_970_pmu_user(env);
-        break;
-    case BOOK3S_CPU_POWER7:
-    case BOOK3S_CPU_POWER8:
-    case BOOK3S_CPU_POWER9:
-        gen_spr_book3s_ids(env);
-        gen_spr_amr(env, version >= BOOK3S_CPU_POWER8);
-        gen_spr_book3s_purr(env);
-        env->ci_large_pages = true;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    if (version >= BOOK3S_CPU_POWER5PLUS) {
-        gen_spr_power5p_common(env);
-        gen_spr_power5p_lpar(env);
-        gen_spr_power5p_ear(env);
-    } else {
-        gen_spr_970_lpar(env);
-    }
-    if (version == BOOK3S_CPU_970) {
-        gen_spr_970_dbg(env);
-    }
-    if (version >= BOOK3S_CPU_POWER6) {
-        gen_spr_power6_common(env);
-        gen_spr_power6_dbg(env);
-    }
-    if (version == BOOK3S_CPU_POWER7) {
-        gen_spr_power7_book4(env);
-    }
-    if (version >= BOOK3S_CPU_POWER8) {
-        gen_spr_power8_tce_address_control(env);
-        gen_spr_power8_ids(env);
-        gen_spr_power8_ebb(env);
-        gen_spr_power8_fscr(env);
-        gen_spr_power8_pmu_sup(env);
-        gen_spr_power8_pmu_user(env);
-        gen_spr_power8_tm(env);
-        gen_spr_power8_pspb(env);
-        gen_spr_vtb(env);
-        gen_spr_power8_ic(env);
-        gen_spr_power8_book4(env);
-        gen_spr_power8_rpr(env);
-    }
-    if (version < BOOK3S_CPU_POWER8) {
-        gen_spr_book3s_dbg(env);
-    } else {
-        gen_spr_book3s_207_dbg(env);
-    }
+static void init_proc_970(CPUPPCState *env)
+{
+    /* Common Registers */
+    init_proc_book3s_common(env);
+    gen_spr_sdr1(env);
+    gen_spr_book3s_dbg(env);
+
+    /* 970 Specific Registers */
+    gen_spr_970_hid(env);
+    gen_spr_970_hior(env);
+    gen_low_BATs(env);
+    gen_spr_970_pmu_sup(env);
+    gen_spr_970_pmu_user(env);
+    gen_spr_970_lpar(env);
+    gen_spr_970_dbg(env);
+
+    /* env variables */
 #if !defined(CONFIG_USER_ONLY)
 #if !defined(CONFIG_USER_ONLY)
-    switch (version) {
-    case BOOK3S_CPU_970:
-    case BOOK3S_CPU_POWER5PLUS:
-        env->slb_nr = 64;
-        break;
-    case BOOK3S_CPU_POWER7:
-    case BOOK3S_CPU_POWER8:
-    case BOOK3S_CPU_POWER9:
-    default:
-        env->slb_nr = 32;
-        break;
-    }
+    env->slb_nr = 64;
 #endif
 #endif
-    /* Allocate hardware IRQ controller */
-    switch (version) {
-    case BOOK3S_CPU_970:
-    case BOOK3S_CPU_POWER5PLUS:
-        init_excp_970(env);
-        ppc970_irq_init(ppc_env_get_cpu(env));
-        break;
-    case BOOK3S_CPU_POWER7:
-        init_excp_POWER7(env);
-        ppcPOWER7_irq_init(ppc_env_get_cpu(env));
-        break;
-    case BOOK3S_CPU_POWER8:
-    case BOOK3S_CPU_POWER9:
-        init_excp_POWER8(env);
-        ppcPOWER7_irq_init(ppc_env_get_cpu(env));
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
     env->dcache_line_size = 128;
     env->dcache_line_size = 128;
     env->icache_line_size = 128;
     env->icache_line_size = 128;
-}
 
 
-static void init_proc_970(CPUPPCState *env)
-{
-    init_proc_book3s_64(env, BOOK3S_CPU_970);
+    /* Allocate hardware IRQ controller */
+    init_excp_970(env);
+    ppc970_irq_init(ppc_env_get_cpu(env));
 }
 }
 
 
 POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
 POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
@@ -8367,7 +8322,31 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
 
 
 static void init_proc_power5plus(CPUPPCState *env)
 static void init_proc_power5plus(CPUPPCState *env)
 {
 {
-    init_proc_book3s_64(env, BOOK3S_CPU_POWER5PLUS);
+    /* Common Registers */
+    init_proc_book3s_common(env);
+    gen_spr_sdr1(env);
+    gen_spr_book3s_dbg(env);
+
+    /* POWER5+ Specific Registers */
+    gen_spr_970_hid(env);
+    gen_spr_970_hior(env);
+    gen_low_BATs(env);
+    gen_spr_970_pmu_sup(env);
+    gen_spr_970_pmu_user(env);
+    gen_spr_power5p_common(env);
+    gen_spr_power5p_lpar(env);
+    gen_spr_power5p_ear(env);
+
+    /* env variables */
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 64;
+#endif
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+
+    /* Allocate hardware IRQ controller */
+    init_excp_970(env);
+    ppc970_irq_init(ppc_env_get_cpu(env));
 }
 }
 
 
 POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
 POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
@@ -8520,7 +8499,33 @@ static const struct ppc_segment_page_sizes POWER7_POWER8_sps = {
 
 
 static void init_proc_POWER7 (CPUPPCState *env)
 static void init_proc_POWER7 (CPUPPCState *env)
 {
 {
-    init_proc_book3s_64(env, BOOK3S_CPU_POWER7);
+    /* Common Registers */
+    init_proc_book3s_common(env);
+    gen_spr_sdr1(env);
+    gen_spr_book3s_dbg(env);
+
+    /* POWER7 Specific Registers */
+    gen_spr_book3s_ids(env);
+    gen_spr_amr(env);
+    gen_spr_book3s_purr(env);
+    gen_spr_power5p_common(env);
+    gen_spr_power5p_lpar(env);
+    gen_spr_power5p_ear(env);
+    gen_spr_power6_common(env);
+    gen_spr_power6_dbg(env);
+    gen_spr_power7_book4(env);
+
+    /* env variables */
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    env->ci_large_pages = true;
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+
+    /* Allocate hardware IRQ controller */
+    init_excp_POWER7(env);
+    ppcPOWER7_irq_init(ppc_env_get_cpu(env));
 }
 }
 
 
 static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr)
 static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr)
@@ -8636,7 +8641,45 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 
 
 static void init_proc_POWER8(CPUPPCState *env)
 static void init_proc_POWER8(CPUPPCState *env)
 {
 {
-    init_proc_book3s_64(env, BOOK3S_CPU_POWER8);
+    /* Common Registers */
+    init_proc_book3s_common(env);
+    gen_spr_sdr1(env);
+    gen_spr_book3s_207_dbg(env);
+
+    /* POWER8 Specific Registers */
+    gen_spr_book3s_ids(env);
+    gen_spr_amr(env);
+    gen_spr_iamr(env);
+    gen_spr_book3s_purr(env);
+    gen_spr_power5p_common(env);
+    gen_spr_power5p_lpar(env);
+    gen_spr_power5p_ear(env);
+    gen_spr_power6_common(env);
+    gen_spr_power6_dbg(env);
+    gen_spr_power8_tce_address_control(env);
+    gen_spr_power8_ids(env);
+    gen_spr_power8_ebb(env);
+    gen_spr_power8_fscr(env);
+    gen_spr_power8_pmu_sup(env);
+    gen_spr_power8_pmu_user(env);
+    gen_spr_power8_tm(env);
+    gen_spr_power8_pspb(env);
+    gen_spr_vtb(env);
+    gen_spr_power8_ic(env);
+    gen_spr_power8_book4(env);
+    gen_spr_power8_rpr(env);
+
+    /* env variables */
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    env->ci_large_pages = true;
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+
+    /* Allocate hardware IRQ controller */
+    init_excp_POWER8(env);
+    ppcPOWER7_irq_init(ppc_env_get_cpu(env));
 }
 }
 
 
 static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr)
 static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr)
@@ -8764,9 +8807,47 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
     pcc->l1_icache_size = 0x8000;
     pcc->l1_icache_size = 0x8000;
     pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
     pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
 }
 }
+
 static void init_proc_POWER9(CPUPPCState *env)
 static void init_proc_POWER9(CPUPPCState *env)
 {
 {
-    init_proc_book3s_64(env, BOOK3S_CPU_POWER9);
+    /* Common Registers */
+    init_proc_book3s_common(env);
+    gen_spr_book3s_207_dbg(env);
+
+    /* POWER8 Specific Registers */
+    gen_spr_book3s_ids(env);
+    gen_spr_amr(env);
+    gen_spr_iamr(env);
+    gen_spr_book3s_purr(env);
+    gen_spr_power5p_common(env);
+    gen_spr_power5p_lpar(env);
+    gen_spr_power5p_ear(env);
+    gen_spr_power6_common(env);
+    gen_spr_power6_dbg(env);
+    gen_spr_power8_tce_address_control(env);
+    gen_spr_power8_ids(env);
+    gen_spr_power8_ebb(env);
+    gen_spr_power8_fscr(env);
+    gen_spr_power8_pmu_sup(env);
+    gen_spr_power8_pmu_user(env);
+    gen_spr_power8_tm(env);
+    gen_spr_power8_pspb(env);
+    gen_spr_vtb(env);
+    gen_spr_power8_ic(env);
+    gen_spr_power8_book4(env);
+    gen_spr_power8_rpr(env);
+
+    /* env variables */
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    env->ci_large_pages = true;
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+
+    /* Allocate hardware IRQ controller */
+    init_excp_POWER8(env);
+    ppcPOWER7_irq_init(ppc_env_get_cpu(env));
 }
 }
 
 
 static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr)
 static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr)
@@ -8777,10 +8858,54 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr)
     return false;
     return false;
 }
 }
 
 
+static bool cpu_has_work_POWER9(CPUState *cs)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+
+    if (cs->halted) {
+        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
+            return false;
+        }
+        /* External Exception */
+        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) &&
+            (env->spr[SPR_LPCR] & LPCR_EEE)) {
+            return true;
+        }
+        /* Decrementer Exception */
+        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) &&
+            (env->spr[SPR_LPCR] & LPCR_DEE)) {
+            return true;
+        }
+        /* Machine Check or Hypervisor Maintenance Exception */
+        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK |
+            1u << PPC_INTERRUPT_HMI)) && (env->spr[SPR_LPCR] & LPCR_OEE)) {
+            return true;
+        }
+        /* Privileged Doorbell Exception */
+        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) &&
+            (env->spr[SPR_LPCR] & LPCR_PDEE)) {
+            return true;
+        }
+        /* Hypervisor Doorbell Exception */
+        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) &&
+            (env->spr[SPR_LPCR] & LPCR_HDEE)) {
+            return true;
+        }
+        if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) {
+            return true;
+        }
+        return false;
+    } else {
+        return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD);
+    }
+}
+
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
     DeviceClass *dc = DEVICE_CLASS(oc);
     PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
     PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+    CPUClass *cc = CPU_CLASS(oc);
 
 
     dc->fw_name = "PowerPC,POWER9";
     dc->fw_name = "PowerPC,POWER9";
     dc->desc = "POWER9";
     dc->desc = "POWER9";
@@ -8791,6 +8916,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
                          PCR_COMPAT_2_05;
                          PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER9;
     pcc->init_proc = init_proc_POWER9;
     pcc->check_pow = check_pow_nocheck;
     pcc->check_pow = check_pow_nocheck;
+    cc->has_work = cpu_has_work_POWER9;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -8830,7 +8956,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
                     (1ull << MSR_LE);
                     (1ull << MSR_LE);
     pcc->mmu_model = POWERPC_MMU_3_00;
     pcc->mmu_model = POWERPC_MMU_3_00;
 #if defined(CONFIG_SOFTMMU)
 #if defined(CONFIG_SOFTMMU)
-    pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
+    pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
     /* segment page size remain the same */
     /* segment page size remain the same */
     pcc->sps = &POWER7_POWER8_sps;
     pcc->sps = &POWER7_POWER8_sps;
 #endif
 #endif

+ 1 - 1
tests/boot-serial-test.c

@@ -29,7 +29,7 @@ static testdef_t tests[] = {
     { "ppc64", "ppce500", "", "U-Boot" },
     { "ppc64", "ppce500", "", "U-Boot" },
     { "ppc64", "prep", "", "Open Hack'Ware BIOS" },
     { "ppc64", "prep", "", "Open Hack'Ware BIOS" },
     { "ppc64", "pseries", "", "Open Firmware" },
     { "ppc64", "pseries", "", "Open Firmware" },
-    { "ppc64", "powernv", "-cpu POWER9", "SkiBoot" },
+    { "ppc64", "powernv", "-cpu POWER8", "SkiBoot" },
     { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
     { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
     { "i386", "pc", "-device sga", "SGABIOS" },
     { "i386", "pc", "-device sga", "SGABIOS" },
     { "i386", "q35", "-device sga", "SGABIOS" },
     { "i386", "q35", "-device sga", "SGABIOS" },

+ 4 - 1
tests/pnv-xscom-test.c

@@ -41,7 +41,9 @@ static const PnvChip pnv_chips[] = {
         .xscom_core_base = 0x10000000ull,
         .xscom_core_base = 0x10000000ull,
         .cfam_id    = 0x120d304980000000ull,
         .cfam_id    = 0x120d304980000000ull,
         .first_core = 0x1,
         .first_core = 0x1,
-    }, {
+    },
+#if 0 /* POWER9 support is not ready yet */
+    {
         .chip_type  = PNV_CHIP_POWER9,
         .chip_type  = PNV_CHIP_POWER9,
         .cpu_model  = "POWER9",
         .cpu_model  = "POWER9",
         .xscom_base = 0x000603fc00000000ull,
         .xscom_base = 0x000603fc00000000ull,
@@ -49,6 +51,7 @@ static const PnvChip pnv_chips[] = {
         .cfam_id    = 0x100d104980000000ull,
         .cfam_id    = 0x100d104980000000ull,
         .first_core = 0x20,
         .first_core = 0x20,
     },
     },
+#endif
 };
 };
 
 
 static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
 static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)

+ 25 - 0
util/mmap-alloc.c

@@ -40,6 +40,31 @@ size_t qemu_fd_getpagesize(int fd)
     return getpagesize();
     return getpagesize();
 }
 }
 
 
+size_t qemu_mempath_getpagesize(const char *mem_path)
+{
+#ifdef CONFIG_LINUX
+    struct statfs fs;
+    int ret;
+
+    do {
+        ret = statfs(mem_path, &fs);
+    } while (ret != 0 && errno == EINTR);
+
+    if (ret != 0) {
+        fprintf(stderr, "Couldn't statfs() memory path: %s\n",
+                strerror(errno));
+        exit(1);
+    }
+
+    if (fs.f_type == HUGETLBFS_MAGIC) {
+        /* It's hugepage, return the huge page size */
+        return fs.f_bsize;
+    }
+#endif
+
+    return getpagesize();
+}
+
 void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared)
 void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared)
 {
 {
     /*
     /*