Commit d76bb735 authored by Aurelien Jarno's avatar Aurelien Jarno
Browse files

Merge branch 'ppc-for-upstream' of git://github.com/agraf/qemu

* 'ppc-for-upstream' of git://github.com/agraf/qemu: (58 commits)
  target-ppc: Use NARROW_MODE macro for tlbie
  target-ppc: Use NARROW_MODE macro for addresses
  target-ppc: Use NARROW_MODE macro for comparisons
  target-ppc: Use NARROW_MODE macro for branches
  target-ppc: Fix add and subf carry generation in narrow mode
  target-ppc: Use QOM method dispatch for MMU fault handling
  target-ppc: Move ppc tlb_fill implementation into mmu_helper.c
  target-ppc: Split user only code out of mmu_helper.c
  mmu-hash64: Implement Virtual Page Class Key Protection
  mmu-hash*: Merge translate and fault handling functions
  mmu-hash*: Don't use full ppc_hash{32, 64}_translate() path for get_phys_page_debug()
  mmu-hash*: Correctly mask RPN from hash PTE
  mmu-hash*: Clean up real address calculation
  mmu-hash*: Clean up PTE flags update
  mmu-hash64: Factor SLB N bit into permissions bits
  mmu-hash*: Clean up permission checking
  mmu-hash32: Remove nx from context structure
  mmu-hash*: Don't update PTE flags when permission is denied
  mmu-hash32: Don't look up page tables on BAT permission error
  mmu-hash32: Cleanup BAT lookup
  ...
parents 52ae646d 9ca3f7f3
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -781,7 +781,8 @@ static int cpu_gdb_write_register(CPUPPCState *env, uint8_t *mem_buf, int n)
            /* fpscr */
            if (gdb_has_xml)
                return 0;
            return 4;
            store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
            return sizeof(target_ulong);
        }
    }
    return 0;
+9 −7
Original line number Diff line number Diff line
@@ -629,7 +629,7 @@ static void ppc_spapr_reset(void)
                       spapr->rtas_size);

    /* Set up the entry state */
    first_cpu_cpu = CPU(first_cpu);
    first_cpu_cpu = ENV_GET_CPU(first_cpu);
    first_cpu->gpr[3] = spapr->fdt_addr;
    first_cpu->gpr[5] = 0;
    first_cpu_cpu->halted = 0;
@@ -779,6 +779,11 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
        spapr->htab_shift++;
    }

    /* Set up Interrupt Controller before we create the VCPUs */
    spapr->icp = xics_system_init(smp_cpus * kvmppc_smt_threads() / smp_threads,
                                  XICS_IRQS);
    spapr->next_irq = XICS_IRQ_BASE;

    /* init CPUs */
    if (cpu_model == NULL) {
        cpu_model = kvm_enabled() ? "host" : "POWER7";
@@ -791,6 +796,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
        }
        env = &cpu->env;

        xics_cpu_setup(spapr->icp, cpu);

        /* Set time-base frequency to 512 MHz */
        cpu_ppc_tb_init(env, TIMEBASE_FREQ);

@@ -830,11 +837,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
    }
    g_free(filename);


    /* Set up Interrupt Controller */
    spapr->icp = xics_system_init(XICS_IRQS);
    spapr->next_irq = XICS_IRQ_BASE;

    /* Set up EPOW events infrastructure */
    spapr_events_init(spapr);

