From 1529ae1bc61a15e9a243dcbad70c95dfcdd1f0c5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 20 Jan 2012 14:41:12 +0100 Subject: [PATCH 01/21] KVM: Update headers (except HIOR mess) This patch is basically what ./scripts/update-linux-headers.sh against upstream KVM's next branch outputs except that all the HIOR bits are removed. These we have to update with the code that uses them. Signed-off-by: Alexander Graf --- linux-headers/asm-powerpc/kvm.h | 9 ++---- linux-headers/asm-powerpc/kvm_para.h | 41 ++++++++++++++++++++++++++-- linux-headers/asm-s390/kvm.h | 9 ++++++ linux-headers/asm-x86/hyperv.h | 1 + linux-headers/asm-x86/kvm.h | 4 +++ linux-headers/linux/kvm.h | 41 ++++++++++++++++++++++++++++ linux-headers/linux/kvm_para.h | 1 - linux-headers/linux/virtio_ring.h | 6 ++-- 8 files changed, 100 insertions(+), 12 deletions(-) diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index fb3fddcd87..1f0cb55af5 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -265,12 +265,9 @@ struct kvm_debug_exit_arch { struct kvm_guest_debug_arch { }; -#define KVM_REG_MASK 0x001f -#define KVM_REG_EXT_MASK 0xffe0 -#define KVM_REG_GPR 0x0000 -#define KVM_REG_FPR 0x0020 -#define KVM_REG_QPR 0x0040 -#define KVM_REG_FQPR 0x0060 +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; #define KVM_INTERRUPT_SET -1U #define KVM_INTERRUPT_UNSET -2U diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h index ad58c90bf5..c047a84000 100644 --- a/linux-headers/asm-powerpc/kvm_para.h +++ b/linux-headers/asm-powerpc/kvm_para.h @@ -22,6 +22,16 @@ #include +/* + * Additions to this struct must only occur at the end, and should be + * accompanied by a KVM_MAGIC_FEAT flag to advertise that they are present + * (albeit not necessarily relevant to the current target hardware platform). + * + * Struct fields are always 32 or 64 bit aligned, depending on them being 32 + * or 64 bit wide respectively. + * + * See Documentation/virtual/kvm/ppc-pv.txt + */ struct kvm_vcpu_arch_shared { __u64 scratch1; __u64 scratch2; @@ -33,11 +43,35 @@ struct kvm_vcpu_arch_shared { __u64 sprg3; __u64 srr0; __u64 srr1; - __u64 dar; + __u64 dar; /* dear on BookE */ __u64 msr; __u32 dsisr; __u32 int_pending; /* Tells the guest if we have an interrupt */ __u32 sr[16]; + __u32 mas0; + __u32 mas1; + __u64 mas7_3; + __u64 mas2; + __u32 mas4; + __u32 mas6; + __u32 esr; + __u32 pir; + + /* + * SPRG4-7 are user-readable, so we can only keep these consistent + * between the shared area and the real registers when there's an + * intervening exit to KVM. This also applies to SPRG3 on some + * chips. + * + * This suffices for access by guest userspace, since in PR-mode + * KVM, an exit must occur when changing the guest's MSR[PR]. + * If the guest kernel writes to SPRG3-7 via the shared area, it + * must also use the shared area for reading while in kernel space. + */ + __u64 sprg4; + __u64 sprg5; + __u64 sprg6; + __u64 sprg7; }; #define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */ @@ -47,7 +81,10 @@ struct kvm_vcpu_arch_shared { #define KVM_FEATURE_MAGIC_PAGE 1 -#define KVM_MAGIC_FEAT_SR (1 << 0) +#define KVM_MAGIC_FEAT_SR (1 << 0) + +/* MASn, ESR, PIR, and high SPRGs */ +#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1) #endif /* __POWERPC_KVM_PARA_H__ */ diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h index 82b32a100c..9acbde4af2 100644 --- a/linux-headers/asm-s390/kvm.h +++ b/linux-headers/asm-s390/kvm.h @@ -41,4 +41,13 @@ struct kvm_debug_exit_arch { struct kvm_guest_debug_arch { }; +#define KVM_SYNC_PREFIX (1UL << 0) +#define KVM_SYNC_GPRS (1UL << 1) +#define KVM_SYNC_ACRS (1UL << 2) +/* definition of registers in kvm_run */ +struct kvm_sync_regs { + __u64 prefix; /* prefix register */ + __u64 gprs[16]; /* general purpose registers */ + __u32 acrs[16]; /* access registers */ +}; #endif diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h index 5df477ac3a..b80420bcd0 100644 --- a/linux-headers/asm-x86/hyperv.h +++ b/linux-headers/asm-x86/hyperv.h @@ -189,5 +189,6 @@ #define HV_STATUS_INVALID_HYPERCALL_CODE 2 #define HV_STATUS_INVALID_HYPERCALL_INPUT 3 #define HV_STATUS_INVALID_ALIGNMENT 4 +#define HV_STATUS_INSUFFICIENT_BUFFERS 19 #endif diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 4d8dcbdfc1..e7d1c194d2 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -321,4 +321,8 @@ struct kvm_xcrs { __u64 padding[16]; }; +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; + #endif /* _ASM_X86_KVM_H */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index a8761d3be6..4847813c55 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -162,6 +162,7 @@ struct kvm_pit_config { #define KVM_EXIT_INTERNAL_ERROR 17 #define KVM_EXIT_OSI 18 #define KVM_EXIT_PAPR_HCALL 19 +#define KVM_EXIT_S390_UCONTROL 20 /* For KVM_EXIT_INTERNAL_ERROR */ #define KVM_INTERNAL_ERROR_EMULATION 1 @@ -249,6 +250,11 @@ struct kvm_run { #define KVM_S390_RESET_CPU_INIT 8 #define KVM_S390_RESET_IPL 16 __u64 s390_reset_flags; + /* KVM_EXIT_S390_UCONTROL */ + struct { + __u64 trans_exc_code; + __u32 pgm_code; + } s390_ucontrol; /* KVM_EXIT_DCR */ struct { __u32 dcrn; @@ -273,6 +279,20 @@ struct kvm_run { /* Fix the size of the union. */ char padding[256]; }; + + /* + * shared registers between kvm and userspace. + * kvm_valid_regs specifies the register classes set by the host + * kvm_dirty_regs specified the register classes dirtied by userspace + * struct kvm_sync_regs is architecture specific, as well as the + * bits for kvm_valid_regs and kvm_dirty_regs + */ + __u64 kvm_valid_regs; + __u64 kvm_dirty_regs; + union { + struct kvm_sync_regs regs; + char padding[1024]; + } s; }; /* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */ @@ -371,6 +391,7 @@ struct kvm_s390_psw { #define KVM_S390_INT_VIRTIO 0xffff2603u #define KVM_S390_INT_SERVICE 0xffff2401u #define KVM_S390_INT_EMERGENCY 0xffff1201u +#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u struct kvm_s390_interrupt { __u32 type; @@ -430,6 +451,11 @@ struct kvm_ppc_pvinfo { #define KVMIO 0xAE +/* machine type bits, to be used as argument to KVM_CREATE_VM */ +#define KVM_VM_S390_UCONTROL 1 + +#define KVM_S390_SIE_PAGE_OFFSET 1 + /* * ioctls for /dev/kvm fds: */ @@ -558,6 +584,10 @@ struct kvm_ppc_pvinfo { #define KVM_CAP_PPC_PAPR 68 #define KVM_CAP_SW_TLB 69 #define KVM_CAP_ONE_REG 70 +#define KVM_CAP_S390_GMAP 71 +#define KVM_CAP_TSC_DEADLINE_TIMER 72 +#define KVM_CAP_S390_UCONTROL 73 +#define KVM_CAP_SYNC_REGS 74 #ifdef KVM_CAP_IRQ_ROUTING @@ -698,6 +728,17 @@ struct kvm_one_reg { struct kvm_userspace_memory_region) #define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47) #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64) + +/* enable ucontrol for s390 */ +struct kvm_s390_ucas_mapping { + __u64 user_addr; + __u64 vcpu_addr; + __u64 length; +}; +#define KVM_S390_UCAS_MAP _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping) +#define KVM_S390_UCAS_UNMAP _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping) +#define KVM_S390_VCPU_FAULT _IOW(KVMIO, 0x52, unsigned long) + /* Device model IOC */ #define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) #define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h index b315e27a9c..7bdcf93c1d 100644 --- a/linux-headers/linux/kvm_para.h +++ b/linux-headers/linux/kvm_para.h @@ -26,4 +26,3 @@ #include #endif /* __LINUX_KVM_PARA_H */ - diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h index 78289eedf2..1b333e2536 100644 --- a/linux-headers/linux/virtio_ring.h +++ b/linux-headers/linux/virtio_ring.h @@ -135,13 +135,13 @@ static __inline__ void vring_init(struct vring *vr, unsigned int num, void *p, vr->num = num; vr->desc = p; vr->avail = p + num*sizeof(struct vring_desc); - vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1) - & ~(align - 1)); + vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(__u16) + + align-1) & ~(align - 1)); } static __inline__ unsigned vring_size(unsigned int num, unsigned long align) { - return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num) + return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num) + align - 1) & ~(align - 1)) + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num; } From a31be480a0b4ede50f260dd29971dca961da3a2c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 6 Jan 2012 04:02:24 +0100 Subject: [PATCH 02/21] PPC: KVM: Update HIOR code to new interface Unfortunately the HIOR setting code slipped into upstream QEMU before it was pulled into upstream KVM. And since Murphy is always right, comments on the patches only emerged on the pull request leading to changes in the interface. So here's an update to the HIOR setting. While at it, I also relaxed it a bit since for HV KVM we can already run fine without and 3.2 works just fine with HV KVM but when not setting HIOR. We will only need this when running PAPR in PR KVM. Since we accidently changed the ABI and API along the way, we have to update the underlying kernel headers together with the code that uses it to not break bisectability. Signed-off-by: Alexander Graf --- linux-headers/asm-powerpc/kvm.h | 2 +- linux-headers/linux/kvm.h | 37 ++++++++++++++++++--------------- target-ppc/kvm.c | 10 ++++++--- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 1f0cb55af5..b921c3f489 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -324,6 +324,6 @@ struct kvm_book3e_206_tlb_params { __u32 reserved[8]; }; -#define KVM_ONE_REG_PPC_HIOR KVM_ONE_REG_PPC | 0x100 +#define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1) #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 4847813c55..f6b53432db 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -684,30 +684,33 @@ struct kvm_dirty_tlb { /* Available with KVM_CAP_ONE_REG */ -#define KVM_ONE_REG_GENERIC 0x0000000000000000ULL +#define KVM_REG_ARCH_MASK 0xff00000000000000ULL +#define KVM_REG_GENERIC 0x0000000000000000ULL /* * Architecture specific registers are to be defined in arch headers and * ORed with the arch identifier. */ -#define KVM_ONE_REG_PPC 0x1000000000000000ULL -#define KVM_ONE_REG_X86 0x2000000000000000ULL -#define KVM_ONE_REG_IA64 0x3000000000000000ULL -#define KVM_ONE_REG_ARM 0x4000000000000000ULL -#define KVM_ONE_REG_S390 0x5000000000000000ULL +#define KVM_REG_PPC 0x1000000000000000ULL +#define KVM_REG_X86 0x2000000000000000ULL +#define KVM_REG_IA64 0x3000000000000000ULL +#define KVM_REG_ARM 0x4000000000000000ULL +#define KVM_REG_S390 0x5000000000000000ULL + +#define KVM_REG_SIZE_SHIFT 52 +#define KVM_REG_SIZE_MASK 0x00f0000000000000ULL +#define KVM_REG_SIZE_U8 0x0000000000000000ULL +#define KVM_REG_SIZE_U16 0x0010000000000000ULL +#define KVM_REG_SIZE_U32 0x0020000000000000ULL +#define KVM_REG_SIZE_U64 0x0030000000000000ULL +#define KVM_REG_SIZE_U128 0x0040000000000000ULL +#define KVM_REG_SIZE_U256 0x0050000000000000ULL +#define KVM_REG_SIZE_U512 0x0060000000000000ULL +#define KVM_REG_SIZE_U1024 0x0070000000000000ULL struct kvm_one_reg { __u64 id; - union { - __u8 reg8; - __u16 reg16; - __u32 reg32; - __u64 reg64; - __u8 reg128[16]; - __u8 reg256[32]; - __u8 reg512[64]; - __u8 reg1024[128]; - } u; + __u64 addr; }; /* @@ -850,7 +853,7 @@ struct kvm_s390_ucas_mapping { /* Available with KVM_CAP_SW_TLB */ #define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb) /* Available with KVM_CAP_ONE_REG */ -#define KVM_GET_ONE_REG _IOWR(KVMIO, 0xab, struct kvm_one_reg) +#define KVM_GET_ONE_REG _IOW(KVMIO, 0xab, struct kvm_one_reg) #define KVM_SET_ONE_REG _IOW(KVMIO, 0xac, struct kvm_one_reg) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index ce8ac5b4de..50cfa02f78 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -740,6 +740,7 @@ void kvmppc_set_papr(CPUState *env) struct kvm_one_reg reg = {}; struct kvm_sregs sregs = {}; int ret; + uint64_t hior = env->spr[SPR_HIOR]; cap.cap = KVM_CAP_PPC_PAPR; ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap); @@ -755,11 +756,14 @@ void kvmppc_set_papr(CPUState *env) * Once we have qdev CPUs, move HIOR to a qdev property and * remove this chunk. */ - reg.id = KVM_ONE_REG_PPC_HIOR; - reg.u.reg64 = env->spr[SPR_HIOR]; + reg.id = KVM_REG_PPC_HIOR; + reg.addr = (uintptr_t)&hior; ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®); if (ret) { - goto fail; + fprintf(stderr, "Couldn't set HIOR. Maybe you're running an old \n" + "kernel with support for HV KVM but no PAPR PR \n" + "KVM in which case things will work. If they don't \n" + "please update your host kernel!\n"); } /* Set SDR1 so kernel space finds the HTAB */ From e9205258ac7de7aba579ee07efc49dda66f51e63 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 19 Jan 2012 19:31:51 +0100 Subject: [PATCH 03/21] PPC: Add IVOR 38-42 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our code only knows IVORs up to 37. Add the new ones defined in ISA 2.06 from 38 - 42. Signed-off-by: Alexander Graf Reviewed-by: Andreas Färber --- target-ppc/cpu.h | 5 +++++ target-ppc/translate_init.c | 29 +++++++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 2d67d1f4b8..6f4cddecfa 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1371,6 +1371,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) #define SPR_BOOKE_IVOR13 (0x19D) #define SPR_BOOKE_IVOR14 (0x19E) #define SPR_BOOKE_IVOR15 (0x19F) +#define SPR_BOOKE_IVOR38 (0x1B0) +#define SPR_BOOKE_IVOR39 (0x1B1) +#define SPR_BOOKE_IVOR40 (0x1B2) +#define SPR_BOOKE_IVOR41 (0x1B3) +#define SPR_BOOKE_IVOR42 (0x1B4) #define SPR_BOOKE_SPEFSCR (0x200) #define SPR_Exxx_BBEAR (0x201) #define SPR_Exxx_BBTAR (0x202) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4d692d0dd3..83348b561a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -526,26 +526,27 @@ static void spr_write_excp_prefix (void *opaque, int sprn, int gprn) static void spr_write_excp_vector (void *opaque, int sprn, int gprn) { DisasContext *ctx = opaque; + int sprn_offs; if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) { - TCGv t0 = tcg_temp_new(); - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask)); - tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR0])); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); + sprn_offs = sprn - SPR_BOOKE_IVOR0; } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) { - TCGv t0 = tcg_temp_new(); - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask)); - tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR32 + 32])); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); + sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32; + } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) { + sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38; } else { printf("Trying to write an unknown exception vector %d %03x\n", sprn, sprn); gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + return; } + + TCGv t0 = tcg_temp_new(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask)); + tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn_offs])); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); } #endif @@ -1434,8 +1435,8 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask) SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVOR32, SPR_BOOKE_IVOR33, SPR_BOOKE_IVOR34, SPR_BOOKE_IVOR35, - SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, - SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVOR38, SPR_BOOKE_IVOR39, + SPR_BOOKE_IVOR40, SPR_BOOKE_IVOR41, SPR_BOOKE_IVOR42, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, From 2c9732dbc0df8c7c40c945b6558da8a448b8c069 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 19 Jan 2012 18:57:26 +0100 Subject: [PATCH 04/21] PPC: e500mc: add missing IVORs to bitmap E500mc supports IVORs 36-41. Add them to the support mask. Drop SPE support too. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 83348b561a..f5fcd1e936 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4433,6 +4433,7 @@ enum fsl_e500_version { static void init_proc_e500 (CPUPPCState *env, int version) { uint32_t tlbncfg[2]; + uint64_t ivor_mask = 0x0000000F0000FFFFULL; #if !defined(CONFIG_USER_ONLY) int i; #endif @@ -4444,7 +4445,10 @@ static void init_proc_e500 (CPUPPCState *env, int version) * complain when accessing them. * gen_spr_BookE(env, 0x0000000F0000FD7FULL); */ - gen_spr_BookE(env, 0x0000000F0000FFFFULL); + if (version == fsl_e500mc) { + ivor_mask = 0x000003FE0000FFFFULL; + } + gen_spr_BookE(env, ivor_mask); /* Processor identification */ spr_register(env, SPR_BOOKE_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, From 53319166318f365db3bb72cf5a80618211ecf9df Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 19 Jan 2012 19:51:50 +0100 Subject: [PATCH 05/21] PPC: e500: msync is 440 only, e500 has real sync The e500 CPUs don't use 440's msync which falls on the same opcode IDs, but instead use the real powerpc sync instruction. This is important, since the invalid mask differs between the two. Signed-off-by: Alexander Graf --- target-ppc/translate.c | 3 +-- target-ppc/translate_init.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 66eae30209..18d52a983a 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -8579,8 +8579,7 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE, PPC2_BOOKE206), -GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801, - PPC_BOOKE, PPC2_BOOKE206), +GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE), GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE, PPC2_BOOKE206), GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC), diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f5fcd1e936..b14a98c2b0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4371,7 +4371,7 @@ static void init_proc_e300 (CPUPPCState *env) PPC_WRTEE | PPC_RFDI | \ PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_TLBIVAX) + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC) #define POWERPC_INSNS2_e500v1 (PPC2_BOOKE206) #define POWERPC_MSRM_e500v1 (0x000000000606FF30ULL) #define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE206) @@ -4390,7 +4390,7 @@ static void init_proc_e300 (CPUPPCState *env) PPC_WRTEE | PPC_RFDI | \ PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_TLBIVAX) + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC) #define POWERPC_INSNS2_e500v2 (PPC2_BOOKE206) #define POWERPC_MSRM_e500v2 (0x000000000606FF30ULL) #define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE206) @@ -4411,7 +4411,7 @@ static void init_proc_e300 (CPUPPCState *env) PPC_FLOAT | PPC_FLOAT_FRES | \ PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ PPC_FLOAT_STFIWX | PPC_WAIT | \ - PPC_MEM_TLBSYNC | PPC_TLBIVAX) + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC) #define POWERPC_INSNS2_e500mc (PPC2_BOOKE206) #define POWERPC_MSRM_e500mc (0x000000001402FB36ULL) #define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206) From dcb2b9e1003a9179650b44c747faa4e5767ce92b Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 21 Jan 2012 03:48:58 +0100 Subject: [PATCH 06/21] PPC: rename msync to msync_4xx The msync instruction as defined today is only valid on 4xx cores, not on e500 which also supports msync, but treats it the same way as sync. Rename it to reflect that it's 4xx only. Signed-off-by: Alexander Graf --- target-ppc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 18d52a983a..adde65b277 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6172,7 +6172,7 @@ static void gen_mbar(DisasContext *ctx) } /* msync replaces sync on 440 */ -static void gen_msync(DisasContext *ctx) +static void gen_msync_4xx(DisasContext *ctx) { /* interpreted as no-op */ } @@ -8579,7 +8579,7 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE, PPC2_BOOKE206), -GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE), +GEN_HANDLER(msync_4xx, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE), GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE, PPC2_BOOKE206), GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC), From ffba87862b37f1d7762370c8d31b09f6e359ff09 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 20 Jan 2012 04:06:18 +0100 Subject: [PATCH 07/21] PPC: booke206: allow NULL raddr in ppcmas_tlb_check We might want to call the tlb check function without actually caring about the real address resolution. Check if we really should write the value back. Signed-off-by: Alexander Graf --- target-ppc/helper.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 58474536c0..2ce2d9238f 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1338,7 +1338,10 @@ int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb, if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) { return -1; } - *raddrp = (tlb->mas7_3 & mask) | (address & ~mask); + + if (raddrp) { + *raddrp = (tlb->mas7_3 & mask) | (address & ~mask); + } return 0; } From a1ef618a3768cc114b6fae4099af95df87654a04 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 21 Jan 2012 04:45:46 +0100 Subject: [PATCH 08/21] PPC: booke: add tlbnps handling When using MAV 2.0 TLB registers, we have another range of TLB registers available to read the supported page sizes from. Add SPR definitions for those and add a helper function that we can use to receive such a bitmap even when using MAV 1.0. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6f4cddecfa..1026254605 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1355,6 +1355,10 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) #define SPR_BOOKE_DVC2 (0x13F) #define SPR_BOOKE_TSR (0x150) #define SPR_BOOKE_TCR (0x154) +#define SPR_BOOKE_TLB0PS (0x158) +#define SPR_BOOKE_TLB1PS (0x159) +#define SPR_BOOKE_TLB2PS (0x15A) +#define SPR_BOOKE_TLB3PS (0x15B) #define SPR_BOOKE_IVOR0 (0x190) #define SPR_BOOKE_IVOR1 (0x191) #define SPR_BOOKE_IVOR2 (0x192) @@ -2116,6 +2120,27 @@ static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn, return &env->tlb.tlbm[r]; } +/* returns bitmap of supported page sizes for a given TLB */ +static inline uint32_t booke206_tlbnps(CPUState *env, const int tlbn) +{ + bool mav2 = false; + uint32_t ret = 0; + + if (mav2) { + ret = env->spr[SPR_BOOKE_TLB0PS + tlbn]; + } else { + uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn]; + uint32_t min = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT; + uint32_t max = (tlbncfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT; + int i; + for (i = min; i <= max; i++) { + ret |= (1 << (i << 1)); + } + } + + return ret; +} + #endif extern void (*cpu_ppc_hypercall)(CPUState *); From 5935ee072d6fbcdf28ff6132ba6d8c3a1356bb0a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 20 Jan 2012 04:07:51 +0100 Subject: [PATCH 09/21] PPC: booke206: Check for min/max TLB entry size When setting a TLB entry, we need to check if the TLB we're putting it in actually supports the given size. According to the 2.06 PowerPC ISA, a value that's out of range can either be redefined to something implementation dependent or we can raise an illegal opcode exception. We do the latter. Signed-off-by: Alexander Graf --- target-ppc/op_helper.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 6339c9559f..3b197f2deb 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -4228,6 +4228,7 @@ void helper_booke206_tlbwe(void) { uint32_t tlbncfg, tlbn; ppcmas_tlb_t *tlb; + uint32_t size_tlb, size_ps; switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) { case MAS0_WQ_ALWAYS: @@ -4259,6 +4260,16 @@ void helper_booke206_tlbwe(void) tlb = booke206_cur_tlb(env); + /* check that we support the targeted size */ + size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; + size_ps = booke206_tlbnps(env, tlbn); + if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) && + !(size_ps & (1 << size_tlb))) { + helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL); + } + if (msr_gs) { cpu_abort(env, "missing HV implementation\n"); } From 6d3db821c18fdc9727108b5b4bbb38cb7ab5c0e6 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 20 Jan 2012 04:09:15 +0100 Subject: [PATCH 10/21] PPC: booke206: Implement tlbilx The PowerPC 2.06 BookE ISA defines an opcode called "tlbilx" which is used to flush TLB entries. It's the recommended way of flushing in virtualized environments. So far we got away without implementing it, but Linux for e500mc uses this instruction, so we better add it :). Signed-off-by: Alexander Graf --- target-ppc/helper.h | 3 ++ target-ppc/op_helper.c | 64 ++++++++++++++++++++++++++++++++++++++++++ target-ppc/translate.c | 35 +++++++++++++++++++++++ 3 files changed, 102 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 470e42f676..4798fd57ee 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -336,6 +336,9 @@ DEF_HELPER_0(booke206_tlbre, void) DEF_HELPER_0(booke206_tlbwe, void) DEF_HELPER_1(booke206_tlbsx, void, tl) DEF_HELPER_1(booke206_tlbivax, void, tl) +DEF_HELPER_1(booke206_tlbilx0, void, tl) +DEF_HELPER_1(booke206_tlbilx1, void, tl) +DEF_HELPER_1(booke206_tlbilx3, void, tl) DEF_HELPER_1(booke206_tlbflush, void, i32) DEF_HELPER_2(booke_setpid, void, i32, tl) DEF_HELPER_1(6xx_tlbd, void, tl) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 3b197f2deb..1f1fa09368 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -4406,6 +4406,70 @@ void helper_booke206_tlbivax(target_ulong address) } } +void helper_booke206_tlbilx0(target_ulong address) +{ + /* XXX missing LPID handling */ + booke206_flush_tlb(env, -1, 1); +} + +void helper_booke206_tlbilx1(target_ulong address) +{ + int i, j; + int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); + ppcmas_tlb_t *tlb = env->tlb.tlbm; + int tlb_size; + + /* XXX missing LPID handling */ + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + tlb_size = booke206_tlb_size(env, i); + for (j = 0; j < tlb_size; j++) { + if (!(tlb[j].mas1 & MAS1_IPROT) && + ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) { + tlb[j].mas1 &= ~MAS1_VALID; + } + } + tlb += booke206_tlb_size(env, i); + } + tlb_flush(env, 1); +} + +void helper_booke206_tlbilx3(target_ulong address) +{ + int i, j; + ppcmas_tlb_t *tlb; + int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); + int pid = tid >> MAS6_SPID_SHIFT; + int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS; + int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0; + /* XXX check for unsupported isize and raise an invalid opcode then */ + int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK; + /* XXX implement MAV2 handling */ + bool mav2 = false; + + /* XXX missing LPID handling */ + /* flush by pid and ea */ + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + int ways = booke206_tlb_ways(env, i); + + for (j = 0; j < ways; j++) { + tlb = booke206_get_tlbm(env, i, address, j); + if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) || + (tlb->mas1 & MAS1_IPROT) || + ((tlb->mas1 & MAS1_IND) != ind) || + ((tlb->mas8 & MAS8_TGS) != sgs)) { + continue; + } + if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) { + /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */ + continue; + } + /* XXX e500mc doesn't match SAS, but other cores might */ + tlb->mas1 &= ~MAS1_VALID; + } + } + tlb_flush(env, 1); +} + void helper_booke206_tlbflush(uint32_t type) { int flags = 0; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index adde65b277..d8ef7196b4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6110,6 +6110,39 @@ static void gen_tlbivax_booke206(DisasContext *ctx) #endif } +static void gen_tlbilx_booke206(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +#else + TCGv t0; + if (unlikely(!ctx->mem_idx)) { + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return; + } + + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + + switch((ctx->opcode >> 21) & 0x3) { + case 0: + gen_helper_booke206_tlbilx0(t0); + break; + case 1: + gen_helper_booke206_tlbilx1(t0); + break; + case 3: + gen_helper_booke206_tlbilx3(t0); + break; + default: + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); + break; + } + + tcg_temp_free(t0); +#endif +} + /* wrtee */ static void gen_wrtee(DisasContext *ctx) @@ -8574,6 +8607,8 @@ GEN_HANDLER2_E(tlbwe_booke206, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001, PPC_NONE, PPC2_BOOKE206), +GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001, + PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), From 3f162d119ef52fda714ebb498fcb4f4b7c354d38 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 25 Jan 2012 16:27:26 +0100 Subject: [PATCH 11/21] PPC: booke206: Check for TLB overrun Our internal helpers to fetch TLB entries were not able to tell us that an entry doesn't even exist. Pass an error out if we hit such a case to not accidently pass beyond the TLB array. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 4 ++++ target-ppc/helper.c | 3 +++ target-ppc/op_helper.c | 22 +++++++++++++++++++++- target-ppc/translate.c | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1026254605..668ddf34cb 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -2112,6 +2112,10 @@ static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn, ea &= (1 << (tlb_bits - ways_bits)) - 1; r = (ea << ways_bits) | way; + if (r >= booke206_tlb_size(env, tlbn)) { + return NULL; + } + /* bump up to tlbn index */ for (i = 0; i < tlbn; i++) { r += booke206_tlb_size(env, i); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 2ce2d9238f..672494c593 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1448,6 +1448,9 @@ static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx, for (j = 0; j < ways; j++) { tlb = booke206_get_tlbm(env, i, address, j); + if (!tlb) { + continue; + } ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, access_type); if (ret != -1) { diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 1f1fa09368..be4e539c2d 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -4260,6 +4260,12 @@ void helper_booke206_tlbwe(void) tlb = booke206_cur_tlb(env); + if (!tlb) { + helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL); + } + /* check that we support the targeted size */ size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; size_ps = booke206_tlbnps(env, tlbn); @@ -4311,7 +4317,11 @@ void helper_booke206_tlbre(void) ppcmas_tlb_t *tlb = NULL; tlb = booke206_cur_tlb(env); - booke206_tlb_to_mas(env, tlb); + if (!tlb) { + env->spr[SPR_BOOKE_MAS1] = 0; + } else { + booke206_tlb_to_mas(env, tlb); + } } void helper_booke206_tlbsx(target_ulong address) @@ -4330,6 +4340,10 @@ void helper_booke206_tlbsx(target_ulong address) for (j = 0; j < ways; j++) { tlb = booke206_get_tlbm(env, i, address, j); + if (!tlb) { + continue; + } + if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) { continue; } @@ -4373,6 +4387,9 @@ static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn, for (i = 0; i < ways; i++) { ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i); + if (!tlb) { + continue; + } mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) && !(tlb->mas1 & MAS1_IPROT)) { @@ -4453,6 +4470,9 @@ void helper_booke206_tlbilx3(target_ulong address) for (j = 0; j < ways; j++) { tlb = booke206_get_tlbm(env, i, address, j); + if (!tlb) { + continue; + } if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) || (tlb->mas1 & MAS1_IPROT) || ((tlb->mas1 & MAS1_IND) != ind) || diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d8ef7196b4..58a4853a0d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6088,6 +6088,7 @@ static void gen_tlbwe_booke206(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } + gen_update_nip(ctx, ctx->nip - 4); gen_helper_booke206_tlbwe(); #endif } From 21a0b6ed1dd9f1d8e3d953954847776c8697bd99 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 25 Jan 2012 17:06:30 +0100 Subject: [PATCH 12/21] PPC: booke206: move avail check to tlbwe We can have TLBs that only support a single page size. This is defined by the absence of the AVAIL flag in TLBnCFG. If this is the case, we currently write invalid size info into the TLB, but override it on internal fault. Let's move the check over to tlbwe, so we don't have the AVAIL check in the hotter fault path. Signed-off-by: Alexander Graf --- target-ppc/helper.c | 8 +------- target-ppc/op_helper.c | 9 +++++++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 672494c593..31a98978dd 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1298,13 +1298,7 @@ target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb) int tlbm_size; tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn]; - - if (tlbncfg & TLBnCFG_AVAIL) { - tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; - } else { - tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT; - tlbm_size <<= 1; - } + tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; return 1024ULL << tlbm_size; } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index be4e539c2d..0d1206a649 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -4282,6 +4282,15 @@ void helper_booke206_tlbwe(void) tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | env->spr[SPR_BOOKE_MAS3]; tlb->mas1 = env->spr[SPR_BOOKE_MAS1]; + + /* MAV 1.0 only */ + if (!(tlbncfg & TLBnCFG_AVAIL)) { + /* force !AVAIL TLB entries to correct page size */ + tlb->mas1 &= ~MAS1_TSIZE_MASK; + /* XXX can be configured in MMUCSR0 */ + tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12; + } + /* XXX needs to change when supporting 64-bit e500 */ tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff; From a9c5eb0db1739d53e7a3b1491e496eb25d3db3f4 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 25 Jan 2012 18:28:05 +0100 Subject: [PATCH 13/21] KVM: Fix compilation on non-x86 Commit 84b058d broke compilation for KVM on non-x86 targets, which don't have KVM_CAP_IRQ_ROUTING defined. Fix by not using the unavailable constant when it's not around. Signed-off-by: Alexander Graf --- kvm-all.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kvm-all.c b/kvm-all.c index 7d4e544c52..0b87658f6a 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1306,7 +1306,11 @@ int kvm_has_many_ioeventfds(void) int kvm_has_gsi_routing(void) { +#ifdef KVM_CAP_IRQ_ROUTING return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING); +#else + return false; +#endif } int kvm_allows_irq0_override(void) From 0ef654e3fc40d15f9a0467dae8b9548b21d3ab93 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Jan 2012 03:09:58 +0100 Subject: [PATCH 14/21] PPC: E500: Add some more excp vectors Our EXCP list is getting outdated. By now, 3 new exception vectors have been introduced. Update the list so we have everything at one place. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 668ddf34cb..c7a6427ea9 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -187,7 +187,10 @@ enum { POWERPC_EXCP_EPERFM = 35, /* Embedded performance monitor interrupt */ POWERPC_EXCP_DOORI = 36, /* Embedded doorbell interrupt */ POWERPC_EXCP_DOORCI = 37, /* Embedded doorbell critical interrupt */ - /* Vectors 38 to 63 are reserved */ + POWERPC_EXCP_GDOORI = 38, /* Embedded guest doorbell interrupt */ + POWERPC_EXCP_GDOORCI = 39, /* Embedded guest doorbell critical interrupt*/ + POWERPC_EXCP_HYPPRIV = 41, /* Embedded hypervisor priv instruction */ + /* Vectors 42 to 63 are reserved */ /* Exceptions defined in the PowerPC server specification */ POWERPC_EXCP_RESET = 64, /* System reset exception */ POWERPC_EXCP_DSEG = 65, /* Data segment exception */ From 58e00a2432ace900eca96c1dec114a8be75c2de8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Jan 2012 03:11:32 +0100 Subject: [PATCH 15/21] PPC: E500: Add doorbell defines We're going to introduce doorbell instructions (called processor control in the spec) soon. Add some defines for easier patch readability later. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index c7a6427ea9..f9cea3d674 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -857,6 +857,22 @@ enum { /* number of possible TLBs */ #define BOOKE206_MAX_TLBN 4 +/*****************************************************************************/ +/* Embedded.Processor Control */ + +#define DBELL_TYPE_SHIFT 27 +#define DBELL_TYPE_MASK (0x1f << DBELL_TYPE_SHIFT) +#define DBELL_TYPE_DBELL (0x00 << DBELL_TYPE_SHIFT) +#define DBELL_TYPE_DBELL_CRIT (0x01 << DBELL_TYPE_SHIFT) +#define DBELL_TYPE_G_DBELL (0x02 << DBELL_TYPE_SHIFT) +#define DBELL_TYPE_G_DBELL_CRIT (0x03 << DBELL_TYPE_SHIFT) +#define DBELL_TYPE_G_DBELL_MC (0x04 << DBELL_TYPE_SHIFT) + +#define DBELL_BRDCAST (1 << 26) +#define DBELL_LPIDTAG_SHIFT 14 +#define DBELL_LPIDTAG_MASK (0xfff << DBELL_LPIDTAG_SHIFT) +#define DBELL_PIRTAG_MASK 0x3fff + /*****************************************************************************/ /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 From 3f9f6a50824f6e6728cbcc008891296102fc045a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Jan 2012 03:13:30 +0100 Subject: [PATCH 16/21] PPC: Add CPU feature for processor control We're soon going to implement processor control features. Add the feature flag, so we're well prepared. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f9cea3d674..fbcf4881a8 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1916,8 +1916,10 @@ enum { PPC2_VSX = 0x0000000000000002ULL, /* Decimal Floating Point (DFP) */ PPC2_DFP = 0x0000000000000004ULL, + /* Embedded.Processor Control */ + PPC2_PRCNTL = 0x0000000000000008ULL, -#define PPC_TCG_INSNS2 (PPC2_BOOKE206) +#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL) }; /*****************************************************************************/ From a9abd71770e64d22ba6cb40c30e4c35998e5c743 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Jan 2012 03:17:24 +0100 Subject: [PATCH 17/21] PPC: Enable doorbell excp handlers We already had all the code available to have doorbell exceptions be handled properly. It was just disabled. Enable it, so we can rely on it. Signed-off-by: Alexander Graf --- target-ppc/helper.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 31a98978dd..e56fac8684 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2698,22 +2698,10 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp) "Performance counter exception is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ - /* XXX: TODO */ - cpu_abort(env, - "Embedded doorbell interrupt is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ - switch (excp_model) { - case POWERPC_EXCP_BOOKE: - srr0 = SPR_BOOKE_CSRR0; - srr1 = SPR_BOOKE_CSRR1; - break; - default: - break; - } - /* XXX: TODO */ - cpu_abort(env, "Embedded doorbell critical interrupt " - "is not implemented yet !\n"); + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; goto store_next; case POWERPC_EXCP_RESET: /* System reset exception */ if (msr_pow) { From 9e0b5cb1ecf5543864fad0628a17be23bb617ed7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Jan 2012 03:18:35 +0100 Subject: [PATCH 18/21] PPC: E500: Implement msgclr This patch implements the msgclr instruction. It is part of the Embedded.Processor Control specification and clears pending doorbell interrupts on the current CPU. Signed-off-by: Alexander Graf --- target-ppc/helper.h | 1 + target-ppc/op_helper.c | 35 +++++++++++++++++++++++++++++++++++ target-ppc/translate.c | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 4798fd57ee..48ceb61462 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -358,6 +358,7 @@ DEF_HELPER_FLAGS_1(load_sr, TCG_CALL_CONST, tl, tl); DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl) DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_1(msgclr, void, tl) #endif DEF_HELPER_3(dlmzb, tl, tl, tl, i32) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 0d1206a649..e2f7614c27 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -4514,4 +4514,39 @@ void helper_booke206_tlbflush(uint32_t type) booke206_flush_tlb(env, flags, 1); } +/* Embedded.Processor Control */ +static int dbell2irq(target_ulong rb) +{ + int msg = rb & DBELL_TYPE_MASK; + int irq = -1; + + switch (msg) { + case DBELL_TYPE_DBELL: + irq = PPC_INTERRUPT_DOORBELL; + break; + case DBELL_TYPE_DBELL_CRIT: + irq = PPC_INTERRUPT_CDOORBELL; + break; + case DBELL_TYPE_G_DBELL: + case DBELL_TYPE_G_DBELL_CRIT: + case DBELL_TYPE_G_DBELL_MC: + /* XXX implement */ + default: + break; + } + + return irq; +} + +void helper_msgclr(target_ulong rb) +{ + int irq = dbell2irq(rb); + + if (irq < 0) { + return; + } + + env->pending_interrupts &= ~(1 << irq); +} + #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 58a4853a0d..01bfe0a1de 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6220,6 +6220,22 @@ static void gen_icbt_440(DisasContext *ctx) */ } +/* Embedded.Processor Control */ + +static void gen_msgclr(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +#else + if (unlikely(ctx->mem_idx == 0)) { + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return; + } + + gen_helper_msgclr(cpu_gpr[rB(ctx->opcode)]); +#endif +} + /*** Altivec vector extension ***/ /* Altivec registers moves */ @@ -8610,6 +8626,8 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001, PPC_NONE, PPC2_BOOKE206), +GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001, + PPC_NONE, PPC2_PRCNTL), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), From d5d11a39a8f761c99276f20974de2f25928830c1 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Jan 2012 03:19:23 +0100 Subject: [PATCH 19/21] PPC: E500: Implement msgsnd This patch implements the msgsnd instruction. It is part of the Embedded.Processor Control specification and allows one CPU to IPI another CPU without going through an interrupt controller. Signed-off-by: Alexander Graf --- target-ppc/helper.h | 1 + target-ppc/op_helper.c | 18 ++++++++++++++++++ target-ppc/translate.c | 16 ++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 48ceb61462..148543a8a1 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -358,6 +358,7 @@ DEF_HELPER_FLAGS_1(load_sr, TCG_CALL_CONST, tl, tl); DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl) DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_1(msgsnd, void, tl) DEF_HELPER_1(msgclr, void, tl) #endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index e2f7614c27..3f4e06789f 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -4549,4 +4549,22 @@ void helper_msgclr(target_ulong rb) env->pending_interrupts &= ~(1 << irq); } +void helper_msgsnd(target_ulong rb) +{ + int irq = dbell2irq(rb); + int pir = rb & DBELL_PIRTAG_MASK; + CPUState *cenv; + + if (irq < 0) { + return; + } + + for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { + if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { + cenv->pending_interrupts |= 1 << irq; + cpu_interrupt(cenv, CPU_INTERRUPT_HARD); + } + } +} + #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 01bfe0a1de..b2780dbe55 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6236,6 +6236,20 @@ static void gen_msgclr(DisasContext *ctx) #endif } +static void gen_msgsnd(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +#else + if (unlikely(ctx->mem_idx == 0)) { + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return; + } + + gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]); +#endif +} + /*** Altivec vector extension ***/ /* Altivec registers moves */ @@ -8626,6 +8640,8 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001, PPC_NONE, PPC2_BOOKE206), +GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001, + PPC_NONE, PPC2_PRCNTL), GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001, PPC_NONE, PPC2_PRCNTL), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), From 8917f4dc62a081c684a1769d38c538df94db9cf0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Jan 2012 03:20:31 +0100 Subject: [PATCH 20/21] PPC: e500mc: Enable processor control The e500mc implements Embedded.Processor Control, so enable it and thus enable guests to IPI each other. This makes -smp work with -cpu e500mc. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index b14a98c2b0..7848cd7394 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4412,7 +4412,7 @@ static void init_proc_e300 (CPUPPCState *env) PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ PPC_FLOAT_STFIWX | PPC_WAIT | \ PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC) -#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206) +#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206 | PPC2_PRCNTL) #define POWERPC_MSRM_e500mc (0x000000001402FB36ULL) #define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206) #define POWERPC_EXCP_e500mc (POWERPC_EXCP_BOOKE) From a496e8eeba51351af136734e475c947a3673dded Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Jan 2012 03:46:55 +0100 Subject: [PATCH 21/21] PPC: E500: Populate L1CFG0 SPR When running Linux on e500 with powersave-nap enabled, Linux tries to read out the L1CFG0 register and calculates some things from it. Passing 0 there ends up in a division by 0, resulting in -1, resulting in badness. So let's populate the L1CFG0 register with reasonable defaults. That way guests aren't completely confused. Reported-by: Shrijeet Mukherjee Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7848cd7394..6253076f68 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4434,6 +4434,8 @@ static void init_proc_e500 (CPUPPCState *env, int version) { uint32_t tlbncfg[2]; uint64_t ivor_mask = 0x0000000F0000FFFFULL; + uint32_t l1cfg0 = 0x3800 /* 8 ways */ + | 0x0020; /* 32 kb */ #if !defined(CONFIG_USER_ONLY) int i; #endif @@ -4485,6 +4487,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64); env->dcache_line_size = 64; env->icache_line_size = 64; + l1cfg0 |= 0x1000000; /* 64 byte cache block size */ break; default: cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); @@ -4535,7 +4538,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0x00000000); + l1cfg0); /* XXX : not implemented */ spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0", SPR_NOACCESS, SPR_NOACCESS,