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/ioport.h"
#include "sysemu/dma.h"
#include "sysemu/numa.h"
#include "exec/address-spaces.h"
#include "sysemu/xen-mapcache.h"
#include "trace-root.h"
@ -1256,6 +1257,87 @@ void qemu_mutex_unlock_ramlist(void)
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__
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,
0x00, 0x00, 0x00, 0x00, 0x80, 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;
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_size = sizeof(pa_features_206);
break;
case POWERPC_MMU_2_07:
case POWERPC_MMU_2_07a:
case POWERPC_MMU_VER_2_07:
pa_features = pa_features_207;
pa_size = sizeof(pa_features_207);
break;
case POWERPC_MMU_VER_3_00:
pa_features = pa_features_300;
pa_size = sizeof(pa_features_300);
break;
default:
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_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
#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 */
foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
spapr->patb_entry = 0;
/* Allocate and/or reset the hash page table */
spapr_reallocate_hpt(spapr,
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 = {
.name = "spapr",
.version_id = 3,
@ -1444,6 +1487,7 @@ static const VMStateDescription vmstate_spapr = {
},
.subsections = (const VMStateDescription*[]) {
&vmstate_spapr_ov5_cas,
&vmstate_spapr_patb_entry,
NULL
}
};
@ -3049,6 +3093,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
vhc->map_hptes = spapr_map_hptes;
vhc->unmap_hptes = spapr_unmap_hptes;
vhc->store_hpte = spapr_store_hpte;
vhc->get_patbe = spapr_get_patbe;
xic->ics_get = spapr_ics_get;
xic->ics_resend = spapr_ics_resend;
xic->icp_get = spapr_icp_get;

View File

@ -238,6 +238,9 @@ static const char *spapr_core_models[] = {
/* POWER8NVL */
"POWER8NVL_v1.0",
/* POWER9 */
"POWER9_v1.0",
};
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",
(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;
}

View File

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

View File

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

View File

@ -5,6 +5,8 @@
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_munmap(void *ptr, size_t size);

View File

@ -3,7 +3,7 @@ obj-y += cpu.o
obj-y += translate.o
ifeq ($(CONFIG_SOFTMMU),y)
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
obj-$(CONFIG_KVM) += kvm.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o

View File

@ -39,29 +39,35 @@ static const CompatInfo compat_table[] = {
*/
{ /* POWER6, ISA2.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,
.max_threads = 2,
},
{ /* POWER7, ISA2.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,
.max_threads = 4,
},
{
.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,
.max_threads = 4,
},
{ /* POWER8, ISA2.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,
.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)

View File

@ -71,6 +71,7 @@ enum powerpc_mmu_t {
#define POWERPC_MMU_1TSEG 0x00020000
#define POWERPC_MMU_AMR 0x00040000
#define POWERPC_MMU_64K 0x00080000
#define POWERPC_MMU_V3 0x00100000 /* ISA V3.00 MMU Support */
/* 64 bits PowerPC MMU */
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
/* 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_64K
| 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 */
POWERPC_MMU_2_07 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
| POWERPC_MMU_64K
| 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 */
POWERPC_MMU_3_00 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
| 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 */

View File

@ -473,6 +473,22 @@ struct ppc_slb_t {
#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 */
#define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */
#define FSCR_TAR (63 - 55) /* Target Address Register */
@ -1216,6 +1232,7 @@ struct PPCVirtualHypervisorClass {
hwaddr ptex, int n);
void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
uint64_t pte0, uint64_t pte1);
uint64_t (*get_patbe)(PPCVirtualHypervisor *vhyp);
};
#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);
}
/* 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)))) {
if (unlikely((float64_is_infinity(arg1) && float64_is_zero(arg2)) ||
(float64_is_zero(arg1) && float64_is_infinity(arg2)))) {
/* 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;
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;
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);
aSign = float64_is_neg(arg1);
bSign = float64_is_neg(arg2);
cSign = float64_is_neg(arg3);
if (madd_flags & float_muladd_negate_c) {
cSign ^= 1;
}
if (aSign ^ bSign ^ cSign) {
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
}
}
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)))) {
/* 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);
}
}
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; \
}
/* fnmadd - fnmadd. */
uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
#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)
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;
}
/* 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;
}
FPU_FMADD(fmadd, MADD_FLGS)
FPU_FMADD(fnmadd, NMADD_FLGS)
FPU_FMADD(fmsub, MSUB_FLGS)
FPU_FMADD(fnmsub, NMSUB_FLGS)
/* frsp - frsp. */
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); \
}
#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(xsmaddmdp, 1, float64, VsrD(0), MADD_FLGS, 0, 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 "sysemu/sysemu.h"
#include "sysemu/hw_accel.h"
#include "sysemu/numa.h"
#include "kvm_ppc.h"
#include "sysemu/cpus.h"
#include "sysemu/device_tree.h"
@ -43,8 +42,10 @@
#include "trace.h"
#include "exec/gdbstub.h"
#include "exec/memattrs.h"
#include "exec/ram_addr.h"
#include "sysemu/hostmem.h"
#include "qemu/cutils.h"
#include "qemu/mmap-alloc.h"
#if defined(TARGET_PPC64)
#include "hw/ppc/spapr_cpu_core.h"
#endif
@ -282,8 +283,8 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu,
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;
} else {
info->slb_size = 64;
@ -297,8 +298,8 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu,
i++;
/* 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].slb_enc = 0x110;
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);
}
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)
{
if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) {
@ -460,7 +361,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
}
if (!max_cpu_page_size) {
max_cpu_page_size = getrampagesize();
max_cpu_page_size = qemu_getrampagesize();
}
/* Convert to QEMU form */
@ -521,7 +422,7 @@ bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
long pagesize;
if (mempath) {
pagesize = gethugepagesize(mempath);
pagesize = qemu_mempath_getpagesize(mempath);
} else {
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
* or equal to the (logical) backing page size of guest RAM */
kvm_get_smmu_info(POWERPC_CPU(first_cpu), &info);
rampagesize = getrampagesize();
rampagesize = qemu_getrampagesize();
best_page_shift = 0;
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 "exec/log.h"
#include "hw/hw.h"
#include "mmu-book3s-v3.h"
//#define DEBUG_SLB
@ -289,6 +290,16 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
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,
ppc_slb_t *slb, ppc_hash_pte64_t pte)
{
@ -307,41 +318,51 @@ static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
case 0x0:
case 0x1:
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
break;
case 0x3:
case 0x6:
prot = PAGE_READ;
prot = PAGE_READ | PAGE_EXEC;
break;
}
} else {
switch (pp) {
case 0x0:
case 0x6:
prot = 0;
break;
case 0x1:
case 0x3:
prot = PAGE_READ;
prot = PAGE_READ | PAGE_EXEC;
break;
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
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;
}
/* 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)
{
CPUPPCState *env = &cpu->env;
@ -374,6 +395,21 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
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;
}
@ -664,8 +700,8 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
unsigned apshift;
hwaddr ptex;
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};
hwaddr raddr;
@ -706,11 +742,11 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
} else {
/* The access failed, generate the approriate interrupt */
if (rwx == 2) {
ppc_hash64_set_isi(cs, env, 0x08000000);
ppc_hash64_set_isi(cs, env, SRR1_PROTFAULT);
} else {
dsisr = 0x08000000;
int dsisr = DSISR_PROTFAULT;
if (rwx == 1) {
dsisr |= 0x02000000;
dsisr |= DSISR_ISSTORE;
}
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 */
slb = slb_lookup(cpu, eaddr);
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) {
cs->exception_index = POWERPC_EXCP_ISEG;
env->error_code = 0;
@ -741,19 +784,19 @@ skip_slb_search:
/* 3. Check for segment level no-execute violation */
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;
}
/* 4. Locate the PTE in the hash table */
ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
if (ptex == -1) {
dsisr = 0x40000000;
if (rwx == 2) {
ppc_hash64_set_isi(cs, env, dsisr);
ppc_hash64_set_isi(cs, env, SRR1_NOPTE);
} else {
int dsisr = DSISR_NOPTE;
if (rwx == 1) {
dsisr |= 0x02000000;
dsisr |= DSISR_ISSTORE;
}
ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
}
@ -764,25 +807,35 @@ skip_slb_search:
/* 5. Check access permissions */
exec_prot = ppc_hash64_pte_noexec_guard(cpu, pte);
pp_prot = ppc_hash64_pte_prot(cpu, slb, 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) {
/* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
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 {
dsisr = 0;
int dsisr = 0;
if (need_prot[rwx] & ~pp_prot) {
dsisr |= 0x08000000;
dsisr |= DSISR_PROTFAULT;
}
if (rwx == 1) {
dsisr |= 0x02000000;
dsisr |= DSISR_ISSTORE;
}
if (need_prot[rwx] & ~amr_prot) {
dsisr |= 0x00200000;
dsisr |= DSISR_AMR;
}
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;
/* 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) {
lpcr |= LPCR_LPES0;
}
@ -1006,26 +1059,26 @@ void helper_store_lpcr(CPUPPCState *env, target_ulong val)
* to dig HRMOR out of HID5
*/
break;
case POWERPC_MMU_2_03: /* P5p */
case POWERPC_MMU_VER_2_03: /* P5p */
lpcr = val & (LPCR_RMLS | LPCR_ILE |
LPCR_LPES0 | LPCR_LPES1 |
LPCR_RMI | LPCR_HDICE);
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_VRMASD | LPCR_RMLS | LPCR_ILE |
LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
LPCR_MER | LPCR_TC |
LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE);
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_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE);
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_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
LPCR_UPRT | LPCR_EVIRT | LPCR_ONL |

View File

@ -29,6 +29,7 @@
#include "exec/log.h"
#include "helper_regs.h"
#include "qemu/error-report.h"
#include "mmu-book3s-v3.h"
//#define DEBUG_MMU
//#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)
{
switch (env->mmu_model) {
switch (POWERPC_MMU_VER(env->mmu_model)) {
case POWERPC_MMU_BOOKE:
mmubooke_dump_mmu(f, cpu_fprintf, env);
break;
@ -1277,14 +1278,19 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
mmu6xx_dump_mmu(f, cpu_fprintf, env);
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_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));
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
default:
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;
mmu_ctx_t ctx;
switch (env->mmu_model) {
switch (POWERPC_MMU_VER(env->mmu_model)) {
#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);
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
case POWERPC_MMU_32B:
@ -1909,6 +1920,12 @@ void ppc_tlb_invalidate_all(CPUPPCState *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) {
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
@ -1933,21 +1950,12 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
break;
case POWERPC_MMU_32B:
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;
tlb_flush(CPU(cpu));
break;
default:
/* 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;
}
}
@ -1956,6 +1964,16 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
{
#if !defined(FLUSH_ALL_TLBS)
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) {
case POWERPC_MMU_SOFT_6xx:
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;
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:
/* Should never reach here with other MMU models */
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)
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_601:
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
#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
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]);
break;
case POWERPC_MMU_BOOKE206:

View File

@ -32,6 +32,7 @@
#include "qapi/visitor.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/ppc.h"
#include "mmu-book3s-v3.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@ -723,7 +724,7 @@ static void gen_spr_generic (CPUPPCState *env)
}
/* 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 */
spr_register_kvm(env, SPR_DSISR, "DSISR",
@ -739,7 +740,11 @@ static void gen_spr_ne_601 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_decr, &spr_write_decr,
0x00000000);
/* Memory management */
}
/* Storage Description Register 1 */
static void gen_spr_sdr1(CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
if (env->has_hv_mode) {
/* 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 */
static void gen_spr_amr(CPUPPCState *env, bool has_iamr)
static void gen_spr_amr(CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
/* Virtual Page Class Key protection */
@ -1206,13 +1211,17 @@ static void gen_spr_amr(CPUPPCState *env, bool has_iamr)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
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 /* TARGET_PPC64 */
@ -4422,6 +4431,7 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data)
static void init_proc_G2 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_G2_755(env);
gen_spr_G2(env);
/* Time base */
@ -4500,6 +4510,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
static void init_proc_G2LE (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_G2_755(env);
gen_spr_G2(env);
/* Time base */
@ -4735,6 +4746,7 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data)
static void init_proc_e300 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_603(env);
/* Time base */
gen_tbl(env);
@ -5234,6 +5246,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
static void init_proc_601 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_601(env);
/* Hardware implementation registers */
/* XXX : not implemented */
@ -5348,6 +5361,7 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
static void init_proc_602 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_602(env);
/* Time base */
gen_tbl(env);
@ -5417,6 +5431,7 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data)
static void init_proc_603 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_603(env);
/* Time base */
gen_tbl(env);
@ -5483,6 +5498,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
static void init_proc_603E (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_603(env);
/* Time base */
gen_tbl(env);
@ -5549,6 +5565,7 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data)
static void init_proc_604 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_604(env);
/* Time base */
gen_tbl(env);
@ -5612,6 +5629,7 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
static void init_proc_604E (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_604(env);
/* XXX : not implemented */
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)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -5765,6 +5784,7 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
static void init_proc_750 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@ -5843,6 +5863,7 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
static void init_proc_750cl (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@ -6044,6 +6065,7 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
static void init_proc_750cx (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@ -6126,6 +6148,7 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
static void init_proc_750fx (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@ -6213,6 +6236,7 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
static void init_proc_750gx (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented (XXX: different from 750fx) */
spr_register(env, SPR_L2CR, "L2CR",
@ -6300,6 +6324,7 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
static void init_proc_745 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
gen_spr_G2_755(env);
/* Time base */
@ -6375,6 +6400,7 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data)
static void init_proc_755 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
gen_spr_G2_755(env);
/* Time base */
@ -6461,6 +6487,7 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data)
static void init_proc_7400 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -6539,6 +6566,7 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
static void init_proc_7410 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -6623,6 +6651,7 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
static void init_proc_7440 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -6730,6 +6759,7 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data)
static void init_proc_7450 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -6863,6 +6893,7 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data)
static void init_proc_7445 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -6999,6 +7030,7 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data)
static void init_proc_7455 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -7137,6 +7169,7 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data)
static void init_proc_7457 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -7299,6 +7332,7 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data)
static void init_proc_e600 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@ -7444,15 +7478,6 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void *data)
#define POWERPC970_HID5_INIT 0x00000000
#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,
int bit, int sprn, int cause)
{
@ -7540,7 +7565,7 @@ static void gen_spr_970_hior(CPUPPCState *env)
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_NOACCESS, SPR_NOACCESS,
@ -8210,112 +8235,42 @@ static void gen_spr_power8_rpr(CPUPPCState *env)
#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_tbl(env);
gen_spr_book3s_altivec(env);
gen_spr_book3s_pmu_sup(env);
gen_spr_book3s_pmu_user(env);
gen_spr_book3s_common(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;
gen_spr_book3s_ctrl(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)
@ -8367,7 +8322,31 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
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)
@ -8520,7 +8499,33 @@ static const struct ppc_segment_page_sizes POWER7_POWER8_sps = {
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)
@ -8636,7 +8641,45 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
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)
@ -8764,9 +8807,47 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
}
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)
@ -8777,10 +8858,54 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr)
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)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
dc->fw_name = "PowerPC,POWER9";
dc->desc = "POWER9";
@ -8791,6 +8916,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER9;
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 |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -8830,7 +8956,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_3_00;
#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 */
pcc->sps = &POWER7_POWER8_sps;
#endif

View File

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

View File

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