@@ -856,7 +858,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
    /* Set up PCI */
    spapr_pci_rtas_init();

    phb = spapr_create_phb(spapr, 0, "pci");
    phb = spapr_create_phb(spapr, 0);

    for (i = 0; i < nb_nics; i++) {
        NICInfo *nd = &nd_table[i];
+35 −67
Original line number Diff line number Diff line
@@ -3,39 +3,7 @@
#include "sysemu/sysemu.h"
#include "helper_regs.h"
#include "hw/spapr.h"

#define HPTES_PER_GROUP 8

#define HPTE_V_SSIZE_SHIFT      62
#define HPTE_V_AVPN_SHIFT       7
#define HPTE_V_AVPN             0x3fffffffffffff80ULL
#define HPTE_V_AVPN_VAL(x)      (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
#define HPTE_V_COMPARE(x, y)    (!(((x) ^ (y)) & 0xffffffffffffff80UL))
#define HPTE_V_BOLTED           0x0000000000000010ULL
#define HPTE_V_LOCK             0x0000000000000008ULL
#define HPTE_V_LARGE            0x0000000000000004ULL
#define HPTE_V_SECONDARY        0x0000000000000002ULL
#define HPTE_V_VALID            0x0000000000000001ULL

#define HPTE_R_PP0              0x8000000000000000ULL
#define HPTE_R_TS               0x4000000000000000ULL
#define HPTE_R_KEY_HI           0x3000000000000000ULL
#define HPTE_R_RPN_SHIFT        12
#define HPTE_R_RPN              0x3ffffffffffff000ULL
#define HPTE_R_FLAGS            0x00000000000003ffULL
#define HPTE_R_PP               0x0000000000000003ULL
#define HPTE_R_N                0x0000000000000004ULL
#define HPTE_R_G                0x0000000000000008ULL
#define HPTE_R_M                0x0000000000000010ULL
#define HPTE_R_I                0x0000000000000020ULL
#define HPTE_R_W                0x0000000000000040ULL
#define HPTE_R_WIMG             0x0000000000000078ULL
#define HPTE_R_C                0x0000000000000080ULL
#define HPTE_R_R                0x0000000000000100ULL
#define HPTE_R_KEY_LO           0x0000000000000e00ULL

#define HPTE_V_1TB_SEG          0x4000000000000000ULL
#define HPTE_V_VRMA_MASK        0x4001ffffff000000ULL
#include "mmu-hash64.h"

static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
                                     target_ulong pte_index)
@@ -44,17 +12,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,

    rb = (v & ~0x7fULL) << 16; /* AVA field */
    va_low = pte_index >> 3;
    if (v & HPTE_V_SECONDARY) {
    if (v & HPTE64_V_SECONDARY) {
        va_low = ~va_low;
    }
    /* xor vsid from AVA */
    if (!(v & HPTE_V_1TB_SEG)) {
    if (!(v & HPTE64_V_1TB_SEG)) {
        va_low ^= v >> 12;
    } else {
        va_low ^= v >> 24;
    }
    va_low &= 0x7ff;
    if (v & HPTE_V_LARGE) {
    if (v & HPTE64_V_LARGE) {
        rb |= 1;                         /* L field */
#if 0 /* Disable that P7 specific bit for now */
        if (r & 0xff000) {
@@ -84,10 +52,10 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
    target_ulong page_shift = 12;
    target_ulong raddr;
    target_ulong i;
    uint8_t *hpte;
    hwaddr hpte;

    /* only handle 4k and 16M pages for now */
    if (pteh & HPTE_V_LARGE) {
    if (pteh & HPTE64_V_LARGE) {
#if 0 /* We don't support 64k pages yet */
        if ((ptel & 0xf000) == 0x1000) {
            /* 64k page */
@@ -105,11 +73,11 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
        }
    }

    raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1);
    raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << page_shift) - 1);

    if (raddr < spapr->ram_limit) {
        /* Regular RAM - should have WIMG=0010 */
        if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
        if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
            return H_PARAMETER;
        }
    } else {
@@ -117,7 +85,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
        /* FIXME: What WIMG combinations could be sensible for IO?
         * For now we allow WIMG=010x, but are there others? */
        /* FIXME: Should we check against registered IO addresses? */
        if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) {
        if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) {
            return H_PARAMETER;
        }
    }
@@ -129,26 +97,26 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
    }
    if (likely((flags & H_EXACT) == 0)) {
        pte_index &= ~7ULL;
        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
        hpte = pte_index * HASH_PTE_SIZE_64;
        for (i = 0; ; ++i) {
            if (i == 8) {
                return H_PTEG_FULL;
            }
            if ((ldq_p(hpte) & HPTE_V_VALID) == 0) {
            if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
                break;
            }
            hpte += HASH_PTE_SIZE_64;
        }
    } else {
        i = 0;
        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
        if (ldq_p(hpte) & HPTE_V_VALID) {
        hpte = pte_index * HASH_PTE_SIZE_64;
        if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
            return H_PTEG_FULL;
        }
    }
    stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
    ppc_hash64_store_hpte1(env, hpte, ptel);
    /* eieio();  FIXME: need some sort of barrier for smp? */
    stq_p(hpte, pteh);
    ppc_hash64_store_hpte0(env, hpte, pteh);

    args[0] = pte_index + i;
    return H_SUCCESS;
@@ -166,26 +134,26 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
                                target_ulong flags,
                                target_ulong *vp, target_ulong *rp)
{
    uint8_t *hpte;
    hwaddr hpte;
    target_ulong v, r, rb;

    if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
        return REMOVE_PARM;
    }

    hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
    hpte = ptex * HASH_PTE_SIZE_64;

    v = ldq_p(hpte);
    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
    v = ppc_hash64_load_hpte0(env, hpte);
    r = ppc_hash64_load_hpte1(env, hpte);

    if ((v & HPTE_V_VALID) == 0 ||
    if ((v & HPTE64_V_VALID) == 0 ||
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
        return REMOVE_NOT_FOUND;
    }
    *vp = v;
    *rp = r;
    stq_p(hpte, 0);
    ppc_hash64_store_hpte0(env, hpte, 0);
    rb = compute_tlbie_rb(v, r, ptex);
    ppc_tlb_invalidate_one(env, rb);
    return REMOVE_SUCCESS;
@@ -271,7 +239,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,

        switch (ret) {
        case REMOVE_SUCCESS:
            *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43;
            *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
            break;

        case REMOVE_PARM:
@@ -292,34 +260,34 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
    target_ulong flags = args[0];
    target_ulong pte_index = args[1];
    target_ulong avpn = args[2];
    uint8_t *hpte;
    hwaddr hpte;
    target_ulong v, r, rb;

    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
        return H_PARAMETER;
    }

    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
    hpte = pte_index * HASH_PTE_SIZE_64;

    v = ldq_p(hpte);
    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
    v = ppc_hash64_load_hpte0(env, hpte);
    r = ppc_hash64_load_hpte1(env, hpte);

    if ((v & HPTE_V_VALID) == 0 ||
    if ((v & HPTE64_V_VALID) == 0 ||
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
        return H_NOT_FOUND;
    }

    r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
           HPTE_R_KEY_HI | HPTE_R_KEY_LO);
    r |= (flags << 55) & HPTE_R_PP0;
    r |= (flags << 48) & HPTE_R_KEY_HI;
    r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
    r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
           HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
    r |= (flags << 55) & HPTE64_R_PP0;
    r |= (flags << 48) & HPTE64_R_KEY_HI;
    r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
    rb = compute_tlbie_rb(v, r, pte_index);
    stq_p(hpte, v & ~HPTE_V_VALID);
    ppc_hash64_store_hpte0(env, hpte, v & ~HPTE64_V_VALID);
    ppc_tlb_invalidate_one(env, rb);
    stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
    ppc_hash64_store_hpte1(env, hpte, r);
    /* Don't need a memory barrier, due to qemu's global lock */
    stq_p(hpte, v);
    ppc_hash64_store_hpte0(env, hpte, v);
    return H_SUCCESS;
}

+25 −32
Original line number Diff line number Diff line
@@ -521,29 +521,13 @@ static void xics_reset(void *opaque)
    }
}

struct icp_state *xics_system_init(int nr_irqs)
void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu)
{
    CPUPPCState *env;
    CPUState *cpu;
    int max_server_num;
    struct icp_state *icp;
    struct ics_state *ics;

    max_server_num = -1;
    for (env = first_cpu; env != NULL; env = env->next_cpu) {
        cpu = CPU(ppc_env_get_cpu(env));
        if (cpu->cpu_index > max_server_num) {
            max_server_num = cpu->cpu_index;
        }
    }

    icp = g_malloc0(sizeof(*icp));
    icp->nr_servers = max_server_num + 1;
    icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state));
    CPUState *cs = CPU(cpu);
    CPUPPCState *env = &cpu->env;
    struct icp_server_state *ss = &icp->ss[cs->cpu_index];

    for (env = first_cpu; env != NULL; env = env->next_cpu) {
        cpu = CPU(ppc_env_get_cpu(env));
        struct icp_server_state *ss = &icp->ss[cpu->cpu_index];
    assert(cs->cpu_index < icp->nr_servers);

    switch (PPC_INPUT(env)) {
    case PPC_FLAGS_INPUT_POWER7:
@@ -555,12 +539,21 @@ struct icp_state *xics_system_init(int nr_irqs)
        break;

    default:
            hw_error("XICS interrupt model does not support this CPU bus "
                     "model\n");
            exit(1);
        fprintf(stderr, "XICS interrupt controller does not support this CPU "
                "bus model\n");
        abort();
    }
}

struct icp_state *xics_system_init(int nr_servers, int nr_irqs)
{
    struct icp_state *icp;
    struct ics_state *ics;

    icp = g_malloc0(sizeof(*icp));
    icp->nr_servers = nr_servers;
    icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state));

    ics = g_malloc0(sizeof(*ics));
    ics->nr_irqs = nr_irqs;
    ics->offset = XICS_IRQ_BASE;
+22 −8
Original line number Diff line number Diff line
@@ -518,6 +518,7 @@ static int spapr_phb_init(SysBusDevice *s)
{
    sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
    PCIHostState *phb = PCI_HOST_BRIDGE(s);
    const char *busname;
    char *namebuf;
    int i;
    PCIBus *bus;
@@ -575,9 +576,6 @@ static int spapr_phb_init(SysBusDevice *s)
    }

    sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
    if (!sphb->busname) {
        sphb->busname = sphb->dtbusname;
    }

    namebuf = alloca(strlen(sphb->dtbusname) + 32);

@@ -621,7 +619,26 @@ static int spapr_phb_init(SysBusDevice *s)
                                    &sphb->msiwindow);
    }

    bus = pci_register_bus(DEVICE(s), sphb->busname,
    /*
     * Selecting a busname is more complex than you'd think, due to
     * interacting constraints.  If the user has specified an id
     * explicitly for the phb , then we want to use the qdev default
     * of naming the bus based on the bridge device (so the user can
     * then assign devices to it in the way they expect).  For the
     * first / default PCI bus (index=0) we want to use just "pci"
     * because libvirt expects there to be a bus called, simply,
     * "pci".  Otherwise, we use the same name as in the device tree,
     * since it's unique by construction, and makes the guest visible
     * BUID clear.
     */
    if (s->qdev.id) {
        busname = NULL;
    } else if (sphb->index == 0) {
        busname = "pci";
    } else {
        busname = sphb->dtbusname;
    }
    bus = pci_register_bus(DEVICE(s), busname,
                           pci_spapr_set_irq, pci_spapr_map_irq, sphb,
                           &sphb->memspace, &sphb->iospace,
                           PCI_DEVFN(0, 0), PCI_NUM_PINS);
@@ -663,7 +680,6 @@ static void spapr_phb_reset(DeviceState *qdev)
}

static Property spapr_phb_properties[] = {
    DEFINE_PROP_STRING("busname", sPAPRPHBState, busname),
    DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1),
    DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, -1),
    DEFINE_PROP_HEX32("liobn", sPAPRPHBState, dma_liobn, -1),
@@ -694,14 +710,12 @@ static const TypeInfo spapr_phb_info = {
    .class_init    = spapr_phb_class_init,
};

PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index,
                               const char *busname)
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
{
    DeviceState *dev;

    dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
    qdev_prop_set_uint32(dev, "index", index);
    qdev_prop_set_string(dev, "busname", busname);
    qdev_init_nofail(dev);

    return PCI_HOST_BRIDGE(dev);
Loading