コード例 #1
0
ファイル: compat.c プロジェクト: giomasce/panda
bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
                      uint32_t min_compat_pvr, uint32_t max_compat_pvr)
{
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
    const CompatInfo *compat = compat_by_pvr(compat_pvr);
    const CompatInfo *min = compat_by_pvr(min_compat_pvr);
    const CompatInfo *max = compat_by_pvr(max_compat_pvr);

#if !defined(CONFIG_USER_ONLY)
    g_assert(cpu->vhyp);
#endif
    g_assert(!min_compat_pvr || min);
    g_assert(!max_compat_pvr || max);

    if (!compat) {
        /* Not a recognized logical PVR */
        return false;
    }
    if ((min && (compat < min)) || (max && (compat > max))) {
        /* Outside specified range */
        return false;
    }
    if (!(pcc->pcr_supported & compat->pcr_level)) {
        /* Not supported by this CPU */
        return false;
    }
    return true;
}
コード例 #2
0
ファイル: spapr_cpu_core.c プロジェクト: CRYP706URU/pyrebox
static void spapr_cpu_reset(void *opaque)
{
    PowerPCCPU *cpu = opaque;
    CPUState *cs = CPU(cpu);
    CPUPPCState *env = &cpu->env;
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);

    cpu_reset(cs);

    /* All CPUs start halted.  CPU0 is unhalted from the machine level
     * reset code and the rest are explicitly started up by the guest
     * using an RTAS call */
    cs->halted = 1;

    env->spr[SPR_HIOR] = 0;

    /* Disable Power-saving mode Exit Cause exceptions for the CPU.
     * This can cause issues when rebooting the guest if a secondary
     * is awaken */
    if (cs != first_cpu) {
        env->spr[SPR_LPCR] &= ~pcc->lpcr_pm;
    }

    /* Set compatibility mode to match the boot CPU, which was either set
     * by the machine reset code or by CAS. This should never fail.
     */
    if (cs != first_cpu) {
        ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &error_abort);
    }
}
コード例 #3
0
ファイル: compat.c プロジェクト: giomasce/panda
void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
{
    const CompatInfo *compat = compat_by_pvr(compat_pvr);
    CPUPPCState *env = &cpu->env;
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
    uint64_t pcr;

    if (!compat_pvr) {
        pcr = 0;
    } else if (!compat) {
        error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
        return;
    } else if (!ppc_check_compat(cpu, compat_pvr, 0, 0)) {
        error_setg(errp, "Compatibility PVR 0x%08"PRIx32" not valid for CPU",
                   compat_pvr);
        return;
    } else {
        pcr = compat->pcr;
    }

    cpu_synchronize_state(CPU(cpu));

    cpu->compat_pvr = compat_pvr;
    env->spr[SPR_PCR] = pcr & pcc->pcr_mask;

    if (kvm_enabled()) {
        int ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
        if (ret < 0) {
            error_setg_errno(errp, -ret,
                             "Unable to set CPU compatibility mode in KVM");
        }
    }
}
コード例 #4
0
ファイル: spapr_cpu_core.c プロジェクト: MaddTheSane/qemu
static void spapr_cpu_reset(void *opaque)
{
    PowerPCCPU *cpu = opaque;
    CPUState *cs = CPU(cpu);
    CPUPPCState *env = &cpu->env;
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
    SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
    target_ulong lpcr;

    cpu_reset(cs);

    /* All CPUs start halted.  CPU0 is unhalted from the machine level
     * reset code and the rest are explicitly started up by the guest
     * using an RTAS call */
    cs->halted = 1;

    /* Set compatibility mode to match the boot CPU, which was either set
     * by the machine reset code or by CAS. This should never fail.
     */
    ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &error_abort);

    env->spr[SPR_HIOR] = 0;

    lpcr = env->spr[SPR_LPCR];

    /* Set emulated LPCR to not send interrupts to hypervisor. Note that
     * under KVM, the actual HW LPCR will be set differently by KVM itself,
     * the settings below ensure proper operations with TCG in absence of
     * a real hypervisor.
     *
     * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
     * real mode accesses, which thankfully defaults to 0 and isn't
     * accessible in guest mode.
     *
     * Disable Power-saving mode Exit Cause exceptions for the CPU, so
     * we don't get spurious wakups before an RTAS start-cpu call.
     */
    lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
    lpcr |= LPCR_LPES0 | LPCR_LPES1;

    /* Set RMLS to the max (ie, 16G) */
    lpcr &= ~LPCR_RMLS;
    lpcr |= 1ull << LPCR_RMLS_SHIFT;

    ppc_store_lpcr(cpu, lpcr);

    /* Set a full AMOR so guest can use the AMR as it sees fit */
    env->spr[SPR_AMOR] = 0xffffffffffffffffull;

    spapr_cpu->vpa_addr = 0;
    spapr_cpu->slb_shadow_addr = 0;
    spapr_cpu->slb_shadow_size = 0;
    spapr_cpu->dtl_addr = 0;
    spapr_cpu->dtl_size = 0;

    spapr_caps_cpu_apply(SPAPR_MACHINE(qdev_get_machine()), cpu);

    kvm_check_mmu(cpu, &error_fatal);
}
コード例 #5
0
ファイル: machine.c プロジェクト: cminyard/qemu
/*
 * Determine if a given PVR is a "close enough" match to the CPU
 * object.  For TCG and KVM PR it would probably be sufficient to
 * require an exact PVR match.  However for KVM HV the user is
 * restricted to a PVR exactly matching the host CPU.  The correct way
 * to handle this is to put the guest into an architected
 * compatibility mode.  However, to allow a more forgiving transition
 * and migration from before this was widely done, we allow migration
 * between sufficiently similar PVRs, as determined by the CPU class's
 * pvr_match() hook.
 */
