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

* 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf: (31 commits)
  PPC: linux-user: Calculate context pointer explicitly
  target-ppc: Error out for -cpu host on unknown PVR
  target-ppc: Slim conversion of model definitions to QOM subclasses
  PPC: Bring EPR support closer to reality
  PPC: KVM: set has-idle in guest device tree
  kvm: Update kernel headers
  openpic: fix CTPR and de-assertion of interrupts
  openpic: move IACK to its own function
  openpic: IRQ_check: search the queue a word at a time
  openpic: fix sense and priority bits
  openpic: add some bounds checking for IRQ numbers
  openpic: use standard bitmap operations
  Revert "openpic: Accelerate pending irq search"
  openpic: always call IRQ_check from IRQ_get_next
  openpic/fsl: critical interrupts ignore mask before v4.1
  openpic: make ctpr signed
  openpic: rework critical interrupt support
  openpic: make register names correspond better with hw docs
  ppc/booke: fix crit/mcheck/debug exceptions
  openpic: lower interrupt when reading the MSI register
  ...
This commit is contained in:
Blue Swirl 2013-01-12 12:47:02 +00:00
commit 02e079c79c
23 changed files with 1237 additions and 662 deletions

File diff suppressed because it is too large Load Diff

View File

@ -225,6 +225,10 @@ static int ppce500_load_device_tree(CPUPPCState *env,
kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
hypercall, sizeof(hypercall));
/* if KVM supports the idle hcall, set property indicating this */
if (kvmppc_get_hasidle(env)) {
qemu_devtree_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
}
}
/* Create CPU nodes */
@ -493,8 +497,8 @@ void ppce500_init(PPCE500Params *params)
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
env->mpic_cpu_base = MPC8544_CCSRBAR_BASE +
MPC8544_MPIC_REGS_OFFSET + 0x20000;
env->mpic_iack = MPC8544_CCSRBAR_BASE +
MPC8544_MPIC_REGS_OFFSET + 0x200A0;
ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);

View File

@ -237,6 +237,17 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val)
}
static void ppc_booke_timer_reset_handle(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
env->spr[SPR_BOOKE_TSR] = 0;
env->spr[SPR_BOOKE_TCR] = 0;
booke_update_irq(cpu);
}
void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
{
ppc_tb_t *tb_env;
@ -257,4 +268,6 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu);
booke_timer->wdt_timer =
qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu);
qemu_register_reset(ppc_booke_timer_reset_handle, cpu);
}

View File

@ -0,0 +1,98 @@
/*
* ePAPR hcall interface
*
* Copyright 2008-2011 Freescale Semiconductor, Inc.
*
* Author: Timur Tabi <timur@freescale.com>
*
* This file is provided under a dual BSD/GPL license. When using or
* redistributing this file, you may do so under either license.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Freescale Semiconductor nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ASM_POWERPC_EPAPR_HCALLS_H
#define _ASM_POWERPC_EPAPR_HCALLS_H
#define EV_BYTE_CHANNEL_SEND 1
#define EV_BYTE_CHANNEL_RECEIVE 2
#define EV_BYTE_CHANNEL_POLL 3
#define EV_INT_SET_CONFIG 4
#define EV_INT_GET_CONFIG 5
#define EV_INT_SET_MASK 6
#define EV_INT_GET_MASK 7
#define EV_INT_IACK 9
#define EV_INT_EOI 10
#define EV_INT_SEND_IPI 11
#define EV_INT_SET_TASK_PRIORITY 12
#define EV_INT_GET_TASK_PRIORITY 13
#define EV_DOORBELL_SEND 14
#define EV_MSGSND 15
#define EV_IDLE 16
/* vendor ID: epapr */
#define EV_LOCAL_VENDOR_ID 0 /* for private use */
#define EV_EPAPR_VENDOR_ID 1
#define EV_FSL_VENDOR_ID 2 /* Freescale Semiconductor */
#define EV_IBM_VENDOR_ID 3 /* IBM */
#define EV_GHS_VENDOR_ID 4 /* Green Hills Software */
#define EV_ENEA_VENDOR_ID 5 /* Enea */
#define EV_WR_VENDOR_ID 6 /* Wind River Systems */
#define EV_AMCC_VENDOR_ID 7 /* Applied Micro Circuits */
#define EV_KVM_VENDOR_ID 42 /* KVM */
/* The max number of bytes that a byte channel can send or receive per call */
#define EV_BYTE_CHANNEL_MAX_BYTES 16
#define _EV_HCALL_TOKEN(id, num) (((id) << 16) | (num))
#define EV_HCALL_TOKEN(hcall_num) _EV_HCALL_TOKEN(EV_EPAPR_VENDOR_ID, hcall_num)
/* epapr return codes */
#define EV_SUCCESS 0
#define EV_EPERM 1 /* Operation not permitted */
#define EV_ENOENT 2 /* Entry Not Found */
#define EV_EIO 3 /* I/O error occured */
#define EV_EAGAIN 4 /* The operation had insufficient
* resources to complete and should be
* retried
*/
#define EV_ENOMEM 5 /* There was insufficient memory to
* complete the operation */
#define EV_EFAULT 6 /* Bad guest address */
#define EV_ENODEV 7 /* No such device */
#define EV_EINVAL 8 /* An argument supplied to the hcall
was out of range or invalid */
#define EV_INTERNAL 9 /* An internal error occured */
#define EV_CONFIG 10 /* A configuration error was detected */
#define EV_INVALID_STATE 11 /* The object is in an invalid state */
#define EV_UNIMPLEMENTED 12 /* Unimplemented hypercall */
#define EV_BUFFER_OVERFLOW 13 /* Caller-supplied buffer too small */
#endif /* _ASM_POWERPC_EPAPR_HCALLS_H */

View File

@ -221,6 +221,12 @@ struct kvm_sregs {
__u32 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */
__u32 dbcr[3];
/*
* iac/dac registers are 64bit wide, while this API
* interface provides only lower 32 bits on 64 bit
* processors. ONE_REG interface is added for 64bit
* iac/dac registers.
*/
__u32 iac[4];
__u32 dac[2];
__u32 dvc[2];
@ -325,6 +331,86 @@ struct kvm_book3e_206_tlb_params {
__u32 reserved[8];
};
/* For KVM_PPC_GET_HTAB_FD */
struct kvm_get_htab_fd {
__u64 flags;
__u64 start_index;
__u64 reserved[2];
};
/* Values for kvm_get_htab_fd.flags */
#define KVM_GET_HTAB_BOLTED_ONLY ((__u64)0x1)
#define KVM_GET_HTAB_WRITE ((__u64)0x2)
/*
* Data read on the file descriptor is formatted as a series of
* records, each consisting of a header followed by a series of
* `n_valid' HPTEs (16 bytes each), which are all valid. Following
* those valid HPTEs there are `n_invalid' invalid HPTEs, which
* are not represented explicitly in the stream. The same format
* is used for writing.
*/
struct kvm_get_htab_header {
__u32 index;
__u16 n_valid;
__u16 n_invalid;
};
#define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
#define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2)
#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3)
#define KVM_REG_PPC_IAC3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x4)
#define KVM_REG_PPC_IAC4 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5)
#define KVM_REG_PPC_DAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6)
#define KVM_REG_PPC_DAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7)
#define KVM_REG_PPC_DABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8)
#define KVM_REG_PPC_DSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9)
#define KVM_REG_PPC_PURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa)
#define KVM_REG_PPC_SPURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb)
#define KVM_REG_PPC_DAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc)
#define KVM_REG_PPC_DSISR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd)
#define KVM_REG_PPC_AMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xe)
#define KVM_REG_PPC_UAMOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xf)
#define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10)
#define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11)
#define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12)
#define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18)
#define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19)
#define KVM_REG_PPC_PMC3 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1a)
#define KVM_REG_PPC_PMC4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1b)
#define KVM_REG_PPC_PMC5 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1c)
#define KVM_REG_PPC_PMC6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1d)
#define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e)
#define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f)
/* 32 floating-point registers */
#define KVM_REG_PPC_FPR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20)
#define KVM_REG_PPC_FPR(n) (KVM_REG_PPC_FPR0 + (n))
#define KVM_REG_PPC_FPR31 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f)
/* 32 VMX/Altivec vector registers */
#define KVM_REG_PPC_VR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40)
#define KVM_REG_PPC_VR(n) (KVM_REG_PPC_VR0 + (n))
#define KVM_REG_PPC_VR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f)
/* 32 double-width FP registers for VSX */
/* High-order halves overlap with FP regs */
#define KVM_REG_PPC_VSR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60)
#define KVM_REG_PPC_VSR(n) (KVM_REG_PPC_VSR0 + (n))
#define KVM_REG_PPC_VSR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f)
/* FP and vector status/control registers */
#define KVM_REG_PPC_FPSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80)
#define KVM_REG_PPC_VSCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81)
/* Virtual processor areas */
/* For SLB & DTL, address in high (first) half, length in low half */
#define KVM_REG_PPC_VPA_ADDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x82)
#define KVM_REG_PPC_VPA_SLB (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x83)
#define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84)
#define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85)
#endif /* __LINUX_KVM_POWERPC_H */

View File

@ -17,8 +17,8 @@
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
#ifndef _UAPI__POWERPC_KVM_PARA_H__
#define _UAPI__POWERPC_KVM_PARA_H__
#ifndef __POWERPC_KVM_PARA_H__
#define __POWERPC_KVM_PARA_H__
#include <linux/types.h>
@ -75,9 +75,10 @@ struct kvm_vcpu_arch_shared {
};
#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
#define HC_VENDOR_KVM (42 << 16)
#define HC_EV_SUCCESS 0
#define HC_EV_UNIMPLEMENTED 12
#define KVM_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num)
#include <asm/epapr_hcalls.h>
#define KVM_FEATURE_MAGIC_PAGE 1
@ -87,4 +88,4 @@ struct kvm_vcpu_arch_shared {
#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
#endif /* _UAPI__POWERPC_KVM_PARA_H__ */
#endif /* __POWERPC_KVM_PARA_H__ */

View File

@ -167,10 +167,15 @@ struct kvm_pit_config {
#define KVM_EXIT_OSI 18
#define KVM_EXIT_PAPR_HCALL 19
#define KVM_EXIT_S390_UCONTROL 20
#define KVM_EXIT_WATCHDOG 21
/* For KVM_EXIT_INTERNAL_ERROR */
#define KVM_INTERNAL_ERROR_EMULATION 1
#define KVM_INTERNAL_ERROR_SIMUL_EX 2
/* Emulate instruction failed. */
#define KVM_INTERNAL_ERROR_EMULATION 1
/* Encounter unexpected simultaneous exceptions. */
#define KVM_INTERNAL_ERROR_SIMUL_EX 2
/* Encounter unexpected vm-exit due to delivery event. */
#define KVM_INTERNAL_ERROR_DELIVERY_EV 3
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
@ -477,6 +482,8 @@ struct kvm_ppc_smmu_info {
struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
};
#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0)
#define KVMIO 0xAE
/* machine type bits, to be used as argument to KVM_CREATE_VM */
@ -626,6 +633,8 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_READONLY_MEM 81
#endif
#define KVM_CAP_IRQFD_RESAMPLE 82
#define KVM_CAP_PPC_BOOKE_WATCHDOG 83
#define KVM_CAP_PPC_HTAB_FD 84
#ifdef KVM_CAP_IRQ_ROUTING
@ -848,6 +857,11 @@ struct kvm_s390_ucas_mapping {
#define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info)
/* Available with KVM_CAP_PPC_ALLOC_HTAB */
#define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32)
#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce)
/* Available with KVM_CAP_RMA */
#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma)
/* Available with KVM_CAP_PPC_HTAB_FD */
#define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd)
/*
* ioctls for vcpu fds
@ -911,9 +925,6 @@ struct kvm_s390_ucas_mapping {
/* Available with KVM_CAP_XCRS */
#define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs)
#define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs)
#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce)
/* Available with KVM_CAP_RMA */
#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma)
/* Available with KVM_CAP_SW_TLB */
#define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb)
/* Available with KVM_CAP_ONE_REG */

View File

@ -1,5 +1,5 @@
#ifndef _UAPI__LINUX_KVM_PARA_H
#define _UAPI__LINUX_KVM_PARA_H
#ifndef __LINUX_KVM_PARA_H
#define __LINUX_KVM_PARA_H
/*
* This header file provides a method for making a hypercall to the host
@ -25,4 +25,4 @@
*/
#include <asm/kvm_para.h>
#endif /* _UAPI__LINUX_KVM_PARA_H */
#endif /* __LINUX_KVM_PARA_H */

View File

@ -8,8 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _UAPIVFIO_H
#define _UAPIVFIO_H
#ifndef VFIO_H
#define VFIO_H
#include <linux/types.h>
#include <linux/ioctl.h>
@ -365,4 +365,4 @@ struct vfio_iommu_type1_dma_unmap {
#define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
#endif /* _UAPIVFIO_H */
#endif /* VFIO_H */

View File

@ -1,5 +1,5 @@
#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H
#define _UAPI_LINUX_VIRTIO_CONFIG_H
#ifndef _LINUX_VIRTIO_CONFIG_H
#define _LINUX_VIRTIO_CONFIG_H
/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
* anyone can use the definitions to implement compatible drivers/servers.
*
@ -51,4 +51,4 @@
* suppressed them? */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */
#endif /* _LINUX_VIRTIO_CONFIG_H */

View File

@ -1,5 +1,5 @@
#ifndef _UAPI_LINUX_VIRTIO_RING_H
#define _UAPI_LINUX_VIRTIO_RING_H
#ifndef _LINUX_VIRTIO_RING_H
#define _LINUX_VIRTIO_RING_H
/* An interface for efficient virtio implementation, currently for use by KVM
* and lguest, but hopefully others soon. Do NOT change this since it will
* break existing servers and clients.
@ -160,4 +160,4 @@ static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old
return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
}
#endif /* _UAPI_LINUX_VIRTIO_RING_H */
#endif /* _LINUX_VIRTIO_RING_H */

View File

@ -4578,7 +4578,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
signal = current_exec_domain_sig(sig);
err |= __put_user(h2g(ka->_sa_handler), &sc->handler);
err |= __put_user(ka->_sa_handler, &sc->handler);
err |= __put_user(set->sig[0], &sc->oldmask);
#if defined(TARGET_PPC64)
err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
@ -4600,7 +4600,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
/* Create a stack frame for the caller of the handler. */
newsp = frame_addr - SIGNAL_FRAMESIZE;
err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
err |= put_user(env->gpr[1], newsp, target_ulong);
if (err)
goto sigsegv;
@ -4608,7 +4608,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
/* Set up registers for signal handler. */
env->gpr[1] = newsp;
env->gpr[3] = signal;
env->gpr[4] = (target_ulong) h2g(sc);
env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
env->nip = (target_ulong) ka->_sa_handler;
/* Signal handlers are entered in big-endian mode. */
env->msr &= ~MSR_LE;

View File

@ -54,6 +54,9 @@ for arch in $ARCHLIST; do
if [ $arch = x86 ]; then
cp "$tmpdir/include/asm/hyperv.h" "$output/linux-headers/asm-x86"
fi
if [ $arch = powerpc ]; then
cp "$tmpdir/include/asm/epapr_hcalls.h" "$output/linux-headers/asm-powerpc/"
fi
done
rm -rf "$output/linux-headers/linux"

View File

@ -1,7 +1,6 @@
obj-y += translate.o helper.o
obj-y += translate.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += helper.o
obj-y += excp_helper.o
obj-y += fpu_helper.o
obj-y += int_helper.o
@ -9,4 +8,3 @@ obj-y += mmu_helper.o
obj-y += timebase_helper.o
obj-y += misc_helper.o
obj-y += mem_helper.o
obj-y += mpic_helper.o

View File

@ -50,6 +50,9 @@ typedef struct PowerPCCPUClass {
/*< public >*/
void (*parent_reset)(CPUState *cpu);
/* TODO inline fields here */
ppc_def_t *info;
} PowerPCCPUClass;
/**
@ -73,5 +76,7 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
#define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e))
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
#endif

View File

@ -1067,7 +1067,9 @@ struct CPUPPCState {
target_ulong ivor_mask;
target_ulong ivpr_mask;
target_ulong hreset_vector;
hwaddr mpic_cpu_base;
hwaddr mpic_iack;
/* true when the external proxy facility mode is enabled */
bool mpic_proxy;
#endif
/* Those resources are used only during code translation */
@ -1156,10 +1158,6 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value);
void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
const ppc_def_t *ppc_find_by_pvr(uint32_t pvr);
const ppc_def_t *cpu_ppc_find_by_name (const char *name);
int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def);
/* Time-base and decrementer management */
#ifndef NO_CPU_IO_DEFS
uint64_t cpu_ppc_load_tbl (CPUPPCState *env);

View File

@ -84,7 +84,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
" => %08x (%02x)\n", env->nip, excp, env->error_code);
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
if (excp_model == POWERPC_EXCP_BOOKE) {
msr = env->msr;
} else {
msr = env->msr & ~0x783f0000ULL;
}
/* new interrupt handler msr */
new_msr = env->msr & ((target_ulong)1 << MSR_ME);
@ -145,6 +149,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
srr1 = SPR_40x_SRR3;
break;
case POWERPC_EXCP_BOOKE:
/* FIXME: choose one or the other based on CPU type */
srr0 = SPR_BOOKE_MCSRR0;
srr1 = SPR_BOOKE_MCSRR1;
asrr0 = SPR_BOOKE_CSRR0;
@ -173,6 +178,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
if (lpes0 == 1) {
new_msr |= (target_ulong)MSR_HVB;
}
if (env->mpic_proxy) {
/* IACK the IRQ on delivery */
env->spr[SPR_BOOKE_EPR] = ldl_phys(env->mpic_iack);
}
goto store_next;
case POWERPC_EXCP_ALIGN: /* Alignment exception */
if (lpes1 == 0) {
@ -275,6 +284,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
case POWERPC_EXCP_DEBUG: /* Debug interrupt */
switch (excp_model) {
case POWERPC_EXCP_BOOKE:
/* FIXME: choose one or the other based on CPU type */
srr0 = SPR_BOOKE_DSRR0;
srr1 = SPR_BOOKE_DSRR1;
asrr0 = SPR_BOOKE_CSRR0;
@ -836,8 +846,13 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
void helper_rfi(CPUPPCState *env)
{
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
~((target_ulong)0x783F0000), 1);
if (env->excp_model == POWERPC_EXCP_BOOKE) {
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
~((target_ulong)0), 0);
} else {
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
~((target_ulong)0x783F0000), 1);
}
}
#if defined(TARGET_PPC64)
@ -864,20 +879,22 @@ void helper_40x_rfci(CPUPPCState *env)
void helper_rfci(CPUPPCState *env)
{
do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
~((target_ulong)0x3FFF0000), 0);
do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
~((target_ulong)0), 0);
}
void helper_rfdi(CPUPPCState *env)
{
do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
~((target_ulong)0x3FFF0000), 0);
/* FIXME: choose CSRR1 or DSRR1 based on cpu type */
do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
~((target_ulong)0), 0);
}
void helper_rfmci(CPUPPCState *env)
{
do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
~((target_ulong)0x3FFF0000), 0);
/* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
~((target_ulong)0), 0);
}
#endif

View File

@ -1,50 +0,0 @@
/*
* PowerPC emulation helpers for QEMU.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
*
* 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 "cpu.h"
#include "helper_regs.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "sysemu/cpus.h"
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
{
PowerPCCPU *cpu;
CPUPPCState *env;
const ppc_def_t *def;
def = cpu_ppc_find_by_name(cpu_model);
if (!def) {
return NULL;
}
cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU));
env = &cpu->env;
if (tcg_enabled()) {
ppc_translate_init();
}
env->cpu_model_str = cpu_model;
cpu_ppc_register_internal(env, def);
qemu_init_vcpu(env);
return cpu;
}

View File

@ -405,7 +405,6 @@ DEF_HELPER_2(store_40x_dbcr0, void, env, tl)
DEF_HELPER_2(store_40x_sler, void, env, tl)
DEF_HELPER_2(store_booke_tcr, void, env, tl)
DEF_HELPER_2(store_booke_tsr, void, env, tl)
DEF_HELPER_1(load_epr, tl, env)
DEF_HELPER_3(store_ibatl, void, env, i32, tl)
DEF_HELPER_3(store_ibatu, void, env, i32, tl)
DEF_HELPER_3(store_dbatl, void, env, i32, tl)

View File

@ -989,18 +989,38 @@ uint32_t kvmppc_get_dfp(void)
return kvmppc_read_int_cpu_dt("ibm,dfp");
}
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
CPUState *cs = CPU(cpu);
uint32_t *hc = (uint32_t*)buf;
struct kvm_ppc_pvinfo pvinfo;
static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
CPUState *cs = CPU(cpu);
if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) &&
!kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) {
memcpy(buf, pvinfo.hcall, buf_len);
!kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, pvinfo)) {
return 0;
}
return 1;
}
int kvmppc_get_hasidle(CPUPPCState *env)
{
struct kvm_ppc_pvinfo pvinfo;
if (!kvmppc_get_pvinfo(env, &pvinfo) &&
(pvinfo.flags & KVM_PPC_PVINFO_FLAGS_EV_IDLE)) {
return 1;
}
return 0;
}
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
{
uint32_t *hc = (uint32_t*)buf;
struct kvm_ppc_pvinfo pvinfo;
if (!kvmppc_get_pvinfo(env, &pvinfo)) {
memcpy(buf, pvinfo.hcall, buf_len);
return 0;
}
@ -1210,18 +1230,37 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on)
}
}
const ppc_def_t *kvmppc_host_cpu_def(void)
static void kvmppc_host_cpu_initfn(Object *obj)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(obj);
assert(kvm_enabled());
if (pcc->info->pvr != mfpvr()) {
fprintf(stderr, "Your host CPU is unsupported.\n"
"Please choose a supported model instead, see -cpu ?.\n");
exit(1);
}
}
static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
{
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
uint32_t host_pvr = mfpvr();
const ppc_def_t *base_spec;
PowerPCCPUClass *pvr_pcc;
ppc_def_t *spec;
uint32_t vmx = kvmppc_get_vmx();
uint32_t dfp = kvmppc_get_dfp();
base_spec = ppc_find_by_pvr(host_pvr);
spec = g_malloc0(sizeof(*spec));
memcpy(spec, base_spec, sizeof(*spec));
pvr_pcc = ppc_cpu_class_by_pvr(host_pvr);
if (pvr_pcc != NULL) {
memcpy(spec, pvr_pcc->info, sizeof(*spec));
}
pcc->info = spec;
/* Override the display name for -cpu ? and QMP */
pcc->info->name = "host";
/* Now fix up the spec with information we can query from the host */
@ -1234,8 +1273,6 @@ const ppc_def_t *kvmppc_host_cpu_def(void)
/* Only override when we know what the host supports */
alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
}
return spec;
}
int kvmppc_fixup_cpu(CPUPPCState *env)
@ -1265,3 +1302,17 @@ int kvm_arch_on_sigbus(int code, void *addr)
{
return 1;
}
static const TypeInfo kvm_host_cpu_type_info = {
.name = TYPE_HOST_POWERPC_CPU,
.parent = TYPE_POWERPC_CPU,
.instance_init = kvmppc_host_cpu_initfn,
.class_init = kvmppc_host_cpu_class_init,
};
static void kvm_ppc_register_types(void)
{
type_register_static(&kvm_host_cpu_type_info);
}
type_init(kvm_ppc_register_types)

