aboutsummaryrefslogtreecommitdiff
path: root/target/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target/ppc')
-rw-r--r--target/ppc/Makefile.objs5
-rw-r--r--target/ppc/arch_dump.c154
-rw-r--r--target/ppc/cpu.c47
-rw-r--r--target/ppc/cpu.h50
-rw-r--r--target/ppc/int_helper.c34
-rw-r--r--target/ppc/kvm.c128
-rw-r--r--target/ppc/kvm_ppc.h20
-rw-r--r--target/ppc/machine.c5
-rw-r--r--target/ppc/misc_helper.c8
-rw-r--r--target/ppc/mmu-hash32.c14
-rw-r--r--target/ppc/mmu-hash32.h34
-rw-r--r--target/ppc/mmu-hash64.c193
-rw-r--r--target/ppc/mmu-hash64.h65
-rw-r--r--target/ppc/mmu_helper.c51
-rw-r--r--target/ppc/translate.c115
-rw-r--r--target/ppc/translate_init.c39
16 files changed, 525 insertions, 437 deletions
diff --git a/target/ppc/Makefile.objs b/target/ppc/Makefile.objs
index a8c7a30cde..0057b319c0 100644
--- a/target/ppc/Makefile.objs
+++ b/target/ppc/Makefile.objs
@@ -1,8 +1,9 @@
obj-y += cpu-models.o
+obj-y += cpu.o
obj-y += translate.o
ifeq ($(CONFIG_SOFTMMU),y)
-obj-y += machine.o mmu_helper.o mmu-hash32.o monitor.o
-obj-$(TARGET_PPC64) += mmu-hash64.o arch_dump.o compat.o
+obj-y += machine.o mmu_helper.o mmu-hash32.o monitor.o arch_dump.o
+obj-$(TARGET_PPC64) += mmu-hash64.o compat.o
endif
obj-$(CONFIG_KVM) += kvm.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c
index 40282a1f50..28d9cc7d79 100644
--- a/target/ppc/arch_dump.c
+++ b/target/ppc/arch_dump.c
@@ -1,5 +1,5 @@
/*
- * writing ELF notes for ppc64 arch
+ * writing ELF notes for ppc{64,} arch
*
*
* Copyright IBM, Corp. 2013
@@ -19,36 +19,48 @@
#include "sysemu/dump.h"
#include "sysemu/kvm.h"
-struct PPC64UserRegStruct {
- uint64_t gpr[32];
- uint64_t nip;
- uint64_t msr;
- uint64_t orig_gpr3;
- uint64_t ctr;
- uint64_t link;
- uint64_t xer;
- uint64_t ccr;
- uint64_t softe;
- uint64_t trap;
- uint64_t dar;
- uint64_t dsisr;
- uint64_t result;
+#ifdef TARGET_PPC64
+#define ELFCLASS ELFCLASS64
+#define cpu_to_dump_reg cpu_to_dump64
+typedef uint64_t reg_t;
+typedef Elf64_Nhdr Elf_Nhdr;
+#else
+#define ELFCLASS ELFCLASS32
+#define cpu_to_dump_reg cpu_to_dump32
+typedef uint32_t reg_t;
+typedef Elf32_Nhdr Elf_Nhdr;
+#endif /* TARGET_PPC64 */
+
+struct PPCUserRegStruct {
+ reg_t gpr[32];
+ reg_t nip;
+ reg_t msr;
+ reg_t orig_gpr3;
+ reg_t ctr;
+ reg_t link;
+ reg_t xer;
+ reg_t ccr;
+ reg_t softe;
+ reg_t trap;
+ reg_t dar;
+ reg_t dsisr;
+ reg_t result;
} QEMU_PACKED;
-struct PPC64ElfPrstatus {
+struct PPCElfPrstatus {
char pad1[112];
- struct PPC64UserRegStruct pr_reg;
- uint64_t pad2[4];
+ struct PPCUserRegStruct pr_reg;
+ reg_t pad2[4];
} QEMU_PACKED;
-struct PPC64ElfFpregset {
+struct PPCElfFpregset {
uint64_t fpr[32];
- uint64_t fpscr;
+ reg_t fpscr;
} QEMU_PACKED;
-struct PPC64ElfVmxregset {
+struct PPCElfVmxregset {
ppc_avr_t avr[32];
ppc_avr_t vscr;
union {
@@ -57,26 +69,26 @@ struct PPC64ElfVmxregset {
} vrsave;
} QEMU_PACKED;
-struct PPC64ElfVsxregset {
+struct PPCElfVsxregset {
uint64_t vsr[32];
} QEMU_PACKED;
-struct PPC64ElfSperegset {
+struct PPCElfSperegset {
uint32_t evr[32];
uint64_t spe_acc;
uint32_t spe_fscr;
} QEMU_PACKED;
typedef struct noteStruct {
- Elf64_Nhdr hdr;
+ Elf_Nhdr hdr;
char name[5];
char pad3[3];
union {
- struct PPC64ElfPrstatus prstatus;
- struct PPC64ElfFpregset fpregset;
- struct PPC64ElfVmxregset vmxregset;
- struct PPC64ElfVsxregset vsxregset;
- struct PPC64ElfSperegset speregset;
+ struct PPCElfPrstatus prstatus;
+ struct PPCElfFpregset fpregset;
+ struct PPCElfVmxregset vmxregset;
+ struct PPCElfVsxregset vsxregset;
+ struct PPCElfSperegset speregset;
} contents;
} QEMU_PACKED Note;
@@ -85,12 +97,12 @@ typedef struct NoteFuncArg {
DumpState *state;
} NoteFuncArg;
-static void ppc64_write_elf64_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
{
int i;
- uint64_t cr;
- struct PPC64ElfPrstatus *prstatus;
- struct PPC64UserRegStruct *reg;
+ reg_t cr;
+ struct PPCElfPrstatus *prstatus;
+ struct PPCUserRegStruct *reg;
Note *note = &arg->note;
DumpState *s = arg->state;
@@ -101,25 +113,25 @@ static void ppc64_write_elf64_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
reg = &prstatus->pr_reg;
for (i = 0; i < 32; i++) {
- reg->gpr[i] = cpu_to_dump64(s, cpu->env.gpr[i]);
+ reg->gpr[i] = cpu_to_dump_reg(s, cpu->env.gpr[i]);
}
- reg->nip = cpu_to_dump64(s, cpu->env.nip);
- reg->msr = cpu_to_dump64(s, cpu->env.msr);
- reg->ctr = cpu_to_dump64(s, cpu->env.ctr);
- reg->link = cpu_to_dump64(s, cpu->env.lr);
- reg->xer = cpu_to_dump64(s, cpu_read_xer(&cpu->env));
+ reg->nip = cpu_to_dump_reg(s, cpu->env.nip);
+ reg->msr = cpu_to_dump_reg(s, cpu->env.msr);
+ reg->ctr = cpu_to_dump_reg(s, cpu->env.ctr);
+ reg->link = cpu_to_dump_reg(s, cpu->env.lr);
+ reg->xer = cpu_to_dump_reg(s, cpu_read_xer(&cpu->env));
cr = 0;
for (i = 0; i < 8; i++) {
cr |= (cpu->env.crf[i] & 15) << (4 * (7 - i));
}
- reg->ccr = cpu_to_dump64(s, cr);
+ reg->ccr = cpu_to_dump_reg(s, cr);
}
-static void ppc64_write_elf64_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
{
int i;
- struct PPC64ElfFpregset *fpregset;
+ struct PPCElfFpregset *fpregset;
Note *note = &arg->note;
DumpState *s = arg->state;
@@ -131,13 +143,13 @@ static void ppc64_write_elf64_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
for (i = 0; i < 32; i++) {
fpregset->fpr[i] = cpu_to_dump64(s, cpu->env.fpr[i]);
}
- fpregset->fpscr = cpu_to_dump64(s, cpu->env.fpscr);
+ fpregset->fpscr = cpu_to_dump_reg(s, cpu->env.fpscr);
}
-static void ppc64_write_elf64_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
{
int i;
- struct PPC64ElfVmxregset *vmxregset;
+ struct PPCElfVmxregset *vmxregset;
Note *note = &arg->note;
DumpState *s = arg->state;
@@ -164,10 +176,11 @@ static void ppc64_write_elf64_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
}
vmxregset->vscr.u32[3] = cpu_to_dump32(s, cpu->env.vscr);
}
-static void ppc64_write_elf64_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+
+static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
{
int i;
- struct PPC64ElfVsxregset *vsxregset;
+ struct PPCElfVsxregset *vsxregset;
Note *note = &arg->note;
DumpState *s = arg->state;
@@ -179,9 +192,10 @@ static void ppc64_write_elf64_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
vsxregset->vsr[i] = cpu_to_dump64(s, cpu->env.vsr[i]);
}
}
-static void ppc64_write_elf64_speregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+
+static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu)
{
- struct PPC64ElfSperegset *speregset;
+ struct PPCElfSperegset *speregset;
Note *note = &arg->note;
DumpState *s = arg->state;
@@ -197,11 +211,11 @@ static const struct NoteFuncDescStruct {
int contents_size;
void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu);
} note_func[] = {
- {sizeof(((Note *)0)->contents.prstatus), ppc64_write_elf64_prstatus},
- {sizeof(((Note *)0)->contents.fpregset), ppc64_write_elf64_fpregset},
- {sizeof(((Note *)0)->contents.vmxregset), ppc64_write_elf64_vmxregset},
- {sizeof(((Note *)0)->contents.vsxregset), ppc64_write_elf64_vsxregset},
- {sizeof(((Note *)0)->contents.speregset), ppc64_write_elf64_speregset},
+ {sizeof(((Note *)0)->contents.prstatus), ppc_write_elf_prstatus},
+ {sizeof(((Note *)0)->contents.fpregset), ppc_write_elf_fpregset},
+ {sizeof(((Note *)0)->contents.vmxregset), ppc_write_elf_vmxregset},
+ {sizeof(((Note *)0)->contents.vsxregset), ppc_write_elf_vsxregset},
+ {sizeof(((Note *)0)->contents.speregset), ppc_write_elf_speregset},
{ 0, NULL}
};
@@ -213,8 +227,9 @@ int cpu_get_dump_info(ArchDumpInfo *info,
PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- info->d_machine = EM_PPC64;
- info->d_class = ELFCLASS64;
+ info->d_machine = PPC_ELF_MACHINE;
+ info->d_class = ELFCLASS;
+
if ((*pcc->interrupts_big_endian)(cpu)) {
info->d_endian = ELFDATA2MSB;
} else {
@@ -236,25 +251,19 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
int note_head_size;
const NoteFuncDesc *nf;
- if (class != ELFCLASS64) {
- return -1;
- }
- assert(machine == EM_PPC64);
-
- note_head_size = sizeof(Elf64_Nhdr);
-
+ note_head_size = sizeof(Elf_Nhdr);
for (nf = note_func; nf->note_contents_func; nf++) {
elf_note_size = elf_note_size + note_head_size + name_size +
- nf->contents_size;
+ nf->contents_size;
}
return (elf_note_size) * nr_cpus;
}
-static int ppc64_write_all_elf64_notes(const char *note_name,
- WriteCoreDumpFunction f,
- PowerPCCPU *cpu, int id,
- void *opaque)
+static int ppc_write_all_elf_notes(const char *note_name,
+ WriteCoreDumpFunction f,
+ PowerPCCPU *cpu, int id,
+ void *opaque)
{
NoteFuncArg arg = { .state = opaque };
int ret = -1;
@@ -282,5 +291,12 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
- return ppc64_write_all_elf64_notes("CORE", f, cpu, cpuid, opaque);
+ return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque);
+}
+
+int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque);
}
diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
new file mode 100644
index 0000000000..28011668e7
--- /dev/null
+++ b/target/ppc/cpu.c
@@ -0,0 +1,47 @@
+/*
+ * PowerPC CPU routines for qemu.
+ *
+ * Copyright (c) 2017 Nikunj A Dadhania, 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 "cpu.h"
+#include "cpu-models.h"
+
+target_ulong cpu_read_xer(CPUPPCState *env)
+{
+ if (is_isa300(env)) {
+ return env->xer | (env->so << XER_SO) |
+ (env->ov << XER_OV) | (env->ca << XER_CA) |
+ (env->ov32 << XER_OV32) | (env->ca32 << XER_CA32);
+ }
+
+ return env->xer | (env->so << XER_SO) | (env->ov << XER_OV) |
+ (env->ca << XER_CA);
+}
+
+void cpu_write_xer(CPUPPCState *env, target_ulong xer)
+{
+ env->so = (xer >> XER_SO) & 1;
+ env->ov = (xer >> XER_OV) & 1;
+ env->ca = (xer >> XER_CA) & 1;
+ /* write all the flags, while reading back check of isa300 */
+ env->ov32 = (xer >> XER_OV32) & 1;
+ env->ca32 = (xer >> XER_CA32) & 1;
+ env->xer = xer & ~((1ul << XER_SO) |
+ (1ul << XER_OV) | (1ul << XER_CA) |
+ (1ul << XER_OV32) | (1ul << XER_CA32));
+}
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 425e79d52d..d33c17e646 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -223,11 +223,12 @@ enum {
typedef struct opc_handler_t opc_handler_t;
/*****************************************************************************/
-/* Types used to describe some PowerPC registers */
+/* Types used to describe some PowerPC registers etc. */
typedef struct DisasContext DisasContext;
typedef struct ppc_spr_t ppc_spr_t;
typedef union ppc_avr_t ppc_avr_t;
typedef union ppc_tlb_t ppc_tlb_t;
+typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
/* SPR access micro-ops generations callbacks */
struct ppc_spr_t {
@@ -305,14 +306,6 @@ union ppc_tlb_t {
#define TLB_MAS 3
#endif
-#define SDR_32_HTABORG 0xFFFF0000UL
-#define SDR_32_HTABMASK 0x000001FFUL
-
-#if defined(TARGET_PPC64)
-#define SDR_64_HTABORG 0xFFFFFFFFFFFC0000ULL
-#define SDR_64_HTABSIZE 0x000000000000001FULL
-#endif /* defined(TARGET_PPC64 */
-
typedef struct ppc_slb_t ppc_slb_t;
struct ppc_slb_t {
uint64_t esid;
@@ -965,6 +958,8 @@ struct CPUPPCState {
target_ulong so;
target_ulong ov;
target_ulong ca;
+ target_ulong ov32;
+ target_ulong ca32;
/* Reservation address */
target_ulong reserve_addr;
/* Reservation value */
@@ -1005,12 +1000,7 @@ struct CPUPPCState {
/* tcg TLB needs flush (deferred slb inval instruction typically) */
#endif
/* segment registers */
- hwaddr htab_base;
- /* mask used to normalize hash value to PTEG index */
- hwaddr htab_mask;
target_ulong sr[32];
- /* externally stored hash table */
- uint8_t *external_htab;
/* BATs */
uint32_t nb_BATs;
target_ulong DBAT[2][8];
@@ -1218,6 +1208,14 @@ struct PPCVirtualHypervisor {
struct PPCVirtualHypervisorClass {
InterfaceClass parent;
void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
+ hwaddr (*hpt_mask)(PPCVirtualHypervisor *vhyp);
+ const ppc_hash_pte64_t *(*map_hptes)(PPCVirtualHypervisor *vhyp,
+ hwaddr ptex, int n);
+ void (*unmap_hptes)(PPCVirtualHypervisor *vhyp,
+ const ppc_hash_pte64_t *hptes,
+ hwaddr ptex, int n);
+ void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
+ uint64_t pte0, uint64_t pte1);
};
#define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
@@ -1243,6 +1241,8 @@ int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
+int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque);
#ifndef CONFIG_USER_ONLY
void ppc_cpu_do_system_reset(CPUState *cs);
extern const struct VMStateDescription vmstate_ppc_cpu;
@@ -1300,8 +1300,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val);
void store_booke_tsr (CPUPPCState *env, target_ulong val);
void ppc_tlb_invalidate_all (CPUPPCState *env);
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
-void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
-void cpu_ppc_set_papr(PowerPCCPU *cpu);
+void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
#endif
#endif
@@ -1372,11 +1371,15 @@ int ppc_compat_max_threads(PowerPCCPU *cpu);
#define XER_SO 31
#define XER_OV 30
#define XER_CA 29
+#define XER_OV32 19
+#define XER_CA32 18
#define XER_CMP 8
#define XER_BC 0
#define xer_so (env->so)
#define xer_ov (env->ov)
#define xer_ca (env->ca)
+#define xer_ov32 (env->ov)
+#define xer_ca32 (env->ca)
#define xer_cmp ((env->xer >> XER_CMP) & 0xFF)
#define xer_bc ((env->xer >> XER_BC) & 0x7F)
@@ -2343,18 +2346,9 @@ enum {
/*****************************************************************************/
-static inline target_ulong cpu_read_xer(CPUPPCState *env)
-{
- return env->xer | (env->so << XER_SO) | (env->ov << XER_OV) | (env->ca << XER_CA);
-}
-
-static inline void cpu_write_xer(CPUPPCState *env, target_ulong xer)
-{
- env->so = (xer >> XER_SO) & 1;
- env->ov = (xer >> XER_OV) & 1;
- env->ca = (xer >> XER_CA) & 1;
- env->xer = xer & ~((1u << XER_SO) | (1u << XER_OV) | (1u << XER_CA));
-}
+#define is_isa300(ctx) (!!(ctx->insns_flags2 & PPC2_ISA300))
+target_ulong cpu_read_xer(CPUPPCState *env);
+void cpu_write_xer(CPUPPCState *env, target_ulong xer);
static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index dd0a8929b3..da4e1a62c9 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -28,6 +28,15 @@
/*****************************************************************************/
/* Fixed point operations helpers */
+static inline void helper_update_ov_legacy(CPUPPCState *env, int ov)
+{
+ if (unlikely(ov)) {
+ env->so = env->ov = 1;
+ } else {
+ env->ov = 0;
+ }
+}
+
target_ulong helper_divweu(CPUPPCState *env, target_ulong ra, target_ulong rb,
uint32_t oe)
{
@@ -49,11 +58,7 @@ target_ulong helper_divweu(CPUPPCState *env, target_ulong ra, target_ulong rb,
}
if (oe) {
- if (unlikely(overflow)) {
- env->so = env->ov = 1;
- } else {
- env->ov = 0;
- }
+ helper_update_ov_legacy(env, overflow);
}
return (target_ulong)rt;
@@ -81,11 +86,7 @@ target_ulong helper_divwe(CPUPPCState *env, target_ulong ra, target_ulong rb,
}
if (oe) {
- if (unlikely(overflow)) {
- env->so = env->ov = 1;
- } else {
- env->ov = 0;
- }
+ helper_update_ov_legacy(env, overflow);
}
return (target_ulong)rt;
@@ -105,11 +106,7 @@ uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe)
}
if (oe) {
- if (unlikely(overflow)) {
- env->so = env->ov = 1;
- } else {
- env->ov = 0;
- }
+ helper_update_ov_legacy(env, overflow);
}
return rt;
@@ -127,12 +124,7 @@ uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
}
if (oe) {
-
- if (unlikely(overflow)) {
- env->so = env->ov = 1;
- } else {
- env->ov = 0;
- }
+ helper_update_ov_legacy(env, overflow);
}
return rt;
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 52bbea514a..acc40ece65 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1251,7 +1251,7 @@ static int kvmppc_get_books_sregs(PowerPCCPU *cpu)
return ret;
}
- if (!env->external_htab) {
+ if (!cpu->vhyp) {
ppc_store_sdr1(env, sregs.u.s.sdr1);
}
@@ -2596,89 +2596,85 @@ void kvm_arch_init_irq_routing(KVMState *s)
{
}
-struct kvm_get_htab_buf {
- struct kvm_get_htab_header header;
- /*
- * We require one extra byte for read
- */
- target_ulong hpte[(HPTES_PER_GROUP * 2) + 1];
-};
-
-uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
+void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, hwaddr ptex, int n)
{
- int htab_fd;
- struct kvm_get_htab_fd ghf;
- struct kvm_get_htab_buf *hpte_buf;
+ struct kvm_get_htab_fd ghf = {
+ .flags = 0,
+ .start_index = ptex,
+ };
+ int fd, rc;
+ int i;
- ghf.flags = 0;
- ghf.start_index = pte_index;
- htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
- if (htab_fd < 0) {
- goto error_out;
+ fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
+ if (fd < 0) {
+ hw_error("kvmppc_read_hptes: Unable to open HPT fd");
}
- hpte_buf = g_malloc0(sizeof(*hpte_buf));
- /*
- * Read the hpte group
- */
- if (read(htab_fd, hpte_buf, sizeof(*hpte_buf)) < 0) {
- goto out_close;
- }
+ i = 0;
+ while (i < n) {
+ struct kvm_get_htab_header *hdr;
+ int m = n < HPTES_PER_GROUP ? n : HPTES_PER_GROUP;
+ char buf[sizeof(*hdr) + m * HASH_PTE_SIZE_64];
- close(htab_fd);
- return (uint64_t)(uintptr_t) hpte_buf->hpte;
+ rc = read(fd, buf, sizeof(buf));
+ if (rc < 0) {
+ hw_error("kvmppc_read_hptes: Unable to read HPTEs");
+ }
-out_close:
- g_free(hpte_buf);
- close(htab_fd);
-error_out:
- return 0;
-}
+ hdr = (struct kvm_get_htab_header *)buf;
+ while ((i < n) && ((char *)hdr < (buf + rc))) {
+ int invalid = hdr->n_invalid;
-void kvmppc_hash64_free_pteg(uint64_t token)
-{
- struct kvm_get_htab_buf *htab_buf;
+ if (hdr->index != (ptex + i)) {
+ hw_error("kvmppc_read_hptes: Unexpected HPTE index %"PRIu32
+ " != (%"HWADDR_PRIu" + %d", hdr->index, ptex, i);
+ }
+
+ memcpy(hptes + i, hdr + 1, HASH_PTE_SIZE_64 * hdr->n_valid);
+ i += hdr->n_valid;
- htab_buf = container_of((void *)(uintptr_t) token, struct kvm_get_htab_buf,
- hpte);
- g_free(htab_buf);
- return;
+ if ((n - i) < invalid) {
+ invalid = n - i;
+ }
+ memset(hptes + i, 0, invalid * HASH_PTE_SIZE_64);
+ i += hdr->n_invalid;
+
+ hdr = (struct kvm_get_htab_header *)
+ ((char *)(hdr + 1) + HASH_PTE_SIZE_64 * hdr->n_valid);
+ }
+ }
+
+ close(fd);
}
-void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
- target_ulong pte0, target_ulong pte1)
+void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1)
{
- int htab_fd;
+ int fd, rc;
struct kvm_get_htab_fd ghf;
- struct kvm_get_htab_buf hpte_buf;
+ struct {
+ struct kvm_get_htab_header hdr;
+ uint64_t pte0;
+ uint64_t pte1;
+ } buf;
ghf.flags = 0;
ghf.start_index = 0; /* Ignored */
- htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
- if (htab_fd < 0) {
- goto error_out;
- }
-
- hpte_buf.header.n_valid = 1;
- hpte_buf.header.n_invalid = 0;
- hpte_buf.header.index = pte_index;
- hpte_buf.hpte[0] = pte0;
- hpte_buf.hpte[1] = pte1;
- /*
- * Write the hpte entry.
- * CAUTION: write() has the warn_unused_result attribute. Hence we
- * need to check the return value, even though we do nothing.
- */
- if (write(htab_fd, &hpte_buf, sizeof(hpte_buf)) < 0) {
- goto out_close;
+ fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
+ if (fd < 0) {
+ hw_error("kvmppc_write_hpte: Unable to open HPT fd");
}
-out_close:
- close(htab_fd);
- return;
+ buf.hdr.n_valid = 1;
+ buf.hdr.n_invalid = 0;
+ buf.hdr.index = ptex;
+ buf.pte0 = cpu_to_be64(pte0);
+ buf.pte1 = cpu_to_be64(pte1);
-error_out:
- return;
+ rc = write(fd, &buf, sizeof(buf));
+ if (rc != sizeof(buf)) {
+ hw_error("kvmppc_write_hpte: Unable to update KVM HPT");
+ }
+ close(fd);
}
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 8da2ee418a..8e9f42d0c6 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -49,11 +49,8 @@ int kvmppc_get_htab_fd(bool write);
int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns);
int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
uint16_t n_valid, uint16_t n_invalid);
-uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index);
-void kvmppc_hash64_free_pteg(uint64_t token);
-
-void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
- target_ulong pte0, target_ulong pte1);
+void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, hwaddr ptex, int n);
+void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1);
bool kvmppc_has_cap_fixup_hcalls(void);
bool kvmppc_has_cap_htm(void);
int kvmppc_enable_hwrng(void);
@@ -234,20 +231,13 @@ static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
abort();
}
-static inline uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu,
- target_ulong pte_index)
-{
- abort();
-}
-
-static inline void kvmppc_hash64_free_pteg(uint64_t token)
+static inline void kvmppc_read_hptes(ppc_hash_pte64_t *hptes,
+ hwaddr ptex, int n)
{
abort();
}
-static inline void kvmppc_hash64_write_pte(CPUPPCState *env,
- target_ulong pte_index,
- target_ulong pte0, target_ulong pte1)
+static inline void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1)
{
abort();
}
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index df9f7a4e05..6cb3a48db1 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -76,7 +76,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
qemu_get_betls(f, &env->pb[i]);
for (i = 0; i < 1024; i++)
qemu_get_betls(f, &env->spr[i]);
- if (!env->external_htab) {
+ if (!cpu->vhyp) {
ppc_store_sdr1(env, sdr1);
}
qemu_get_be32s(f, &env->vscr);
@@ -228,8 +228,7 @@ static int cpu_post_load(void *opaque, int version_id)
env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1];
}
- if (!env->external_htab) {
- /* Restore htab_base and htab_mask variables */
+ if (!cpu->vhyp) {
ppc_store_sdr1(env, env->spr[SPR_SDR1]);
}
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index ab432bafaf..fa573dd7d2 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -82,11 +82,9 @@ void helper_store_sdr1(CPUPPCState *env, target_ulong val)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
- if (!env->external_htab) {
- if (env->spr[SPR_SDR1] != val) {
- ppc_store_sdr1(env, val);
- tlb_flush(CPU(cpu));
- }
+ if (env->spr[SPR_SDR1] != val) {
+ ppc_store_sdr1(env, val);
+ tlb_flush(CPU(cpu));
}
}
diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
index 29bace622a..03ae3c1279 100644
--- a/target/ppc/mmu-hash32.c
+++ b/target/ppc/mmu-hash32.c
@@ -304,9 +304,9 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
{
- CPUPPCState *env = &cpu->env;
+ target_ulong mask = ppc_hash32_hpt_mask(cpu);
- return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
+ return (hash * HASH_PTEG_SIZE_32) & mask;
}
static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
@@ -339,7 +339,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
target_ulong sr, target_ulong eaddr,
ppc_hash_pte32_t *pte)
{
- CPUPPCState *env = &cpu->env;
hwaddr pteg_off, pte_offset;
hwaddr hash;
uint32_t vsid, pgidx, ptem;
@@ -353,21 +352,22 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
" htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
+ ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
/* Primary PTEG lookup */
qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=%" PRIx32 " ptem=%" PRIx32
" hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ptem, hash);
+ ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
+ vsid, ptem, hash);
pteg_off = get_pteg_offset32(cpu, hash);
pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
if (pte_offset == -1) {
/* Secondary PTEG lookup */
qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=%" PRIx32 " api=%" PRIx32
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ptem, ~hash);
+ " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
+ ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
pteg_off = get_pteg_offset32(cpu, ~hash);
pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
}
diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
index 5b9fb08d1a..898021f0d8 100644
--- a/target/ppc/mmu-hash32.h
+++ b/target/ppc/mmu-hash32.h
@@ -44,6 +44,8 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
/*
* Hash page table definitions
*/
+#define SDR_32_HTABORG 0xFFFF0000UL
+#define SDR_32_HTABMASK 0x000001FFUL
#define HPTES_PER_GROUP 8
#define HASH_PTE_SIZE_32 8
@@ -65,42 +67,46 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
#define HPTE32_R_WIMG 0x00000078
#define HPTE32_R_PP 0x00000003
+static inline hwaddr ppc_hash32_hpt_base(PowerPCCPU *cpu)
+{
+ return cpu->env.spr[SPR_SDR1] & SDR_32_HTABORG;
+}
+
+static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
+{
+ return ((cpu->env.spr[SPR_SDR1] & SDR_32_HTABMASK) << 16) | 0xFFFF;
+}
+
static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
hwaddr pte_offset)
{
- CPUPPCState *env = &cpu->env;
+ target_ulong base = ppc_hash32_hpt_base(cpu);
- assert(!env->external_htab); /* Not supported on 32-bit for now */
- return ldl_phys(CPU(cpu)->as, env->htab_base + pte_offset);
+ return ldl_phys(CPU(cpu)->as, base + pte_offset);
}
static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
hwaddr pte_offset)
{
- CPUPPCState *env = &cpu->env;
+ target_ulong base = ppc_hash32_hpt_base(cpu);
- assert(!env->external_htab); /* Not supported on 32-bit for now */
- return ldl_phys(CPU(cpu)->as,
- env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2);
+ return ldl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2);
}
static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
hwaddr pte_offset, target_ulong pte0)
{
- CPUPPCState *env = &cpu->env;
+ target_ulong base = ppc_hash32_hpt_base(cpu);
- assert(!env->external_htab); /* Not supported on 32-bit for now */
- stl_phys(CPU(cpu)->as, env->htab_base + pte_offset, pte0);
+ stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
}
static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
hwaddr pte_offset, target_ulong pte1)
{
- CPUPPCState *env = &cpu->env;
+ target_ulong base = ppc_hash32_hpt_base(cpu);
- assert(!env->external_htab); /* Not supported on 32-bit for now */
- stl_phys(CPU(cpu)->as,
- env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
+ stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
}
typedef struct {
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index 76669ed82c..d44f2bb432 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -27,6 +27,7 @@
#include "kvm_ppc.h"
#include "mmu-hash64.h"
#include "exec/log.h"
+#include "hw/hw.h"
//#define DEBUG_SLB
@@ -37,12 +38,6 @@
#endif
/*
- * Used to indicate that a CPU has its hash page table (HPT) managed
- * within the host kernel
- */
-#define MMU_HASH64_KVM_MANAGED_HPT ((void *)-1)
-
-/*
* SLB handling
*/
@@ -294,55 +289,6 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
return rt;
}
-/*
- * 64-bit hash table MMU handling
- */
-void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
- Error **errp)
-{
- CPUPPCState *env = &cpu->env;
- target_ulong htabsize = value & SDR_64_HTABSIZE;
-
- env->spr[SPR_SDR1] = value;
- if (htabsize > 28) {
- error_setg(errp,
- "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
- htabsize);
- htabsize = 28;
- }
- env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
- env->htab_base = value & SDR_64_HTABORG;
-}
-
-void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
- Error **errp)
-{
- CPUPPCState *env = &cpu->env;
- Error *local_err = NULL;
-
- if (hpt) {
- env->external_htab = hpt;
- } else {
- env->external_htab = MMU_HASH64_KVM_MANAGED_HPT;
- }
- ppc_hash64_set_sdr1(cpu, (target_ulong)(uintptr_t)hpt | (shift - 18),
- &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* Not strictly necessary, but makes it clearer that an external
- * htab is in use when debugging */
- env->htab_base = -1;
-
- if (kvm_enabled()) {
- if (kvmppc_put_books_sregs(cpu) < 0) {
- error_setg(errp, "Unable to update SDR1 in KVM");
- }
- }
-}
-
static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
ppc_slb_t *slb, ppc_hash_pte64_t pte)
{
@@ -431,34 +377,43 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
return prot;
}
-uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
+const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
+ hwaddr ptex, int n)
{
- uint64_t token = 0;
- hwaddr pte_offset;
+ hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
+ hwaddr base = ppc_hash64_hpt_base(cpu);
+ hwaddr plen = n * HASH_PTE_SIZE_64;
+ const ppc_hash_pte64_t *hptes;
+
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ return vhc->map_hptes(cpu->vhyp, ptex, n);
+ }
- pte_offset = pte_index * HASH_PTE_SIZE_64;
- if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
- /*
- * HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
- */
- token = kvmppc_hash64_read_pteg(cpu, pte_index);
- } else if (cpu->env.external_htab) {
- /*
- * HTAB is controlled by QEMU. Just point to the internally
- * accessible PTEG.
- */
- token = (uint64_t)(uintptr_t) cpu->env.external_htab + pte_offset;
- } else if (cpu->env.htab_base) {
- token = cpu->env.htab_base + pte_offset;
+ if (!base) {
+ return NULL;
}
- return token;
+
+ hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false);
+ if (plen < (n * HASH_PTE_SIZE_64)) {
+ hw_error("%s: Unable to map all requested HPTEs\n", __func__);
+ }
+ return hptes;
}
-void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token)
+void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
+ hwaddr ptex, int n)
{
- if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
- kvmppc_hash64_free_pteg(token);
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->unmap_hptes(cpu->vhyp, hptes, ptex, n);
+ return;
}
+
+ address_space_unmap(CPU(cpu)->as, (void *)hptes, n * HASH_PTE_SIZE_64,
+ false, n * HASH_PTE_SIZE_64);
}
static unsigned hpte_page_shift(const struct ppc_one_seg_page_size *sps,
@@ -503,20 +458,19 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
target_ulong ptem,
ppc_hash_pte64_t *pte, unsigned *pshift)
{
- CPUPPCState *env = &cpu->env;
int i;
- uint64_t token;
+ const ppc_hash_pte64_t *pteg;
target_ulong pte0, pte1;
- target_ulong pte_index;
+ target_ulong ptex;
- pte_index = (hash & env->htab_mask) * HPTES_PER_GROUP;
- token = ppc_hash64_start_access(cpu, pte_index);
- if (!token) {
+ ptex = (hash & ppc_hash64_hpt_mask(cpu)) * HPTES_PER_GROUP;
+ pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
+ if (!pteg) {
return -1;
}
for (i = 0; i < HPTES_PER_GROUP; i++) {
- pte0 = ppc_hash64_load_hpte0(cpu, token, i);
- pte1 = ppc_hash64_load_hpte1(cpu, token, i);
+ pte0 = ppc_hash64_hpte0(cpu, pteg, i);
+ pte1 = ppc_hash64_hpte1(cpu, pteg, i);
/* This compares V, B, H (secondary) and the AVPN */
if (HPTE64_V_COMPARE(pte0, ptem)) {
@@ -536,11 +490,11 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
*/
pte->pte0 = pte0;
pte->pte1 = pte1;
- ppc_hash64_stop_access(cpu, token);
- return (pte_index + i) * HASH_PTE_SIZE_64;
+ ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
+ return ptex + i;
}
}
- ppc_hash64_stop_access(cpu, token);
+ ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
/*
* We didn't find a valid entry.
*/
@@ -552,8 +506,7 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
ppc_hash_pte64_t *pte, unsigned *pshift)
{
CPUPPCState *env = &cpu->env;
- hwaddr pte_offset;
- hwaddr hash;
+ hwaddr hash, ptex;
uint64_t vsid, epnmask, epn, ptem;
const struct ppc_one_seg_page_size *sps = slb->sps;
@@ -588,29 +541,30 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
qemu_log_mask(CPU_LOG_MMU,
"htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
+ ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), hash);
/* Primary PTEG lookup */
qemu_log_mask(CPU_LOG_MMU,
"0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ptem, hash);
- pte_offset = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
+ ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
+ vsid, ptem, hash);
+ ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
- if (pte_offset == -1) {
+ if (ptex == -1) {
/* Secondary PTEG lookup */
ptem |= HPTE64_V_SECONDARY;
qemu_log_mask(CPU_LOG_MMU,
"1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ptem, ~hash);
+ " hash=" TARGET_FMT_plx "\n", ppc_hash64_hpt_base(cpu),
+ ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash);
- pte_offset = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
+ ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
}
- return pte_offset;
+ return ptex;
}
unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
@@ -708,7 +662,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
CPUPPCState *env = &cpu->env;
ppc_slb_t *slb;
unsigned apshift;
- hwaddr pte_offset;
+ hwaddr ptex;
ppc_hash_pte64_t pte;
int pp_prot, amr_prot, prot;
uint64_t new_pte1, dsisr;
@@ -792,8 +746,8 @@ skip_slb_search:
}
/* 4. Locate the PTE in the hash table */
- pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
- if (pte_offset == -1) {
+ 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);
@@ -806,7 +760,7 @@ skip_slb_search:
return 1;
}
qemu_log_mask(CPU_LOG_MMU,
- "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
+ "found PTE at index %08" HWADDR_PRIx "\n", ptex);
/* 5. Check access permissions */
@@ -849,8 +803,7 @@ skip_slb_search:
}
if (new_pte1 != pte.pte1) {
- ppc_hash64_store_hpte(cpu, pte_offset / HASH_PTE_SIZE_64,
- pte.pte0, new_pte1);
+ ppc_hash64_store_hpte(cpu, ptex, pte.pte0, new_pte1);
}
/* 7. Determine the real address from the PTE */
@@ -867,7 +820,7 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
{
CPUPPCState *env = &cpu->env;
ppc_slb_t *slb;
- hwaddr pte_offset, raddr;
+ hwaddr ptex, raddr;
ppc_hash_pte64_t pte;
unsigned apshift;
@@ -900,8 +853,8 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
}
}
- pte_offset = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
- if (pte_offset == -1) {
+ ptex = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
+ if (ptex == -1) {
return -1;
}
@@ -909,30 +862,24 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
& TARGET_PAGE_MASK;
}
-void ppc_hash64_store_hpte(PowerPCCPU *cpu,
- target_ulong pte_index,
- target_ulong pte0, target_ulong pte1)
+void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
+ uint64_t pte0, uint64_t pte1)
{
- CPUPPCState *env = &cpu->env;
+ hwaddr base = ppc_hash64_hpt_base(cpu);
+ hwaddr offset = ptex * HASH_PTE_SIZE_64;
- if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
- kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->store_hpte(cpu->vhyp, ptex, pte0, pte1);
return;
}
- pte_index *= HASH_PTE_SIZE_64;
- if (env->external_htab) {
- stq_p(env->external_htab + pte_index, pte0);
- stq_p(env->external_htab + pte_index + HASH_PTE_SIZE_64 / 2, pte1);
- } else {
- stq_phys(CPU(cpu)->as, env->htab_base + pte_index, pte0);
- stq_phys(CPU(cpu)->as,
- env->htab_base + pte_index + HASH_PTE_SIZE_64 / 2, pte1);
- }
+ stq_phys(CPU(cpu)->as, base + offset, pte0);
+ stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
}
-void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
- target_ulong pte_index,
+void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
target_ulong pte0, target_ulong pte1)
{
/*
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index 7a0b7fca41..54f1e37655 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -10,8 +10,8 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot,
hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr);
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
int mmu_idx);
-void ppc_hash64_store_hpte(PowerPCCPU *cpu, target_ulong index,
- target_ulong pte0, target_ulong pte1);
+void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
+ uint64_t pte0, uint64_t pte1);
void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
target_ulong pte_index,
target_ulong pte0, target_ulong pte1);
@@ -56,6 +56,9 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
* Hash page table definitions
*/
+#define SDR_64_HTABORG 0x0FFFFFFFFFFC0000ULL
+#define SDR_64_HTABSIZE 0x000000000000001FULL
+
#define HPTES_PER_GROUP 8
#define HASH_PTE_SIZE_64 16
#define HASH_PTEG_SIZE_64 (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
@@ -91,45 +94,41 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL
-void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
- Error **errp);
-void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
- Error **errp);
-
-uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index);
-void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token);
-
-static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
- uint64_t token, int index)
+static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
{
- CPUPPCState *env = &cpu->env;
- uint64_t addr;
-
- addr = token + (index * HASH_PTE_SIZE_64);
- if (env->external_htab) {
- return ldq_p((const void *)(uintptr_t)addr);
- } else {
- return ldq_phys(CPU(cpu)->as, addr);
- }
+ return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG;
}
-static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu,
- uint64_t token, int index)
+static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
{
- CPUPPCState *env = &cpu->env;
- uint64_t addr;
-
- addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
- if (env->external_htab) {
- return ldq_p((const void *)(uintptr_t)addr);
- } else {
- return ldq_phys(CPU(cpu)->as, addr);
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ return vhc->hpt_mask(cpu->vhyp);
}
+ return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18 - 7)) - 1;
}
-typedef struct {
+struct ppc_hash_pte64 {
uint64_t pte0, pte1;
-} ppc_hash_pte64_t;
+};
+
+const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
+ hwaddr ptex, int n);
+void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
+ hwaddr ptex, int n);
+
+static inline uint64_t ppc_hash64_hpte0(PowerPCCPU *cpu,
+ const ppc_hash_pte64_t *hptes, int i)
+{
+ return ldq_p(&(hptes[i].pte0));
+}
+
+static inline uint64_t ppc_hash64_hpte1(PowerPCCPU *cpu,
+ const ppc_hash_pte64_t *hptes, int i)
+{
+ return ldq_p(&(hptes[i].pte1));
+}
#endif /* CONFIG_USER_ONLY */
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index eb2d482ef7..a1af3d6bf2 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -28,6 +28,7 @@
#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "helper_regs.h"
+#include "qemu/error-report.h"
//#define DEBUG_MMU
//#define DEBUG_BATS
@@ -466,6 +467,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int type)
{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
hwaddr hash;
target_ulong vsid;
int ds, pr, target_page_bits;
@@ -503,7 +505,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
" htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
+ ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
ctx->hash[0] = hash;
ctx->hash[1] = ~hash;
@@ -518,9 +520,11 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
uint32_t a0, a1, a2, a3;
qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
- "\n", env->htab_base, env->htab_mask + 0x80);
- for (curaddr = env->htab_base;
- curaddr < (env->htab_base + env->htab_mask + 0x80);
+ "\n", ppc_hash32_hpt_base(cpu),
+ ppc_hash32_hpt_mask(env) + 0x80);
+ for (curaddr = ppc_hash32_hpt_base(cpu);
+ curaddr < (ppc_hash32_hpt_base(cpu)
+ + ppc_hash32_hpt_mask(cpu) + 0x80);
curaddr += 16) {
a0 = ldl_phys(cs->as, curaddr);
a1 = ldl_phys(cs->as, curaddr + 4);
@@ -1205,12 +1209,13 @@ static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
CPUPPCState *env)
{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
ppc6xx_tlb_t *tlb;
target_ulong sr;
int type, way, entry, i;
- cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
- cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
+ cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
+ cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
cpu_fprintf(f, "\nSegment registers:\n");
for (i = 0; i < 32; i++) {
@@ -1592,9 +1597,9 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
tlb_miss:
env->error_code |= ctx.key << 19;
- env->spr[SPR_HASH1] = env->htab_base +
+ env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
get_pteg_offset32(cpu, ctx.hash[0]);
- env->spr[SPR_HASH2] = env->htab_base +
+ env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
get_pteg_offset32(cpu, ctx.hash[1]);
break;
case POWERPC_MMU_SOFT_74xx:
@@ -1997,26 +2002,28 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
/* Special registers manipulation */
void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
- assert(!env->external_htab);
- env->spr[SPR_SDR1] = value;
+ assert(!cpu->vhyp);
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
- Error *local_err = NULL;
+ target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
+ target_ulong htabsize = value & SDR_64_HTABSIZE;
- ppc_hash64_set_sdr1(cpu, value, &local_err);
- if (local_err) {
- error_report_err(local_err);
- error_free(local_err);
+ if (value & ~sdr_mask) {
+ error_report("Invalid bits 0x"TARGET_FMT_lx" set in SDR1",
+ value & ~sdr_mask);
+ value &= sdr_mask;
+ }
+ if (htabsize > 28) {
+ error_report("Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
+ htabsize);
+ return;
}
- } else
-#endif /* defined(TARGET_PPC64) */
- {
- /* FIXME: Should check for valid HTABMASK values */
- env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
- env->htab_base = value & SDR_32_HTABORG;
}
+#endif /* defined(TARGET_PPC64) */
+ /* FIXME: Should check for valid HTABMASK values in 32-bit case */
+ env->spr[SPR_SDR1] = value;
}
/* Segment registers load and store */
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 3ba2616b8a..6e6868b7a0 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -71,7 +71,7 @@ static TCGv cpu_lr;
#if defined(TARGET_PPC64)
static TCGv cpu_cfar;
#endif
-static TCGv cpu_xer, cpu_so, cpu_ov, cpu_ca;
+static TCGv cpu_xer, cpu_so, cpu_ov, cpu_ca, cpu_ov32, cpu_ca32;
static TCGv cpu_reserve;
static TCGv cpu_fpscr;
static TCGv_i32 cpu_access_type;
@@ -173,6 +173,10 @@ void ppc_translate_init(void)
offsetof(CPUPPCState, ov), "OV");
cpu_ca = tcg_global_mem_new(cpu_env,
offsetof(CPUPPCState, ca), "CA");
+ cpu_ov32 = tcg_global_mem_new(cpu_env,
+ offsetof(CPUPPCState, ov32), "OV32");
+ cpu_ca32 = tcg_global_mem_new(cpu_env,
+ offsetof(CPUPPCState, ca32), "CA32");
cpu_reserve = tcg_global_mem_new(cpu_env,
offsetof(CPUPPCState, reserve_addr),
@@ -806,12 +810,40 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
}
tcg_temp_free(t0);
if (NARROW_MODE(ctx)) {
- tcg_gen_ext32s_tl(cpu_ov, cpu_ov);
+ tcg_gen_extract_tl(cpu_ov, cpu_ov, 31, 1);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ov32, cpu_ov);
+ }
+ } else {
+ if (is_isa300(ctx)) {
+ tcg_gen_extract_tl(cpu_ov32, cpu_ov, 31, 1);
+ }
+ tcg_gen_extract_tl(cpu_ov, cpu_ov, 63, 1);
}
- tcg_gen_shri_tl(cpu_ov, cpu_ov, TARGET_LONG_BITS - 1);
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
+static inline void gen_op_arith_compute_ca32(DisasContext *ctx,
+ TCGv res, TCGv arg0, TCGv arg1,
+ int sub)
+{
+ TCGv t0;
+
+ if (!is_isa300(ctx)) {
+ return;
+ }
+
+ t0 = tcg_temp_new();
+ if (sub) {
+ tcg_gen_eqv_tl(t0, arg0, arg1);
+ } else {
+ tcg_gen_xor_tl(t0, arg0, arg1);
+ }
+ tcg_gen_xor_tl(t0, t0, res);
+ tcg_gen_extract_tl(cpu_ca32, t0, 32, 1);
+ tcg_temp_free(t0);
+}
+
/* Common add function */
static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
TCGv arg2, bool add_ca, bool compute_ca,
@@ -838,6 +870,9 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_temp_free(t1);
tcg_gen_shri_tl(cpu_ca, cpu_ca, 32); /* extract bit 32 */
tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ca32, cpu_ca);
+ }
} else {
TCGv zero = tcg_const_tl(0);
if (add_ca) {
@@ -846,6 +881,7 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
} else {
tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
}
+ gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, 0);
tcg_temp_free(zero);
}
} else {
@@ -985,6 +1021,9 @@ static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1,
}
if (compute_ov) {
tcg_gen_extu_i32_tl(cpu_ov, t2);
+ if (is_isa300(ctx)) {
+ tcg_gen_extu_i32_tl(cpu_ov32, t2);
+ }
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
tcg_temp_free_i32(t0);
@@ -1056,6 +1095,9 @@ static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1,
}
if (compute_ov) {
tcg_gen_mov_tl(cpu_ov, t2);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ov32, t2);
+ }
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
tcg_temp_free_i64(t0);
@@ -1074,10 +1116,10 @@ static void glue(gen_, name)(DisasContext *ctx)
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
sign, compute_ov); \
}
-/* divwu divwu. divwuo divwuo. */
+/* divdu divdu. divduo divduo. */
GEN_INT_ARITH_DIVD(divdu, 0x0E, 0, 0);
GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1);
-/* divw divw. divwo divwo. */
+/* divd divd. divdo divdo. */
GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0);
GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1);
@@ -1249,6 +1291,9 @@ static void gen_mullwo(DisasContext *ctx)
tcg_gen_sari_i32(t0, t0, 31);
tcg_gen_setcond_i32(TCG_COND_NE, t0, t0, t1);
tcg_gen_extu_i32_tl(cpu_ov, t0);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ov32, cpu_ov);
+ }
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
tcg_temp_free_i32(t0);
@@ -1310,6 +1355,9 @@ static void gen_mulldo(DisasContext *ctx)
tcg_gen_sari_i64(t0, t0, 63);
tcg_gen_setcond_i64(TCG_COND_NE, cpu_ov, t0, t1);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ov32, cpu_ov);
+ }
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
tcg_temp_free_i64(t0);
@@ -1353,17 +1401,22 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_temp_free(t1);
tcg_gen_shri_tl(cpu_ca, cpu_ca, 32); /* extract bit 32 */
tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ca32, cpu_ca);
+ }
} else if (add_ca) {
TCGv zero, inv1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1);
zero = tcg_const_tl(0);
tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero);
tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero);
+ gen_op_arith_compute_ca32(ctx, t0, inv1, arg2, 0);
tcg_temp_free(zero);
tcg_temp_free(inv1);
} else {
tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1);
tcg_gen_sub_tl(t0, arg2, arg1);
+ gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, 1);
}
} else if (add_ca) {
/* Since we're ignoring carry-out, we can simplify the
@@ -1442,7 +1495,10 @@ static inline void gen_op_arith_neg(DisasContext *ctx, bool compute_ov)
static void gen_neg(DisasContext *ctx)
{
- gen_op_arith_neg(ctx, 0);
+ tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+ if (unlikely(Rc(ctx->opcode))) {
+ gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+ }
}
static void gen_nego(DisasContext *ctx)
@@ -3703,7 +3759,7 @@ static void gen_tdi(DisasContext *ctx)
/*** Processor control ***/
-static void gen_read_xer(TCGv dst)
+static void gen_read_xer(DisasContext *ctx, TCGv dst)
{
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
@@ -3715,6 +3771,12 @@ static void gen_read_xer(TCGv dst)
tcg_gen_or_tl(t0, t0, t1);
tcg_gen_or_tl(dst, dst, t2);
tcg_gen_or_tl(dst, dst, t0);
+ if (is_isa300(ctx)) {
+ tcg_gen_shli_tl(t0, cpu_ov32, XER_OV32);
+ tcg_gen_or_tl(dst, dst, t0);
+ tcg_gen_shli_tl(t0, cpu_ca32, XER_CA32);
+ tcg_gen_or_tl(dst, dst, t0);
+ }
tcg_temp_free(t0);
tcg_temp_free(t1);
tcg_temp_free(t2);
@@ -3722,14 +3784,16 @@ static void gen_read_xer(TCGv dst)
static void gen_write_xer(TCGv src)
{
+ /* Write all flags, while reading back check for isa300 */
tcg_gen_andi_tl(cpu_xer, src,
- ~((1u << XER_SO) | (1u << XER_OV) | (1u << XER_CA)));
- tcg_gen_shri_tl(cpu_so, src, XER_SO);
- tcg_gen_shri_tl(cpu_ov, src, XER_OV);
- tcg_gen_shri_tl(cpu_ca, src, XER_CA);
- tcg_gen_andi_tl(cpu_so, cpu_so, 1);
- tcg_gen_andi_tl(cpu_ov, cpu_ov, 1);
- tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
+ ~((1u << XER_SO) |
+ (1u << XER_OV) | (1u << XER_OV32) |
+ (1u << XER_CA) | (1u << XER_CA32)));
+ tcg_gen_extract_tl(cpu_ov32, src, XER_OV32, 1);
+ tcg_gen_extract_tl(cpu_ca32, src, XER_CA32, 1);
+ tcg_gen_extract_tl(cpu_so, src, XER_SO, 1);
+ tcg_gen_extract_tl(cpu_ov, src, XER_OV, 1);
+ tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
}
/* mcrxr */
@@ -3755,6 +3819,28 @@ static void gen_mcrxr(DisasContext *ctx)
tcg_gen_movi_tl(cpu_ca, 0);
}
+#ifdef TARGET_PPC64
+/* mcrxrx */
+static void gen_mcrxrx(DisasContext *ctx)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv_i32 dst = cpu_crf[crfD(ctx->opcode)];
+
+ /* copy OV and OV32 */
+ tcg_gen_shli_tl(t0, cpu_ov, 1);
+ tcg_gen_or_tl(t0, t0, cpu_ov32);
+ tcg_gen_shli_tl(t0, t0, 2);
+ /* copy CA and CA32 */
+ tcg_gen_shli_tl(t1, cpu_ca, 1);
+ tcg_gen_or_tl(t1, t1, cpu_ca32);
+ tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_trunc_tl_i32(dst, t0);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+#endif
+
/* mfcr mfocrf */
static void gen_mfcr(DisasContext *ctx)
{
@@ -6424,6 +6510,7 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC),
#if defined(TARGET_PPC64)
GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B),
GEN_HANDLER_E(setb, 0x1F, 0x00, 0x04, 0x0003F801, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(mcrxrx, 0x1F, 0x00, 0x12, 0x007FF801, PPC_NONE, PPC2_ISA300),
#endif
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001EF801, PPC_MISC),
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC),
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index be35cbd3a2..37f74be984 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -107,7 +107,7 @@ static void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
/* XER */
static void spr_read_xer (DisasContext *ctx, int gprn, int sprn)
{
- gen_read_xer(cpu_gpr[gprn]);
+ gen_read_xer(ctx, cpu_gpr[gprn]);
}
static void spr_write_xer (DisasContext *ctx, int sprn, int gprn)
@@ -740,10 +740,22 @@ static void gen_spr_ne_601 (CPUPPCState *env)
&spr_read_decr, &spr_write_decr,
0x00000000);
/* Memory management */
- spr_register(env, SPR_SDR1, "SDR1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_sdr1,
- 0x00000000);
+#ifndef CONFIG_USER_ONLY
+ if (env->has_hv_mode) {
+ /* SDR1 is a hypervisor resource on CPUs which have a
+ * hypervisor mode */
+ spr_register_hv(env, SPR_SDR1, "SDR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_sdr1,
+ 0x00000000);
+ } else {
+ spr_register(env, SPR_SDR1, "SDR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_sdr1,
+ 0x00000000);
+ }
+#endif
}
/* BATs 0-3 */
@@ -8835,18 +8847,14 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
}
#if !defined(CONFIG_USER_ONLY)
-
-void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
-{
- cpu->vhyp = vhyp;
-}
-
-void cpu_ppc_set_papr(PowerPCCPU *cpu)
+void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
{
CPUPPCState *env = &cpu->env;
ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR];
ppc_spr_t *amor = &env->spr_cb[SPR_AMOR];
+ cpu->vhyp = vhyp;
+
/* PAPR always has exception vectors in RAM not ROM. To ensure this,
* MSR[IP] should never be set.
*
@@ -10489,11 +10497,12 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
#else
cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_ppc_cpu;
-#if defined(TARGET_PPC64)
- cc->write_elf64_note = ppc64_cpu_write_elf64_note;
-#endif
#endif
cc->cpu_exec_enter = ppc_cpu_exec_enter;
+#if defined(CONFIG_SOFTMMU)
+ cc->write_elf64_note = ppc64_cpu_write_elf64_note;
+ cc->write_elf32_note = ppc32_cpu_write_elf32_note;
+#endif
cc->gdb_num_core_regs = 71;