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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJYuOEEAAoJEGw4ysog2bOSHD0P/jBg/qr/4KnsB1KhnlVrB2sP
 vy2d3bGGlUWr9Z+CK/PMCRB8ekFgQLjidLIXji6mviUocv6m3WsVrnbLF/oOL/IT
 NPMVAffw7q804YVu1Ns9R82d6CIqHTy//bpg69tFMcJmhL9fqPan3wTZZ9JeiyAm
 SikqkAHBSW4SxKqg8ApaSqx5L2QTqyfkClR0sLmgM0JtmfJrbobpQ6bMtdPjUZ9L
 n2gnpO2vaWCa1SEQrRrdELqvcD8PHkSJapWOBXOkpGWxoeov/PYxOgkpdDUW4qYY
 lVLtp1Vd3OB/h3Unqfw32DNiHA5p89hWPX5UybKMgRVL9Cv2/lyY47pcY8XTeNzn
 bv84YRbFJeI+GgoEnghmtq+IM8XiW/cr9rWm9wATKfKGcmmFauumALrsffUpHVCM
 4hSNgBv5t2V9ptZ+MDlM/Ku+zk9GoqwQ+hemdpVtiyhOtGUPGFBn5YLE4c2DHFxV
 +L9JtBnFn8obnssNoz0wL+QvZchT1qUHMhH5CWAanjw9CTDp/YwQ2P01zK+00s9d
 4cB7fUG3WNto5eXXEGMaXeDsUEz8z//hTe3j5sVbnHsXi0R3dhv7iryifmx4bUKU
 H9EwAc+uNUHbvBy7u6IWg0I8P2n00CCO6JqXijQ92zELJ5j0XhzHUI2dOXn+zyEo
 3FZu56LFnSSUBEXuTjq4
 =PcNw
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2017-03-04 16:31:14 +00:00
commit 17783ac828
22 changed files with 737 additions and 497 deletions

82
exec.c
View File

@ -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)
{ {

View File

@ -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) { switch (POWERPC_MMU_VER(env->mmu_model)) {
case POWERPC_MMU_2_06: case POWERPC_MMU_VER_2_06:
case POWERPC_MMU_2_06a:
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_VER_2_07:
case POWERPC_MMU_2_07a:
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;

View File

@ -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)

View File

@ -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;
} }

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
| PCR_TM_DIS | PCR_VSX_DIS, 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)

View File

@ -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 */

View File

@ -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"

View File

