[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-ppc] [PATCH 53/77] ppc: Add proper real mode translation support
From: |
Benjamin Herrenschmidt |
Subject: |
[Qemu-ppc] [PATCH 53/77] ppc: Add proper real mode translation support |
Date: |
Wed, 11 Nov 2015 11:28:06 +1100 |
This adds proper support for translating real mode addresses based
on the combination of HV and LPCR bits. This handles HRMOR offset
for hypervisor real mode, and both RMA and VRMA modes for guest
real mode. PAPR mode adjusts the offsets appropriately to match the
RMA used in TCG, but we need to limit to the max supported by the
implementation (16G).
Signed-off-by: Benjamin Herrenschmidt <address@hidden>
---
hw/ppc/spapr.c | 7 +++
target-ppc/mmu-hash64.c | 146 ++++++++++++++++++++++++++++++++++++++------
target-ppc/mmu-hash64.h | 1 +
target-ppc/translate_init.c | 10 ++-
4 files changed, 144 insertions(+), 20 deletions(-)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index d8a84ca..13fe2d5 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1741,6 +1741,13 @@ static void ppc_spapr_init(MachineState *machine)
spapr->vrma_adjust = 1;
spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
}
+
+ /* Actually we don't support unbounded RMA anymore since we
+ * added proper emulation of HV mode. The max we can get is
+ * 16G which also happens to be what we configure for PAPR
+ * mode so make sure we don't do anything bigger than that
+ */
+ spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
}
if (spapr->rma_size > node0_size) {
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 835245a..328998f 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -504,12 +504,41 @@ static void ppc_hash64_set_dsi(CPUState *cs, CPUPPCState
*env, uint64_t dar, uin
env->error_code = 0;
}
+static int64_t ppc_hash64_get_rmls(CPUPPCState *env)
+{
+ uint64_t lpcr = env->spr[SPR_LPCR];
+
+ /*
+ * This is the full 4 bits encoding of POWER8. Previous
+ * CPUs only support a subset of these but the filtering
+ * is done when writing LPCR
+ */
+ switch((lpcr & LPCR_RMLS) >> LPCR_RMLS_SHIFT) {
+ case 0x8: /* 32MB */
+ return 0x2000000ull;
+ case 0x3: /* 64MB */
+ return 0x4000000ull;
+ case 0x7: /* 128MB */
+ return 0x8000000ull;
+ case 0x4: /* 256MB */
+ return 0x10000000ull;
+ case 0x2: /* 1GB */
+ return 0x40000000ull;
+ case 0x1: /* 16GB */
+ return 0x400000000ull;
+ default:
+ /* What to do here ??? */
+ return 0;
+ }
+}
+
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,
int rwx, int mmu_idx)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- ppc_slb_t *slb;
+ ppc_slb_t *slb_ptr;
+ ppc_slb_t slb;
hwaddr pte_offset;
ppc_hash_pte64_t pte;
int pp_prot, amr_prot, prot;
@@ -519,11 +548,52 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
target_ulong eaddr,
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
+ /* Note on LPCR usage: 970 uses HID4, but our special variant
+ * of store_spr copies relevant fields into env->spr[SPR_LPCR].
+ * Similarily we filter unimplemented bits when storing into
+ * LPCR depending on the MMU version. This code can thus just
+ * use the LPCR "as-is".
+ */
+
/* 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 */
+ /* Translation is supposedly "off" */
+ /* In real mode the top 4 effective address bits are (mostly) ignored
*/
raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
+
+ /* In HV mode, add HRMOR if top EA bit is clear */
+ if (msr_hv) {
+ if (!(eaddr >> 63)) {
+ raddr |= env->spr[SPR_HRMOR];
+ }
+ } else {
+ /* Otherwise, check VPM for RMA vs VRMA */
+ if (env->spr[SPR_LPCR] & LPCR_VPM0) {
+ uint32_t vrmasd;
+ /* VRMA, we make up an SLB entry */
+ slb.vsid = SLB_VSID_VRMA;
+ vrmasd = (env->spr[SPR_LPCR] & LPCR_VRMASD) >>
LPCR_VRMASD_SHIFT;
+ slb.vsid |= (vrmasd << 4) & (SLB_VSID_L | SLB_VSID_LP);
+ slb.esid = SLB_ESID_V;
+ goto skip_slb;
+ }
+ /* RMA. Check bounds in RMLS */
+ if (raddr < ppc_hash64_get_rmls(env)) {
+ raddr |= env->spr[SPR_RMOR];
+ } else {
+ /* The access failed, generate the approriate interrupt */
+ if (rwx == 2) {
+ ppc_hash64_set_isi(cs, env, 0x08000000);
+ } else {
+ dsisr = 0x08000000;
+ if (rwx == 1) {
+ dsisr |= 0x02000000;
+ }
+ ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
+ }
+ return 1;
+ }
+ }
tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
TARGET_PAGE_SIZE);
@@ -531,9 +601,8 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
target_ulong eaddr,
}
/* 2. Translation is on, so look up the SLB */
- slb = slb_lookup(env, eaddr);
-
- if (!slb) {
+ slb_ptr = slb_lookup(env, eaddr);
+ if (!slb_ptr) {
if (rwx == 2) {
cs->exception_index = POWERPC_EXCP_ISEG;
env->error_code = 0;
@@ -545,14 +614,29 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
target_ulong eaddr,
return 1;
}
+ /* We grab a local copy because we can modify it (or get a
+ * pre-cooked one from the VRMA code
+ */
+ slb = *slb_ptr;
+
+ /* 2.5 Clamp L||LP in ISL mode */
+ if (env->spr[SPR_LPCR] & LPCR_ISL) {
+ slb.vsid &= ~SLB_VSID_LLP_MASK;
+ }
+
/* 3. Check for segment level no-execute violation */
- if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
+ if ((rwx == 2) && (slb.vsid & SLB_VSID_N)) {
ppc_hash64_set_isi(cs, env, 0x10000000);
return 1;
}
+ /* We go straight here for VRMA translations as none of the
+ * above applies in that case
+ */
+ skip_slb:
+
/* 4. Locate the PTE in the hash table */
- pte_offset = ppc_hash64_htab_lookup(env, slb, eaddr, &pte);
+ pte_offset = ppc_hash64_htab_lookup(env, &slb, eaddr, &pte);
if (pte_offset == -1) {
dsisr = 0x40000000;
if (rwx == 2) {
@@ -570,7 +654,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
target_ulong eaddr,
/* 5. Check access permissions */
- pp_prot = ppc_hash64_pte_prot(env, slb, pte);
+ pp_prot = ppc_hash64_pte_prot(env, &slb, pte);
amr_prot = ppc_hash64_amr_prot(env, pte);
prot = pp_prot & amr_prot;
@@ -615,7 +699,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
target_ulong eaddr,
/* 7. Determine the real address from the PTE */
- raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
+ raddr = ppc_hash64_pte_raddr(&slb, pte, eaddr);
tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
prot, mmu_idx, TARGET_PAGE_SIZE);
@@ -625,26 +709,50 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
target_ulong eaddr,
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
- ppc_slb_t *slb;
- hwaddr pte_offset;
+ ppc_slb_t slb;
+ ppc_slb_t *slb_ptr;
+ hwaddr pte_offset, raddr;
ppc_hash_pte64_t pte;
+ /* Handle real mode */
if (msr_dr == 0) {
- /* In real mode the top 4 effective address bits are ignored */
- return addr & 0x0FFFFFFFFFFFFFFFULL;
- }
+ raddr = addr & 0x0FFFFFFFFFFFFFFFULL;
- slb = slb_lookup(env, addr);
- if (!slb) {
+ /* In HV mode, add HRMOR if top EA bit is clear */
+ if (msr_hv & !(addr >> 63)) {
+ return raddr | env->spr[SPR_HRMOR];
+ }
+
+ /* Otherwise, check VPM for RMA vs VRMA */
+ if (env->spr[SPR_LPCR] & LPCR_VPM0) {
+ uint32_t vrmasd;
+
+ /* VRMA, we make up an SLB entry */
+ slb.vsid = SLB_VSID_VRMA;
+ vrmasd = (env->spr[SPR_LPCR] & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
+ slb.vsid |= (vrmasd << 4) & (SLB_VSID_L | SLB_VSID_LP);
+ slb.esid = SLB_ESID_V;
+ goto skip_slb;
+ }
+ /* RMA. Check bounds in RMLS */
+ if (raddr < ppc_hash64_get_rmls(env)) {
+ return raddr | env->spr[SPR_RMOR];
+ }
return -1;
}
- pte_offset = ppc_hash64_htab_lookup(env, slb, addr, &pte);
+ slb_ptr = slb_lookup(env, addr);
+ if (!slb_ptr) {
+ return -1;
+ }
+ slb = *slb_ptr;
+ skip_slb:
+ 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;
+ return ppc_hash64_pte_raddr(&slb, pte, addr) & TARGET_PAGE_MASK;
}
void ppc_hash64_store_hpte(CPUPPCState *env,
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 291750f..729f718 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -29,6 +29,7 @@ void ppc_hash64_store_hpte(CPUPPCState *env, target_ulong
index,
#define SLB_VSID_B_256M 0x0000000000000000ULL
#define SLB_VSID_B_1T 0x4000000000000000ULL
#define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL
+#define SLB_VSID_VRMA (0x0001FFFFFF000000ULL | SLB_VSID_B_1T)
#define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID)
#define SLB_VSID_KS 0x0000000000000800ULL
#define SLB_VSID_KP 0x0000000000000400ULL
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 853a084..504564d 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8558,11 +8558,19 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu)
/* Set emulated LPCR to not send interrupts to hypervisor. Note that
* under KVM, the actual HW LPCR will be set differently by KVM itself,
* the settings below ensure proper operations with TCG in absence of
- * a real hypervisor
+ * a real hypervisor.
+ *
+ * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
+ * real mode accesses, which thankfully defaults to 0 and isn't
+ * accessible in guest mode.
*/
lpcr->default_value &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV);
lpcr->default_value |= LPCR_LPES0 | LPCR_LPES1;
+ /* Set RMLS to the max (ie, 16G) */
+ lpcr->default_value &= ~LPCR_RMLS;
+ lpcr->default_value |= 1ull << LPCR_RMLS_SHIFT;
+
/* P7 and P8 has slightly different PECE bits, mostly because P8 adds
* bit 47 and 48 which are reserved on P7. Here we set them all, which
* will work as expected for both implementations
--
2.5.0
- Re: [Qemu-ppc] [Qemu-devel] [PATCH 41/77] ppc/pnv: Add LPC controller and hook it up with a UART and RTC, (continued)
- [Qemu-ppc] [PATCH 47/77] pci: Don't call pci_irq_handler() for a negative intx, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 46/77] pci: Use the new pci_can_add_device() to enforce devfn_min/max, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 43/77] ppc/pnv: Add OCC model stub with interrupt support, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 42/77] ppc/pnv: Add cut down PSI bridge model and hookup external interrupt, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 50/77] ppc: Update LPCR definitions, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 49/77] ppc/pnv: Create a default PCI layout, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 51/77] ppc: Use a helper to filter writes to LPCR, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 53/77] ppc: Add proper real mode translation support,
Benjamin Herrenschmidt <=
- [Qemu-ppc] [PATCH 52/77] ppc: Cosmetic, align some comments, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 63/77] ppc: Initialize AMOR in PAPR mode, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 57/77] ppc: Enforce setting MSR:EE, IR and DR when MSR:PR is set, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 61/77] ppc: SPURR & PURR are HV writeable and privileged, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 55/77] ppc/pnv+spapr: Add "ibm, pa-features" property to the device-tree, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 56/77] ppc: Fix conditions for delivering external interrupts to a guest, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 54/77] ppc: Fix 64K pages support in full emulation, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 58/77] ppc: Initial HDEC support, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 59/77] ppc: Add placeholder SPRs for DPDES and DHDES on P8, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 62/77] ppc: Add dummy SPR_IC for POWER8, Benjamin Herrenschmidt, 2015/11/10