qemu-devel
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]