From a4e044c30e0044947fd0d69b1888d916f96bba6b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 14 Mar 2013 17:59:29 +0000 Subject: pseries: Fix breakage in CPU QOM conversion Commit 259186a7d2f7184efc96ae99bc5658e6159f53ad "cpu: Move halted and interrupt_request fields to CPUState" broke the pseries machine. That's because it uses CPU() instead of ENV_GET_CPU() to convert from the global first_cpu pointer (still a CPUArchState) to a CPUState. This patch fixes the breakage. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/ppc') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f355a9bb84..d45098d096 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -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; -- cgit 1.4.1 From 89dfd6e1b3c0b31ef700203808be2a9a71947d1d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 13 Mar 2013 15:53:25 +0000 Subject: pseries: Remove "busname" property for PCI host bridge Currently the "spapr-pci-host-bridge" device has a "busname" property which can be used to override the default assignment of qbus names for the bus subordinate to the PHB. We use that for the default primary PCI bus, to make libvirt happy, which expects there to be a bus named simply "pci". The default qdev core logic would name the bus "pci.0", and the pseries code would otherwise name it "pci@800000020000000" which is the name it is given in the device tree based on its BUID. The "busname" property is rather clunky though, so this patch simplifies things by just using a special case hack for the default PHB, setting busname to "pci" when index=0. Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 2 +- hw/spapr_pci.c | 30 ++++++++++++++++++++++-------- hw/spapr_pci.h | 4 +--- 3 files changed, 24 insertions(+), 12 deletions(-) (limited to 'hw/ppc') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index d45098d096..74ae83bb77 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -856,7 +856,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]; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 36adbc5592..42c8b61c74 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -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); diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index 8bb3c62c3d..8bd8a663c5 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -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, -- cgit 1.4.1 From 7b5651605836fd29572fd4c8769af5378d351712 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 13 Mar 2013 15:53:28 +0000 Subject: pseries: Move XICS initialization before cpu initialization Currently, the pseries machine initializes the cpus, then the XICS interrupt controller. However, to support the upcoming in-kernel XICS implementation we will need to initialize the irq controller before the vcpus. This patch makes the necesssary rearrangement. This means the xics init code can no longer auto-detect the number of cpus ("interrupt servers" in XICS terminology) and so we must pass that in explicitly from the platform code. Signed-off-by: Michael Ellerman Signed-off-by: Ben Herrenschmidt Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 12 +++++++----- hw/ppc/xics.c | 57 +++++++++++++++++++++++++-------------------------------- hw/xics.h | 3 ++- 3 files changed, 34 insertions(+), 38 deletions(-) (limited to 'hw/ppc') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 74ae83bb77..7b2a11fbe4 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -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); diff --git a/hw/ppc/xics.c b/hw/ppc/xics.c index c3ef12fff4..374da5bbfd 100644 --- a/hw/ppc/xics.c +++ b/hw/ppc/xics.c @@ -521,45 +521,38 @@ static void xics_reset(void *opaque) } } -struct icp_state *xics_system_init(int nr_irqs) +void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu) { - CPUPPCState *env; - CPUState *cpu; - int max_server_num; - struct icp_state *icp; - struct ics_state *ics; + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + struct icp_server_state *ss = &icp->ss[cs->cpu_index]; - 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; - } - } + assert(cs->cpu_index < icp->nr_servers); - icp = g_malloc0(sizeof(*icp)); - icp->nr_servers = max_server_num + 1; - icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_POWER7: + ss->output = env->irq_inputs[POWER7_INPUT_INT]; + break; - 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]; + case PPC_FLAGS_INPUT_970: + ss->output = env->irq_inputs[PPC970_INPUT_INT]; + break; - switch (PPC_INPUT(env)) { - case PPC_FLAGS_INPUT_POWER7: - ss->output = env->irq_inputs[POWER7_INPUT_INT]; - break; + default: + fprintf(stderr, "XICS interrupt controller does not support this CPU " + "bus model\n"); + abort(); + } +} - case PPC_FLAGS_INPUT_970: - ss->output = env->irq_inputs[PPC970_INPUT_INT]; - break; +struct icp_state *xics_system_init(int nr_servers, int nr_irqs) +{ + struct icp_state *icp; + struct ics_state *ics; - default: - hw_error("XICS interrupt model does not support this CPU bus " - "model\n"); - exit(1); - } - } + icp = g_malloc0(sizeof(*icp)); + icp->nr_servers = nr_servers; + icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); ics = g_malloc0(sizeof(*ics)); ics->nr_irqs = nr_irqs; diff --git a/hw/xics.h b/hw/xics.h index c3bf0083e2..6bce0424df 100644 --- a/hw/xics.h +++ b/hw/xics.h @@ -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__ */ -- cgit 1.4.1 From d5aea6f367d25b630a952a5a0c8289add774a8e8 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 12 Mar 2013 00:31:18 +0000 Subject: mmu-hash*: Add header file for definitions Currently cpu.h contains a number of definitions relating to the 64-bit hash MMU. Some are used in the MMU emulation code, but some are only used in the spapr MMU management hcall implementations. This patch moves these definitions (except for a few that are needed more widely) into mmu-hash64.h header, shared between the MMU emulation code and the spapr hcall code. The MMU emulation code is also updated to actually use a number of those definitions in place of hard coded constants. Similarly, we add new analogous definitions to mmu-hash32.h and use those in place of many hard-coded constants in mmu-hash32.c Signed-off-by: David Gibson [agraf: fix 32-bit hosts] Signed-off-by: Alexander Graf --- hw/ppc/spapr_hcall.c | 70 ++++++++++++-------------------------------- target-ppc/cpu.h | 24 --------------- target-ppc/kvm.c | 1 + target-ppc/mmu-hash32.c | 78 +++++++++++++++++++++---------------------------- target-ppc/mmu-hash32.h | 61 ++++++++++++++++++++++++++++++++++++++ target-ppc/mmu-hash64.c | 35 +++++++++------------- target-ppc/mmu-hash64.h | 62 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 190 insertions(+), 141 deletions(-) (limited to 'hw/ppc') diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index dd72743b52..7be743c723 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -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) { @@ -87,7 +55,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint8_t *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; } } @@ -134,7 +102,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, if (i == 8) { return H_PTEG_FULL; } - if ((ldq_p(hpte) & HPTE_V_VALID) == 0) { + if ((ldq_p(hpte) & HPTE64_V_VALID) == 0) { break; } hpte += HASH_PTE_SIZE_64; @@ -142,7 +110,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, } else { i = 0; hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - if (ldq_p(hpte) & HPTE_V_VALID) { + if (ldq_p(hpte) & HPTE64_V_VALID) { return H_PTEG_FULL; } } @@ -178,7 +146,7 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, v = ldq_p(hpte); r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); - 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; @@ -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: @@ -304,18 +272,18 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, v = ldq_p(hpte); r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); - 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); + stq_p(hpte, v & ~HPTE64_V_VALID); ppc_tlb_invalidate_one(env, rb); stq_p(hpte + (HASH_PTE_SIZE_64/2), r); /* Don't need a memory barrier, due to qemu's global lock */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e5f46b3418..e96afa61ec 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -394,36 +394,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)) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 9870d60884..597066f5a0 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -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" diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c index 5b48aa8486..a1bbd50398 100644 --- a/target-ppc/mmu-hash32.c +++ b/target-ppc/mmu-hash32.c @@ -51,7 +51,6 @@ struct mmu_ctx_hash32 { int nx; /* Non-execute area */ }; -#define PTE_PTEM_MASK 0x7FFFFFBF #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) static int ppc_hash32_pp_check(int key, int pp, int nx) @@ -127,13 +126,13 @@ static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp, target_ulong bl; int pp, valid, prot; - bl = (*BATu & 0x00001FFC) << 15; + bl = (*BATu & BATU32_BL) << 15; valid = 0; prot = 0; - if (((msr_pr == 0) && (*BATu & 0x00000002)) || - ((msr_pr != 0) && (*BATu & 0x00000001))) { + if (((msr_pr == 0) && (*BATu & BATU32_VS)) || + ((msr_pr != 0) && (*BATu & BATU32_VP))) { valid = 1; - pp = *BATl & 0x00000003; + pp = *BATl & BATL32_PP; if (pp != 0) { prot = PAGE_READ | PAGE_EXEC; if (pp == 0x2) { @@ -153,17 +152,17 @@ static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp, target_ulong bl; int key, pp, valid, prot; - bl = (*BATl & 0x0000003F) << 17; + bl = (*BATl & BATL32_601_BL) << 17; LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n", - (uint8_t)(*BATl & 0x0000003F), bl, ~bl); + (uint8_t)(*BATl & BATL32_601_BL), bl, ~bl); prot = 0; - valid = (*BATl >> 6) & 1; + valid = !!(*BATl & BATL32_601_V); if (valid) { - pp = *BATu & 0x00000003; + pp = *BATu & BATU32_601_PP; if (msr_pr == 0) { - key = (*BATu >> 3) & 1; + key = !!(*BATu & BATU32_601_KS); } else { - key = (*BATu >> 2) & 1; + key = !!(*BATu & BATU32_601_KP); } prot = ppc_hash32_pp_check(key, pp, 0); } @@ -195,8 +194,8 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, for (i = 0; i < env->nb_BATs; i++) { BATu = &BATut[i]; BATl = &BATlt[i]; - BEPIu = *BATu & 0xF0000000; - BEPIl = *BATu & 0x0FFE0000; + BEPIu = *BATu & BATU32_BEPIU; + BEPIl = *BATu & BATU32_BEPIL; if (unlikely(env->mmu_model == POWERPC_MMU_601)) { hash32_bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl); } else { @@ -205,13 +204,13 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, 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, virtual, *BATu, *BATl); - if ((virtual & 0xF0000000) == BEPIu && - ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { + if ((virtual & BATU32_BEPIU) == BEPIu && + ((virtual & BATU32_BEPIL) & ~bl) == BEPIl) { /* BAT matches */ if (valid != 0) { /* Get physical address */ - ctx->raddr = (*BATl & 0xF0000000) | - ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | + ctx->raddr = (*BATl & BATL32_BRPNU) | + ((virtual & BATU32_BEPIL & bl) | (*BATl & BATL32_BRPNL)) | (virtual & 0x0001F000); /* Compute access rights */ ctx->prot = prot; @@ -232,8 +231,8 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, for (i = 0; i < 4; i++) { BATu = &BATut[i]; BATl = &BATlt[i]; - BEPIu = *BATu & 0xF0000000; - BEPIl = *BATu & 0x0FFE0000; + 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 " " @@ -248,28 +247,19 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, return ret; } - -static inline int pte_is_valid_hash32(target_ulong pte0) -{ - return pte0 & 0x80000000 ? 1 : 0; -} - static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0, target_ulong pte1, int h, int rw, int type) { - target_ulong ptem, mmask; - int access, ret, pteh, ptev, pp; + target_ulong mmask; + int access, ret, pp; ret = -1; /* Check validity and table match */ - ptev = pte_is_valid_hash32(pte0); - pteh = (pte0 >> 6) & 1; - if (ptev && h == pteh) { + if ((pte0 & HPTE32_V_VALID) && (h == !!(pte0 & HPTE32_V_SECONDARY))) { /* Check vsid & api */ - ptem = pte0 & PTE_PTEM_MASK; mmask = PTE_CHECK_MASK; - pp = pte1 & 0x00000003; - if (ptem == ctx->ptem) { + pp = pte1 & HPTE32_R_PP; + if (HPTE32_V_COMPARE(pte0, ctx->ptem)) { if (ctx->raddr != (hwaddr)-1ULL) { /* all matches should have equal RPN, WIMG & PP */ if ((ctx->raddr & mmask) != (pte1 & mmask)) { @@ -302,15 +292,15 @@ static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong int store = 0; /* Update page flags */ - if (!(*pte1p & 0x00000100)) { + if (!(*pte1p & HPTE32_R_R)) { /* Update accessed flag */ - *pte1p |= 0x00000100; + *pte1p |= HPTE32_R_R; store = 1; } - if (!(*pte1p & 0x00000080)) { + if (!(*pte1p & HPTE32_R_C)) { if (rw == 1 && ret == 0) { /* Update changed flag */ - *pte1p |= 0x00000080; + *pte1p |= HPTE32_R_C; store = 1; } else { /* Force page fault for first write access */ @@ -323,7 +313,7 @@ static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash) { - return (hash * HASH_PTE_SIZE_32 * 8) & env->htab_mask; + return (hash * HASH_PTEG_SIZE_32) & env->htab_mask; } /* PTE table lookup */ @@ -337,7 +327,7 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h, ret = -1; /* No entry found */ pteg_off = get_pteg_offset32(env, ctx->hash[h]); - for (i = 0; i < 8; i++) { + for (i = 0; i < HPTES_PER_GROUP; i++) { if (env->external_htab) { pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); @@ -413,11 +403,11 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, ctx->eaddr = eaddr; sr = env->sr[eaddr >> 28]; - ctx->key = (((sr & 0x20000000) && (pr != 0)) || - ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; - ds = sr & 0x80000000 ? 1 : 0; - ctx->nx = sr & 0x10000000 ? 1 : 0; - vsid = sr & 0x00FFFFFF; + ctx->key = (((sr & SR32_KP) && (pr != 0)) || + ((sr & SR32_KS) && (pr == 0))) ? 1 : 0; + ds = !!(sr & SR32_T); + ctx->nx = !!(sr & SR32_NX); + vsid = sr & SR32_VSID; target_page_bits = TARGET_PAGE_BITS; LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h index 3435aa5513..a09ccb3d38 100644 --- a/target-ppc/mmu-hash32.h +++ b/target-ppc/mmu-hash32.h @@ -8,6 +8,67 @@ 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_BEPIU 0xf0000000 +#define BATU32_BEPIL 0x0ffe0000 +#define BATU32_BEPI 0xfffe0000 +#define BATU32_BL 0x00001ffc +#define BATU32_VS 0x00000002 +#define BATU32_VP 0x00000001 + + +#define BATL32_BRPNU 0xf0000000 +#define BATL32_BRPNL 0x0ffe0000 +#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 + #endif /* CONFIG_USER_ONLY */ #endif /* __MMU_HASH32_H__ */ diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 3008be8ee9..f3223dd383 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -233,7 +233,6 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) * 64-bit hash table MMU handling */ -#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) static int ppc_hash64_pp_check(int key, int pp, int nx) @@ -304,29 +303,21 @@ static int ppc_hash64_check_prot(int prot, int rw, int access_type) return ret; } -static inline int pte64_is_valid(target_ulong pte0) -{ - return pte0 & 0x0000000000000001ULL ? 1 : 0; -} - static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0, target_ulong pte1, int h, int rw, int type) { - target_ulong ptem, mmask; - int access, ret, pteh, ptev, pp; + target_ulong mmask; + int access, ret, pp; ret = -1; /* Check validity and table match */ - ptev = pte64_is_valid(pte0); - pteh = (pte0 >> 1) & 1; - if (ptev && h == pteh) { + if ((pte0 & HPTE64_V_VALID) && (h == !!(pte0 & HPTE64_V_SECONDARY))) { /* Check vsid & api */ - ptem = pte0 & PTE64_PTEM_MASK; mmask = PTE64_CHECK_MASK; - pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004); - ctx->nx = (pte1 >> 2) & 1; /* No execute bit */ - ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */ - if (ptem == ctx->ptem) { + pp = (pte1 & HPTE64_R_PP) | ((pte1 & HPTE64_R_PP0) >> 61); + /* No execute if either noexec or guarded bits set */ + ctx->nx = (pte1 & HPTE64_R_N) || (pte1 & HPTE64_R_G); + if (HPTE64_V_COMPARE(pte0, ctx->ptem)) { if (ctx->raddr != (hwaddr)-1ULL) { /* all matches should have equal RPN, WIMG & PP */ if ((ctx->raddr & mmask) != (pte1 & mmask)) { @@ -360,15 +351,15 @@ static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx, int store = 0; /* Update page flags */ - if (!(*pte1p & 0x00000100)) { + if (!(*pte1p & HPTE64_R_R)) { /* Update accessed flag */ - *pte1p |= 0x00000100; + *pte1p |= HPTE64_R_R; store = 1; } - if (!(*pte1p & 0x00000080)) { + if (!(*pte1p & HPTE64_R_C)) { if (rw == 1 && ret == 0) { /* Update changed flag */ - *pte1p |= 0x00000080; + *pte1p |= HPTE64_R_C; store = 1; } else { /* Force page fault for first write access */ @@ -389,8 +380,8 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h, int ret, r; ret = -1; /* No entry found */ - pteg_off = (ctx->hash[h] * HASH_PTE_SIZE_64 * 8) & env->htab_mask; - for (i = 0; i < 8; i++) { + pteg_off = (ctx->hash[h] * HASH_PTEG_SIZE_64) & env->htab_mask; + for (i = 0; i < HPTES_PER_GROUP; i++) { if (env->external_htab) { pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h index 665d3b0247..80b86d91ae 100644 --- a/target-ppc/mmu-hash64.h +++ b/target-ppc/mmu-hash64.h @@ -11,6 +11,68 @@ 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_V_1TB_SEG 0x4000000000000000ULL +#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL + #endif /* CONFIG_USER_ONLY */ #endif /* !defined (__MMU_HASH64_H__) */ -- cgit 1.4.1 From dffdaf6162d20b992e34c4708969ed4de0353417 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 12 Mar 2013 00:31:19 +0000 Subject: mmu-hash*: Add hash pte load/store helpers On real hardware the ppc hash page table is stored in memory; accordingly our mmu emulation code can read a hash page table in guest memory. But, when paravirtualized under PAPR, the real hash page table is in host memory, accessible to the guest only via hypercalls. We model this by also allowing the MMU emulation code to access a specially allocated hash page table outside the guest's memory image. At present these two options are implemented with some ugly conditionals at each access point in the mmu emulation code. In the implementation of the PAPR hypercalls, we assume the external hash table. This patch cleans things up by adding helpers to load and store from the hash table for both 32-bit and 64-bit hash mmus. The 64-bit versions handle both the in-guest-memory and outside guest memory cases. The 32-bit versions only handle the in-guest-memory case since no 32-bit systems can have an external hash table at present. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc/spapr_hcall.c | 38 +++++++++++++++++++------------------- target-ppc/mmu-hash32.c | 18 ++++-------------- target-ppc/mmu-hash32.h | 28 ++++++++++++++++++++++++++++ target-ppc/mmu-hash64.c | 17 +++-------------- target-ppc/mmu-hash64.h | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 94 insertions(+), 47 deletions(-) (limited to 'hw/ppc') diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 7be743c723..22cfb7e674 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -52,7 +52,7 @@ 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 & HPTE64_V_LARGE) { @@ -97,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) & HPTE64_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) & HPTE64_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; @@ -134,17 +134,17 @@ 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 & HPTE64_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || @@ -153,7 +153,7 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, } *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; @@ -260,17 +260,17 @@ 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 & HPTE64_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { @@ -283,11 +283,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, 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 & ~HPTE64_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; } diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c index a1bbd50398..a7c2e356e8 100644 --- a/target-ppc/mmu-hash32.c +++ b/target-ppc/mmu-hash32.c @@ -328,13 +328,8 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h, ret = -1; /* No entry found */ pteg_off = get_pteg_offset32(env, ctx->hash[h]); for (i = 0; i < HPTES_PER_GROUP; i++) { - if (env->external_htab) { - pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); - pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); - } else { - pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); - pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); - } + pte0 = ppc_hash32_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_32); + pte1 = ppc_hash32_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_32); r = pte_check_hash32(ctx, pte0, pte1, h, rw, type); LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " " TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", @@ -371,13 +366,8 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h, /* Update page flags */ pte1 = ctx->raddr; if (ppc_hash32_pte_update_flags(ctx, &pte1, ret, rw) == 1) { - if (env->external_htab) { - stl_p(env->external_htab + pteg_off + (good * 8) + 4, - pte1); - } else { - stl_phys_notdirty(env->htab_base + pteg_off + - (good * 8) + 4, pte1); - } + ppc_hash32_store_hpte1(env, pteg_off + good * HASH_PTE_SIZE_32, + pte1); } } diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h index a09ccb3d38..2344184584 100644 --- a/target-ppc/mmu-hash32.h +++ b/target-ppc/mmu-hash32.h @@ -69,6 +69,34 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, #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); +} + #endif /* CONFIG_USER_ONLY */ #endif /* __MMU_HASH32_H__ */ diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index f3223dd383..30c25dd24b 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -382,13 +382,8 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h, ret = -1; /* No entry found */ pteg_off = (ctx->hash[h] * HASH_PTEG_SIZE_64) & env->htab_mask; for (i = 0; i < HPTES_PER_GROUP; i++) { - if (env->external_htab) { - pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); - pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); - } else { - pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); - pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); - } + pte0 = ppc_hash64_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_64); + pte1 = ppc_hash64_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_64); r = pte64_check(ctx, pte0, pte1, h, rw, type); LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " " @@ -426,13 +421,7 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h, /* Update page flags */ pte1 = ctx->raddr; if (ppc_hash64_pte_update_flags(ctx, &pte1, ret, rw) == 1) { - if (env->external_htab) { - stq_p(env->external_htab + pteg_off + (good * 16) + 8, - pte1); - } else { - stq_phys_notdirty(env->htab_base + pteg_off + - (good * 16) + 8, pte1); - } + ppc_hash64_store_hpte1(env, pteg_off + good * HASH_PTE_SIZE_64, pte1); } } diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h index 80b86d91ae..84576c0648 100644 --- a/target-ppc/mmu-hash64.h +++ b/target-ppc/mmu-hash64.h @@ -73,6 +73,46 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, #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); + } +} + #endif /* CONFIG_USER_ONLY */ #endif /* !defined (__MMU_HASH64_H__) */ -- cgit 1.4.1