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