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
  ...
			
			
This commit is contained in:
		@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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];
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -521,46 +521,39 @@ 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)
 | 
			
		||||
{
 | 
			
		||||
    CPUState *cs = CPU(cpu);
 | 
			
		||||
    CPUPPCState *env = &cpu->env;
 | 
			
		||||
    struct icp_server_state *ss = &icp->ss[cs->cpu_index];
 | 
			
		||||
 | 
			
		||||
    assert(cs->cpu_index < icp->nr_servers);
 | 
			
		||||
 | 
			
		||||
    switch (PPC_INPUT(env)) {
 | 
			
		||||
    case PPC_FLAGS_INPUT_POWER7:
 | 
			
		||||
        ss->output = env->irq_inputs[POWER7_INPUT_INT];
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case PPC_FLAGS_INPUT_970:
 | 
			
		||||
        ss->output = env->irq_inputs[PPC970_INPUT_INT];
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        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)
 | 
			
		||||
{
 | 
			
		||||
    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->nr_servers = nr_servers;
 | 
			
		||||
    icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state));
 | 
			
		||||
 | 
			
		||||
    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];
 | 
			
		||||
 | 
			
		||||
        switch (PPC_INPUT(env)) {
 | 
			
		||||
        case PPC_FLAGS_INPUT_POWER7:
 | 
			
		||||
            ss->output = env->irq_inputs[POWER7_INPUT_INT];
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case PPC_FLAGS_INPUT_970:
 | 
			
		||||
            ss->output = env->irq_inputs[PPC970_INPUT_INT];
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            hw_error("XICS interrupt model does not support this CPU bus "
 | 
			
		||||
                     "model\n");
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ics = g_malloc0(sizeof(*ics));
 | 
			
		||||
    ics->nr_irqs = nr_irqs;
 | 
			
		||||
    ics->offset = XICS_IRQ_BASE;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,6 @@ typedef struct sPAPRPHBState {
 | 
			
		||||
 | 
			
		||||
    int32_t index;
 | 
			
		||||
    uint64_t buid;
 | 
			
		||||
    char *busname;
 | 
			
		||||
    char *dtbusname;
 | 
			
		||||
 | 
			
		||||
    MemoryRegion memspace, iospace;
 | 
			
		||||
@@ -82,8 +81,7 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
 | 
			
		||||
    return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index,
 | 
			
		||||
                               const char *busname);
 | 
			
		||||
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index);
 | 
			
		||||
 | 
			
		||||
int spapr_populate_pci_dt(sPAPRPHBState *phb,
 | 
			
		||||
                          uint32_t xics_phandle,
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@ struct icp_state;
 | 
			
		||||
qemu_irq xics_get_qirq(struct icp_state *icp, int irq);
 | 
			
		||||
void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi);
 | 
			
		||||
 | 
			
		||||
struct icp_state *xics_system_init(int nr_irqs);
 | 
			
		||||
struct icp_state *xics_system_init(int nr_servers, int nr_irqs);
 | 
			
		||||
void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu);
 | 
			
		||||
 | 
			
		||||
#endif /* __XICS_H__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -2960,10 +2960,6 @@ static const MonitorDef monitor_defs[] = {
 | 
			
		||||
    { "xer", 0, &monitor_get_xer, },
 | 
			
		||||
    { "tbu", 0, &monitor_get_tbu, },
 | 
			
		||||
    { "tbl", 0, &monitor_get_tbl, },
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    /* Address space register */
 | 
			
		||||
    { "asr", offsetof(CPUPPCState, asr) },
 | 
			
		||||
#endif
 | 
			
		||||
    /* Segment registers */
 | 
			
		||||
    { "sdr1", offsetof(CPUPPCState, spr[SPR_SDR1]) },
 | 
			
		||||
    { "sr0", offsetof(CPUPPCState, sr[0]) },
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,14 @@
 | 
			
		||||
obj-y += cpu-models.o
 | 
			
		||||
obj-y += translate.o
 | 
			
		||||
obj-$(CONFIG_SOFTMMU) += machine.o
 | 
			
		||||
ifeq ($(CONFIG_SOFTMMU),y)
 | 
			
		||||
obj-y += machine.o mmu_helper.o mmu-hash32.o
 | 
			
		||||
obj-$(TARGET_PPC64) += mmu-hash64.o
 | 
			
		||||
endif
 | 
			
		||||
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
 | 
			
		||||
obj-y += excp_helper.o
 | 
			
		||||
obj-y += fpu_helper.o
 | 
			
		||||
obj-y += int_helper.o
 | 
			
		||||
obj-y += mmu_helper.o
 | 
			
		||||
obj-y += timebase_helper.o
 | 
			
		||||
obj-y += misc_helper.o
 | 
			
		||||
obj-y += mem_helper.o
 | 
			
		||||
obj-$(CONFIG_USER_ONLY) += user_only_helper.o
 | 
			
		||||
 
 | 
			
		||||
@@ -1101,9 +1101,9 @@
 | 
			
		||||
                "PowerPC 7457A v1.2 (G4)")
 | 
			
		||||
    /* 64 bits PowerPC                                                       */
 | 
			
		||||
#if defined (TARGET_PPC64)
 | 
			
		||||
#if defined(TODO)
 | 
			
		||||
    POWERPC_DEF("620",           CPU_POWERPC_620,                    620,
 | 
			
		||||
                "PowerPC 620")
 | 
			
		||||
#if defined(TODO)
 | 
			
		||||
    POWERPC_DEF("630",           CPU_POWERPC_630,                    630,
 | 
			
		||||
                "PowerPC 630 (POWER3)")
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -68,6 +68,10 @@ typedef struct PowerPCCPUClass {
 | 
			
		||||
#endif
 | 
			
		||||
    void (*init_proc)(CPUPPCState *env);
 | 
			
		||||
    int  (*check_pow)(CPUPPCState *env);
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    int (*handle_mmu_fault)(CPUPPCState *env, target_ulong eaddr, int rwx,
 | 
			
		||||
                            int mmu_idx);
 | 
			
		||||
#endif
 | 
			
		||||
} PowerPCCPUClass;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -113,13 +113,13 @@ enum powerpc_mmu_t {
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
#define POWERPC_MMU_64       0x00010000
 | 
			
		||||
#define POWERPC_MMU_1TSEG    0x00020000
 | 
			
		||||
#define POWERPC_MMU_AMR      0x00040000
 | 
			
		||||
    /* 64 bits PowerPC MMU                                     */
 | 
			
		||||
    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,
 | 
			
		||||
    /* Architecture 2.06 "degraded" (no 1T segments)           */
 | 
			
		||||
    POWERPC_MMU_2_06       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
 | 
			
		||||
                             | POWERPC_MMU_AMR | 0x00000003,
 | 
			
		||||
    /* Architecture 2.06 "degraded" (no 1T segments or AMR)    */
 | 
			
		||||
    POWERPC_MMU_2_06d      = POWERPC_MMU_64 | 0x00000003,
 | 
			
		||||
#endif /* defined(TARGET_PPC64) */
 | 
			
		||||
};
 | 
			
		||||
@@ -396,36 +396,12 @@ union ppc_tlb_t {
 | 
			
		||||
#define SDR_64_HTABSIZE        0x000000000000001FULL
 | 
			
		||||
#endif /* defined(TARGET_PPC64 */
 | 
			
		||||
 | 
			
		||||
#define HASH_PTE_SIZE_32       8
 | 
			
		||||
#define HASH_PTE_SIZE_64       16
 | 
			
		||||
 | 
			
		||||
typedef struct ppc_slb_t ppc_slb_t;
 | 
			
		||||
struct ppc_slb_t {
 | 
			
		||||
    uint64_t esid;
 | 
			
		||||
    uint64_t vsid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Bits in the SLB ESID word */
 | 
			
		||||
#define SLB_ESID_ESID           0xFFFFFFFFF0000000ULL
 | 
			
		||||
#define SLB_ESID_V              0x0000000008000000ULL /* valid */
 | 
			
		||||
 | 
			
		||||
/* Bits in the SLB VSID word */
 | 
			
		||||
#define SLB_VSID_SHIFT          12
 | 
			
		||||
#define SLB_VSID_SHIFT_1T       24
 | 
			
		||||
#define SLB_VSID_SSIZE_SHIFT    62
 | 
			
		||||
#define SLB_VSID_B              0xc000000000000000ULL
 | 
			
		||||
#define SLB_VSID_B_256M         0x0000000000000000ULL
 | 
			
		||||
#define SLB_VSID_B_1T           0x4000000000000000ULL
 | 
			
		||||
#define SLB_VSID_VSID           0x3FFFFFFFFFFFF000ULL
 | 
			
		||||
#define SLB_VSID_PTEM           (SLB_VSID_B | SLB_VSID_VSID)
 | 
			
		||||
#define SLB_VSID_KS             0x0000000000000800ULL
 | 
			
		||||
#define SLB_VSID_KP             0x0000000000000400ULL
 | 
			
		||||
#define SLB_VSID_N              0x0000000000000200ULL /* no-execute */
 | 
			
		||||
#define SLB_VSID_L              0x0000000000000100ULL
 | 
			
		||||
#define SLB_VSID_C              0x0000000000000080ULL /* class */
 | 
			
		||||
#define SLB_VSID_LP             0x0000000000000030ULL
 | 
			
		||||
#define SLB_VSID_ATTR           0x0000000000000FFFULL
 | 
			
		||||
 | 
			
		||||
#define SEGMENT_SHIFT_256M      28
 | 
			
		||||
#define SEGMENT_MASK_256M       (~((1ULL << SEGMENT_SHIFT_256M) - 1))
 | 
			
		||||
 | 
			
		||||
@@ -965,8 +941,6 @@ struct CPUPPCState {
 | 
			
		||||
    /* MMU context - only relevant for full system emulation */
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    /* Address space register */
 | 
			
		||||
    target_ulong asr;
 | 
			
		||||
    /* PowerPC 64 SLB area */
 | 
			
		||||
    ppc_slb_t slb[64];
 | 
			
		||||
    int slb_nr;
 | 
			
		||||
@@ -1105,20 +1079,6 @@ do {                                            \
 | 
			
		||||
    env->wdt_period[3] = (d_);                  \
 | 
			
		||||
 } while (0)
 | 
			
		||||
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
/* Context used internally during MMU translations */
 | 
			
		||||
typedef struct mmu_ctx_t mmu_ctx_t;
 | 
			
		||||
struct mmu_ctx_t {
 | 
			
		||||
    hwaddr raddr;      /* Real address              */
 | 
			
		||||
    hwaddr eaddr;      /* Effective address         */
 | 
			
		||||
    int prot;                      /* Protection bits           */
 | 
			
		||||
    hwaddr hash[2];    /* Pagetable hash values     */
 | 
			
		||||
    target_ulong ptem;             /* Virtual segment ID | API  */
 | 
			
		||||
    int key;                       /* Access key                */
 | 
			
		||||
    int nx;                        /* Non-execute area          */
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "cpu-qom.h"
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************/
 | 
			
		||||
@@ -1130,17 +1090,14 @@ int cpu_ppc_exec (CPUPPCState *s);
 | 
			
		||||
   is returned if the signal was handled by the virtual CPU.  */
 | 
			
		||||
int cpu_ppc_signal_handler (int host_signum, void *pinfo,
 | 
			
		||||
                            void *puc);
 | 
			
		||||
int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
 | 
			
		||||
                              int mmu_idx);
 | 
			
		||||
#define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault
 | 
			
		||||
void ppc_hw_interrupt (CPUPPCState *env);
 | 
			
		||||
#if defined(CONFIG_USER_ONLY)
 | 
			
		||||
int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
 | 
			
		||||
                         int mmu_idx);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
void ppc_store_asr (CPUPPCState *env, target_ulong value);
 | 
			
		||||
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
 | 
			
		||||
#endif /* defined(TARGET_PPC64) */
 | 
			
		||||
#endif /* !defined(CONFIG_USER_ONLY) */
 | 
			
		||||
void ppc_store_msr (CPUPPCState *env, target_ulong value);
 | 
			
		||||
 | 
			
		||||
@@ -1172,14 +1129,13 @@ void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
 | 
			
		||||
void store_40x_sler (CPUPPCState *env, uint32_t val);
 | 
			
		||||
void store_booke_tcr (CPUPPCState *env, target_ulong val);
 | 
			
		||||
void store_booke_tsr (CPUPPCState *env, target_ulong val);
 | 
			
		||||
int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
 | 
			
		||||
                     hwaddr *raddrp, target_ulong address,
 | 
			
		||||
                     uint32_t pid);
 | 
			
		||||
void ppc_tlb_invalidate_all (CPUPPCState *env);
 | 
			
		||||
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask);
 | 
			
		||||
 | 
			
		||||
static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t gprv;
 | 
			
		||||
@@ -1270,6 +1226,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
 | 
			
		||||
#define SPR_601_UDECR         (0x006)
 | 
			
		||||
#define SPR_LR                (0x008)
 | 
			
		||||
#define SPR_CTR               (0x009)
 | 
			
		||||
#define SPR_UAMR              (0x00C)
 | 
			
		||||
#define SPR_DSCR              (0x011)
 | 
			
		||||
#define SPR_DSISR             (0x012)
 | 
			
		||||
#define SPR_DAR               (0x013) /* DAE for PowerPC 601 */
 | 
			
		||||
@@ -1307,6 +1264,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
 | 
			
		||||
#define SPR_MPC_CMPH          (0x09B)
 | 
			
		||||
#define SPR_MPC_LCTRL1        (0x09C)
 | 
			
		||||
#define SPR_MPC_LCTRL2        (0x09D)
 | 
			
		||||
#define SPR_UAMOR             (0x09D)
 | 
			
		||||
#define SPR_MPC_ICTRL         (0x09E)
 | 
			
		||||
#define SPR_MPC_BAR           (0x09F)
 | 
			
		||||