static bool pvr_match(PowerPCCPU *cpu, uint32_t pvr)
{
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);

    if (pvr == pcc->pvr) {
        return true;
    }
    return pcc->pvr_match(pcc, pvr);
}
コード例 #6
0
ファイル: spapr_rtas.c プロジェクト: CRYP706URU/pyrebox
static void spapr_cpu_set_endianness(PowerPCCPU *cpu)
{
    PowerPCCPU *fcpu = POWERPC_CPU(first_cpu);
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(fcpu);

    if (!pcc->interrupts_big_endian(fcpu)) {
        cpu->env.spr[SPR_LPCR] |= LPCR_ILE;
    }
}
コード例 #7
0
ファイル: spapr_rtas.c プロジェクト: CRYP706URU/pyrebox
static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
                           uint32_t token, uint32_t nargs,
                           target_ulong args,
                           uint32_t nret, target_ulong rets)
{
    target_ulong id, start, r3;
    PowerPCCPU *cpu;

    if (nargs != 3 || nret != 1) {
        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
        return;
    }

    id = rtas_ld(args, 0);
    start = rtas_ld(args, 1);
    r3 = rtas_ld(args, 2);

    cpu = spapr_find_cpu(id);
    if (cpu != NULL) {
        CPUState *cs = CPU(cpu);
        CPUPPCState *env = &cpu->env;
        PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);

        if (!cs->halted) {
            rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
            return;
        }

        /* This will make sure qemu state is up to date with kvm, and
         * mark it dirty so our changes get flushed back before the
         * new cpu enters */
        kvm_cpu_synchronize_state(cs);

        env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);

        /* Enable Power-saving mode Exit Cause exceptions for the new CPU */
        env->spr[SPR_LPCR] |= pcc->lpcr_pm;

        env->nip = start;
        env->gpr[3] = r3;
        cs->halted = 0;
        spapr_cpu_set_endianness(cpu);
        spapr_cpu_update_tb_offset(cpu);

        qemu_cpu_kick(cs);

        rtas_st(rets, 0, RTAS_OUT_SUCCESS);
        return;
    }

    /* Didn't find a matching cpu */
    rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
