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:
commit
17783ac828
82
exec.c
82
exec.c
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
117
target/ppc/kvm.c
117
target/ppc/kvm.c
@ -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++) {
|
||||
|
37
target/ppc/mmu-book3s-v3.c
Normal file
37
target/ppc/mmu-book3s-v3.c
Normal 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);
|
||||
}
|
||||
}
|
50
target/ppc/mmu-book3s-v3.h
Normal file
50
target/ppc/mmu-book3s-v3.h
Normal 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 */
|
@ -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 |
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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" },
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user