mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
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:
commit
02e079c79c
23 changed files with 1237 additions and 662 deletions
1032
hw/openpic.c
1032
hw/openpic.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
98
linux-headers/asm-powerpc/epapr_hcalls.h
Normal file
98
linux-headers/asm-powerpc/epapr_hcalls.h
Normal 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue