[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] Re: [PATCH 13/15] Add POWER7 support for ppc
From: |
Alexander Graf |
Subject: |
[Qemu-devel] Re: [PATCH 13/15] Add POWER7 support for ppc |
Date: |
Sat, 12 Feb 2011 17:09:39 +0100 |
On 12.02.2011, at 15:54, David Gibson wrote:
> 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 <address@hidden>
> ---
> hw/ppc.c | 83 ++++++++++++++++++++++++++++++++++
> hw/ppc.h | 1 +
> target-ppc/cpu.h | 19 ++++++++
> target-ppc/helper.c | 6 +++
> target-ppc/translate_init.c | 103 +++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 212 insertions(+), 0 deletions(-)
>
> diff --git a/hw/ppc.c b/hw/ppc.c
> index 968aec1..6975636 100644
> --- a/hw/ppc.c
> +++ b/hw/ppc.c
> @@ -246,6 +246,89 @@ 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;
> + /* Don't generate spurious events */
> + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
Did you hit this? Qemu's irq framework should already ensure that property. I'm
also not sure it's actually correct - if a level interrupt is on, the guest
would get another interrupt injected, no? That would be cur_level ==1 && level
== 1 IIUC.
> + 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;
> + case POWER7_INPUT_THINT:
> + /* Level sensitive - active high */
> + LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__,
> + level);
> + ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
> + break;
> + case POWER7_INPUT_MCP:
> + /* Negative edge sensitive */
> + /* XXX: TODO: actual reaction may depends on HID0 status
> + * 603/604/740/750: check HID0[EMCP]
> + */
> + if (cur_level == 1 && level == 0) {
> + LOG_IRQ("%s: raise machine check state\n",
> + __func__);
> + ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
> + }
> + break;
> + case POWER7_INPUT_CKSTP:
POWER7 has checkstop?
> + /* Level sensitive - active low */
> + /* XXX: TODO: relay the signal to CKSTP_OUT pin */
> + if (level) {
> + LOG_IRQ("%s: stop the CPU\n", __func__);
> + env->halted = 1;
> + } else {
> + LOG_IRQ("%s: restart the CPU\n", __func__);
> + env->halted = 0;
> + }
> + break;
> + case POWER7_INPUT_HRESET:
Does this ever get triggered? POWER7 is run in lpar only, so there is no
hreset, right?
> + /* Level sensitive - active low */
> + if (level) {
> +#if 0 // XXX: TOFIX
> + LOG_IRQ("%s: reset the CPU\n", __func__);
> + cpu_reset(env);
> +#endif
> + }
> + break;
> + case POWER7_INPUT_SRESET:
> + LOG_IRQ("%s: set the RESET IRQ state to %d\n",
> + __func__, level);
> + ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
> + break;
> + case POWER7_INPUT_TBEN:
> + LOG_IRQ("%s: set the TBEN state to %d\n", __func__,
> + level);
> + /* XXX: TODO */
Hrm - what is this?
> + break;
> + default:
> + /* Unknown pin - do nothing */
> + LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
> + return;
> + }
> + if (level)
Braces
> + 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 */
> diff --git a/hw/ppc.h b/hw/ppc.h
> index 34f54cf..3ccf134 100644
> --- a/hw/ppc.h
> +++ b/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 {
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index 53b788f..fa3cd7f 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -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 */
> @@ -1003,6 +1009,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)
> @@ -1627,6 +1634,18 @@ enum {
> PPC970_INPUT_THINT = 6,
> PPC970_INPUT_NB,
> };
> +
> +enum {
> + /* POWER7 input pins */
> + POWER7_INPUT_HRESET = 0,
> + POWER7_INPUT_SRESET = 1,
> + POWER7_INPUT_CKSTP = 2,
> + POWER7_INPUT_TBEN = 3,
> + POWER7_INPUT_MCP = 4,
> + POWER7_INPUT_INT = 5,
> + POWER7_INPUT_THINT = 6,
> + POWER7_INPUT_NB,
> +};
> #endif
>
> /* Hardware exceptions definitions */
> diff --git a/target-ppc/helper.c b/target-ppc/helper.c
> index 158da09..a630148 100644
> --- a/target-ppc/helper.c
> +++ b/target-ppc/helper.c
> @@ -1192,6 +1192,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;
> @@ -1269,6 +1270,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 */
> @@ -1368,6 +1370,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;
> @@ -1475,6 +1478,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;
> @@ -1798,6 +1802,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;
> @@ -1865,6 +1870,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,
> diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> index c84581e..2faa591 100644
> --- a/target-ppc/translate_init.c
> +++ b/target-ppc/translate_init.c
> @@ -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:
> @@ -3087,6 +3088,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 = 0x00000000FFF00000ULL;
> + /* Hardware reset vector */
> + env->hreset_vector = 0x0000000000000100ULL;
> +#endif
> +}
> #endif
>
> /*****************************************************************************/
> @@ -6268,6 +6298,74 @@ static void init_proc_970MP (CPUPPCState *env)
> vscr_init(env, 0x00010000);
> }
>
> +/* POWER7 (actually a somewhat hacked 970FX for now...) */
> +#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);
> + /* 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);
> + /* 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;
POWER7 has 64, no? Please check this :).
> +#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);
> +}
> +
> /* PowerPC 620
> */
> #define POWERPC_INSNS_620 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> \
> PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> \
> @@ -6990,6 +7088,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,
> @@ -8792,6 +8892,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)
> */
Alex
- Re: [Qemu-devel] Re: [PATCH 09/15] Parse SDR1 on mtspr instead of at translate time, (continued)
[Qemu-devel] [PATCH 13/15] Add POWER7 support for ppc, David Gibson, 2011/02/12
- [Qemu-devel] Re: [PATCH 13/15] Add POWER7 support for ppc,
Alexander Graf <=
[Qemu-devel] [PATCH 14/15] Start implementing pSeries logical partition machine, David Gibson, 2011/02/12
[Qemu-devel] [PATCH 15/15] Implement the bus structure for PAPR virtual IO, David Gibson, 2011/02/12