mirror of https://github.com/xqemu/xqemu.git
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
1020
hw/openpic.c
1020
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));
|
kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
|
||||||
qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
|
qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
|
||||||
hypercall, sizeof(hypercall));
|
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 */
|
/* 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_INT] = input[PPCE500_INPUT_INT];
|
||||||
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
|
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
|
||||||
env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
|
env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
|
||||||
env->mpic_cpu_base = MPC8544_CCSRBAR_BASE +
|
env->mpic_iack = MPC8544_CCSRBAR_BASE +
|
||||||
MPC8544_MPIC_REGS_OFFSET + 0x20000;
|
MPC8544_MPIC_REGS_OFFSET + 0x200A0;
|
||||||
|
|
||||||
ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
|
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)
|
void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
|
||||||
{
|
{
|
||||||
ppc_tb_t *tb_env;
|
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);
|
qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu);
|
||||||
booke_timer->wdt_timer =
|
booke_timer->wdt_timer =
|
||||||
qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu);
|
qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu);
|
||||||
|
|
||||||
|
qemu_register_reset(ppc_booke_timer_reset_handle, cpu);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */
|
||||||
__u32 dbcr[3];
|
__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 iac[4];
|
||||||
__u32 dac[2];
|
__u32 dac[2];
|
||||||
__u32 dvc[2];
|
__u32 dvc[2];
|
||||||
|
@ -325,6 +331,86 @@ struct kvm_book3e_206_tlb_params {
|
||||||
__u32 reserved[8];
|
__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_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 */
|
#endif /* __LINUX_KVM_POWERPC_H */
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
|
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _UAPI__POWERPC_KVM_PARA_H__
|
#ifndef __POWERPC_KVM_PARA_H__
|
||||||
#define _UAPI__POWERPC_KVM_PARA_H__
|
#define __POWERPC_KVM_PARA_H__
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
@ -75,9 +75,10 @@ struct kvm_vcpu_arch_shared {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
|
#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
|
||||||
#define HC_VENDOR_KVM (42 << 16)
|
|
||||||
#define HC_EV_SUCCESS 0
|
#define KVM_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num)
|
||||||
#define HC_EV_UNIMPLEMENTED 12
|
|
||||||
|
#include <asm/epapr_hcalls.h>
|
||||||
|
|
||||||
#define KVM_FEATURE_MAGIC_PAGE 1
|
#define KVM_FEATURE_MAGIC_PAGE 1
|
||||||
|
|
||||||
|
@ -87,4 +88,4 @@ struct kvm_vcpu_arch_shared {
|
||||||
#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
|
#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_OSI 18
|
||||||
#define KVM_EXIT_PAPR_HCALL 19
|
#define KVM_EXIT_PAPR_HCALL 19
|
||||||
#define KVM_EXIT_S390_UCONTROL 20
|
#define KVM_EXIT_S390_UCONTROL 20
|
||||||
|
#define KVM_EXIT_WATCHDOG 21
|
||||||
|
|
||||||
/* For KVM_EXIT_INTERNAL_ERROR */
|
/* For KVM_EXIT_INTERNAL_ERROR */
|
||||||
|
/* Emulate instruction failed. */
|
||||||
#define KVM_INTERNAL_ERROR_EMULATION 1
|
#define KVM_INTERNAL_ERROR_EMULATION 1
|
||||||
|
/* Encounter unexpected simultaneous exceptions. */
|
||||||
#define KVM_INTERNAL_ERROR_SIMUL_EX 2
|
#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) */
|
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
|
||||||
struct kvm_run {
|
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];
|
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
|
#define KVMIO 0xAE
|
||||||
|
|
||||||
/* machine type bits, to be used as argument to KVM_CREATE_VM */
|
/* 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
|
#define KVM_CAP_READONLY_MEM 81
|
||||||
#endif
|
#endif
|
||||||
#define KVM_CAP_IRQFD_RESAMPLE 82
|
#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
|
#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)
|
#define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info)
|
||||||
/* Available with KVM_CAP_PPC_ALLOC_HTAB */
|
/* Available with KVM_CAP_PPC_ALLOC_HTAB */
|
||||||
#define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32)
|
#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
|
* ioctls for vcpu fds
|
||||||
|
@ -911,9 +925,6 @@ struct kvm_s390_ucas_mapping {
|
||||||
/* Available with KVM_CAP_XCRS */
|
/* Available with KVM_CAP_XCRS */
|
||||||
#define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs)
|
#define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs)
|
||||||
#define KVM_SET_XCRS _IOW(KVMIO, 0xa7, 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 */
|
/* Available with KVM_CAP_SW_TLB */
|
||||||
#define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb)
|
#define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb)
|
||||||
/* Available with KVM_CAP_ONE_REG */
|
/* Available with KVM_CAP_ONE_REG */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef _UAPI__LINUX_KVM_PARA_H
|
#ifndef __LINUX_KVM_PARA_H
|
||||||
#define _UAPI__LINUX_KVM_PARA_H
|
#define __LINUX_KVM_PARA_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This header file provides a method for making a hypercall to the host
|
* This header file provides a method for making a hypercall to the host
|
||||||
|
@ -25,4 +25,4 @@
|
||||||
*/
|
*/
|
||||||
#include <asm/kvm_para.h>
|
#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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
#ifndef _UAPIVFIO_H
|
#ifndef VFIO_H
|
||||||
#define _UAPIVFIO_H
|
#define VFIO_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/ioctl.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)
|
#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
|
#ifndef _LINUX_VIRTIO_CONFIG_H
|
||||||
#define _UAPI_LINUX_VIRTIO_CONFIG_H
|
#define _LINUX_VIRTIO_CONFIG_H
|
||||||
/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
|
/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
|
||||||
* anyone can use the definitions to implement compatible drivers/servers.
|
* anyone can use the definitions to implement compatible drivers/servers.
|
||||||
*
|
*
|
||||||
|
@ -51,4 +51,4 @@
|
||||||
* suppressed them? */
|
* suppressed them? */
|
||||||
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
|
#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
|
#ifndef _LINUX_VIRTIO_RING_H
|
||||||
#define _UAPI_LINUX_VIRTIO_RING_H
|
#define _LINUX_VIRTIO_RING_H
|
||||||
/* An interface for efficient virtio implementation, currently for use by KVM
|
/* An interface for efficient virtio implementation, currently for use by KVM
|
||||||
* and lguest, but hopefully others soon. Do NOT change this since it will
|
* and lguest, but hopefully others soon. Do NOT change this since it will
|
||||||
* break existing servers and clients.
|
* 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);
|
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);
|
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);
|
err |= __put_user(set->sig[0], &sc->oldmask);
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
|
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. */
|
/* Create a stack frame for the caller of the handler. */
|
||||||
newsp = frame_addr - SIGNAL_FRAMESIZE;
|
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)
|
if (err)
|
||||||
goto sigsegv;
|
goto sigsegv;
|
||||||
|
@ -4608,7 +4608,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
||||||
/* Set up registers for signal handler. */
|
/* Set up registers for signal handler. */
|
||||||
env->gpr[1] = newsp;
|
env->gpr[1] = newsp;
|
||||||
env->gpr[3] = signal;
|
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;
|
env->nip = (target_ulong) ka->_sa_handler;
|
||||||
/* Signal handlers are entered in big-endian mode. */
|
/* Signal handlers are entered in big-endian mode. */
|
||||||
env->msr &= ~MSR_LE;
|
env->msr &= ~MSR_LE;
|
||||||
|
|
|
@ -54,6 +54,9 @@ for arch in $ARCHLIST; do
|
||||||
if [ $arch = x86 ]; then
|
if [ $arch = x86 ]; then
|
||||||
cp "$tmpdir/include/asm/hyperv.h" "$output/linux-headers/asm-x86"
|
cp "$tmpdir/include/asm/hyperv.h" "$output/linux-headers/asm-x86"
|
||||||
fi
|
fi
|
||||||
|
if [ $arch = powerpc ]; then
|
||||||
|
cp "$tmpdir/include/asm/epapr_hcalls.h" "$output/linux-headers/asm-powerpc/"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
rm -rf "$output/linux-headers/linux"
|
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_SOFTMMU) += machine.o
|
||||||
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
|
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
|
||||||
obj-y += helper.o
|
|
||||||
obj-y += excp_helper.o
|
obj-y += excp_helper.o
|
||||||
obj-y += fpu_helper.o
|
obj-y += fpu_helper.o
|
||||||
obj-y += int_helper.o
|
obj-y += int_helper.o
|
||||||
|
@ -9,4 +8,3 @@ obj-y += mmu_helper.o
|
||||||
obj-y += timebase_helper.o
|
obj-y += timebase_helper.o
|
||||||
obj-y += misc_helper.o
|
obj-y += misc_helper.o
|
||||||
obj-y += mem_helper.o
|
obj-y += mem_helper.o
|
||||||
obj-y += mpic_helper.o
|
|
||||||
|
|
|
@ -50,6 +50,9 @@ typedef struct PowerPCCPUClass {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
void (*parent_reset)(CPUState *cpu);
|
void (*parent_reset)(CPUState *cpu);
|
||||||
|
|
||||||
|
/* TODO inline fields here */
|
||||||
|
ppc_def_t *info;
|
||||||
} PowerPCCPUClass;
|
} 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))
|
#define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e))
|
||||||
|
|
||||||
|
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1067,7 +1067,9 @@ struct CPUPPCState {
|
||||||
target_ulong ivor_mask;
|
target_ulong ivor_mask;
|
||||||
target_ulong ivpr_mask;
|
target_ulong ivpr_mask;
|
||||||
target_ulong hreset_vector;
|
target_ulong hreset_vector;
|
||||||
hwaddr mpic_cpu_base;
|
hwaddr mpic_iack;
|
||||||
|
/* true when the external proxy facility mode is enabled */
|
||||||
|
bool mpic_proxy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Those resources are used only during code translation */
|
/* 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);
|
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 */
|
/* Time-base and decrementer management */
|
||||||
#ifndef NO_CPU_IO_DEFS
|
#ifndef NO_CPU_IO_DEFS
|
||||||
uint64_t cpu_ppc_load_tbl (CPUPPCState *env);
|
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);
|
" => %08x (%02x)\n", env->nip, excp, env->error_code);
|
||||||
|
|
||||||
/* new srr1 value excluding must-be-zero bits */
|
/* new srr1 value excluding must-be-zero bits */
|
||||||
|
if (excp_model == POWERPC_EXCP_BOOKE) {
|
||||||
|
msr = env->msr;
|
||||||
|
} else {
|
||||||
msr = env->msr & ~0x783f0000ULL;
|
msr = env->msr & ~0x783f0000ULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* new interrupt handler msr */
|
/* new interrupt handler msr */
|
||||||
new_msr = env->msr & ((target_ulong)1 << MSR_ME);
|
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;
|
srr1 = SPR_40x_SRR3;
|
||||||
break;
|
break;
|
||||||
case POWERPC_EXCP_BOOKE:
|
case POWERPC_EXCP_BOOKE:
|
||||||
|
/* FIXME: choose one or the other based on CPU type */
|
||||||
srr0 = SPR_BOOKE_MCSRR0;
|
srr0 = SPR_BOOKE_MCSRR0;
|
||||||
srr1 = SPR_BOOKE_MCSRR1;
|
srr1 = SPR_BOOKE_MCSRR1;
|
||||||
asrr0 = SPR_BOOKE_CSRR0;
|
asrr0 = SPR_BOOKE_CSRR0;
|
||||||
|
@ -173,6 +178,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||||
if (lpes0 == 1) {
|
if (lpes0 == 1) {
|
||||||
new_msr |= (target_ulong)MSR_HVB;
|
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;
|
goto store_next;
|
||||||
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||||
if (lpes1 == 0) {
|
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 */
|
case POWERPC_EXCP_DEBUG: /* Debug interrupt */
|
||||||
switch (excp_model) {
|
switch (excp_model) {
|
||||||
case POWERPC_EXCP_BOOKE:
|
case POWERPC_EXCP_BOOKE:
|
||||||
|
/* FIXME: choose one or the other based on CPU type */
|
||||||
srr0 = SPR_BOOKE_DSRR0;
|
srr0 = SPR_BOOKE_DSRR0;
|
||||||
srr1 = SPR_BOOKE_DSRR1;
|
srr1 = SPR_BOOKE_DSRR1;
|
||||||
asrr0 = SPR_BOOKE_CSRR0;
|
asrr0 = SPR_BOOKE_CSRR0;
|
||||||
|
@ -836,9 +846,14 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
|
||||||
|
|
||||||
void helper_rfi(CPUPPCState *env)
|
void helper_rfi(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
|
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],
|
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
|
||||||
~((target_ulong)0x783F0000), 1);
|
~((target_ulong)0x783F0000), 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
void helper_rfid(CPUPPCState *env)
|
void helper_rfid(CPUPPCState *env)
|
||||||
|
@ -864,20 +879,22 @@ void helper_40x_rfci(CPUPPCState *env)
|
||||||
|
|
||||||
void helper_rfci(CPUPPCState *env)
|
void helper_rfci(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
|
do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
|
||||||
~((target_ulong)0x3FFF0000), 0);
|
~((target_ulong)0), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_rfdi(CPUPPCState *env)
|
void helper_rfdi(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
|
/* FIXME: choose CSRR1 or DSRR1 based on cpu type */
|
||||||
~((target_ulong)0x3FFF0000), 0);
|
do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
|
||||||
|
~((target_ulong)0), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_rfmci(CPUPPCState *env)
|
void helper_rfmci(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
|
/* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
|
||||||
~((target_ulong)0x3FFF0000), 0);
|
do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
|
||||||
|
~((target_ulong)0), 0);
|
||||||
}
|
}
|
||||||
#endif
|
#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_40x_sler, void, env, tl)
|
||||||
DEF_HELPER_2(store_booke_tcr, void, env, tl)
|
DEF_HELPER_2(store_booke_tcr, void, env, tl)
|
||||||
DEF_HELPER_2(store_booke_tsr, 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_ibatl, void, env, i32, tl)
|
||||||
DEF_HELPER_3(store_ibatu, void, env, i32, tl)
|
DEF_HELPER_3(store_ibatu, void, env, i32, tl)
|
||||||
DEF_HELPER_3(store_dbatl, 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");
|
return kvmppc_read_int_cpu_dt("ibm,dfp");
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
|
static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
uint32_t *hc = (uint32_t*)buf;
|
|
||||||
|
|
||||||
struct kvm_ppc_pvinfo pvinfo;
|
|
||||||
|
|
||||||
if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) &&
|
if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) &&
|
||||||
!kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) {
|
!kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, pvinfo)) {
|
||||||
memcpy(buf, pvinfo.hcall, buf_len);
|
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;
|
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();
|
uint32_t host_pvr = mfpvr();
|
||||||
const ppc_def_t *base_spec;
|
PowerPCCPUClass *pvr_pcc;
|
||||||
ppc_def_t *spec;
|
ppc_def_t *spec;
|
||||||
uint32_t vmx = kvmppc_get_vmx();
|
uint32_t vmx = kvmppc_get_vmx();
|
||||||
uint32_t dfp = kvmppc_get_dfp();
|
uint32_t dfp = kvmppc_get_dfp();
|
||||||
|
|
||||||
base_spec = ppc_find_by_pvr(host_pvr);
|
|
||||||
|
|
||||||
spec = g_malloc0(sizeof(*spec));
|
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 */
|
/* 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 */
|
/* Only override when we know what the host supports */
|
||||||
alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
|
alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return spec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvmppc_fixup_cpu(CPUPPCState *env)
|
int kvmppc_fixup_cpu(CPUPPCState *env)
|
||||||
|
@ -1265,3 +1302,17 @@ int kvm_arch_on_sigbus(int code, void *addr)
|
||||||
{
|
{
|
||||||
return 1;
|
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"
|
#include "exec/memory.h"
|
||||||
|
|
||||||
|
#define TYPE_HOST_POWERPC_CPU "host-" TYPE_POWERPC_CPU
|
||||||
|
|
||||||
void kvmppc_init(void);
|
void kvmppc_init(void);
|
||||||
|
|
||||||
#ifdef CONFIG_KVM
|
#ifdef CONFIG_KVM
|
||||||
|
@ -19,6 +21,7 @@ uint32_t kvmppc_get_tbfreq(void);
|
||||||
uint64_t kvmppc_get_clockfreq(void);
|
uint64_t kvmppc_get_clockfreq(void);
|
||||||
uint32_t kvmppc_get_vmx(void);
|
uint32_t kvmppc_get_vmx(void);
|
||||||
uint32_t kvmppc_get_dfp(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_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len);
|
||||||
int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
|
int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
|
||||||
void kvmppc_set_papr(PowerPCCPU *cpu);
|
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);
|
int kvmppc_reset_htab(int shift_hint);
|
||||||
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
|
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
const ppc_def_t *kvmppc_host_cpu_def(void);
|
|
||||||
int kvmppc_fixup_cpu(CPUPPCState *env);
|
int kvmppc_fixup_cpu(CPUPPCState *env);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -55,6 +57,11 @@ static inline uint32_t kvmppc_get_dfp(void)
|
||||||
return 0;
|
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)
|
static inline int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -115,11 +122,6 @@ static inline int kvmppc_update_sdr1(CPUPPCState *env)
|
||||||
|
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#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)
|
static inline int kvmppc_fixup_cpu(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
return -1;
|
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);
|
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
|
#endif
|
||||||
|
|
||||||
enum fsl_e500_version {
|
enum fsl_e500_version {
|
||||||
|
@ -4656,7 +4651,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
|
||||||
0x00000000);
|
0x00000000);
|
||||||
spr_register(env, SPR_BOOKE_EPR, "EPR",
|
spr_register(env, SPR_BOOKE_EPR, "EPR",
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
SPR_NOACCESS, SPR_NOACCESS,
|
||||||
&spr_load_epr, SPR_NOACCESS,
|
&spr_read_generic, SPR_NOACCESS,
|
||||||
0x00000000);
|
0x00000000);
|
||||||
/* XXX better abstract into Emb.xxx features */
|
/* XXX better abstract into Emb.xxx features */
|
||||||
if (version == fsl_e5500) {
|
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;
|
opcode_t *opc;
|
||||||
|
|
||||||
fill_new_table(env->opcodes, 0x40);
|
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) ||
|
if (((opc->handler.type & def->insns_flags) != 0) ||
|
||||||
((opc->handler.type2 & def->insns_flags2) != 0)) {
|
((opc->handler.type2 & def->insns_flags2) != 0)) {
|
||||||
if (register_insn(env->opcodes, opc) < 0) {
|
if (register_insn(env->opcodes, opc) < 0) {
|
||||||
printf("*** ERROR initializing PowerPC instruction "
|
error_setg(errp, "ERROR initializing PowerPC instruction "
|
||||||
"0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
|
"0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
|
||||||
opc->opc3);
|
opc->opc3);
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fix_opcode_tables(env->opcodes);
|
fix_opcode_tables(env->opcodes);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(PPC_DUMP_CPU)
|
#if defined(PPC_DUMP_CPU)
|
||||||
|
@ -10031,53 +10027,31 @@ static int ppc_fixup_cpu(CPUPPCState *env)
|
||||||
return 0;
|
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;
|
PowerPCCPU *cpu = POWERPC_CPU(obj);
|
||||||
env->mmu_model = def->mmu_model;
|
CPUPPCState *env = &cpu->env;
|
||||||
env->excp_model = def->excp_model;
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||||
env->bus_model = def->bus_model;
|
ppc_def_t *def = pcc->info;
|
||||||
env->insns_flags = def->insns_flags;
|
Error *local_err = NULL;
|
||||||
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) */
|
|
||||||
|
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
if (kvmppc_fixup_cpu(env) != 0) {
|
if (kvmppc_fixup_cpu(env) != 0) {
|
||||||
fprintf(stderr, "Unable to virtualize selected CPU with KVM\n");
|
error_setg(errp, "Unable to virtualize selected CPU with KVM");
|
||||||
exit(1);
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ppc_fixup_cpu(env) != 0) {
|
if (ppc_fixup_cpu(env) != 0) {
|
||||||
fprintf(stderr, "Unable to emulate selected CPU with TCG\n");
|
error_setg(errp, "Unable to emulate selected CPU with TCG");
|
||||||
exit(1);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_ppc_opcodes(env, def) < 0)
|
create_ppc_opcodes(cpu, &local_err);
|
||||||
return -1;
|
if (local_err != NULL) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
init_ppc_proc(env, def);
|
init_ppc_proc(env, def);
|
||||||
|
|
||||||
if (def->insns_flags & PPC_FLOAT) {
|
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);
|
34, "power-spe.xml", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_init_vcpu(env);
|
||||||
|
|
||||||
#if defined(PPC_DUMP_CPU)
|
#if defined(PPC_DUMP_CPU)
|
||||||
{
|
{
|
||||||
const char *mmu_model, *excp_model, *bus_model;
|
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);
|
dump_ppc_sprs(env);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
ObjectClass *oc = (ObjectClass *)a;
|
||||||
|
uint32_t pvr = *(uint32_t *)b;
|
||||||
|
PowerPCCPUClass *pcc = (PowerPCCPUClass *)a;
|
||||||
|
|
||||||
|
/* -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr)
|
||||||
|
{
|
||||||
|
GSList *list, *item;
|
||||||
|
PowerPCCPUClass *pcc = NULL;
|
||||||
|
|
||||||
|
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 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 0;
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
static bool ppc_cpu_usable(const ppc_def_t *def)
|
|
||||||
{
|
|
||||||
#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
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ppc_def_t *ppc_find_by_pvr(uint32_t pvr)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <ctype.h>
|
#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;
|
const char *p;
|
||||||
int i, max, len;
|
int i, len;
|
||||||
|
|
||||||
if (kvm_enabled() && (strcasecmp(name, "host") == 0)) {
|
if (strcasecmp(name, "host") == 0) {
|
||||||
return kvmppc_host_cpu_def();
|
if (kvm_enabled()) {
|
||||||
|
ret = object_class_by_name(TYPE_HOST_POWERPC_CPU);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the given name is a PVR */
|
/* 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++))
|
if (!qemu_isxdigit(*p++))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i == 8)
|
if (i == 8) {
|
||||||
return ppc_find_by_pvr(strtoul(name, NULL, 16));
|
ret = OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16)));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
ret = NULL;
|
|
||||||
max = ARRAY_SIZE(ppc_defs);
|
|
||||||
for (i = 0; i < max; i++) {
|
|
||||||
if (!ppc_cpu_usable(&ppc_defs[i])) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(name, ppc_defs[i].name) == 0) {
|
list = object_class_get_list(TYPE_POWERPC_CPU, false);
|
||||||
ret = &ppc_defs[i];
|
item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name);
|
||||||
break;
|
if (item != NULL) {
|
||||||
}
|
ret = OBJECT_CLASS(item->data);
|
||||||
}
|
}
|
||||||
|
g_slist_free(list);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
|
||||||
|
{
|
||||||
|
PowerPCCPU *cpu;
|
||||||
|
CPUPPCState *env;
|
||||||
|
ObjectClass *oc;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
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)
|
void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
|
||||||
{
|
{
|
||||||
int i, max;
|
CPUListState s = {
|
||||||
|
.file = f,
|
||||||
|
.cpu_fprintf = cpu_fprintf,
|
||||||
|
};
|
||||||
|
GSList *list;
|
||||||
|
|
||||||
max = ARRAY_SIZE(ppc_defs);
|
list = object_class_get_list(TYPE_POWERPC_CPU, false);
|
||||||
for (i = 0; i < max; i++) {
|
list = g_slist_sort(list, ppc_cpu_list_compare);
|
||||||
if (!ppc_cpu_usable(&ppc_defs[i])) {
|
g_slist_foreach(list, ppc_cpu_list_entry, &s);
|
||||||
continue;
|
g_slist_free(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n",
|
static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
|
||||||
ppc_defs[i].name, ppc_defs[i].pvr);
|
{
|
||||||
}
|
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 *arch_query_cpu_definitions(Error **errp)
|
||||||
{
|
{
|
||||||
CpuDefinitionInfoList *cpu_list = NULL;
|
CpuDefinitionInfoList *cpu_list = NULL;
|
||||||
int i;
|
GSList *list;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
|
list = object_class_get_list(TYPE_POWERPC_CPU, false);
|
||||||
CpuDefinitionInfoList *entry;
|
g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list);
|
||||||
CpuDefinitionInfo *info;
|
g_slist_free(list);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cpu_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() */
|
/* CPUClass::reset() */
|
||||||
static void ppc_cpu_reset(CPUState *s)
|
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)
|
static void ppc_cpu_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(obj);
|
PowerPCCPU *cpu = POWERPC_CPU(obj);
|
||||||
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
|
ppc_def_t *def = pcc->info;
|
||||||
|
|
||||||
cpu_exec_init(env);
|
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)
|
static void ppc_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
|
@ -10458,14 +10571,27 @@ static const TypeInfo ppc_cpu_type_info = {
|
||||||
.parent = TYPE_CPU,
|
.parent = TYPE_CPU,
|
||||||
.instance_size = sizeof(PowerPCCPU),
|
.instance_size = sizeof(PowerPCCPU),
|
||||||
.instance_init = ppc_cpu_initfn,
|
.instance_init = ppc_cpu_initfn,
|
||||||
.abstract = false,
|
.abstract = true,
|
||||||
.class_size = sizeof(PowerPCCPUClass),
|
.class_size = sizeof(PowerPCCPUClass),
|
||||||
.class_init = ppc_cpu_class_init,
|
.class_init = ppc_cpu_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ppc_cpu_register_types(void)
|
static void ppc_cpu_register_types(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
type_register_static(&ppc_cpu_type_info);
|
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)
|
type_init(ppc_cpu_register_types)
|
||||||
|
|
Loading…
Reference in New Issue