#define SPR_VRSAVE            (0x100)
 | 
			
		||||
@@ -1489,11 +1447,9 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
 | 
			
		||||
#define SPR_RCPU_MI_RBA2      (0x302)
 | 
			
		||||
#define SPR_MPC_MI_AP         (0x302)
 | 
			
		||||
#define SPR_PERF3             (0x303)
 | 
			
		||||
#define SPR_620_PMC1R         (0x303)
 | 
			
		||||
#define SPR_RCPU_MI_RBA3      (0x303)
 | 
			
		||||
#define SPR_MPC_MI_EPN        (0x303)
 | 
			
		||||
#define SPR_PERF4             (0x304)
 | 
			
		||||
#define SPR_620_PMC2R         (0x304)
 | 
			
		||||
#define SPR_PERF5             (0x305)
 | 
			
		||||
#define SPR_MPC_MI_TWC        (0x305)
 | 
			
		||||
#define SPR_PERF6             (0x306)
 | 
			
		||||
@@ -1509,7 +1465,6 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
 | 
			
		||||
#define SPR_RCPU_L2U_RBA2     (0x30A)
 | 
			
		||||
#define SPR_MPC_MD_AP         (0x30A)
 | 
			
		||||
#define SPR_PERFB             (0x30B)
 | 
			
		||||
#define SPR_620_MMCR0R        (0x30B)
 | 
			
		||||
#define SPR_RCPU_L2U_RBA3     (0x30B)
 | 
			
		||||
#define SPR_MPC_MD_EPN        (0x30B)
 | 
			
		||||
#define SPR_PERFC             (0x30C)
 | 
			
		||||
@@ -1524,9 +1479,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
 | 
			
		||||
#define SPR_UPERF1            (0x311)
 | 
			
		||||
#define SPR_UPERF2            (0x312)
 | 
			
		||||
#define SPR_UPERF3            (0x313)
 | 
			
		||||
#define SPR_620_PMC1W         (0x313)
 | 
			
		||||
#define SPR_UPERF4            (0x314)
 | 
			
		||||
#define SPR_620_PMC2W         (0x314)
 | 
			
		||||
#define SPR_UPERF5            (0x315)
 | 
			
		||||
#define SPR_UPERF6            (0x316)
 | 
			
		||||
#define SPR_UPERF7            (0x317)
 | 
			
		||||
@@ -1534,7 +1487,6 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
 | 
			
		||||
#define SPR_UPERF9            (0x319)
 | 
			
		||||
#define SPR_UPERFA            (0x31A)
 | 
			
		||||
#define SPR_UPERFB            (0x31B)
 | 
			
		||||
#define SPR_620_MMCR0W        (0x31B)
 | 
			
		||||
#define SPR_UPERFC            (0x31C)
 | 
			
		||||
#define SPR_UPERFD            (0x31D)
 | 
			
		||||
#define SPR_UPERFE            (0x31E)
 | 
			
		||||
@@ -1606,49 +1558,33 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
 | 
			
		||||
#define SPR_USDA              (0x3AF)
 | 
			
		||||
#define SPR_40x_ZPR           (0x3B0)
 | 
			
		||||
#define SPR_BOOKE_MAS7        (0x3B0)
 | 
			
		||||
#define SPR_620_PMR0          (0x3B0)
 | 
			
		||||
#define SPR_MMCR2             (0x3B0)
 | 
			
		||||
#define SPR_PMC5              (0x3B1)
 | 
			
		||||
#define SPR_40x_PID           (0x3B1)
 | 
			
		||||
#define SPR_620_PMR1          (0x3B1)
 | 
			
		||||
#define SPR_PMC6              (0x3B2)
 | 
			
		||||
#define SPR_440_MMUCR         (0x3B2)
 | 
			
		||||
#define SPR_620_PMR2          (0x3B2)
 | 
			
		||||
#define SPR_4xx_CCR0          (0x3B3)
 | 
			
		||||
#define SPR_BOOKE_EPLC        (0x3B3)
 | 
			
		||||
#define SPR_620_PMR3          (0x3B3)
 | 
			
		||||
#define SPR_405_IAC3          (0x3B4)
 | 
			
		||||
#define SPR_BOOKE_EPSC        (0x3B4)
 | 
			
		||||
#define SPR_620_PMR4          (0x3B4)
 | 
			
		||||
#define SPR_405_IAC4          (0x3B5)
 | 
			
		||||
#define SPR_620_PMR5          (0x3B5)
 | 
			
		||||
#define SPR_405_DVC1          (0x3B6)
 | 
			
		||||
#define SPR_620_PMR6          (0x3B6)
 | 
			
		||||
#define SPR_405_DVC2          (0x3B7)
 | 
			
		||||
#define SPR_620_PMR7          (0x3B7)
 | 
			
		||||
#define SPR_BAMR              (0x3B7)
 | 
			
		||||
#define SPR_MMCR0             (0x3B8)
 | 
			
		||||
#define SPR_620_PMR8          (0x3B8)
 | 
			
		||||
#define SPR_PMC1              (0x3B9)
 | 
			
		||||
#define SPR_40x_SGR           (0x3B9)
 | 
			
		||||
#define SPR_620_PMR9          (0x3B9)
 | 
			
		||||
#define SPR_PMC2              (0x3BA)
 | 
			
		||||
#define SPR_40x_DCWR          (0x3BA)
 | 
			
		||||
#define SPR_620_PMRA          (0x3BA)
 | 
			
		||||
#define SPR_SIAR              (0x3BB)
 | 
			
		||||
#define SPR_405_SLER          (0x3BB)
 | 
			
		||||
#define SPR_620_PMRB          (0x3BB)
 | 
			
		||||
#define SPR_MMCR1             (0x3BC)
 | 
			
		||||
#define SPR_405_SU0R          (0x3BC)
 | 
			
		||||
#define SPR_620_PMRC          (0x3BC)
 | 
			
		||||
#define SPR_401_SKR           (0x3BC)
 | 
			
		||||
#define SPR_PMC3              (0x3BD)
 | 
			
		||||
#define SPR_405_DBCR1         (0x3BD)
 | 
			
		||||
#define SPR_620_PMRD          (0x3BD)
 | 
			
		||||
#define SPR_PMC4              (0x3BE)
 | 
			
		||||
#define SPR_620_PMRE          (0x3BE)
 | 
			
		||||
#define SPR_SDA               (0x3BF)
 | 
			
		||||
#define SPR_620_PMRF          (0x3BF)
 | 
			
		||||
#define SPR_403_VTBL          (0x3CC)
 | 
			
		||||
#define SPR_403_VTBU          (0x3CD)
 | 
			
		||||
#define SPR_DMISS             (0x3D0)
 | 
			
		||||
@@ -1716,15 +1652,12 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
 | 
			
		||||
#define SPR_LDSTCR            (0x3F8)
 | 
			
		||||
#define SPR_L2PMCR            (0x3F8)
 | 
			
		||||
#define SPR_750FX_HID2        (0x3F8)
 | 
			
		||||
#define SPR_620_BUSCSR        (0x3F8)
 | 
			
		||||
#define SPR_Exxx_L1FINV0      (0x3F8)
 | 
			
		||||
#define SPR_L2CR              (0x3F9)
 | 
			
		||||
#define SPR_620_L2CR          (0x3F9)
 | 
			
		||||
#define SPR_L3CR              (0x3FA)
 | 
			
		||||
#define SPR_750_TDCH          (0x3FA)
 | 
			
		||||
#define SPR_IABR2             (0x3FA)
 | 
			
		||||
#define SPR_40x_DCCR          (0x3FA)
 | 
			
		||||
#define SPR_620_L2SR          (0x3FA)
 | 
			
		||||
#define SPR_ICTC              (0x3FB)
 | 
			
		||||
#define SPR_40x_ICCR          (0x3FB)
 | 
			
		||||
#define SPR_THRM1             (0x3FC)
 | 
			
		||||
 
 | 
			
		||||
@@ -463,6 +463,11 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
 | 
			
		||||
    fpscr_set_rounding_mode(env);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
 | 
			
		||||
{
 | 
			
		||||
    helper_store_fpscr(env, arg, mask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void helper_float_check_status(CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
 | 
			
		||||
 
 | 
			
		||||
@@ -382,7 +382,6 @@ DEF_HELPER_1(load_601_rtcl, tl, env)
 | 
			
		||||
DEF_HELPER_1(load_601_rtcu, tl, env)
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
DEF_HELPER_2(store_asr, void, env, tl)
 | 
			
		||||
DEF_HELPER_1(load_purr, tl, env)
 | 
			
		||||
#endif
 | 
			
		||||
DEF_HELPER_2(store_sdr1, void, env, tl)
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@
 | 
			
		||||
#include "sysemu/device_tree.h"
 | 
			
		||||
#include "hw/sysbus.h"
 | 
			
		||||
#include "hw/spapr.h"
 | 
			
		||||
#include "mmu-hash64.h"
 | 
			
		||||
 | 
			
		||||
#include "hw/sysbus.h"
 | 
			
		||||
#include "hw/spapr.h"
 | 
			
		||||
@@ -1077,7 +1078,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 | 
			
		||||
        dprintf("handle halt\n");
 | 
			
		||||
        ret = kvmppc_handle_halt(cpu);
 | 
			
		||||
        break;
 | 
			
		||||
#ifdef CONFIG_PSERIES
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    case KVM_EXIT_PAPR_HCALL:
 | 
			
		||||
        dprintf("handle PAPR hypercall\n");
 | 
			
		||||
        run->papr_hcall.ret = spapr_hypercall(cpu,
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ void cpu_save(QEMUFile *f, void *opaque)
 | 
			
		||||
    qemu_put_be32s(f, &fpscr);
 | 
			
		||||
    qemu_put_sbe32s(f, &env->access_type);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    qemu_put_betls(f, &env->asr);
 | 
			
		||||
    qemu_put_betls(f, &env->spr[SPR_ASR]);
 | 
			
		||||
    qemu_put_sbe32s(f, &env->slb_nr);
 | 
			
		||||
#endif
 | 
			
		||||
    qemu_put_betls(f, &env->spr[SPR_SDR1]);
 | 
			
		||||
@@ -125,7 +125,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 | 
			
		||||
    env->fpscr = fpscr;
 | 
			
		||||
    qemu_get_sbe32s(f, &env->access_type);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    qemu_get_betls(f, &env->asr);
 | 
			
		||||
    qemu_get_betls(f, &env->spr[SPR_ASR]);
 | 
			
		||||
    qemu_get_sbe32s(f, &env->slb_nr);
 | 
			
		||||
#endif
 | 
			
		||||
    qemu_get_betls(f, &sdr1);
 | 
			
		||||
 
 | 
			
		||||
@@ -252,41 +252,3 @@ STVE(stvewx, cpu_stl_data, bswap32, u32)
 | 
			
		||||
 | 
			
		||||
#undef HI_IDX
 | 
			
		||||
#undef LO_IDX
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************/
 | 
			
		||||
/* Softmmu support */
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
 | 
			
		||||
#define MMUSUFFIX _mmu
 | 
			
		||||
 | 
			
		||||
#define SHIFT 0
 | 
			
		||||
#include "exec/softmmu_template.h"
 | 
			
		||||
 | 
			
		||||
#define SHIFT 1
 | 
			
		||||
#include "exec/softmmu_template.h"
 | 
			
		||||
 | 
			
		||||
#define SHIFT 2
 | 
			
		||||
#include "exec/softmmu_template.h"
 | 
			
		||||
 | 
			
		||||
#define SHIFT 3
 | 
			
		||||
#include "exec/softmmu_template.h"
 | 
			
		||||
 | 
			
		||||
/* try to fill the TLB and return an exception if error. If retaddr is
 | 
			
		||||
   NULL, it means that the function was called in C code (i.e. not
 | 
			
		||||
   from generated code or from helper.c) */
 | 
			
		||||
/* XXX: fix it to restore all registers */
 | 
			
		||||
void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
 | 
			
		||||
              uintptr_t retaddr)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
 | 
			
		||||
    if (unlikely(ret != 0)) {
 | 
			
		||||
        if (likely(retaddr)) {
 | 
			
		||||
            /* now we have a real cpu fault */
 | 
			
		||||
            cpu_restore_state(env, retaddr);
 | 
			
		||||
        }
 | 
			
		||||
        helper_raise_exception_err(env, env->exception_index, env->error_code);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif /* !CONFIG_USER_ONLY */
 | 
			
		||||
 
 | 
			
		||||
@@ -35,12 +35,6 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
 | 
			
		||||
             env->spr[sprn]);
 | 
			
		||||
}
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
void helper_store_asr(CPUPPCState *env, target_ulong val)
 | 
			
		||||
{
 | 
			
		||||
    ppc_store_asr(env, val);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										560
									
								
								target-ppc/mmu-hash32.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										560
									
								
								target-ppc/mmu-hash32.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,560 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  PowerPC MMU, TLB and BAT emulation helpers for QEMU.
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (c) 2003-2007 Jocelyn Mayer
 | 
			
		||||
 *  Copyright (c) 2013 David Gibson, IBM Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "cpu.h"
 | 
			
		||||
#include "helper.h"
 | 
			
		||||
#include "sysemu/kvm.h"
 | 
			
		||||
#include "kvm_ppc.h"
 | 
			
		||||
#include "mmu-hash32.h"
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_MMU
 | 
			
		||||
//#define DEBUG_BAT
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_MMU
 | 
			
		||||
#  define LOG_MMU(...) qemu_log(__VA_ARGS__)
 | 
			
		||||
#  define LOG_MMU_STATE(env) log_cpu_state((env), 0)
 | 
			
		||||
#else
 | 
			
		||||
#  define LOG_MMU(...) do { } while (0)
 | 
			
		||||
#  define LOG_MMU_STATE(...) do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_BATS
 | 
			
		||||
#  define LOG_BATS(...) qemu_log(__VA_ARGS__)
 | 
			
		||||
#else
 | 
			
		||||
#  define LOG_BATS(...) do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct mmu_ctx_hash32 {
 | 
			
		||||
    hwaddr raddr;      /* Real address              */
 | 
			
		||||
    int prot;                      /* Protection bits           */
 | 
			
		||||
    int key;                       /* Access key                */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int ppc_hash32_pp_prot(int key, int pp, int nx)
 | 
			
		||||
{
 | 
			
		||||
    int prot;
 | 
			
		||||
 | 
			
		||||
    if (key == 0) {
 | 
			
		||||
        switch (pp) {
 | 
			
		||||
        case 0x0:
 | 
			
		||||
        case 0x1:
 | 
			
		||||
        case 0x2:
 | 
			
		||||
            prot = PAGE_READ | PAGE_WRITE;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case 0x3:
 | 
			
		||||
            prot = PAGE_READ;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            abort();
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        switch (pp) {
 | 
			
		||||
        case 0x0:
 | 
			
		||||
            prot = 0;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case 0x1:
 | 
			
		||||
        case 0x3:
 | 
			
		||||
            prot = PAGE_READ;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case 0x2:
 | 
			
		||||
            prot = PAGE_READ | PAGE_WRITE;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (nx == 0) {
 | 
			
		||||
        prot |= PAGE_EXEC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return prot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ppc_hash32_pte_prot(CPUPPCState *env,
 | 
			
		||||
                               target_ulong sr, ppc_hash_pte32_t pte)
 | 
			
		||||
{
 | 
			
		||||
    unsigned pp, key;
 | 
			
		||||
 | 
			
		||||
    key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
 | 
			
		||||
    pp = pte.pte1 & HPTE32_R_PP;
 | 
			
		||||
 | 
			
		||||
    return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static target_ulong hash32_bat_size(CPUPPCState *env,
 | 
			
		||||
                                    target_ulong batu, target_ulong batl)
 | 
			
		||||
{
 | 
			
		||||
    if ((msr_pr && !(batu & BATU32_VP))
 | 
			
		||||
        || (!msr_pr && !(batu & BATU32_VS))) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int hash32_bat_prot(CPUPPCState *env,
 | 
			
		||||
                           target_ulong batu, target_ulong batl)
 | 
			
		||||
{
 | 
			
		||||
    int pp, prot;
 | 
			
		||||
 | 
			
		||||
    prot = 0;
 | 
			
		||||
    pp = batl & BATL32_PP;
 | 
			
		||||
    if (pp != 0) {
 | 
			
		||||
        prot = PAGE_READ | PAGE_EXEC;
 | 
			
		||||
        if (pp == 0x2) {
 | 
			
		||||
            prot |= PAGE_WRITE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return prot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static target_ulong hash32_bat_601_size(CPUPPCState *env,
 | 
			
		||||
                                target_ulong batu, target_ulong batl)
 | 
			
		||||
{
 | 
			
		||||
    if (!(batl & BATL32_601_V)) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int hash32_bat_601_prot(CPUPPCState *env,
 | 
			
		||||
                               target_ulong batu, target_ulong batl)
 | 
			
		||||
{
 | 
			
		||||
    int key, pp;
 | 
			
		||||
 | 
			
		||||
    pp = batu & BATU32_601_PP;
 | 
			
		||||
    if (msr_pr == 0) {
 | 
			
		||||
        key = !!(batu & BATU32_601_KS);
 | 
			
		||||
    } else {
 | 
			
		||||
        key = !!(batu & BATU32_601_KP);
 | 
			
		||||
    }
 | 
			
		||||
    return ppc_hash32_pp_prot(key, pp, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static hwaddr ppc_hash32_bat_lookup(CPUPPCState *env, target_ulong ea, int rwx,
 | 
			
		||||
                                    int *prot)
 | 
			
		||||
{
 | 
			
		||||
    target_ulong *BATlt, *BATut;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
 | 
			
		||||
             rwx == 2 ? 'I' : 'D', ea);
 | 
			
		||||
    if (rwx == 2) {
 | 
			
		||||
        BATlt = env->IBAT[1];
 | 
			
		||||
        BATut = env->IBAT[0];
 | 
			
		||||
    } else {
 | 
			
		||||
        BATlt = env->DBAT[1];
 | 
			
		||||
        BATut = env->DBAT[0];
 | 
			
		||||
    }
 | 
			
		||||
    for (i = 0; i < env->nb_BATs; i++) {
 | 
			
		||||
        target_ulong batu = BATut[i];
 | 
			
		||||
        target_ulong batl = BATlt[i];
 | 
			
		||||
        target_ulong mask;
 | 
			
		||||
 | 
			
		||||
        if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
 | 
			
		||||
            mask = hash32_bat_601_size(env, batu, batl);
 | 
			
		||||
        } else {
 | 
			
		||||
            mask = hash32_bat_size(env, batu, batl);
 | 
			
		||||
        }
 | 
			
		||||
        LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
 | 
			
		||||
                 " BATl " TARGET_FMT_lx "\n", __func__,
 | 
			
		||||
                 type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl);
 | 
			
		||||
 | 
			
		||||
        if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
 | 
			
		||||
            hwaddr raddr = (batl & mask) | (ea & ~mask);
 | 
			
		||||
 | 
			
		||||
            if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
 | 
			
		||||
                *prot = hash32_bat_601_prot(env, batu, batl);
 | 
			
		||||
            } else {
 | 
			
		||||
                *prot = hash32_bat_prot(env, batu, batl);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return raddr & TARGET_PAGE_MASK;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* No hit */
 | 
			
		||||
#if defined(DEBUG_BATS)
 | 
			
		||||
    if (qemu_log_enabled()) {
 | 
			
		||||
        LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
 | 
			
		||||
        for (i = 0; i < 4; i++) {
 | 
			
		||||
            BATu = &BATut[i];
 | 
			
		||||
            BATl = &BATlt[i];
 | 
			
		||||
            BEPIu = *BATu & BATU32_BEPIU;
 | 
			
		||||
            BEPIl = *BATu & BATU32_BEPIL;
 | 
			
		||||
            bl = (*BATu & 0x00001FFC) << 15;
 | 
			
		||||
            LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
 | 
			
		||||
                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
 | 
			
		||||
                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
 | 
			
		||||
                     __func__, type == ACCESS_CODE ? 'I' : 'D', i, ea,
 | 
			
		||||
                     *BATu, *BATl, BEPIu, BEPIl, bl);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
 | 
			
		||||
                                   target_ulong eaddr, int rwx,
 | 
			
		||||
                                   hwaddr *raddr, int *prot)
 | 
			
		||||
{
 | 
			
		||||
    int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
 | 
			
		||||
 | 
			
		||||
    LOG_MMU("direct store...\n");
 | 
			
		||||
 | 
			
		||||
    if ((sr & 0x1FF00000) >> 20 == 0x07f) {
 | 
			
		||||
        /* Memory-forced I/O controller interface access */
 | 
			
		||||
        /* If T=1 and BUID=x'07F', the 601 performs a memory access
 | 
			
		||||
         * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
 | 
			
		||||
         */
 | 
			
		||||
        *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
 | 
			
		||||
        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rwx == 2) {
 | 
			
		||||
        /* No code fetch is allowed in direct-store areas */
 | 
			
		||||
        env->exception_index = POWERPC_EXCP_ISI;
 | 
			
		||||
        env->error_code = 0x10000000;
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (env->access_type) {
 | 
			
		||||
    case ACCESS_INT:
 | 
			
		||||
        /* Integer load/store : only access allowed */
 | 
			
		||||
        break;
 | 
			
		||||
    case ACCESS_FLOAT:
 | 
			
		||||
        /* Floating point load/store */
 | 
			
		||||
        env->exception_index = POWERPC_EXCP_ALIGN;
 | 
			
		||||
        env->error_code = POWERPC_EXCP_ALIGN_FP;
 | 
			
		||||
        env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
        return 1;
 | 
			
		||||
    case ACCESS_RES:
 | 
			
		||||
        /* lwarx, ldarx or srwcx. */
 | 
			
		||||
        env->error_code = 0;
 | 
			
		||||
        env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
        if (rwx == 1) {
 | 
			
		||||
            env->spr[SPR_DSISR] = 0x06000000;
 | 
			
		||||
        } else {
 | 
			
		||||
            env->spr[SPR_DSISR] = 0x04000000;
 | 
			
		||||
        }
 | 
			
		||||
        return 1;
 | 
			
		||||
    case ACCESS_CACHE:
 | 
			
		||||
        /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
 | 
			
		||||
        /* Should make the instruction do no-op.
 | 
			
		||||
         * As it already do no-op, it's quite easy :-)
 | 
			
		||||
         */
 | 
			
		||||
        *raddr = eaddr;
 | 
			
		||||
        return 0;
 | 
			
		||||
    case ACCESS_EXT:
 | 
			
		||||
        /* eciwx or ecowx */
 | 
			
		||||
        env->exception_index = POWERPC_EXCP_DSI;
 | 
			
		||||
        env->error_code = 0;
 | 
			
		||||
        env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
        if (rwx == 1) {
 | 
			
		||||
            env->spr[SPR_DSISR] = 0x06100000;
 | 
			
		||||
        } else {
 | 
			
		||||
            env->spr[SPR_DSISR] = 0x04100000;
 | 
			
		||||
        }
 | 
			
		||||
        return 1;
 | 
			
		||||
    default:
 | 
			
		||||
        qemu_log("ERROR: instruction should not need "
 | 
			
		||||
                 "address translation\n");
 | 
			
		||||
        abort();
 | 
			
		||||
    }
 | 
			
		||||
    if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
 | 
			
		||||
        *raddr = eaddr;
 | 
			
		||||
        return 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        env->exception_index = POWERPC_EXCP_DSI;
 | 
			
		||||
        env->error_code = 0;
 | 
			
		||||
        env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
        if (rwx == 1) {
 | 
			
		||||
            env->spr[SPR_DSISR] = 0x0a000000;
 | 
			
		||||
        } else {
 | 
			
		||||
            env->spr[SPR_DSISR] = 0x08000000;
 | 
			
		||||
        }
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
 | 
			
		||||
{
 | 
			
		||||
    return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
 | 
			
		||||
                                     bool secondary, target_ulong ptem,
 | 
			
		||||
                                     ppc_hash_pte32_t *pte)
 | 
			
		||||
{
 | 
			
		||||
    hwaddr pte_offset = pteg_off;
 | 
			
		||||
    target_ulong pte0, pte1;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < HPTES_PER_GROUP; i++) {
 | 
			
		||||
        pte0 = ppc_hash32_load_hpte0(env, pte_offset);
 | 
			
		||||
        pte1 = ppc_hash32_load_hpte1(env, pte_offset);
 | 
			
		||||
 | 
			
		||||
        if ((pte0 & HPTE32_V_VALID)
 | 
			
		||||
            && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
 | 
			
		||||
            && HPTE32_V_COMPARE(pte0, ptem)) {
 | 
			
		||||
            pte->pte0 = pte0;
 | 
			
		||||
            pte->pte1 = pte1;
 | 
			
		||||
            return pte_offset;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pte_offset += HASH_PTE_SIZE_32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
 | 
			
		||||
                                     target_ulong sr, target_ulong eaddr,
 | 
			
		||||
                                     ppc_hash_pte32_t *pte)
 | 
			
		||||
{
 | 
			
		||||
    hwaddr pteg_off, pte_offset;
 | 
			
		||||
    hwaddr hash;
 | 
			
		||||
    uint32_t vsid, pgidx, ptem;
 | 
			
		||||
 | 
			
		||||
    vsid = sr & SR32_VSID;
 | 
			
		||||
    pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
 | 
			
		||||
    hash = vsid ^ pgidx;
 | 
			
		||||
    ptem = (vsid << 7) | (pgidx >> 10);
 | 
			
		||||
 | 
			
		||||
    /* Page address translation */
 | 
			
		||||
    LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
 | 
			
		||||
            " hash " TARGET_FMT_plx "\n",
 | 
			
		||||
            env->htab_base, env->htab_mask, hash);
 | 
			
		||||
 | 
			
		||||
    /* Primary PTEG lookup */
 | 
			
		||||
    LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
 | 
			
		||||
            " vsid=%" PRIx32 " ptem=%" PRIx32
 | 
			
		||||
            " hash=" TARGET_FMT_plx "\n",
 | 
			
		||||
            env->htab_base, env->htab_mask, vsid, ptem, hash);
 | 
			
		||||
    pteg_off = get_pteg_offset32(env, hash);
 | 
			
		||||
    pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte);
 | 
			
		||||
    if (pte_offset == -1) {
 | 
			
		||||
        /* Secondary PTEG lookup */
 | 
			
		||||
        LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
 | 
			
		||||
                " vsid=%" PRIx32 " api=%" PRIx32
 | 
			
		||||
                " hash=" TARGET_FMT_plx "\n", env->htab_base,
 | 
			
		||||
                env->htab_mask, vsid, ptem, ~hash);
 | 
			
		||||
        pteg_off = get_pteg_offset32(env, ~hash);
 | 
			
		||||
        pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return pte_offset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
 | 
			
		||||
                                   target_ulong eaddr)
 | 
			
		||||
{
 | 
			
		||||
    hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
 | 
			
		||||
    hwaddr mask = ~TARGET_PAGE_MASK;
 | 
			
		||||
 | 
			
		||||
    return (rpn & ~mask) | (eaddr & mask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr, int rwx,
 | 
			
		||||
                                int mmu_idx)
 | 
			
		||||
{
 | 
			
		||||
    target_ulong sr;
 | 
			
		||||
    hwaddr pte_offset;
 | 
			
		||||
    ppc_hash_pte32_t pte;
 | 
			
		||||
    int prot;
 | 
			
		||||
    uint32_t new_pte1;
 | 
			
		||||
    const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
 | 
			
		||||
    hwaddr raddr;
 | 
			
		||||
 | 
			
		||||
    assert((rwx == 0) || (rwx == 1) || (rwx == 2));
 | 
			
		||||
 | 
			
		||||
    /* 1. Handle real mode accesses */
 | 
			
		||||
    if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
 | 
			
		||||
        /* Translation is off */
 | 
			
		||||
        raddr = eaddr;
 | 
			
		||||
        tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
 | 
			
		||||
                     PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
 | 
			
		||||
                     TARGET_PAGE_SIZE);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 2. Check Block Address Translation entries (BATs) */
 | 
			
		||||
    if (env->nb_BATs != 0) {
 | 
			
		||||
        raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &prot);
 | 
			
		||||
        if (raddr != -1) {
 | 
			
		||||
            if (need_prot[rwx] & ~prot) {
 | 
			
		||||
                if (rwx == 2) {
 | 
			
		||||
                    env->exception_index = POWERPC_EXCP_ISI;
 | 
			
		||||
                    env->error_code = 0x08000000;
 | 
			
		||||
                } else {
 | 
			
		||||
                    env->exception_index = POWERPC_EXCP_DSI;
 | 
			
		||||
                    env->error_code = 0;
 | 
			
		||||
                    env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
                    if (rwx == 1) {
 | 
			
		||||
                        env->spr[SPR_DSISR] = 0x0a000000;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        env->spr[SPR_DSISR] = 0x08000000;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            tlb_set_page(env, eaddr & TARGET_PAGE_MASK,
 | 
			
		||||
                         raddr & TARGET_PAGE_MASK, prot, mmu_idx,
 | 
			
		||||
                         TARGET_PAGE_SIZE);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 3. Look up the Segment Register */
 | 
			
		||||
    sr = env->sr[eaddr >> 28];
 | 
			
		||||
 | 
			
		||||
    /* 4. Handle direct store segments */
 | 
			
		||||
    if (sr & SR32_T) {
 | 
			
		||||
        if (ppc_hash32_direct_store(env, sr, eaddr, rwx,
 | 
			
		||||
                                    &raddr, &prot) == 0) {
 | 
			
		||||
            tlb_set_page(env, eaddr & TARGET_PAGE_MASK,
 | 
			
		||||
                         raddr & TARGET_PAGE_MASK, prot, mmu_idx,
 | 
			
		||||
                         TARGET_PAGE_SIZE);
 | 
			
		||||
            return 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 5. Check for segment level no-execute violation */
 | 
			
		||||
    if ((rwx == 2) && (sr & SR32_NX)) {
 | 
			
		||||
        env->exception_index = POWERPC_EXCP_ISI;
 | 
			
		||||
        env->error_code = 0x10000000;
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 6. Locate the PTE in the hash table */
 | 
			
		||||
    pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
 | 
			
		||||
    if (pte_offset == -1) {
 | 
			
		||||
        if (rwx == 2) {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_ISI;
 | 
			
		||||
            env->error_code = 0x40000000;
 | 
			
		||||
        } else {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_DSI;
 | 
			
		||||
            env->error_code = 0;
 | 
			
		||||
            env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
            if (rwx == 1) {
 | 
			
		||||
                env->spr[SPR_DSISR] = 0x42000000;
 | 
			
		||||
            } else {
 | 
			
		||||
                env->spr[SPR_DSISR] = 0x40000000;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
 | 
			
		||||
 | 
			
		||||
    /* 7. Check access permissions */
 | 
			
		||||
 | 
			
		||||
    prot = ppc_hash32_pte_prot(env, sr, pte);
 | 
			
		||||
 | 
			
		||||
    if (need_prot[rwx] & ~prot) {
 | 
			
		||||
        /* Access right violation */
 | 
			
		||||
        LOG_MMU("PTE access rejected\n");
 | 
			
		||||
        if (rwx == 2) {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_ISI;
 | 
			
		||||
            env->error_code = 0x08000000;
 | 
			
		||||
        } else {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_DSI;
 | 
			
		||||
            env->error_code = 0;
 | 
			
		||||
            env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
            if (rwx == 1) {
 | 
			
		||||
                env->spr[SPR_DSISR] = 0x0a000000;
 | 
			
		||||
            } else {
 | 
			
		||||
                env->spr[SPR_DSISR] = 0x08000000;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOG_MMU("PTE access granted !\n");
 | 
			
		||||
 | 
			
		||||
    /* 8. Update PTE referenced and changed bits if necessary */
 | 
			
		||||
 | 
			
		||||
    new_pte1 = pte.pte1 | HPTE32_R_R; /* set referenced bit */
 | 
			
		||||
    if (rwx == 1) {
 | 
			
		||||
        new_pte1 |= HPTE32_R_C; /* set changed (dirty) bit */
 | 
			
		||||
    } else {
 | 
			
		||||
        /* Treat the page as read-only for now, so that a later write
 | 
			
		||||
         * will pass through this function again to set the C bit */
 | 
			
		||||
        prot &= ~PAGE_WRITE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (new_pte1 != pte.pte1) {
 | 
			
		||||
        ppc_hash32_store_hpte1(env, pte_offset, new_pte1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 9. Determine the real address from the PTE */
 | 
			
		||||
 | 
			
		||||
    raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
 | 
			
		||||
 | 
			
		||||
    tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
 | 
			
		||||
                 prot, mmu_idx, TARGET_PAGE_SIZE);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong eaddr)
 | 
			
		||||
{
 | 
			
		||||
    target_ulong sr;
 | 
			
		||||
    hwaddr pte_offset;
 | 
			
		||||
    ppc_hash_pte32_t pte;
 | 
			
		||||
    int prot;
 | 
			
		||||
 | 
			
		||||
    if (msr_dr == 0) {
 | 
			
		||||
        /* Translation is off */
 | 
			
		||||
        return eaddr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (env->nb_BATs != 0) {
 | 
			
		||||
        hwaddr raddr = ppc_hash32_bat_lookup(env, eaddr, 0, &prot);
 | 
			
		||||
        if (raddr != -1) {
 | 
			
		||||
            return raddr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sr = env->sr[eaddr >> 28];
 | 
			
		||||
 | 
			
		||||
    if (sr & SR32_T) {
 | 
			
		||||
        /* FIXME: Add suitable debug support for Direct Store segments */
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
 | 
			
		||||
    if (pte_offset == -1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										102
									
								
								target-ppc/mmu-hash32.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								target-ppc/mmu-hash32.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
#if !defined (__MMU_HASH32_H__)
 | 
			
		||||
#define __MMU_HASH32_H__
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_USER_ONLY
 | 
			
		||||
 | 
			
		||||
hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash);
 | 
			
		||||
hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
 | 
			
		||||
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
 | 
			
		||||
                                int mmu_idx);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Segment register definitions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define SR32_T                  0x80000000
 | 
			
		||||
#define SR32_KS                 0x40000000
 | 
			
		||||
#define SR32_KP                 0x20000000
 | 
			
		||||
#define SR32_NX                 0x10000000
 | 
			
		||||
#define SR32_VSID               0x00ffffff
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Block Address Translation (BAT) definitions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define BATU32_BEPI             0xfffe0000
 | 
			
		||||
#define BATU32_BL               0x00001ffc
 | 
			
		||||
#define BATU32_VS               0x00000002
 | 
			
		||||
#define BATU32_VP               0x00000001
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define BATL32_BRPN             0xfffe0000
 | 
			
		||||
#define BATL32_WIMG             0x00000078
 | 
			
		||||
#define BATL32_PP               0x00000003
 | 
			
		||||
 | 
			
		||||
/* PowerPC 601 has slightly different BAT registers */
 | 
			
		||||
 | 
			
		||||
#define BATU32_601_KS           0x00000008
 | 
			
		||||
#define BATU32_601_KP           0x00000004
 | 
			
		||||
#define BATU32_601_PP           0x00000003
 | 
			
		||||
 | 
			
		||||
#define BATL32_601_V            0x00000040
 | 
			
		||||
#define BATL32_601_BL           0x0000003f
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Hash page table definitions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define HPTES_PER_GROUP         8
 | 
			
		||||
#define HASH_PTE_SIZE_32        8
 | 
			
		||||
#define HASH_PTEG_SIZE_32       (HASH_PTE_SIZE_32 * HPTES_PER_GROUP)
 | 
			
		||||
 | 
			
		||||
#define HPTE32_V_VALID          0x80000000
 | 
			
		||||
#define HPTE32_V_VSID           0x7fffff80
 | 
			
		||||
#define HPTE32_V_SECONDARY      0x00000040
 | 
			
		||||
#define HPTE32_V_API            0x0000003f
 | 
			
		||||
#define HPTE32_V_COMPARE(x, y)  (!(((x) ^ (y)) & 0x7fffffbf))
 | 
			
		||||
 | 
			
		||||
#define HPTE32_R_RPN            0xfffff000
 | 
			
		||||
#define HPTE32_R_R              0x00000100
 | 
			
		||||
#define HPTE32_R_C              0x00000080
 | 
			
		||||
#define HPTE32_R_W              0x00000040
 | 
			
		||||
#define HPTE32_R_I              0x00000020
 | 
			
		||||
#define HPTE32_R_M              0x00000010
 | 
			
		||||
#define HPTE32_R_G              0x00000008
 | 
			
		||||
#define HPTE32_R_WIMG           0x00000078
 | 
			
		||||
#define HPTE32_R_PP             0x00000003
 | 
			
		||||
 | 
			
		||||
static inline target_ulong ppc_hash32_load_hpte0(CPUPPCState *env,
 | 
			
		||||
                                                 hwaddr pte_offset)
 | 
			
		||||
{
 | 
			
		||||
    assert(!env->external_htab); /* Not supported on 32-bit for now */
 | 
			
		||||
    return ldl_phys(env->htab_base + pte_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline target_ulong ppc_hash32_load_hpte1(CPUPPCState *env,
 | 
			
		||||
                                                 hwaddr pte_offset)
 | 
			
		||||
{
 | 
			
		||||
    assert(!env->external_htab); /* Not supported on 32-bit for now */
 | 
			
		||||
    return ldl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ppc_hash32_store_hpte0(CPUPPCState *env,
 | 
			
		||||
                                          hwaddr pte_offset, target_ulong pte0)
 | 
			
		||||
{
 | 
			
		||||
    assert(!env->external_htab); /* Not supported on 32-bit for now */
 | 
			
		||||
    stl_phys(env->htab_base + pte_offset, pte0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ppc_hash32_store_hpte1(CPUPPCState *env,
 | 
			
		||||
                                          hwaddr pte_offset, target_ulong pte1)
 | 
			
		||||
{
 | 
			
		||||
    assert(!env->external_htab); /* Not supported on 32-bit for now */
 | 
			
		||||
    stl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2, pte1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t pte0, pte1;
 | 
			
		||||
} ppc_hash_pte32_t;
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_USER_ONLY */
 | 
			
		||||
 | 
			
		||||
#endif /* __MMU_HASH32_H__ */
 | 
			
		||||
							
								
								
									
										546
									
								
								target-ppc/mmu-hash64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										546
									
								
								target-ppc/mmu-hash64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,546 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (c) 2003-2007 Jocelyn Mayer
 | 
			
		||||
 *  Copyright (c) 2013 David Gibson, IBM Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
#include "cpu.h"
 | 
			
		||||
#include "helper.h"
 | 
			
		||||
#include "sysemu/kvm.h"
 | 
			
		||||
#include "kvm_ppc.h"
 | 
			
		||||
#include "mmu-hash64.h"
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_MMU
 | 
			
		||||
//#define DEBUG_SLB
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_MMU
 | 
			
		||||
#  define LOG_MMU(...) qemu_log(__VA_ARGS__)
 | 
			
		||||
#  define LOG_MMU_STATE(env) log_cpu_state((env), 0)
 | 
			
		||||
#else
 | 
			
		||||
#  define LOG_MMU(...) do { } while (0)
 | 
			
		||||
#  define LOG_MMU_STATE(...) do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_SLB
 | 
			
		||||
#  define LOG_SLB(...) qemu_log(__VA_ARGS__)
 | 
			
		||||
#else
 | 
			
		||||
#  define LOG_SLB(...) do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SLB handling
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t esid_256M, esid_1T;
 | 
			
		||||
    int n;
 | 
			
		||||
 | 
			
		||||
    LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
 | 
			
		||||
 | 
			
		||||
    esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
 | 
			
		||||
    esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
 | 
			
		||||
 | 
			
		||||
    for (n = 0; n < env->slb_nr; n++) {
 | 
			
		||||
        ppc_slb_t *slb = &env->slb[n];
 | 
			
		||||
 | 
			
		||||
        LOG_SLB("%s: slot %d %016" PRIx64 " %016"
 | 
			
		||||
                    PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
 | 
			
		||||
        /* We check for 1T matches on all MMUs here - if the MMU
 | 
			
		||||
         * doesn't have 1T segment support, we will have prevented 1T
 | 
			
		||||
         * entries from being inserted in the slbmte code. */
 | 
			
		||||
        if (((slb->esid == esid_256M) &&
 | 
			
		||||
             ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
 | 
			
		||||
            || ((slb->esid == esid_1T) &&
 | 
			
		||||
                ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
 | 
			
		||||
            return slb;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    uint64_t slbe, slbv;
 | 
			
		||||
 | 
			
		||||
    cpu_synchronize_state(env);
 | 
			
		||||
 | 
			
		||||
    cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
 | 
			
		||||
    for (i = 0; i < env->slb_nr; i++) {
 | 
			
		||||
        slbe = env->slb[i].esid;
 | 
			
		||||
        slbv = env->slb[i].vsid;
 | 
			
		||||
        if (slbe == 0 && slbv == 0) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
 | 
			
		||||
                    i, slbe, slbv);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void helper_slbia(CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    int n, do_invalidate;
 | 
			
		||||
 | 
			
		||||
    do_invalidate = 0;
 | 
			
		||||
    /* XXX: Warning: slbia never invalidates the first segment */
 | 
			
		||||
    for (n = 1; n < env->slb_nr; n++) {
 | 
			
		||||
        ppc_slb_t *slb = &env->slb[n];
 | 
			
		||||
 | 
			
		||||
        if (slb->esid & SLB_ESID_V) {
 | 
			
		||||
            slb->esid &= ~SLB_ESID_V;
 | 
			
		||||
            /* XXX: given the fact that segment size is 256 MB or 1TB,
 | 
			
		||||
             *      and we still don't have a tlb_flush_mask(env, n, mask)
 | 
			
		||||
             *      in QEMU, we just invalidate all TLBs
 | 
			
		||||
             */
 | 
			
		||||
            do_invalidate = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (do_invalidate) {
 | 
			
		||||
        tlb_flush(env, 1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void helper_slbie(CPUPPCState *env, target_ulong addr)
 | 
			
		||||
{
 | 
			
		||||
    ppc_slb_t *slb;
 | 
			
		||||
 | 
			
		||||
    slb = slb_lookup(env, addr);
 | 
			
		||||
    if (!slb) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (slb->esid & SLB_ESID_V) {
 | 
			
		||||
        slb->esid &= ~SLB_ESID_V;
 | 
			
		||||
 | 
			
		||||
        /* XXX: given the fact that segment size is 256 MB or 1TB,
 | 
			
		||||
         *      and we still don't have a tlb_flush_mask(env, n, mask)
 | 
			
		||||
         *      in QEMU, we just invalidate all TLBs
 | 
			
		||||
         */
 | 
			
		||||
        tlb_flush(env, 1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
 | 
			
		||||
{
 | 
			
		||||
    int slot = rb & 0xfff;
 | 
			
		||||
    ppc_slb_t *slb = &env->slb[slot];
 | 
			
		||||
 | 
			
		||||
    if (rb & (0x1000 - env->slb_nr)) {
 | 
			
		||||
        return -1; /* Reserved bits set or slot too high */
 | 
			
		||||
    }
 | 
			
		||||
    if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
 | 
			
		||||
        return -1; /* Bad segment size */
 | 
			
		||||
    }
 | 
			
		||||
    if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
 | 
			
		||||
        return -1; /* 1T segment on MMU that doesn't support it */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Mask out the slot number as we store the entry */
 | 
			
		||||
    slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
 | 
			
		||||
    slb->vsid = rs;
 | 
			
		||||
 | 
			
		||||
    LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
 | 
			
		||||
            " %016" PRIx64 "\n", __func__, slot, rb, rs,
 | 
			
		||||
            slb->esid, slb->vsid);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb,
 | 
			
		||||
                             target_ulong *rt)
 | 
			
		||||
{
 | 
			
		||||
    int slot = rb & 0xfff;
 | 
			
		||||
    ppc_slb_t *slb = &env->slb[slot];
 | 
			
		||||
 | 
			
		||||
    if (slot >= env->slb_nr) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *rt = slb->esid;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,
 | 
			
		||||
                             target_ulong *rt)
 | 
			
		||||
{
 | 
			
		||||
    int slot = rb & 0xfff;
 | 
			
		||||
    ppc_slb_t *slb = &env->slb[slot];
 | 
			
		||||
 | 
			
		||||
    if (slot >= env->slb_nr) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *rt = slb->vsid;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
 | 
			
		||||
{
 | 
			
		||||
    if (ppc_store_slb(env, rb, rs) < 0) {
 | 
			
		||||
        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
 | 
			
		||||
                                   POWERPC_EXCP_INVAL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
 | 
			
		||||
{
 | 
			
		||||
    target_ulong rt = 0;
 | 
			
		||||
 | 
			
		||||
    if (ppc_load_slb_esid(env, rb, &rt) < 0) {
 | 
			
		||||
        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
 | 
			
		||||
                                   POWERPC_EXCP_INVAL);
 | 
			
		||||
    }
 | 
			
		||||
    return rt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
 | 
			
		||||
{
 | 
			
		||||
    target_ulong rt = 0;
 | 
			
		||||
 | 
			
		||||
    if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
 | 
			
		||||
        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
 | 
			
		||||
                                   POWERPC_EXCP_INVAL);
 | 
			
		||||
    }
 | 
			
		||||
    return rt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 64-bit hash table MMU handling
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int ppc_hash64_pte_prot(CPUPPCState *env,
 | 
			
		||||
                               ppc_slb_t *slb, ppc_hash_pte64_t pte)
 | 
			
		||||
{
 | 
			
		||||
    unsigned pp, key;
 | 
			
		||||
    /* Some pp bit combinations have undefined behaviour, so default
 | 
			
		||||
     * to no access in those cases */
 | 
			
		||||
    int prot = 0;
 | 
			
		||||
 | 
			
		||||
    key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP)
 | 
			
		||||
             : (slb->vsid & SLB_VSID_KS));
 | 
			
		||||
    pp = (pte.pte1 & HPTE64_R_PP) | ((pte.pte1 & HPTE64_R_PP0) >> 61);
 | 
			
		||||
 | 
			
		||||
    if (key == 0) {
 | 
			
		||||
        switch (pp) {
 | 
			
		||||
        case 0x0:
 | 
			
		||||
        case 0x1:
 | 
			
		||||
        case 0x2:
 | 
			
		||||
            prot = PAGE_READ | PAGE_WRITE;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case 0x3:
 | 
			
		||||
        case 0x6:
 | 
			
		||||
            prot = PAGE_READ;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        switch (pp) {
 | 
			
		||||
        case 0x0:
 | 
			
		||||
        case 0x6:
 | 
			
		||||
            prot = 0;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case 0x1:
 | 
			
		||||
        case 0x3:
 | 
			
		||||
            prot = PAGE_READ;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case 0x2:
 | 
			
		||||
            prot = PAGE_READ | PAGE_WRITE;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* No execute if either noexec or guarded bits set */
 | 
			
		||||
    if (!(pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G)
 | 
			
		||||
        || (slb->vsid & SLB_VSID_N)) {
 | 
			
		||||
        prot |= PAGE_EXEC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return prot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
 | 
			
		||||
{
 | 
			
		||||
    int key, amrbits;
 | 
			
		||||
    int prot = PAGE_EXEC;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* Only recent MMUs implement Virtual Page Class Key Protection */
 | 
			
		||||
    if (!(env->mmu_model & POWERPC_MMU_AMR)) {
 | 
			
		||||
        return PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    key = HPTE64_R_KEY(pte.pte1);
 | 
			
		||||
    amrbits = (env->spr[SPR_AMR] >> 2*(31 - key)) & 0x3;
 | 
			
		||||
 | 
			
		||||
    /* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */
 | 
			
		||||
    /*         env->spr[SPR_AMR]); */
 | 
			
		||||
 | 
			
		||||
    if (amrbits & 0x2) {
 | 
			
		||||
        prot |= PAGE_WRITE;
 | 
			
		||||
    }
 | 
			
		||||
    if (amrbits & 0x1) {
 | 
			
		||||
        prot |= PAGE_READ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return prot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
 | 
			
		||||
                                     bool secondary, target_ulong ptem,
 | 
			
		||||
                                     ppc_hash_pte64_t *pte)
 | 
			
		||||
{
 | 
			
		||||
    hwaddr pte_offset = pteg_off;
 | 
			
		||||
    target_ulong pte0, pte1;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < HPTES_PER_GROUP; i++) {
 | 
			
		||||
        pte0 = ppc_hash64_load_hpte0(env, pte_offset);
 | 
			
		||||
        pte1 = ppc_hash64_load_hpte1(env, pte_offset);
 | 
			
		||||
 | 
			
		||||
        if ((pte0 & HPTE64_V_VALID)
 | 
			
		||||
            && (secondary == !!(pte0 & HPTE64_V_SECONDARY))
 | 
			
		||||
            && HPTE64_V_COMPARE(pte0, ptem)) {
 | 
			
		||||
            pte->pte0 = pte0;
 | 
			
		||||
            pte->pte1 = pte1;
 | 
			
		||||
            return pte_offset;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pte_offset += HASH_PTE_SIZE_64;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
 | 
			
		||||
                                     ppc_slb_t *slb, target_ulong eaddr,
 | 
			
		||||
                                     ppc_hash_pte64_t *pte)
 | 
			
		||||
{
 | 
			
		||||
    hwaddr pteg_off, pte_offset;
 | 
			
		||||
    hwaddr hash;
 | 
			
		||||
    uint64_t vsid, epnshift, epnmask, epn, ptem;
 | 
			
		||||
 | 
			
		||||
    /* Page size according to the SLB, which we use to generate the
 | 
			
		||||
     * EPN for hash table lookup..  When we implement more recent MMU
 | 
			
		||||
     * extensions this might be different from the actual page size
 | 
			
		||||
     * encoded in the PTE */
 | 
			
		||||
    epnshift = (slb->vsid & SLB_VSID_L)
 | 
			
		||||
        ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
 | 
			
		||||
    epnmask = ~((1ULL << epnshift) - 1);
 | 
			
		||||
 | 
			
		||||
    if (slb->vsid & SLB_VSID_B) {
 | 
			
		||||
        /* 1TB segment */
 | 
			
		||||
        vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
 | 
			
		||||
        epn = (eaddr & ~SEGMENT_MASK_1T) & epnmask;
 | 
			
		||||
        hash = vsid ^ (vsid << 25) ^ (epn >> epnshift);
 | 
			
		||||
    } else {
 | 
			
		||||
        /* 256M segment */
 | 
			
		||||
        vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
 | 
			
		||||
        epn = (eaddr & ~SEGMENT_MASK_256M) & epnmask;
 | 
			
		||||
        hash = vsid ^ (epn >> epnshift);
 | 
			
		||||
    }
 | 
			
		||||
    ptem = (slb->vsid & SLB_VSID_PTEM) | ((epn >> 16) & HPTE64_V_AVPN);
 | 
			
		||||
 | 
			
		||||
    /* Page address translation */
 | 
			
		||||
    LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
 | 
			
		||||
            " hash " TARGET_FMT_plx "\n",
 | 
			
		||||
            env->htab_base, env->htab_mask, hash);
 | 
			
		||||
 | 
			
		||||
    /* Primary PTEG lookup */
 | 
			
		||||
    LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
 | 
			
		||||
            " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
 | 
			
		||||
            " hash=" TARGET_FMT_plx "\n",
 | 
			
		||||
            env->htab_base, env->htab_mask, vsid, ptem,  hash);
 | 
			
		||||
    pteg_off = (hash * HASH_PTEG_SIZE_64) & env->htab_mask;
 | 
			
		||||
    pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, pte);
 | 
			
		||||
 | 
			
		||||
    if (pte_offset == -1) {
 | 
			
		||||
        /* Secondary PTEG lookup */
 | 
			
		||||
        LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
 | 
			
		||||
                " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
 | 
			
		||||
                " hash=" TARGET_FMT_plx "\n", env->htab_base,
 | 
			
		||||
                env->htab_mask, vsid, ptem, ~hash);
 | 
			
		||||
 | 
			
		||||
        pteg_off = (~hash * HASH_PTEG_SIZE_64) & env->htab_mask;
 | 
			
		||||
        pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, pte);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return pte_offset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,
 | 
			
		||||
                                   target_ulong eaddr)
 | 
			
		||||
{
 | 
			
		||||
    hwaddr rpn = pte.pte1 & HPTE64_R_RPN;
 | 
			
		||||
    /* FIXME: Add support for SLLP extended page sizes */
 | 
			
		||||
    int target_page_bits = (slb->vsid & SLB_VSID_L)
 | 
			
		||||
        ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
 | 
			
		||||
    hwaddr mask = (1ULL << target_page_bits) - 1;
 | 
			
		||||
 | 
			
		||||
    return (rpn & ~mask) | (eaddr & mask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
 | 
			
		||||
                                int rwx, int mmu_idx)
 | 
			
		||||
{
 | 
			
		||||
    ppc_slb_t *slb;
 | 
			
		||||
    hwaddr pte_offset;
 | 
			
		||||
    ppc_hash_pte64_t pte;
 | 
			
		||||
    int pp_prot, amr_prot, prot;
 | 
			
		||||
    uint64_t new_pte1;
 | 
			
		||||
    const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
 | 
			
		||||
    hwaddr raddr;
 | 
			
		||||
 | 
			
		||||
    assert((rwx == 0) || (rwx == 1) || (rwx == 2));
 | 
			
		||||
 | 
			
		||||
    /* 1. Handle real mode accesses */
 | 
			
		||||
    if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
 | 
			
		||||
        /* Translation is off */
 | 
			
		||||
        /* In real mode the top 4 effective address bits are ignored */
 | 
			
		||||
        raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
 | 
			
		||||
        tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
 | 
			
		||||
                     PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
 | 
			
		||||
                     TARGET_PAGE_SIZE);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 2. Translation is on, so look up the SLB */
 | 
			
		||||
    slb = slb_lookup(env, eaddr);
 | 
			
		||||
 | 
			
		||||
    if (!slb) {
 | 
			
		||||
        if (rwx == 2) {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_ISEG;
 | 
			
		||||
            env->error_code = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_DSEG;
 | 
			
		||||
            env->error_code = 0;
 | 
			
		||||
            env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
        }
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 3. Check for segment level no-execute violation */
 | 
			
		||||
    if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
 | 
			
		||||
        env->exception_index = POWERPC_EXCP_ISI;
 | 
			
		||||
        env->error_code = 0x10000000;
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 4. Locate the PTE in the hash table */
 | 
			
		||||
    pte_offset = ppc_hash64_htab_lookup(env, slb, eaddr, &pte);
 | 
			
		||||
    if (pte_offset == -1) {
 | 
			
		||||
        if (rwx == 2) {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_ISI;
 | 
			
		||||
            env->error_code = 0x40000000;
 | 
			
		||||
        } else {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_DSI;
 | 
			
		||||
            env->error_code = 0;
 | 
			
		||||
            env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
            if (rwx == 1) {
 | 
			
		||||
                env->spr[SPR_DSISR] = 0x42000000;
 | 
			
		||||
            } else {
 | 
			
		||||
                env->spr[SPR_DSISR] = 0x40000000;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
 | 
			
		||||
 | 
			
		||||
    /* 5. Check access permissions */
 | 
			
		||||
 | 
			
		||||
    pp_prot = ppc_hash64_pte_prot(env, slb, pte);
 | 
			
		||||
    amr_prot = ppc_hash64_amr_prot(env, pte);
 | 
			
		||||
    prot = pp_prot & amr_prot;
 | 
			
		||||
 | 
			
		||||
    if ((need_prot[rwx] & ~prot) != 0) {
 | 
			
		||||
        /* Access right violation */
 | 
			
		||||
        LOG_MMU("PTE access rejected\n");
 | 
			
		||||
        if (rwx == 2) {
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_ISI;
 | 
			
		||||
            env->error_code = 0x08000000;
 | 
			
		||||
        } else {
 | 
			
		||||
            target_ulong dsisr = 0;
 | 
			
		||||
 | 
			
		||||
            env->exception_index = POWERPC_EXCP_DSI;
 | 
			
		||||
            env->error_code = 0;
 | 
			
		||||
            env->spr[SPR_DAR] = eaddr;
 | 
			
		||||
            if (need_prot[rwx] & ~pp_prot) {
 | 
			
		||||
                dsisr |= 0x08000000;
 | 
			
		||||
            }
 | 
			
		||||
            if (rwx == 1) {
 | 
			
		||||
                dsisr |= 0x02000000;
 | 
			
		||||
            }
 | 
			
		||||
            if (need_prot[rwx] & ~amr_prot) {
 | 
			
		||||
                dsisr |= 0x00200000;
 | 
			
		||||
            }
 | 
			
		||||
            env->spr[SPR_DSISR] = dsisr;
 | 
			
		||||
        }
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOG_MMU("PTE access granted !\n");
 | 
			
		||||
 | 
			
		||||
    /* 6. Update PTE referenced and changed bits if necessary */
 | 
			
		||||
 | 
			
		||||
    new_pte1 = pte.pte1 | HPTE64_R_R; /* set referenced bit */
 | 
			
		||||
    if (rwx == 1) {
 | 
			
		||||
        new_pte1 |= HPTE64_R_C; /* set changed (dirty) bit */
 | 
			
		||||
    } else {
 | 
			
		||||
        /* Treat the page as read-only for now, so that a later write
 | 
			
		||||
         * will pass through this function again to set the C bit */
 | 
			
		||||
        prot &= ~PAGE_WRITE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (new_pte1 != pte.pte1) {
 | 
			
		||||
        ppc_hash64_store_hpte1(env, pte_offset, new_pte1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 7. Determine the real address from the PTE */
 | 
			
		||||
 | 
			
		||||
    raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
 | 
			
		||||
 | 
			
		||||
    tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
 | 
			
		||||
                 prot, mmu_idx, TARGET_PAGE_SIZE);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
 | 
			
		||||
{
 | 
			
		||||
    ppc_slb_t *slb;
 | 
			
		||||
    hwaddr pte_offset;
 | 
			
		||||
    ppc_hash_pte64_t pte;
 | 
			
		||||
 | 
			
		||||
    if (msr_dr == 0) {
 | 
			
		||||
        /* In real mode the top 4 effective address bits are ignored */
 | 
			
		||||
        return addr & 0x0FFFFFFFFFFFFFFFULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    slb = slb_lookup(env, addr);
 | 
			
		||||
    if (!slb) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pte_offset = ppc_hash64_htab_lookup(env, slb, addr, &pte);
 | 
			
		||||
    if (pte_offset == -1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ppc_hash64_pte_raddr(slb, pte, addr) & TARGET_PAGE_MASK;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										124
									
								
								target-ppc/mmu-hash64.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								target-ppc/mmu-hash64.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
#if !defined (__MMU_HASH64_H__)
 | 
			
		||||
#define __MMU_HASH64_H__
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_USER_ONLY
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_PPC64
 | 
			
		||||
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
 | 
			
		||||
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
 | 
			
		||||
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
 | 
			
		||||
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
 | 
			
		||||
                                int mmu_idx);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SLB definitions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Bits in the SLB ESID word */
 | 
			
		||||
#define SLB_ESID_ESID           0xFFFFFFFFF0000000ULL
 | 
			
		||||
#define SLB_ESID_V              0x0000000008000000ULL /* valid */
 | 
			
		||||
 | 
			
		||||
/* Bits in the SLB VSID word */
 | 
			
		||||
#define SLB_VSID_SHIFT          12
 | 
			
		||||
#define SLB_VSID_SHIFT_1T       24
 | 
			
		||||
#define SLB_VSID_SSIZE_SHIFT    62
 | 
			
		||||
#define SLB_VSID_B              0xc000000000000000ULL
 | 
			
		||||
#define SLB_VSID_B_256M         0x0000000000000000ULL
 | 
			
		||||
#define SLB_VSID_B_1T           0x4000000000000000ULL
 | 
			
		||||
#define SLB_VSID_VSID           0x3FFFFFFFFFFFF000ULL
 | 
			
		||||
#define SLB_VSID_PTEM           (SLB_VSID_B | SLB_VSID_VSID)
 | 
			
		||||
#define SLB_VSID_KS             0x0000000000000800ULL
 | 
			
		||||
#define SLB_VSID_KP             0x0000000000000400ULL
 | 
			
		||||
#define SLB_VSID_N              0x0000000000000200ULL /* no-execute */
 | 
			
		||||
#define SLB_VSID_L              0x0000000000000100ULL
 | 
			
		||||
#define SLB_VSID_C              0x0000000000000080ULL /* class */
 | 
			
		||||
#define SLB_VSID_LP             0x0000000000000030ULL
 | 
			
		||||
#define SLB_VSID_ATTR           0x0000000000000FFFULL
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Hash page table definitions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define HPTES_PER_GROUP         8
 | 
			
		||||
#define HASH_PTE_SIZE_64        16
 | 
			
		||||
#define HASH_PTEG_SIZE_64       (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
 | 
			
		||||
 | 
			
		||||
#define HPTE64_V_SSIZE_SHIFT    62
 | 
			
		||||
#define HPTE64_V_AVPN_SHIFT     7
 | 
			
		||||
#define HPTE64_V_AVPN           0x3fffffffffffff80ULL
 | 
			
		||||
#define HPTE64_V_AVPN_VAL(x)    (((x) & HPTE64_V_AVPN) >> HPTE64_V_AVPN_SHIFT)
 | 
			
		||||
#define HPTE64_V_COMPARE(x, y)  (!(((x) ^ (y)) & 0xffffffffffffff80ULL))
 | 
			
		||||
#define HPTE64_V_LARGE          0x0000000000000004ULL
 | 
			
		||||
#define HPTE64_V_SECONDARY      0x0000000000000002ULL
 | 
			
		||||
#define HPTE64_V_VALID          0x0000000000000001ULL
 | 
			
		||||
 | 
			
		||||
#define HPTE64_R_PP0            0x8000000000000000ULL
 | 
			
		||||
#define HPTE64_R_TS             0x4000000000000000ULL
 | 
			
		||||
#define HPTE64_R_KEY_HI         0x3000000000000000ULL
 | 
			
		||||
#define HPTE64_R_RPN_SHIFT      12
 | 
			
		||||
#define HPTE64_R_RPN            0x0ffffffffffff000ULL
 | 
			
		||||
#define HPTE64_R_FLAGS          0x00000000000003ffULL
 | 
			
		||||
#define HPTE64_R_PP             0x0000000000000003ULL
 | 
			
		||||
#define HPTE64_R_N              0x0000000000000004ULL
 | 
			
		||||
#define HPTE64_R_G              0x0000000000000008ULL
 | 
			
		||||
#define HPTE64_R_M              0x0000000000000010ULL
 | 
			
		||||
#define HPTE64_R_I              0x0000000000000020ULL
 | 
			
		||||
#define HPTE64_R_W              0x0000000000000040ULL
 | 
			
		||||
#define HPTE64_R_WIMG           0x0000000000000078ULL
 | 
			
		||||
#define HPTE64_R_C              0x0000000000000080ULL
 | 
			
		||||
#define HPTE64_R_R              0x0000000000000100ULL
 | 
			
		||||
#define HPTE64_R_KEY_LO         0x0000000000000e00ULL
 | 
			
		||||
#define HPTE64_R_KEY(x)         ((((x) & HPTE64_R_KEY_HI) >> 60) | \
 | 
			
		||||
                                 (((x) & HPTE64_R_KEY_LO) >> 9))
 | 
			
		||||
 | 
			
		||||
#define HPTE64_V_1TB_SEG        0x4000000000000000ULL
 | 
			
		||||
#define HPTE64_V_VRMA_MASK      0x4001ffffff000000ULL
 | 
			
		||||
 | 
			
		||||
static inline target_ulong ppc_hash64_load_hpte0(CPUPPCState *env,
 | 
			
		||||
                                                 hwaddr pte_offset)
 | 
			
		||||
{
 | 
			
		||||
    if (env->external_htab) {
 | 
			
		||||
        return  ldq_p(env->external_htab + pte_offset);
 | 
			
		||||
    } else {
 | 
			
		||||
        return ldq_phys(env->htab_base + pte_offset);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline target_ulong ppc_hash64_load_hpte1(CPUPPCState *env,
 | 
			
		||||
                                                 hwaddr pte_offset)
 | 
			
		||||
{
 | 
			
		||||
    if (env->external_htab) {
 | 
			
		||||
        return ldq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2);
 | 
			
		||||
    } else {
 | 
			
		||||
        return ldq_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_64/2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ppc_hash64_store_hpte0(CPUPPCState *env,
 | 
			
		||||
                                          hwaddr pte_offset, target_ulong pte0)
 | 
			
		||||
{
 | 
			
		||||
    if (env->external_htab) {
 | 
			
		||||
        stq_p(env->external_htab + pte_offset, pte0);
 | 
			
		||||
    } else {
 | 
			
		||||
        stq_phys(env->htab_base + pte_offset, pte0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ppc_hash64_store_hpte1(CPUPPCState *env,
 | 
			
		||||
                                          hwaddr pte_offset, target_ulong pte1)
 | 
			
		||||
{
 | 
			
		||||
    if (env->external_htab) {
 | 
			
		||||
        stq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2, pte1);
 | 
			
		||||
    } else {
 | 
			
		||||
        stq_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_64/2, pte1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint64_t pte0, pte1;
 | 
			
		||||
} ppc_hash_pte64_t;
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_USER_ONLY */
 | 
			
		||||
 | 
			
		||||
#endif /* !defined (__MMU_HASH64_H__) */
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -204,6 +204,13 @@ typedef struct DisasContext {
 | 
			
		||||
    int singlestep_enabled;
 | 
			
		||||
} DisasContext;
 | 
			
		||||
 | 
			
		||||
/* True when active word size < size of target_long.  */
 | 
			
		||||
#ifdef TARGET_PPC64
 | 
			
		||||
# define NARROW_MODE(C)  (!(C)->sf_mode)
 | 
			
		||||
#else
 | 
			
		||||
# define NARROW_MODE(C)  0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct opc_handler_t {
 | 
			
		||||
    /* invalid bits for instruction 1 (Rc(opcode) == 0) */
 | 
			
		||||
    uint32_t inval1;
 | 
			
		||||
@@ -260,12 +267,10 @@ static inline void gen_set_access_type(DisasContext *ctx, int access_type)
 | 
			
		||||
 | 
			
		||||
static inline void gen_update_nip(DisasContext *ctx, target_ulong nip)
 | 
			
		||||
{
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (ctx->sf_mode)
 | 
			
		||||
        tcg_gen_movi_tl(cpu_nip, nip);
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
        tcg_gen_movi_tl(cpu_nip, (uint32_t)nip);
 | 
			
		||||
    if (NARROW_MODE(ctx)) {
 | 
			
		||||
        nip = (uint32_t)nip;
 | 
			
		||||
    }
 | 
			
		||||
    tcg_gen_movi_tl(cpu_nip, nip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
 | 
			
		||||
@@ -627,7 +632,6 @@ static inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
 | 
			
		||||
    tcg_temp_free(t0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
static inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf)
 | 
			
		||||
{
 | 
			
		||||
    TCGv t0, t1;
 | 
			
		||||
@@ -651,68 +655,62 @@ static inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf)
 | 
			
		||||
    gen_op_cmp32(arg0, t0, s, crf);
 | 
			
		||||
    tcg_temp_free(t0);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline void gen_set_Rc0(DisasContext *ctx, TCGv reg)
 | 
			
		||||
{
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!(ctx->sf_mode))
 | 
			
		||||
    if (NARROW_MODE(ctx)) {
 | 
			
		||||
        gen_op_cmpi32(reg, 0, 1, 0);
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
    } else {
 | 
			
		||||
        gen_op_cmpi(reg, 0, 1, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* cmp */
 | 
			
		||||
static void gen_cmp(DisasContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
 | 
			
		||||
    if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
 | 
			
		||||
        gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
 | 
			
		||||
                     1, crfD(ctx->opcode));
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
    } else {
 | 
			
		||||
        gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
 | 
			
		||||
                   1, crfD(ctx->opcode));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* cmpi */
 | 
			
		||||
static void gen_cmpi(DisasContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
 | 
			
		||||
    if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
 | 
			
		||||
        gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
 | 
			
		||||
                      1, crfD(ctx->opcode));
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
    } else {
 | 
			
		||||
        gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
 | 
			
		||||
                    1, crfD(ctx->opcode));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* cmpl */
 | 
			
		||||
static void gen_cmpl(DisasContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
 | 
			
		||||
    if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
 | 
			
		||||
        gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
 | 
			
		||||
                     0, crfD(ctx->opcode));
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
    } else {
 | 
			
		||||
        gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
 | 
			
		||||
                   0, crfD(ctx->opcode));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* cmpli */
 | 
			
		||||
static void gen_cmpli(DisasContext *ctx)
 | 
			
		||||
{
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
 | 
			
		||||
    if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
 | 
			
		||||
        gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
 | 
			
		||||
                      0, crfD(ctx->opcode));
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
    } else {
 | 
			
		||||
        gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
 | 
			
		||||
                    0, crfD(ctx->opcode));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* isel (PowerPC 2.03 specification) */
 | 
			
		||||
@@ -756,11 +754,9 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
 | 
			
		||||
        tcg_gen_andc_tl(cpu_ov, cpu_ov, t0);
 | 
			
		||||
    }
 | 
			
		||||
    tcg_temp_free(t0);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!ctx->sf_mode) {
 | 
			
		||||
    if (NARROW_MODE(ctx)) {
 | 
			
		||||
        tcg_gen_ext32s_tl(cpu_ov, cpu_ov);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    tcg_gen_shri_tl(cpu_ov, cpu_ov, TARGET_LONG_BITS - 1);
 | 
			
		||||
    tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
 | 
			
		||||
}
 | 
			
		||||
@@ -778,14 +774,26 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (compute_ca) {
 | 
			
		||||
        TCGv zero = tcg_const_tl(0);
 | 
			
		||||
        if (add_ca) {
 | 
			
		||||
            tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero);
 | 
			
		||||
            tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero);
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            TCGv t1 = tcg_temp_new();
 | 
			
		||||
            tcg_gen_ext32u_tl(t1, arg2);
 | 
			
		||||
            tcg_gen_ext32u_tl(t0, arg1);
 | 
			
		||||
            tcg_gen_add_tl(t0, t0, t1);
 | 
			
		||||
            tcg_temp_free(t1);
 | 
			
		||||
            if (add_ca) {
 | 
			
		||||
                tcg_gen_add_tl(t0, t0, cpu_ca);
 | 
			
		||||
            }
 | 
			
		||||
            tcg_gen_shri_tl(cpu_ca, t0, 32);
 | 
			
		||||
        } else {
 | 
			
		||||
            tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
 | 
			
		||||
            TCGv zero = tcg_const_tl(0);
 | 
			
		||||
            if (add_ca) {
 | 
			
		||||
                tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero);
 | 
			
		||||
                tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero);
 | 
			
		||||
            } else {
 | 
			
		||||
                tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
 | 
			
		||||
            }
 | 
			
		||||
            tcg_temp_free(zero);
 | 
			
		||||
        }
 | 
			
		||||
        tcg_temp_free(zero);
 | 
			
		||||
    } else {
 | 
			
		||||
        tcg_gen_add_tl(t0, arg1, arg2);
 | 
			
		||||
        if (add_ca) {
 | 
			
		||||
@@ -1114,14 +1122,25 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
 | 
			
		||||
{
 | 
			
		||||
    TCGv t0 = ret;
 | 
			
		||||
 | 
			
		||||
    if (((add_ca && compute_ca) || compute_ov)
 | 
			
		||||
        && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2)))  {
 | 
			
		||||
    if (compute_ov && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2)))  {
 | 
			
		||||
        t0 = tcg_temp_new();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (add_ca) {
 | 
			
		||||
        /* dest = ~arg1 + arg2 + ca.  */
 | 
			
		||||
        if (compute_ca) {
 | 
			
		||||
    if (compute_ca) {
 | 
			
		||||
        /* dest = ~arg1 + arg2 [+ ca].  */
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            TCGv inv1 = tcg_temp_new();
 | 
			
		||||
            tcg_gen_not_tl(inv1, arg1);
 | 
			
		||||
            tcg_gen_ext32u_tl(t0, arg2);
 | 
			
		||||
            tcg_gen_ext32u_tl(inv1, inv1);
 | 
			
		||||
            if (add_ca) {
 | 
			
		||||
                tcg_gen_add_tl(t0, t0, cpu_ca);
 | 
			
		||||
            } else {
 | 
			
		||||
                tcg_gen_addi_tl(t0, t0, 1);
 | 
			
		||||
            }
 | 
			
		||||
            tcg_gen_add_tl(t0, t0, inv1);
 | 
			
		||||
            tcg_gen_shri_tl(cpu_ca, t0, 32);
 | 
			
		||||
        } else if (add_ca) {
 | 
			
		||||
            TCGv zero, inv1 = tcg_temp_new();
 | 
			
		||||
            tcg_gen_not_tl(inv1, arg1);
 | 
			
		||||
            zero = tcg_const_tl(0);
 | 
			
		||||
@@ -1130,14 +1149,16 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
 | 
			
		||||
            tcg_temp_free(zero);
 | 
			
		||||
            tcg_temp_free(inv1);
 | 
			
		||||
        } else {
 | 
			
		||||
            tcg_gen_sub_tl(t0, arg2, arg1);
 | 
			
		||||
            tcg_gen_add_tl(t0, t0, cpu_ca);
 | 
			
		||||
            tcg_gen_subi_tl(t0, t0, 1);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (compute_ca) {
 | 
			
		||||
            tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1);
 | 
			
		||||
            tcg_gen_sub_tl(t0, arg2, arg1);
 | 
			
		||||
        }
 | 
			
		||||
    } else if (add_ca) {
 | 
			
		||||
        /* Since we're ignoring carry-out, we can simplify the
 | 
			
		||||
           standard ~arg1 + arg2 + ca to arg2 - arg1 + ca - 1.  */
 | 
			
		||||
        tcg_gen_sub_tl(t0, arg2, arg1);
 | 
			
		||||
        tcg_gen_add_tl(t0, t0, cpu_ca);
 | 
			
		||||
        tcg_gen_subi_tl(t0, t0, 1);
 | 
			
		||||
    } else {
 | 
			
		||||
        tcg_gen_sub_tl(t0, arg2, arg1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -2311,45 +2332,37 @@ static inline void gen_addr_imm_index(DisasContext *ctx, TCGv EA,
 | 
			
		||||
 | 
			
		||||
    simm &= ~maskl;
 | 
			
		||||
    if (rA(ctx->opcode) == 0) {
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!ctx->sf_mode) {
 | 
			
		||||
            tcg_gen_movi_tl(EA, (uint32_t)simm);
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            simm = (uint32_t)simm;
 | 
			
		||||
        }
 | 
			
		||||
        tcg_gen_movi_tl(EA, simm);
 | 
			
		||||
    } else if (likely(simm != 0)) {
 | 
			
		||||
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!ctx->sf_mode) {
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            tcg_gen_ext32u_tl(EA, EA);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
    } else {
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!ctx->sf_mode) {
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
 | 
			
		||||
        } else {
 | 
			
		||||
            tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void gen_addr_reg_index(DisasContext *ctx, TCGv EA)
 | 
			
		||||
{
 | 
			
		||||
    if (rA(ctx->opcode) == 0) {
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!ctx->sf_mode) {
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            tcg_gen_ext32u_tl(EA, cpu_gpr[rB(ctx->opcode)]);
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
        tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
 | 
			
		||||
        } else {
 | 
			
		||||
            tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!ctx->sf_mode) {
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            tcg_gen_ext32u_tl(EA, EA);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2357,13 +2370,10 @@ static inline void gen_addr_register(DisasContext *ctx, TCGv EA)
 | 
			
		||||
{
 | 
			
		||||
    if (rA(ctx->opcode) == 0) {
 | 
			
		||||
        tcg_gen_movi_tl(EA, 0);
 | 
			
		||||
    } else if (NARROW_MODE(ctx)) {
 | 
			
		||||
        tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
 | 
			
		||||
    } else {
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!ctx->sf_mode) {
 | 
			
		||||
            tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
            tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
 | 
			
		||||
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2371,11 +2381,9 @@ static inline void gen_addr_add(DisasContext *ctx, TCGv ret, TCGv arg1,
 | 
			
		||||
                                target_long val)
 | 
			
		||||
{
 | 
			
		||||
    tcg_gen_addi_tl(ret, arg1, val);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!ctx->sf_mode) {
 | 
			
		||||
    if (NARROW_MODE(ctx)) {
 | 
			
		||||
        tcg_gen_ext32u_tl(ret, ret);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
 | 
			
		||||
@@ -3320,10 +3328,9 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
 | 
			
		||||
{
 | 
			
		||||
    TranslationBlock *tb;
 | 
			
		||||
    tb = ctx->tb;
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!ctx->sf_mode)
 | 
			
		||||
    if (NARROW_MODE(ctx)) {
 | 
			
		||||
        dest = (uint32_t) dest;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
 | 
			
		||||
        likely(!ctx->singlestep_enabled)) {
 | 
			
		||||
        tcg_gen_goto_tb(n);
 | 
			
		||||
@@ -3351,12 +3358,10 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
 | 
			
		||||
 | 
			
		||||
static inline void gen_setlr(DisasContext *ctx, target_ulong nip)
 | 
			
		||||
{
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (ctx->sf_mode == 0)
 | 
			
		||||
        tcg_gen_movi_tl(cpu_lr, (uint32_t)nip);
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
        tcg_gen_movi_tl(cpu_lr, nip);
 | 
			
		||||
    if (NARROW_MODE(ctx)) {
 | 
			
		||||
        nip = (uint32_t)nip;
 | 
			
		||||
    }
 | 
			
		||||
    tcg_gen_movi_tl(cpu_lr, nip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* b ba bl bla */
 | 
			
		||||
@@ -3366,18 +3371,16 @@ static void gen_b(DisasContext *ctx)
 | 
			
		||||
 | 
			
		||||
    ctx->exception = POWERPC_EXCP_BRANCH;
 | 
			
		||||
    /* sign extend LI */
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (ctx->sf_mode)
 | 
			
		||||
        li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
        li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
 | 
			
		||||
    if (likely(AA(ctx->opcode) == 0))
 | 
			
		||||
    li = LI(ctx->opcode);
 | 
			
		||||
    li = (li ^ 0x02000000) - 0x02000000;
 | 
			
		||||
    if (likely(AA(ctx->opcode) == 0)) {
 | 
			
		||||
        target = ctx->nip + li - 4;
 | 
			
		||||
    else
 | 
			
		||||
    } else {
 | 
			
		||||
        target = li;
 | 
			
		||||
    if (LK(ctx->opcode))
 | 
			
		||||
    }
 | 
			
		||||
    if (LK(ctx->opcode)) {
 | 
			
		||||
        gen_setlr(ctx, ctx->nip);
 | 
			
		||||
    }
 | 
			
		||||
    gen_update_cfar(ctx, ctx->nip);
 | 
			
		||||
    gen_goto_tb(ctx, 0, target);
 | 
			
		||||
}
 | 
			
		||||
@@ -3413,12 +3416,11 @@ static inline void gen_bcond(DisasContext *ctx, int type)
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!ctx->sf_mode)
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            tcg_gen_ext32u_tl(temp, cpu_ctr);
 | 
			
		||||
        else
 | 
			
		||||
#endif
 | 
			
		||||
        } else {
 | 
			
		||||
            tcg_gen_mov_tl(temp, cpu_ctr);
 | 
			
		||||
        }
 | 
			
		||||
        if (bo & 0x2) {
 | 
			
		||||
            tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -3452,20 +3454,14 @@ static inline void gen_bcond(DisasContext *ctx, int type)
 | 
			
		||||
        gen_set_label(l1);
 | 
			
		||||
        gen_goto_tb(ctx, 1, ctx->nip);
 | 
			
		||||
    } else {
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!(ctx->sf_mode))
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3);
 | 
			
		||||
        else
 | 
			
		||||
#endif
 | 
			
		||||
        } else {
 | 
			
		||||
            tcg_gen_andi_tl(cpu_nip, target, ~3);
 | 
			
		||||
        }
 | 
			
		||||
        tcg_gen_exit_tb(0);
 | 
			
		||||
        gen_set_label(l1);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!(ctx->sf_mode))
 | 
			
		||||
            tcg_gen_movi_tl(cpu_nip, (uint32_t)ctx->nip);
 | 
			
		||||
        else
 | 
			
		||||
#endif
 | 
			
		||||
            tcg_gen_movi_tl(cpu_nip, ctx->nip);
 | 
			
		||||
        gen_update_nip(ctx, ctx->nip);
 | 
			
		||||
        tcg_gen_exit_tb(0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4324,15 +4320,14 @@ static void gen_tlbie(DisasContext *ctx)
 | 
			
		||||
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    if (!ctx->sf_mode) {
 | 
			
		||||
    if (NARROW_MODE(ctx)) {
 | 
			
		||||
        TCGv t0 = tcg_temp_new();
 | 
			
		||||
        tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
 | 
			
		||||
        gen_helper_tlbie(cpu_env, t0);
 | 
			
		||||
        tcg_temp_free(t0);
 | 
			
		||||
    } else
 | 
			
		||||
#endif
 | 
			
		||||
    } else {
 | 
			
		||||
        gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -7577,11 +7572,9 @@ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh)
 | 
			
		||||
        tcg_gen_movi_tl(EA, uimm << sh);
 | 
			
		||||
    } else {
 | 
			
		||||
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
        if (!ctx->sf_mode) {
 | 
			
		||||
        if (NARROW_MODE(ctx)) {
 | 
			
		||||
            tcg_gen_ext32u_tl(EA, EA);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -9428,7 +9421,6 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf,
 | 
			
		||||
    case POWERPC_MMU_SOFT_6xx:
 | 
			
		||||
    case POWERPC_MMU_SOFT_74xx:
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
    case POWERPC_MMU_620:
 | 
			
		||||
    case POWERPC_MMU_64B:
 | 
			
		||||
#endif
 | 
			
		||||
        cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]);
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,8 @@
 | 
			
		||||
#include "sysemu/arch_init.h"
 | 
			
		||||
#include "sysemu/cpus.h"
 | 
			
		||||
#include "cpu-models.h"
 | 
			
		||||
#include "mmu-hash32.h"
 | 
			
		||||
#include "mmu-hash64.h"
 | 
			
		||||
 | 
			
		||||
//#define PPC_DUMP_CPU
 | 
			
		||||
//#define PPC_DEBUG_SPR
 | 
			
		||||
@@ -365,7 +367,6 @@ static void spr_write_sdr1 (void *opaque, int sprn, int gprn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 64 bits PowerPC specific SPRs */
 | 
			
		||||
/* ASR */
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
static void spr_read_hior (void *opaque, int gprn, int sprn)
 | 
			
		||||
{
 | 
			
		||||
@@ -379,16 +380,6 @@ static void spr_write_hior (void *opaque, int sprn, int gprn)
 | 
			
		||||
    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
 | 
			
		||||
    tcg_temp_free(t0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spr_read_asr (void *opaque, int gprn, int sprn)
 | 
			
		||||
{
 | 
			
		||||
    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, asr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spr_write_asr (void *opaque, int sprn, int gprn)
 | 
			
		||||
{
 | 
			
		||||
    gen_helper_store_asr(cpu_env, cpu_gpr[gprn]);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -1028,6 +1019,54 @@ static void gen_spr_7xx (CPUPPCState *env)
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_PPC64
 | 
			
		||||
#ifndef CONFIG_USER_ONLY
 | 
			
		||||
static void spr_read_uamr (void *opaque, int gprn, int sprn)
 | 
			
		||||
{
 | 
			
		||||
    gen_load_spr(cpu_gpr[gprn], SPR_AMR);
 | 
			
		||||
    spr_load_dump_spr(SPR_AMR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spr_write_uamr (void *opaque, int sprn, int gprn)
 | 
			
		||||
{
 | 
			
		||||
    gen_store_spr(SPR_AMR, cpu_gpr[gprn]);
 | 
			
		||||
    spr_store_dump_spr(SPR_AMR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spr_write_uamr_pr (void *opaque, int sprn, int gprn)
 | 
			
		||||
{
 | 
			
		||||
    TCGv t0 = tcg_temp_new();
 | 
			
		||||
 | 
			
		||||
    gen_load_spr(t0, SPR_UAMOR);
 | 
			
		||||
    tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
 | 
			
		||||
    gen_store_spr(SPR_AMR, t0);
 | 
			
		||||
    spr_store_dump_spr(SPR_AMR);
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_USER_ONLY */
 | 
			
		||||
 | 
			
		||||
static void gen_spr_amr (CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
#ifndef CONFIG_USER_ONLY
 | 
			
		||||
    /* Virtual Page Class Key protection */
 | 
			
		||||
    /* The AMR is accessible either via SPR 13 or SPR 29.  13 is
 | 
			
		||||
     * userspace accessible, 29 is privileged.  So we only need to set
 | 
			
		||||
     * the kvm ONE_REG id on one of them, we use 29 */
 | 
			
		||||
    spr_register(env, SPR_UAMR, "UAMR",
 | 
			
		||||
                 &spr_read_uamr, &spr_write_uamr_pr,
 | 
			
		||||
                 &spr_read_uamr, &spr_write_uamr,
 | 
			
		||||
                 0);
 | 
			
		||||
    spr_register_kvm(env, SPR_AMR, "AMR",
 | 
			
		||||
                     SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                     &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                     KVM_REG_PPC_AMR, 0xffffffffffffffffULL);
 | 
			
		||||
    spr_register_kvm(env, SPR_UAMOR, "UAMOR",
 | 
			
		||||
                     SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                     &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                     KVM_REG_PPC_UAMOR, 0);
 | 
			
		||||
#endif /* !CONFIG_USER_ONLY */
 | 
			
		||||
}
 | 
			
		||||
#endif /* TARGET_PPC64 */
 | 
			
		||||
 | 
			
		||||
static void gen_spr_thrm (CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    /* Thermal management */
 | 
			
		||||
@@ -2151,173 +2190,6 @@ static void gen_spr_compress (CPUPPCState *env)
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined (TARGET_PPC64)
 | 
			
		||||
/* SPR specific to PowerPC 620 */
 | 
			
		||||
static void gen_spr_620 (CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    /* Processor identification */
 | 
			
		||||
    spr_register(env, SPR_PIR, "PIR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_pir,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    spr_register(env, SPR_ASR, "ASR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_asr, &spr_write_asr,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* Breakpoints */
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_IABR, "IABR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_DABR, "DABR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_SIAR, "SIAR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, SPR_NOACCESS,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_SDA, "SDA",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, SPR_NOACCESS,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMC1R, "PMC1",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, SPR_NOACCESS,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    spr_register(env, SPR_620_PMC1W, "PMC1",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                  SPR_NOACCESS, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMC2R, "PMC2",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, SPR_NOACCESS,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    spr_register(env, SPR_620_PMC2W, "PMC2",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                  SPR_NOACCESS, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_MMCR0R, "MMCR0",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, SPR_NOACCESS,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    spr_register(env, SPR_620_MMCR0W, "MMCR0",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                  SPR_NOACCESS, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* External access control */
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_EAR, "EAR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
#if 0 // XXX: check this
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR0, "PMR0",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR1, "PMR1",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR2, "PMR2",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR3, "PMR3",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR4, "PMR4",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR5, "PMR5",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR6, "PMR6",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR7, "PMR7",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR8, "PMR8",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMR9, "PMR9",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMRA, "PMR10",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMRB, "PMR11",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMRC, "PMR12",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMRD, "PMR13",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMRE, "PMR14",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_PMRF, "PMR15",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
#endif
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_BUSCSR, "BUSCSR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_L2CR, "L2CR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_620_L2SR, "L2SR",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
}
 | 
			
		||||
#endif /* defined (TARGET_PPC64) */
 | 
			
		||||
 | 
			
		||||
static void gen_spr_5xx_8xx (CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    /* Exception processing */
 | 
			
		||||
@@ -2993,31 +2865,6 @@ static void init_excp_604 (CPUPPCState *env)
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
static void init_excp_620 (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_ISI]      = 0x00000400;
 | 
			
		||||
    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_SYSCALL]  = 0x00000C00;
 | 
			
		||||
    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
 | 
			
		||||
    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
 | 
			
		||||
    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
 | 
			
		||||
    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
 | 
			
		||||
    env->hreset_excp_prefix = 0xFFF00000UL;
 | 
			
		||||
    /* Hardware reset vector */
 | 
			
		||||
    env->hreset_vector = 0x0000000000000100ULL;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
#endif /* defined(TARGET_PPC64) */
 | 
			
		||||
 | 
			
		||||
static void init_excp_7x0 (CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
@@ -4951,6 +4798,9 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000000FD70ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_601;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_601;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_601;
 | 
			
		||||
@@ -4985,7 +4835,9 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000000FD70ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_601;
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_601;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_601;
 | 
			
		||||
    pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK;
 | 
			
		||||
@@ -5192,6 +5044,9 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_604;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_604;
 | 
			
		||||
@@ -5258,6 +5113,9 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_604;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_604;
 | 
			
		||||
@@ -5311,6 +5169,9 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_7x0;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_750;
 | 
			
		||||
@@ -5372,6 +5233,9 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_7x0;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_750;
 | 
			
		||||
@@ -5556,6 +5420,9 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_7x0;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_750;
 | 
			
		||||
@@ -5621,6 +5488,9 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_7x0;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_750;
 | 
			
		||||
@@ -5691,6 +5561,9 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_7x0;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_750;
 | 
			
		||||
@@ -5761,6 +5634,9 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_7x0;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_750;
 | 
			
		||||
@@ -5953,6 +5829,9 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000205FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_74xx;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_7400;
 | 
			
		||||
@@ -6019,6 +5898,9 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x000000000205FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_32B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_74xx;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc_7400;
 | 
			
		||||
@@ -6725,6 +6607,9 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x900000000204FF36ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_64B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_970;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_970;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc64;
 | 
			
		||||
@@ -6835,6 +6720,9 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x800000000204FF36ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_64B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_970;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_970;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc64;
 | 
			
		||||
@@ -6933,6 +6821,9 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x800000000204FF36ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_64B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_970;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_970;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc64;
 | 
			
		||||
@@ -7031,6 +6922,9 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x900000000204FF36ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_64B;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_970;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_970;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc64;
 | 
			
		||||
@@ -7075,6 +6969,7 @@ static void init_proc_POWER7 (CPUPPCState *env)
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, SPR_NOACCESS,
 | 
			
		||||
                 0x00000000); /* TOFIX */
 | 
			
		||||
    gen_spr_amr(env);
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_CTRL, "SPR_CTRLT",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
@@ -7122,6 +7017,9 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 | 
			
		||||
    pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX;
 | 
			
		||||
    pcc->msr_mask = 0x800000000204FF36ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_2_06;
 | 
			
		||||
#if defined(CONFIG_SOFTMMU)
 | 
			
		||||
    pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
 | 
			
		||||
#endif
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_POWER7;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc64;
 | 
			
		||||
@@ -7129,55 +7027,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 | 
			
		||||
                 POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
 | 
			
		||||
                 POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void init_proc_620 (CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    gen_spr_ne_601(env);
 | 
			
		||||
    gen_spr_620(env);
 | 
			
		||||
    /* Time base */
 | 
			
		||||
    gen_tbl(env);
 | 
			
		||||
    /* Hardware implementation registers */
 | 
			
		||||
    /* XXX : not implemented */
 | 
			
		||||
    spr_register(env, SPR_HID0, "HID0",
 | 
			
		||||
                 SPR_NOACCESS, SPR_NOACCESS,
 | 
			
		||||
                 &spr_read_generic, &spr_write_generic,
 | 
			
		||||
                 0x00000000);
 | 
			
		||||
    /* Memory management */
 | 
			
		||||
    gen_low_BATs(env);
 | 
			
		||||
    init_excp_620(env);
 | 
			
		||||
    env->dcache_line_size = 64;
 | 
			
		||||
    env->icache_line_size = 64;
 | 
			
		||||
    /* Allocate hardware IRQ controller */
 | 
			
		||||
    ppc6xx_irq_init(env);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
POWERPC_FAMILY(620)(ObjectClass *oc, void *data)
 | 
			
		||||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(oc);
 | 
			
		||||
    PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
 | 
			
		||||
 | 
			
		||||
    dc->desc = "PowerPC 620";
 | 
			
		||||
    pcc->init_proc = init_proc_620;
 | 
			
		||||
    pcc->check_pow = check_pow_nocheck; /* Check this */
 | 
			
		||||
    pcc->insns_flags = 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_DCBZ |
 | 
			
		||||
                       PPC_MEM_SYNC | PPC_MEM_EIEIO |
 | 
			
		||||
                       PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
 | 
			
		||||
                       PPC_SEGMENT | PPC_EXTERN |
 | 
			
		||||
                       PPC_64B | PPC_SLBI;
 | 
			
		||||
    pcc->insns_flags2 = PPC_NONE;
 | 
			
		||||
    pcc->msr_mask = 0x800000000005FF77ULL;
 | 
			
		||||
    pcc->mmu_model = POWERPC_MMU_620;
 | 
			
		||||
    pcc->excp_model = POWERPC_EXCP_970;
 | 
			
		||||
    pcc->bus_model = PPC_FLAGS_INPUT_6xx;
 | 
			
		||||
    pcc->bfd_mach = bfd_mach_ppc64;
 | 
			
		||||
    pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
 | 
			
		||||
                 POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* defined (TARGET_PPC64) */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -7693,7 +7542,7 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
 | 
			
		||||
        return 8;
 | 
			
		||||
    }
 | 
			
		||||
    if (n == 32) {
 | 
			
		||||
        /* FPSCR not implemented  */
 | 
			
		||||
        helper_store_fpscr(env, ldl_p(mem_buf), 0xffffffff);
 | 
			
		||||
        return 4;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
@@ -7915,9 +7764,6 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
 | 
			
		||||
        case POWERPC_MMU_64B:
 | 
			
		||||
            mmu_model = "PowerPC 64";
 | 
			
		||||
            break;
 | 
			
		||||
        case POWERPC_MMU_620:
 | 
			
		||||
            mmu_model = "PowerPC 620";
 | 
			
		||||
            break;
 | 
			
		||||
#endif
 | 
			
		||||
        default:
 | 
			
		||||
            mmu_model = "Unknown or invalid";
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								target-ppc/user_only_helper.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								target-ppc/user_only_helper.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  PowerPC MMU stub handling for user mode emulation
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (c) 2003-2007 Jocelyn Mayer
 | 
			
		||||
 *  Copyright (c) 2013 David Gibson, IBM Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "cpu.h"
 | 
			
		||||
 | 
			
		||||
int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
 | 
			
		||||
                         int mmu_idx)
 | 
			
		||||
{
 | 
			
		||||
    int exception, error_code;
 | 
			
		||||
 | 
			
		||||
    if (rw == 2) {
 | 
			
		||||
        exception = POWERPC_EXCP_ISI;
 | 
			
		||||
        error_code = 0x40000000;
 | 
			
		||||
    } else {
 | 
			
		||||
        exception = POWERPC_EXCP_DSI;
 | 
			
		||||
        error_code = 0x40000000;
 | 
			
		||||
        if (rw) {
 | 
			
		||||
            error_code |= 0x02000000;
 | 
			
		||||
        }
 | 
			
		||||
        env->spr[SPR_DAR] = address;
 | 
			
		||||
        env->spr[SPR_DSISR] = error_code;
 | 
			
		||||
    }
 | 
			
		||||
    env->exception_index = exception;
 | 
			
		||||
    env->error_code = error_code;
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user