@ -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. */ static void float64_maddsub_update_excp(CPUPPCState *env, float64 arg1,
uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, float64 arg2, float64 arg3,
uint64_t arg3) unsigned int madd_flags)
{ {
CPU_DoubleU farg1, farg2, farg3; if (unlikely((float64_is_infinity(arg1) && float64_is_zero(arg2)) ||
(float64_is_zero(arg1) && float64_is_infinity(arg2)))) {
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 */ /* Multiplication of zero by infinity */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); arg1 = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else { } else if (unlikely(float64_is_signaling_nan(arg1, &env->fp_status) ||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(arg2, &env->fp_status) ||
float64_is_signaling_nan(farg2.d, &env->fp_status) || float64_is_signaling_nan(arg3, &env->fp_status))) {
float64_is_signaling_nan(farg3.d, &env->fp_status))) { /* sNaN operation */
/* sNaN operation */ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } else if ((float64_is_infinity(arg1) || float64_is_infinity(arg2)) &&
} float64_is_infinity(arg3)) {
/* This is the way the PowerPC specification defines it */ uint8_t aSign, bSign, cSign;
float128 ft0_128, ft1_128;
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); aSign = float64_is_neg(arg1);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); bSign = float64_is_neg(arg2);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); cSign = float64_is_neg(arg3);
if (unlikely(float128_is_infinity(ft0_128) && if (madd_flags & float_muladd_negate_c) {
float64_is_infinity(farg3.d) && cSign ^= 1;
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { }
/* Magnitude subtraction of infinities */ if (aSign ^ bSign ^ cSign) {
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); 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. */ #define FPU_FMADD(op, madd_flags) \
uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \
uint64_t arg3) uint64_t arg2, uint64_t arg3) \
{ { \
CPU_DoubleU farg1, farg2, farg3; uint32_t flags; \
float64 ret = float64_muladd(arg1, arg2, arg3, madd_flags, \
farg1.ll = arg1; &env->fp_status); \
farg2.ll = arg2; flags = get_float_exception_flags(&env->fp_status); \
farg3.ll = arg3; if (flags) { \
if (flags & float_flag_invalid) { \
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || float64_maddsub_update_excp(env, arg1, arg2, arg3, \
(float64_is_zero(farg1.d) && madd_flags); \
float64_is_infinity(farg2.d)))) { } \
/* Multiplication of zero by infinity */ float_check_status(env); \
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); } \
} else { return ret; \
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);
}
}
return farg1.ll;
} }
/* fnmadd - fnmadd. */ #define MADD_FLGS 0
uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, #define MSUB_FLGS float_muladd_negate_c
uint64_t arg3) #define NMADD_FLGS float_muladd_negate_result
{ #define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
CPU_DoubleU farg1, farg2, farg3;
farg1.ll = arg1; FPU_FMADD(fmadd, MADD_FLGS)
farg2.ll = arg2; FPU_FMADD(fnmadd, NMADD_FLGS)
farg3.ll = arg3; FPU_FMADD(fmsub, MSUB_FLGS)
FPU_FMADD(fnmsub, NMSUB_FLGS)
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;
}
/* 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;
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;
}
/* 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)

View File

@ -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 || if (POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_06 ||
env->mmu_model == POWERPC_MMU_2_07) { 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 || if (POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_06 ||
env->mmu_model == POWERPC_MMU_2_07) { 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++) {

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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; int exec_prot, pp_prot, amr_prot, prot;
uint64_t new_pte1, dsisr; 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) { switch (POWERPC_MMU_VER(env->mmu_model)) {
case POWERPC_MMU_64B: /* 970 */ 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 |

View File

@ -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_VER_64B:
case POWERPC_MMU_2_03: case POWERPC_MMU_VER_2_03:
case POWERPC_MMU_2_06: case POWERPC_MMU_VER_2_06:
case POWERPC_MMU_2_06a: case POWERPC_MMU_VER_2_07:
case POWERPC_MMU_2_07:
case POWERPC_MMU_2_07a:
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_VER_64B:
case POWERPC_MMU_2_03: case POWERPC_MMU_VER_2_03:
case POWERPC_MMU_2_06: case POWERPC_MMU_VER_2_06:
case POWERPC_MMU_2_06a: case POWERPC_MMU_VER_2_07:
case POWERPC_MMU_2_07:
case POWERPC_MMU_2_07a:
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);

View File

@ -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_VER_64B:
case POWERPC_MMU_2_03: case POWERPC_MMU_VER_2_03:
case POWERPC_MMU_2_06: case POWERPC_MMU_VER_2_06:
case POWERPC_MMU_2_06a: case POWERPC_MMU_VER_2_07:
case POWERPC_MMU_2_07: case POWERPC_MMU_VER_3_00:
case POWERPC_MMU_2_07a:
#endif #endif
cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " DAR " TARGET_FMT_lx if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */
" DSISR " TARGET_FMT_lx "\n", env->spr[SPR_SDR1], 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:

View File

@ -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) { #endif /* !CONFIG_USER_ONLY */
spr_register_kvm_hv(env, SPR_IAMR, "IAMR", }
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_iamr, static void gen_spr_iamr(CPUPPCState *env)
&spr_read_generic, &spr_write_generic, {
KVM_REG_PPC_IAMR, 0); #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);
}
#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;
}
#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->icache_line_size = 128;
} }
static void init_proc_970(CPUPPCState *env) static void init_proc_970(CPUPPCState *env)
{ {
init_proc_book3s_64(env, BOOK3S_CPU_970); /* 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)
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(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

View File

@ -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" },

View File

@ -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)

View File

@ -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)
{ {
/* /*