Merge branch 'for-upstream' of git://repo.or.cz/qemu/agraf

* 'for-upstream' of git://repo.or.cz/qemu/agraf: (21 commits)
  PPC: E500: Populate L1CFG0 SPR
  PPC: e500mc: Enable processor control
  PPC: E500: Implement msgsnd
  PPC: E500: Implement msgclr
  PPC: Enable doorbell excp handlers
  PPC: Add CPU feature for processor control
  PPC: E500: Add doorbell defines
  PPC: E500: Add some more excp vectors
  KVM: Fix compilation on non-x86
  PPC: booke206: move avail check to tlbwe
  PPC: booke206: Check for TLB overrun
  PPC: booke206: Implement tlbilx
  PPC: booke206: Check for min/max TLB entry size
  PPC: booke: add tlbnps handling
  PPC: booke206: allow NULL raddr in ppcmas_tlb_check
  PPC: rename msync to msync_4xx
  PPC: e500: msync is 440 only, e500 has real sync
  PPC: e500mc: add missing IVORs to bitmap
  PPC: Add IVOR 38-42
  PPC: KVM: Update HIOR code to new interface
  ...
This commit is contained in:
Blue Swirl 2012-02-04 09:37:55 +00:00
commit f0c4d3ebc3
16 changed files with 462 additions and 81 deletions

View File

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

View File

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

View File

@ -22,6 +22,16 @@
#include <linux/types.h>
/*
* 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__ */

View File

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

View File

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

View File

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

View File

@ -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
@ -654,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;
};
/*
@ -698,6 +731,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)
@ -809,7 +853,7 @@ struct kvm_one_reg {
/* 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)

View File

@ -26,4 +26,3 @@
#include <asm/kvm_para.h>
#endif /* __LINUX_KVM_PARA_H */

View File

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

View File

@ -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 */
@ -854,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
@ -1355,6 +1374,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)
@ -1371,6 +1394,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)
@ -1888,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)
};
/*****************************************************************************/
@ -2103,6 +2133,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);
@ -2111,6 +2145,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 *);

View File

@ -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;
}
@ -1338,7 +1332,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;
}
@ -1445,6 +1442,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) {
@ -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) {

View File

@ -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)
@ -355,6 +358,8 @@ 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
DEF_HELPER_3(dlmzb, tl, tl, tl, i32)

View File

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

View File

@ -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,12 +4260,37 @@ 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);
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");
}
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;
@ -4300,7 +4326,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)
@ -4319,6 +4349,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;
}
@ -4362,6 +4396,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)) {
@ -4395,6 +4432,73 @@ 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 (!tlb) {
continue;
}
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;
@ -4410,4 +4514,57 @@ 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);
}
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 */

View File

@ -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
}
@ -6110,6 +6111,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)
@ -6172,7 +6206,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 */
}
@ -6186,6 +6220,36 @@ 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
}
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 */
@ -8574,13 +8638,18 @@ 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_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),
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_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),

View File

@ -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,
@ -4370,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)
@ -4389,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)
@ -4410,8 +4411,8 @@ 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)
#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206)
PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
#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)
@ -4432,6 +4433,9 @@ enum fsl_e500_version {
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
@ -4443,7 +4447,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,
@ -4480,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]);
@ -4530,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,