mirror of https://gitee.com/openkylin/qemu.git
Add POWER7 support for ppc
This adds emulation support for the recent POWER7 cpu to qemu. It's far from perfect - it's missing a number of POWER7 features so far, including any support for VSX or decimal floating point instructions. However, it's close enough to boot a kernel with the POWER7 PVR. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
cdaee00633
commit
9d52e9079d
35
hw/ppc.c
35
hw/ppc.c
|
@ -247,6 +247,41 @@ void ppc970_irq_init (CPUState *env)
|
|||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env,
|
||||
PPC970_INPUT_NB);
|
||||
}
|
||||
|
||||
/* POWER7 internal IRQ controller */
|
||||
static void power7_set_irq (void *opaque, int pin, int level)
|
||||
{
|
||||
CPUState *env = opaque;
|
||||
int cur_level;
|
||||
|
||||
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
|
||||
env, pin, level);
|
||||
cur_level = (env->irq_input_state >> pin) & 1;
|
||||
|
||||
switch (pin) {
|
||||
case POWER7_INPUT_INT:
|
||||
/* Level sensitive - active high */
|
||||
LOG_IRQ("%s: set the external IRQ state to %d\n",
|
||||
__func__, level);
|
||||
ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
|
||||
break;
|
||||
default:
|
||||
/* Unknown pin - do nothing */
|
||||
LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
|
||||
return;
|
||||
}
|
||||
if (level) {
|
||||
env->irq_input_state |= 1 << pin;
|
||||
} else {
|
||||
env->irq_input_state &= ~(1 << pin);
|
||||
}
|
||||
}
|
||||
|
||||
void ppcPOWER7_irq_init (CPUState *env)
|
||||
{
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, env,
|
||||
POWER7_INPUT_NB);
|
||||
}
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
|
||||
/* PowerPC 40x internal IRQ controller */
|
||||
|
|
1
hw/ppc.h
1
hw/ppc.h
|
@ -36,6 +36,7 @@ void ppc40x_irq_init (CPUState *env);
|
|||
void ppce500_irq_init (CPUState *env);
|
||||
void ppc6xx_irq_init (CPUState *env);
|
||||
void ppc970_irq_init (CPUState *env);
|
||||
void ppcPOWER7_irq_init (CPUState *env);
|
||||
|
||||
/* PPC machines for OpenBIOS */
|
||||
enum {
|
||||
|
|
|
@ -119,6 +119,8 @@ enum powerpc_mmu_t {
|
|||
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
|
||||
/* 620 variant (no segment exceptions) */
|
||||
POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002,
|
||||
/* Architecture 2.06 variant */
|
||||
POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
};
|
||||
|
||||
|
@ -154,6 +156,8 @@ enum powerpc_excp_t {
|
|||
#if defined(TARGET_PPC64)
|
||||
/* PowerPC 970 exception model */
|
||||
POWERPC_EXCP_970,
|
||||
/* POWER7 exception model */
|
||||
POWERPC_EXCP_POWER7,
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
};
|
||||
|
||||
|
@ -289,6 +293,8 @@ enum powerpc_input_t {
|
|||
PPC_FLAGS_INPUT_405,
|
||||
/* PowerPC 970 bus */
|
||||
PPC_FLAGS_INPUT_970,
|
||||
/* PowerPC POWER7 bus */
|
||||
PPC_FLAGS_INPUT_POWER7,
|
||||
/* PowerPC 401 bus */
|
||||
PPC_FLAGS_INPUT_401,
|
||||
/* Freescale RCPU bus */
|
||||
|
@ -1001,6 +1007,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
|
|||
#define SPR_HSPRG1 (0x131)
|
||||
#define SPR_HDSISR (0x132)
|
||||
#define SPR_HDAR (0x133)
|
||||
#define SPR_SPURR (0x134)
|
||||
#define SPR_BOOKE_DBCR0 (0x134)
|
||||
#define SPR_IBCR (0x135)
|
||||
#define SPR_PURR (0x135)
|
||||
|
@ -1625,6 +1632,15 @@ enum {
|
|||
PPC970_INPUT_THINT = 6,
|
||||
PPC970_INPUT_NB,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* POWER7 input pins */
|
||||
POWER7_INPUT_INT = 0,
|
||||
/* POWER7 probably has other inputs, but we don't care about them
|
||||
* for any existing machine. We can wire these up when we need
|
||||
* them */
|
||||
POWER7_INPUT_NB,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Hardware exceptions definitions */
|
||||
|
|
|
@ -1200,6 +1200,7 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
|
|||
#if defined(TARGET_PPC64)
|
||||
case POWERPC_MMU_620:
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_2_06:
|
||||
/* Real address are 60 bits long */
|
||||
ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
|
||||
ctx->prot |= PAGE_WRITE;
|
||||
|
@ -1277,6 +1278,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
|
|||
#if defined(TARGET_PPC64)
|
||||
case POWERPC_MMU_620:
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_2_06:
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
/* We didn't match any BAT entry or don't have BATs */
|
||||
|
@ -1376,6 +1378,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
|||
#if defined(TARGET_PPC64)
|
||||
case POWERPC_MMU_620:
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_2_06:
|
||||
#endif
|
||||
env->exception_index = POWERPC_EXCP_ISI;
|
||||
env->error_code = 0x40000000;
|
||||
|
@ -1485,6 +1488,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
|||
#if defined(TARGET_PPC64)
|
||||
case POWERPC_MMU_620:
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_2_06:
|
||||
#endif
|
||||
env->exception_index = POWERPC_EXCP_DSI;
|
||||
env->error_code = 0;
|
||||
|
@ -1808,6 +1812,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
|
|||
#if defined(TARGET_PPC64)
|
||||
case POWERPC_MMU_620:
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_2_06:
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
tlb_flush(env, 1);
|
||||
break;
|
||||
|
@ -1875,6 +1880,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
|
|||
#if defined(TARGET_PPC64)
|
||||
case POWERPC_MMU_620:
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_2_06:
|
||||
/* tlbie invalidate TLBs for all segments */
|
||||
/* XXX: given the fact that there are too many segments to invalidate,
|
||||
* and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
|
||||
|
|
|
@ -61,6 +61,7 @@ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env);
|
|||
PPC_IRQ_INIT_FN(40x);
|
||||
PPC_IRQ_INIT_FN(6xx);
|
||||
PPC_IRQ_INIT_FN(970);
|
||||
PPC_IRQ_INIT_FN(POWER7);
|
||||
PPC_IRQ_INIT_FN(e500);
|
||||
|
||||
/* Generic callbacks:
|
||||
|
@ -3131,6 +3132,35 @@ static void init_excp_970 (CPUPPCState *env)
|
|||
env->hreset_vector = 0x0000000000000100ULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void init_excp_POWER7 (CPUPPCState *env)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100;
|
||||
env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200;
|
||||
env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300;
|
||||
env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380;
|
||||
env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400;
|
||||
env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480;
|
||||
env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
|
||||
env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600;
|
||||
env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700;
|
||||
env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800;
|
||||
env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900;
|
||||
env->excp_vectors[POWERPC_EXCP_HDECR] = 0x00000980;
|
||||
env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
|
||||
env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00;
|
||||
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
|
||||
env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20;
|
||||
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
|
||||
env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600;
|
||||
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700;
|
||||
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800;
|
||||
env->hreset_excp_prefix = 0;
|
||||
/* Hardware reset vector */
|
||||
env->hreset_vector = 0x0000000000000100ULL;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -6312,6 +6342,78 @@ static void init_proc_970MP (CPUPPCState *env)
|
|||
vscr_init(env, 0x00010000);
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
/* POWER7 */
|
||||
#define POWERPC_INSNS_POWER7 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \
|
||||
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \
|
||||
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \
|
||||
PPC_FLOAT_STFIWX | \
|
||||
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_64B | PPC_ALTIVEC | \
|
||||
PPC_SEGMENT_64B | PPC_SLBI | \
|
||||
PPC_POPCNTB | PPC_POPCNTWD)
|
||||
#define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL)
|
||||
#define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06)
|
||||
#define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7)
|
||||
#define POWERPC_INPUT_POWER7 (PPC_FLAGS_INPUT_POWER7)
|
||||
#define POWERPC_BFDM_POWER7 (bfd_mach_ppc64)
|
||||
#define POWERPC_FLAG_POWER7 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \
|
||||
POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \
|
||||
POWERPC_FLAG_BUS_CLK)
|
||||
#define check_pow_POWER7 check_pow_nocheck
|
||||
|
||||
static void init_proc_POWER7 (CPUPPCState *env)
|
||||
{
|
||||
gen_spr_ne_601(env);
|
||||
gen_spr_7xx(env);
|
||||
/* Time base */
|
||||
gen_tbl(env);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* PURR & SPURR: Hack - treat these as aliases for the TB for now */
|
||||
spr_register(env, SPR_PURR, "PURR",
|
||||
&spr_read_purr, SPR_NOACCESS,
|
||||
&spr_read_purr, SPR_NOACCESS,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_SPURR, "SPURR",
|
||||
&spr_read_purr, SPR_NOACCESS,
|
||||
&spr_read_purr, SPR_NOACCESS,
|
||||
0x00000000);
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
/* Memory management */
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_MMUCFG, "MMUCFG",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000); /* TOFIX */
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_CTRL, "SPR_CTRLT",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x80800000);
|
||||
spr_register(env, SPR_UCTRL, "SPR_CTRLF",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x80800000);
|
||||
spr_register(env, SPR_VRSAVE, "SPR_VRSAVE",
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
env->slb_nr = 32;
|
||||
#endif
|
||||
init_excp_POWER7(env);
|
||||
env->dcache_line_size = 128;
|
||||
env->icache_line_size = 128;
|
||||
/* Allocate hardware IRQ controller */
|
||||
ppcPOWER7_irq_init(env);
|
||||
/* Can't find information on what this should be on reset. This
|
||||
* value is the one used by 74xx processors. */
|
||||
vscr_init(env, 0x00010000);
|
||||
}
|
||||
#endif /* TARGET_PPC64 */
|
||||
|
||||
/* PowerPC 620 */
|
||||
#define POWERPC_INSNS_620 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \
|
||||
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \
|
||||
|
@ -7034,6 +7136,8 @@ enum {
|
|||
CPU_POWERPC_POWER6 = 0x003E0000,
|
||||
CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */
|
||||
CPU_POWERPC_POWER6A = 0x0F000002,
|
||||
#define CPU_POWERPC_POWER7 CPU_POWERPC_POWER7_v20
|
||||
CPU_POWERPC_POWER7_v20 = 0x003F0200,
|
||||
CPU_POWERPC_970 = 0x00390202,
|
||||
#define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31
|
||||
CPU_POWERPC_970FX_v10 = 0x00391100,
|
||||
|
@ -8836,6 +8940,9 @@ static const ppc_def_t ppc_defs[] = {
|
|||
/* POWER6A */
|
||||
POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6),
|
||||
#endif
|
||||
/* POWER7 */
|
||||
POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7),
|
||||
POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7),
|
||||
/* PowerPC 970 */
|
||||
POWERPC_DEF("970", CPU_POWERPC_970, 970),
|
||||
/* PowerPC 970FX (G5) */
|
||||
|
|
Loading…
Reference in New Issue