View File

@ -11,6 +11,8 @@
#include "exec/memory.h"
#define TYPE_HOST_POWERPC_CPU "host-" TYPE_POWERPC_CPU
void kvmppc_init(void);
#ifdef CONFIG_KVM
@ -19,6 +21,7 @@ uint32_t kvmppc_get_tbfreq(void);
uint64_t kvmppc_get_clockfreq(void);
uint32_t kvmppc_get_vmx(void);
uint32_t kvmppc_get_dfp(void);
int kvmppc_get_hasidle(CPUPPCState *env);
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len);
int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
void kvmppc_set_papr(PowerPCCPU *cpu);
@ -30,7 +33,6 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
int kvmppc_reset_htab(int shift_hint);
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
#endif /* !CONFIG_USER_ONLY */
const ppc_def_t *kvmppc_host_cpu_def(void);
int kvmppc_fixup_cpu(CPUPPCState *env);
#else
@ -55,6 +57,11 @@ static inline uint32_t kvmppc_get_dfp(void)
return 0;
}
static inline int kvmppc_get_hasidle(CPUPPCState *env)
{
return 0;
}
static inline int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
{
return -1;
@ -115,11 +122,6 @@ static inline int kvmppc_update_sdr1(CPUPPCState *env)
#endif /* !CONFIG_USER_ONLY */
static inline const ppc_def_t *kvmppc_host_cpu_def(void)
{
return NULL;
}
static inline int kvmppc_fixup_cpu(CPUPPCState *env)
{
return -1;

View File

@ -1,35 +0,0 @@
/*
* PowerPC emulation helpers for QEMU.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
*
* 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 "cpu.h"
#include "helper.h"
/*****************************************************************************/
/* SPR accesses */
#if !defined(CONFIG_USER_ONLY)
/*
* This is an ugly helper for EPR, which is basically the same as accessing
* the IACK (PIAC) register on the MPIC. Because we model the MPIC as a device
* that can only talk to the CPU through MMIO, let's access it that way!
*/
target_ulong helper_load_epr(CPUPPCState *env)
{
return ldl_phys(env->mpic_cpu_base + 0xA0);
}
#endif

View File

@ -4493,11 +4493,6 @@ static void spr_read_mas73(void *opaque, int gprn, int sprn)
tcg_temp_free(mas7);
}
static void spr_load_epr(void *opaque, int gprn, int sprn)
{
gen_helper_load_epr(cpu_gpr[gprn], cpu_env);
}
#endif
enum fsl_e500_version {
@ -4656,7 +4651,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
0x00000000);
spr_register(env, SPR_BOOKE_EPR, "EPR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_load_epr, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
/* XXX better abstract into Emb.xxx features */
if (version == fsl_e5500) {
@ -9797,8 +9792,11 @@ static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
}
/*****************************************************************************/
static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
const ppc_def_t *def = pcc->info;
opcode_t *opc;
fill_new_table(env->opcodes, 0x40);
@ -9806,18 +9804,16 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
if (((opc->handler.type & def->insns_flags) != 0) ||
((opc->handler.type2 & def->insns_flags2) != 0)) {
if (register_insn(env->opcodes, opc) < 0) {
printf("*** ERROR initializing PowerPC instruction "
"0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
opc->opc3);
return -1;
error_setg(errp, "ERROR initializing PowerPC instruction "
"0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
opc->opc3);
return;
}
}
}
fix_opcode_tables(env->opcodes);
fflush(stdout);
fflush(stderr);
return 0;
}
#if defined(PPC_DUMP_CPU)
@ -10031,53 +10027,31 @@ static int ppc_fixup_cpu(CPUPPCState *env)
return 0;
}
int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
static void ppc_cpu_realize(Object *obj, Error **errp)
{
env->msr_mask = def->msr_mask;
env->mmu_model = def->mmu_model;
env->excp_model = def->excp_model;
env->bus_model = def->bus_model;
env->insns_flags = def->insns_flags;
env->insns_flags2 = def->insns_flags2;
env->flags = def->flags;
env->bfd_mach = def->bfd_mach;
env->check_pow = def->check_pow;
#if defined(TARGET_PPC64)
if (def->sps)
env->sps = *def->sps;
else if (env->mmu_model & POWERPC_MMU_64) {
/* Use default sets of page sizes */
static const struct ppc_segment_page_sizes defsps = {
.sps = {
{ .page_shift = 12, /* 4K */
.slb_enc = 0,
.enc = { { .page_shift = 12, .pte_enc = 0 } }
},
{ .page_shift = 24, /* 16M */
.slb_enc = 0x100,
.enc = { { .page_shift = 24, .pte_enc = 0 } }
},
},
};
env->sps = defsps;
}
#endif /* defined(TARGET_PPC64) */
PowerPCCPU *cpu = POWERPC_CPU(obj);
CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
ppc_def_t *def = pcc->info;
Error *local_err = NULL;
if (kvm_enabled()) {
if (kvmppc_fixup_cpu(env) != 0) {
fprintf(stderr, "Unable to virtualize selected CPU with KVM\n");
exit(1);
error_setg(errp, "Unable to virtualize selected CPU with KVM");
return;
}
} else {
if (ppc_fixup_cpu(env) != 0) {
fprintf(stderr, "Unable to emulate selected CPU with TCG\n");
exit(1);
error_setg(errp, "Unable to emulate selected CPU with TCG");
return;
}
}
if (create_ppc_opcodes(env, def) < 0)
return -1;
create_ppc_opcodes(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
init_ppc_proc(env, def);
if (def->insns_flags & PPC_FLOAT) {
@ -10093,6 +10067,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
34, "power-spe.xml", 0);
}
qemu_init_vcpu(env);
#if defined(PPC_DUMP_CPU)
{
const char *mmu_model, *excp_model, *bus_model;
@ -10254,50 +10230,65 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
dump_ppc_sprs(env);
fflush(stdout);
#endif
return 0;
}
static bool ppc_cpu_usable(const ppc_def_t *def)
static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
{
#if defined(TARGET_PPCEMB)
/* When using the ppcemb target, we only support 440 style cores */
if (def->mmu_model != POWERPC_MMU_BOOKE) {
return false;
}
#endif
ObjectClass *oc = (ObjectClass *)a;
uint32_t pvr = *(uint32_t *)b;
PowerPCCPUClass *pcc = (PowerPCCPUClass *)a;
return true;
/* -cpu host does a PVR lookup during construction */
if (unlikely(strcmp(object_class_get_name(oc),
TYPE_HOST_POWERPC_CPU) == 0)) {
return -1;
}
return pcc->info->pvr == pvr ? 0 : -1;
}
const ppc_def_t *ppc_find_by_pvr(uint32_t pvr)
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr)
{
int i;
GSList *list, *item;
PowerPCCPUClass *pcc = NULL;
for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
if (!ppc_cpu_usable(&ppc_defs[i])) {
continue;
}
/* If we have an exact match, we're done */
if (pvr == ppc_defs[i].pvr) {
return &ppc_defs[i];
}
list = object_class_get_list(TYPE_POWERPC_CPU, false);
item = g_slist_find_custom(list, &pvr, ppc_cpu_compare_class_pvr);
if (item != NULL) {
pcc = POWERPC_CPU_CLASS(item->data);
}
g_slist_free(list);
return NULL;
return pcc;
}
static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b)
{
ObjectClass *oc = (ObjectClass *)a;
const char *name = b;
if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 &&
strcmp(object_class_get_name(oc) + strlen(name),
"-" TYPE_POWERPC_CPU) == 0) {
return 0;
}
return -1;
}
#include <ctype.h>
const ppc_def_t *cpu_ppc_find_by_name (const char *name)
static ObjectClass *ppc_cpu_class_by_name(const char *name)
{
const ppc_def_t *ret;
GSList *list, *item;
ObjectClass *ret = NULL;
const char *p;
int i, max, len;
int i, len;
if (kvm_enabled() && (strcasecmp(name, "host") == 0)) {
return kvmppc_host_cpu_def();
if (strcasecmp(name, "host") == 0) {
if (kvm_enabled()) {
ret = object_class_by_name(TYPE_HOST_POWERPC_CPU);
}
return ret;
}
/* Check if the given name is a PVR */
@ -10312,65 +10303,154 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name)
if (!qemu_isxdigit(*p++))
break;
}
if (i == 8)
return ppc_find_by_pvr(strtoul(name, NULL, 16));
}
ret = NULL;
max = ARRAY_SIZE(ppc_defs);
for (i = 0; i < max; i++) {
if (!ppc_cpu_usable(&ppc_defs[i])) {
continue;
if (i == 8) {
ret = OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16)));
return ret;
}
}
if (strcasecmp(name, ppc_defs[i].name) == 0) {
ret = &ppc_defs[i];
break;
}
list = object_class_get_list(TYPE_POWERPC_CPU, false);
item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name);
if (item != NULL) {
ret = OBJECT_CLASS(item->data);
}
g_slist_free(list);
return ret;
}
void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
{
int i, max;
PowerPCCPU *cpu;
CPUPPCState *env;
ObjectClass *oc;
Error *err = NULL;
max = ARRAY_SIZE(ppc_defs);
for (i = 0; i < max; i++) {
if (!ppc_cpu_usable(&ppc_defs[i])) {
continue;
}
(*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n",
ppc_defs[i].name, ppc_defs[i].pvr);
oc = ppc_cpu_class_by_name(cpu_model);
if (oc == NULL) {
return NULL;
}
cpu = POWERPC_CPU(object_new(object_class_get_name(oc)));
env = &cpu->env;
if (tcg_enabled()) {
ppc_translate_init();
}
env->cpu_model_str = cpu_model;
ppc_cpu_realize(OBJECT(cpu), &err);
if (err != NULL) {
fprintf(stderr, "%s\n", error_get_pretty(err));
error_free(err);
object_delete(OBJECT(cpu));
return NULL;
}
return cpu;
}
/* Sort by PVR, ordering special case "host" last. */
static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b)
{
ObjectClass *oc_a = (ObjectClass *)a;
ObjectClass *oc_b = (ObjectClass *)b;
PowerPCCPUClass *pcc_a = POWERPC_CPU_CLASS(oc_a);
PowerPCCPUClass *pcc_b = POWERPC_CPU_CLASS(oc_b);
const char *name_a = object_class_get_name(oc_a);
const char *name_b = object_class_get_name(oc_b);
if (strcmp(name_a, TYPE_HOST_POWERPC_CPU) == 0) {
return 1;
} else if (strcmp(name_b, TYPE_HOST_POWERPC_CPU) == 0) {
return -1;
} else {
/* Avoid an integer overflow during subtraction */
if (pcc_a->info->pvr < pcc_b->info->pvr) {
return -1;
} else if (pcc_a->info->pvr > pcc_b->info->pvr) {
return 1;
} else {
return 0;
}
}
}
static void ppc_cpu_list_entry(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
CPUListState *s = user_data;
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
(*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n",
pcc->info->name, pcc->info->pvr);
}
void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
CPUListState s = {
.file = f,
.cpu_fprintf = cpu_fprintf,
};
GSList *list;
list = object_class_get_list(TYPE_POWERPC_CPU, false);
list = g_slist_sort(list, ppc_cpu_list_compare);
g_slist_foreach(list, ppc_cpu_list_entry, &s);
g_slist_free(list);
}
static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
CpuDefinitionInfoList **first = user_data;
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
info = g_malloc0(sizeof(*info));
info->name = g_strdup(pcc->info->name);
entry = g_malloc0(sizeof(*entry));
entry->value = info;
entry->next = *first;
*first = entry;
}
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
{
CpuDefinitionInfoList *cpu_list = NULL;
int i;
GSList *list;
for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
if (!ppc_cpu_usable(&ppc_defs[i])) {
continue;
}
info = g_malloc0(sizeof(*info));
info->name = g_strdup(ppc_defs[i].name);
entry = g_malloc0(sizeof(*entry));
entry->value = info;
entry->next = cpu_list;
cpu_list = entry;
}
list = object_class_get_list(TYPE_POWERPC_CPU, false);
g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list);
g_slist_free(list);
return cpu_list;
}
static void ppc_cpu_def_class_init(ObjectClass *oc, void *data)
{
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
ppc_def_t *info = data;
pcc->info = info;
}
static void ppc_cpu_register_model(const ppc_def_t *def)
{
TypeInfo type_info = {
.parent = TYPE_POWERPC_CPU,
.class_init = ppc_cpu_def_class_init,
.class_data = (void *)def,
};
type_info.name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, def->name),
type_register(&type_info);
g_free((gpointer)type_info.name);
}
/* CPUClass::reset() */
static void ppc_cpu_reset(CPUState *s)
{
@ -10439,9 +10519,42 @@ static void ppc_cpu_reset(CPUState *s)
static void ppc_cpu_initfn(Object *obj)
{
PowerPCCPU *cpu = POWERPC_CPU(obj);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
ppc_def_t *def = pcc->info;
cpu_exec_init(env);
env->msr_mask = def->msr_mask;
env->mmu_model = def->mmu_model;
env->excp_model = def->excp_model;
env->bus_model = def->bus_model;
env->insns_flags = def->insns_flags;
env->insns_flags2 = def->insns_flags2;
env->flags = def->flags;
env->bfd_mach = def->bfd_mach;
env->check_pow = def->check_pow;
#if defined(TARGET_PPC64)
if (def->sps) {
env->sps = *def->sps;
} else if (env->mmu_model & POWERPC_MMU_64) {
/* Use default sets of page sizes */
static const struct ppc_segment_page_sizes defsps = {
.sps = {
{ .page_shift = 12, /* 4K */
.slb_enc = 0,
.enc = { { .page_shift = 12, .pte_enc = 0 } }
},
{ .page_shift = 24, /* 16M */
.slb_enc = 0x100,
.enc = { { .page_shift = 24, .pte_enc = 0 } }
},
},
};
env->sps = defsps;
}
#endif /* defined(TARGET_PPC64) */
}
static void ppc_cpu_class_init(ObjectClass *oc, void *data)
@ -10458,14 +10571,27 @@ static const TypeInfo ppc_cpu_type_info = {
.parent = TYPE_CPU,
.instance_size = sizeof(PowerPCCPU),
.instance_init = ppc_cpu_initfn,
.abstract = false,
.abstract = true,
.class_size = sizeof(PowerPCCPUClass),
.class_init = ppc_cpu_class_init,
};
static void ppc_cpu_register_types(void)
{
int i;
type_register_static(&ppc_cpu_type_info);
for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
const ppc_def_t *def = &ppc_defs[i];
#if defined(TARGET_PPCEMB)
/* When using the ppcemb target, we only support 440 style cores */
if (def->mmu_model != POWERPC_MMU_BOOKE) {
continue;
}
#endif
ppc_cpu_register_model(def);
}
}
type_init(ppc_cpu_register_types)