コード例 #8
0
ファイル: spapr_cpu_core.c プロジェクト: MaddTheSane/qemu
void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
{
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
    CPUPPCState *env = &cpu->env;

    env->nip = nip;
    env->gpr[3] = r3;
    kvmppc_set_reg_ppc_online(cpu, 1);
    CPU(cpu)->halted = 0;
    /* Enable Power-saving mode Exit Cause exceptions */
    ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm);
}
コード例 #9
0
ファイル: spapr_rtas.c プロジェクト: CRYP706URU/pyrebox
static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
                           uint32_t token, uint32_t nargs,
                           target_ulong args,
                           uint32_t nret, target_ulong rets)
{
    CPUState *cs = CPU(cpu);
    CPUPPCState *env = &cpu->env;
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);

    cs->halted = 1;
    qemu_cpu_kick(cs);

    /* Disable Power-saving mode Exit Cause exceptions for the CPU.
     * This could deliver an interrupt on a dying CPU and crash the
     * guest */
    env->spr[SPR_LPCR] &= ~pcc->lpcr_pm;
}
コード例 #10
0
ファイル: pnv.c プロジェクト: 8tab/qemu
/*
 * The PowerNV cores (and threads) need to use real HW ids and not an
 * incremental index like it has been done on other platforms. This HW
 * id is stored in the CPU PIR, it is used to create cpu nodes in the
 * device tree, used in XSCOM to address cores and in interrupt
 * servers.
 */
static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
{
    CPUState *cs = CPU(DEVICE(pc->threads));
    DeviceClass *dc = DEVICE_GET_CLASS(cs);
    PowerPCCPU *cpu = POWERPC_CPU(cs);
    int smt_threads = CPU_CORE(pc)->nr_threads;
    CPUPPCState *env = &cpu->env;
    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
    uint32_t servers_prop[smt_threads];
    int i;
    uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
                       0xffffffff, 0xffffffff};
    uint32_t tbfreq = PNV_TIMEBASE_FREQ;
    uint32_t cpufreq = 1000000000;
    uint32_t page_sizes_prop[64];
    size_t page_sizes_prop_size;
    const uint8_t pa_features[] = { 24, 0,
                                    0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
                                    0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
                                    0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
                                    0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
    int offset;
    char *nodename;
    int cpus_offset = get_cpus_node(fdt);

    nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
    offset = fdt_add_subnode(fdt, cpus_offset, nodename);
    _FDT(offset);
    g_free(nodename);

    _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));

    _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
    _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
    _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));

    _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
                            env->dcache_line_size)));
    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
                            env->dcache_line_size)));
    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
                            env->icache_line_size)));
    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
                            env->icache_line_size)));

    if (pcc->l1_dcache_size) {
        _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
                               pcc->l1_dcache_size)));
    } else {
        warn_report("Unknown L1 dcache size for cpu");
    }
    if (pcc->l1_icache_size) {
        _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
                               pcc->l1_icache_size)));
    } else {
        warn_report("Unknown L1 icache size for cpu");
    }

    _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
    _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
    _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
    _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
    _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));

    if (env->spr_cb[SPR_PURR].oea_read) {
        _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
    }

    if (env->mmu_model & POWERPC_MMU_1TSEG) {
        _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
                           segs, sizeof(segs))));
    }

    /* Advertise VMX/VSX (vector extensions) if available
     *   0 / no property == no vector extensions
     *   1               == VMX / Altivec available
     *   2               == VSX available */
    if (env->insns_flags & PPC_ALTIVEC) {
        uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;

        _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
    }

    /* Advertise DFP (Decimal Floating Point) if available
     *   0 / no property == no DFP
     *   1               == DFP available */
    if (env->insns_flags2 & PPC2_DFP) {
        _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
    }

    page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
                                                  sizeof(page_sizes_prop));
    if (page_sizes_prop_size) {
        _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
                           page_sizes_prop, page_sizes_prop_size)));
    }

    _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
                       pa_features, sizeof(pa_features))));

    /* Build interrupt servers properties */
    for (i = 0; i < smt_threads; i++) {
        servers_prop[i] = cpu_to_be32(pc->pir + i);
    }
    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
                       servers_prop, sizeof(servers_prop))));
}