* [PATCH 0/5 v4] Read guest last instruction from kvmppc_get_last_inst()
From: Mihai Caraman @ 2014-06-27 22:49 UTC (permalink / raw)
To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
Read guest last instruction from kvmppc_get_last_inst() allowing the function
to fail in order to emulate again. On bookehv architecture search for
the physical address and kmap it, instead of using Load External PID (lwepx)
instruction. This fixes an infinite loop caused by lwepx's data TLB miss
exception handled in the host and the TODO for execute-but-not-read entries
and TLB eviction.
Mihai Caraman (5):
KVM: PPC: e500mc: Revert "add load inst fixup"
KVM: PPC: Book3e: Add TLBSEL/TSIZE defines for MAS0/1
KVM: PPC: Book3s: Remove kvmppc_read_inst() function
KVM: PPC: Alow kvmppc_get_last_inst() to fail
KVM: PPC: Bookehv: Get vcpu's last instruction for emulation
arch/powerpc/include/asm/kvm_book3s.h | 26 -------
arch/powerpc/include/asm/kvm_booke.h | 5 --
arch/powerpc/include/asm/kvm_ppc.h | 24 +++++++
arch/powerpc/include/asm/mmu-book3e.h | 7 +-
arch/powerpc/kvm/book3s.c | 11 +++
arch/powerpc/kvm/book3s_64_mmu_hv.c | 17 ++---
arch/powerpc/kvm/book3s_paired_singles.c | 38 ++++++----
arch/powerpc/kvm/book3s_pr.c | 116 +++++++++++++++++--------------
arch/powerpc/kvm/booke.c | 47 +++++++++++++
arch/powerpc/kvm/bookehv_interrupts.S | 55 ++-------------
arch/powerpc/kvm/e500_mmu_host.c | 97 ++++++++++++++++++++++++++
arch/powerpc/kvm/emulate.c | 18 +++--
arch/powerpc/kvm/powerpc.c | 10 ++-
13 files changed, 302 insertions(+), 169 deletions(-)
--
1.7.11.7
^ permalink raw reply
* [PATCH 1/5 v4] KVM: PPC: e500mc: Revert "add load inst fixup"
From: Mihai Caraman @ 2014-06-27 22:49 UTC (permalink / raw)
To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1403909347-31622-1-git-send-email-mihai.caraman@freescale.com>
The commit 1d628af7 "add load inst fixup" made an attempt to handle
failures generated by reading the guest current instruction. The fixup
code that was added works by chance hiding the real issue.
Load external pid (lwepx) instruction, used by KVM to read guest
instructions, is executed in a subsituted guest translation context
(EPLC[EGS] = 1). In consequence lwepx's TLB error and data storage
interrupts need to be handled by KVM, even though these interrupts
are generated from host context (MSR[GS] = 0) where lwepx is executed.
Currently, KVM hooks only interrupts generated from guest context
(MSR[GS] = 1), doing minimal checks on the fast path to avoid host
performance degradation. As a result, the host kernel handles lwepx
faults searching the faulting guest data address (loaded in DEAR) in
its own Logical Partition ID (LPID) 0 context. In case a host translation
is found the execution returns to the lwepx instruction instead of the
fixup, the host ending up in an infinite loop.
Revert the commit "add load inst fixup". lwepx issue will be addressed
in a subsequent patch without needing fixup code.
Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v4-v2:
- no change
arch/powerpc/kvm/bookehv_interrupts.S | 26 +-------------------------
1 file changed, 1 insertion(+), 25 deletions(-)
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index a1712b8..6ff4480 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -29,7 +29,6 @@
#include <asm/asm-compat.h>
#include <asm/asm-offsets.h>
#include <asm/bitsperlong.h>
-#include <asm/thread_info.h>
#ifdef CONFIG_64BIT
#include <asm/exception-64e.h>
@@ -164,32 +163,9 @@
PPC_STL r30, VCPU_GPR(R30)(r4)
PPC_STL r31, VCPU_GPR(R31)(r4)
mtspr SPRN_EPLC, r8
-
- /* disable preemption, so we are sure we hit the fixup handler */
- CURRENT_THREAD_INFO(r8, r1)
- li r7, 1
- stw r7, TI_PREEMPT(r8)
-
isync
-
- /*
- * In case the read goes wrong, we catch it and write an invalid value
- * in LAST_INST instead.
- */
-1: lwepx r9, 0, r5
-2:
-.section .fixup, "ax"
-3: li r9, KVM_INST_FETCH_FAILED
- b 2b
-.previous
-.section __ex_table,"a"
- PPC_LONG_ALIGN
- PPC_LONG 1b,3b
-.previous
-
+ lwepx r9, 0, r5
mtspr SPRN_EPLC, r3
- li r7, 0
- stw r7, TI_PREEMPT(r8)
stw r9, VCPU_LAST_INST(r4)
.endif
--
1.7.11.7
^ permalink raw reply related
* [PATCH 3/5 v4] KVM: PPC: Book3s: Remove kvmppc_read_inst() function
From: Mihai Caraman @ 2014-06-27 22:49 UTC (permalink / raw)
To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1403909347-31622-1-git-send-email-mihai.caraman@freescale.com>
In the context of replacing kvmppc_ld() function calls with a version of
kvmppc_get_last_inst() which allow to fail, Alex Graf suggested this:
"If we get EMULATE_AGAIN, we just have to make sure we go back into the guest.
No need to inject an ISI into the guest - it'll do that all by itself.
With an error returning kvmppc_get_last_inst we can just use completely
get rid of kvmppc_read_inst() and only use kvmppc_get_last_inst() instead."
As a intermediate step get rid of kvmppc_read_inst() and only use kvmppc_ld()
instead.
Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v4:
- new patch
arch/powerpc/kvm/book3s_pr.c | 85 ++++++++++++++++++--------------------------
1 file changed, 35 insertions(+), 50 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 15fd6c2..d247d88 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -665,42 +665,6 @@ static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac)
#endif
}
-static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
-{
- ulong srr0 = kvmppc_get_pc(vcpu);
- u32 last_inst = kvmppc_get_last_inst(vcpu);
- int ret;
-
- ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
- if (ret == -ENOENT) {
- ulong msr = kvmppc_get_msr(vcpu);
-
- msr = kvmppc_set_field(msr, 33, 33, 1);
- msr = kvmppc_set_field(msr, 34, 36, 0);
- msr = kvmppc_set_field(msr, 42, 47, 0);
- kvmppc_set_msr_fast(vcpu, msr);
- kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
- return EMULATE_AGAIN;
- }
-
- return EMULATE_DONE;
-}
-
-static int kvmppc_check_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr)
-{
-
- /* Need to do paired single emulation? */
- if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE))
- return EMULATE_DONE;
-
- /* Read out the instruction */
- if (kvmppc_read_inst(vcpu) == EMULATE_DONE)
- /* Need to emulate */
- return EMULATE_FAIL;
-
- return EMULATE_AGAIN;
-}
-
/* Handle external providers (FPU, Altivec, VSX) */
static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
ulong msr)
@@ -1101,31 +1065,51 @@ program_interrupt:
case BOOK3S_INTERRUPT_VSX:
{
int ext_msr = 0;
+ int emul;
+ ulong pc;
+ u32 last_inst;
- switch (exit_nr) {
- case BOOK3S_INTERRUPT_FP_UNAVAIL: ext_msr = MSR_FP; break;
- case BOOK3S_INTERRUPT_ALTIVEC: ext_msr = MSR_VEC; break;
- case BOOK3S_INTERRUPT_VSX: ext_msr = MSR_VSX; break;
- }
+ if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)) {
+ /* Do paired single emulation */
+
+ switch (exit_nr) {
+ case BOOK3S_INTERRUPT_FP_UNAVAIL:
+ ext_msr = MSR_FP;
+ break;
+
+ case BOOK3S_INTERRUPT_ALTIVEC:
+ ext_msr = MSR_VEC;
+ break;
+
+ case BOOK3S_INTERRUPT_VSX:
+ ext_msr = MSR_VSX;
+ break;
+ }
- switch (kvmppc_check_ext(vcpu, exit_nr)) {
- case EMULATE_DONE:
- /* everything ok - let's enable the ext */
r = kvmppc_handle_ext(vcpu, exit_nr, ext_msr);
break;
- case EMULATE_FAIL:
+ }
+
+ pc = kvmppc_get_pc(vcpu);
+ last_inst = kvmppc_get_last_inst(vcpu);
+ emul = kvmppc_ld(vcpu, &pc, sizeof(u32), &last_inst, false);
+ if (emul == EMULATE_DONE) {
/* we need to emulate this instruction */
goto program_interrupt;
break;
- default:
- /* nothing to worry about - go again */
- break;
+ } else {
+ r = RESUME_GUEST;
}
+
break;
}
case BOOK3S_INTERRUPT_ALIGNMENT:
- if (kvmppc_read_inst(vcpu) == EMULATE_DONE) {
- u32 last_inst = kvmppc_get_last_inst(vcpu);
+ {
+ ulong pc = kvmppc_get_pc(vcpu);
+ u32 last_inst = kvmppc_get_last_inst(vcpu);
+ int emul = kvmppc_ld(vcpu, &pc, sizeof(u32), &last_inst, false);
+
+ if (emul == EMULATE_DONE) {
u32 dsisr;
u64 dar;
@@ -1139,6 +1123,7 @@ program_interrupt:
}
r = RESUME_GUEST;
break;
+ }
#ifdef CONFIG_PPC_BOOK3S_64
case BOOK3S_INTERRUPT_FAC_UNAVAIL:
kvmppc_handle_fac(vcpu, vcpu->arch.shadow_fscr >> 56);
--
1.7.11.7
^ permalink raw reply related
* [PATCH 2/5 v4] KVM: PPC: Book3e: Add TLBSEL/TSIZE defines for MAS0/1
From: Mihai Caraman @ 2014-06-27 22:49 UTC (permalink / raw)
To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1403909347-31622-1-git-send-email-mihai.caraman@freescale.com>
Add mising defines MAS0_GET_TLBSEL() and MAS1_GET_TSIZE() for Book3E.
Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v4-v2:
- no change
arch/powerpc/include/asm/mmu-book3e.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 901dac6..60a949a 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -40,7 +40,11 @@
/* MAS registers bit definitions */
-#define MAS0_TLBSEL(x) (((x) << 28) & 0x30000000)
+#define MAS0_TLBSEL_MASK 0x30000000
+#define MAS0_TLBSEL_SHIFT 28
+#define MAS0_TLBSEL(x) (((x) << MAS0_TLBSEL_SHIFT) & MAS0_TLBSEL_MASK)
+#define MAS0_GET_TLBSEL(mas0) (((mas0) & MAS0_TLBSEL_MASK) >> \
+ MAS0_TLBSEL_SHIFT)
#define MAS0_ESEL_MASK 0x0FFF0000
#define MAS0_ESEL_SHIFT 16
#define MAS0_ESEL(x) (((x) << MAS0_ESEL_SHIFT) & MAS0_ESEL_MASK)
@@ -58,6 +62,7 @@
#define MAS1_TSIZE_MASK 0x00000f80
#define MAS1_TSIZE_SHIFT 7
#define MAS1_TSIZE(x) (((x) << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
+#define MAS1_GET_TSIZE(mas1) (((mas1) & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT)
#define MAS2_EPN (~0xFFFUL)
#define MAS2_X0 0x00000040
--
1.7.11.7
^ permalink raw reply related
* [PATCH 5/5 v4] KVM: PPC: Bookehv: Get vcpu's last instruction for emulation
From: Mihai Caraman @ 2014-06-27 22:49 UTC (permalink / raw)
To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1403909347-31622-1-git-send-email-mihai.caraman@freescale.com>
On book3e, KVM uses load external pid (lwepx) dedicated instruction to read
guest last instruction on the exit path. lwepx exceptions (DTLB_MISS, DSI
and LRAT), generated by loading a guest address, needs to be handled by KVM.
These exceptions are generated in a substituted guest translation context
(EPLC[EGS] = 1) from host context (MSR[GS] = 0).
Currently, KVM hooks only interrupts generated from guest context (MSR[GS] = 1),
doing minimal checks on the fast path to avoid host performance degradation.
lwepx exceptions originate from host state (MSR[GS] = 0) which implies
additional checks in DO_KVM macro (beside the current MSR[GS] = 1) by looking
at the Exception Syndrome Register (ESR[EPID]) and the External PID Load Context
Register (EPLC[EGS]). Doing this on each Data TLB miss exception is obvious
too intrusive for the host.
Read guest last instruction from kvmppc_load_last_inst() by searching for the
physical address and kmap it. This address the TODO for TLB eviction and
execute-but-not-read entries, and allow us to get rid of lwepx until we are
able to handle failures.
A simple stress benchmark shows a 1% sys performance degradation compared with
previous approach (lwepx without failure handling):
time for i in `seq 1 10000`; do /bin/echo > /dev/null; done
real 0m 8.85s
user 0m 4.34s
sys 0m 4.48s
vs
real 0m 8.84s
user 0m 4.36s
sys 0m 4.44s
An alternative solution, to handle lwepx exceptions in KVM, is to temporary
highjack the interrupt vector from host. Some cores share host IVOR registers
between hardware threads, which is the case of FSL e6500, which impose additional
synchronization logic for this solution to work. The optimization can be addressed
later on top of this patch.
Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v4:
- add switch and new function when getting last inst earlier
- use enum instead of prev semnatic
- get rid of mas0, optimize mas7_mas3
- give more context in visible messages
- check storage attributes mismatch on MMUv2
- get rid of pfn_valid check
v3:
- reworked patch description
- use unaltered kmap addr for kunmap
- get last instruction before beeing preempted
v2:
- reworked patch description
- used pr_* functions
- addressed cosmetic feedback
arch/powerpc/kvm/booke.c | 44 +++++++++++++++++
arch/powerpc/kvm/bookehv_interrupts.S | 37 ++++----------
arch/powerpc/kvm/e500_mmu_host.c | 91 +++++++++++++++++++++++++++++++++++
3 files changed, 144 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 34a42b9..843077b 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -869,6 +869,28 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
}
}
+static int kvmppc_resume_inst_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ enum emulation_result emulated, u32 last_inst)
+{
+ switch (emulated) {
+ case EMULATE_AGAIN:
+ return RESUME_GUEST;
+
+ case EMULATE_FAIL:
+ pr_debug("%s: load instruction from guest address %lx failed\n",
+ __func__, vcpu->arch.pc);
+ /* For debugging, encode the failing instruction and
+ * report it to userspace. */
+ run->hw.hardware_exit_reason = ~0ULL << 32;
+ run->hw.hardware_exit_reason |= last_inst;
+ kvmppc_core_queue_program(vcpu, ESR_PIL);
+ return RESUME_HOST;
+
+ default:
+ BUG();
+ }
+}
+
/**
* kvmppc_handle_exit
*
@@ -880,6 +902,8 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
int r = RESUME_HOST;
int s;
int idx;
+ u32 last_inst = KVM_INST_FETCH_FAILED;
+ enum emulation_result emulated = EMULATE_DONE;
/* update before a new last_exit_type is rewritten */
kvmppc_update_timing_stats(vcpu);
@@ -887,6 +911,20 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
/* restart interrupts if they were meant for the host */
kvmppc_restart_interrupt(vcpu, exit_nr);
+ /*
+ * get last instruction before beeing preempted
+ * TODO: for e6500 check also BOOKE_INTERRUPT_LRAT_ERROR & ESR_DATA
+ */
+ switch (exit_nr) {
+ case BOOKE_INTERRUPT_DATA_STORAGE:
+ case BOOKE_INTERRUPT_DTLB_MISS:
+ case BOOKE_INTERRUPT_HV_PRIV:
+ emulated = kvmppc_get_last_inst(vcpu, false, &last_inst);
+ break;
+ default:
+ break;
+ }
+
local_irq_enable();
trace_kvm_exit(exit_nr, vcpu);
@@ -895,6 +933,11 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
run->exit_reason = KVM_EXIT_UNKNOWN;
run->ready_for_interrupt_injection = 1;
+ if (emulated != EMULATE_DONE) {
+ r = kvmppc_resume_inst_load(run, vcpu, emulated, last_inst);
+ goto out;
+ }
+
switch (exit_nr) {
case BOOKE_INTERRUPT_MACHINE_CHECK:
printk("MACHINE CHECK: %lx\n", mfspr(SPRN_MCSR));
@@ -1184,6 +1227,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
BUG();
}
+out:
/*
* To avoid clobbering exit_reason, only check for signals if we
* aren't already exiting to userspace for some other reason.
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index 6ff4480..e000b39 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -121,38 +121,14 @@
1:
.if \flags & NEED_EMU
- /*
- * This assumes you have external PID support.
- * To support a bookehv CPU without external PID, you'll
- * need to look up the TLB entry and create a temporary mapping.
- *
- * FIXME: we don't currently handle if the lwepx faults. PR-mode
- * booke doesn't handle it either. Since Linux doesn't use
- * broadcast tlbivax anymore, the only way this should happen is
- * if the guest maps its memory execute-but-not-read, or if we
- * somehow take a TLB miss in the middle of this entry code and
- * evict the relevant entry. On e500mc, all kernel lowmem is
- * bolted into TLB1 large page mappings, and we don't use
- * broadcast invalidates, so we should not take a TLB miss here.
- *
- * Later we'll need to deal with faults here. Disallowing guest
- * mappings that are execute-but-not-read could be an option on
- * e500mc, but not on chips with an LRAT if it is used.
- */
-
- mfspr r3, SPRN_EPLC /* will already have correct ELPID and EGS */
PPC_STL r15, VCPU_GPR(R15)(r4)
PPC_STL r16, VCPU_GPR(R16)(r4)
PPC_STL r17, VCPU_GPR(R17)(r4)
PPC_STL r18, VCPU_GPR(R18)(r4)
PPC_STL r19, VCPU_GPR(R19)(r4)
- mr r8, r3
PPC_STL r20, VCPU_GPR(R20)(r4)
- rlwimi r8, r6, EPC_EAS_SHIFT - MSR_IR_LG, EPC_EAS
PPC_STL r21, VCPU_GPR(R21)(r4)
- rlwimi r8, r6, EPC_EPR_SHIFT - MSR_PR_LG, EPC_EPR
PPC_STL r22, VCPU_GPR(R22)(r4)
- rlwimi r8, r10, EPC_EPID_SHIFT, EPC_EPID
PPC_STL r23, VCPU_GPR(R23)(r4)
PPC_STL r24, VCPU_GPR(R24)(r4)
PPC_STL r25, VCPU_GPR(R25)(r4)
@@ -162,10 +138,15 @@
PPC_STL r29, VCPU_GPR(R29)(r4)
PPC_STL r30, VCPU_GPR(R30)(r4)
PPC_STL r31, VCPU_GPR(R31)(r4)
- mtspr SPRN_EPLC, r8
- isync
- lwepx r9, 0, r5
- mtspr SPRN_EPLC, r3
+
+ /*
+ * We don't use external PID support. lwepx faults would need to be
+ * handled by KVM and this implies aditional code in DO_KVM (for
+ * DTB_MISS, DSI and LRAT) to check ESR[EPID] and EPLC[EGS] which
+ * is too intrusive for the host. Get last instuction in
+ * kvmppc_get_last_inst().
+ */
+ li r9, KVM_INST_FETCH_FAILED
stw r9, VCPU_LAST_INST(r4)
.endif
diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
index 4b4e8d6..57463e5 100644
--- a/arch/powerpc/kvm/e500_mmu_host.c
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -606,11 +606,102 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
}
}
+#ifdef CONFIG_KVM_BOOKE_HV
int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type,
u32 *instr)
{
+ gva_t geaddr;
+ hpa_t addr;
+ hfn_t pfn;
+ hva_t eaddr;
+ u32 mas1, mas2, mas3;
+ u64 mas7_mas3;
+ struct page *page;
+ unsigned int addr_space, psize_shift;
+ bool pr;
+ unsigned long flags;
+
+ /* Search TLB for guest pc to get the real address */
+ geaddr = kvmppc_get_pc(vcpu);
+
+ addr_space = (vcpu->arch.shared->msr & MSR_IS) >> MSR_IR_LG;
+
+ local_irq_save(flags);
+ mtspr(SPRN_MAS6, (vcpu->arch.pid << MAS6_SPID_SHIFT) | addr_space);
+ mtspr(SPRN_MAS5, MAS5_SGS | vcpu->kvm->arch.lpid);
+ asm volatile("tlbsx 0, %[geaddr]\n" : :
+ [geaddr] "r" (geaddr));
+ mtspr(SPRN_MAS5, 0);
+ mtspr(SPRN_MAS8, 0);
+ mas1 = mfspr(SPRN_MAS1);
+ mas2 = mfspr(SPRN_MAS2);
+ mas3 = mfspr(SPRN_MAS3);
+#ifdef CONFIG_64BIT
+ mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
+#else
+ mas7_mas3 = ((u64)mfspr(SPRN_MAS7) << 32) | mas3;
+#endif
+ local_irq_restore(flags);
+
+ /*
+ * If the TLB entry for guest pc was evicted, return to the guest.
+ * There are high chances to find a valid TLB entry next time.
+ */
+ if (!(mas1 & MAS1_VALID))
+ return EMULATE_AGAIN;
+
+ /*
+ * Another thread may rewrite the TLB entry in parallel, don't
+ * execute from the address if the execute permission is not set
+ */
+ pr = vcpu->arch.shared->msr & MSR_PR;
+ if (unlikely((pr && !(mas3 & MAS3_UX)) ||
+ (!pr && !(mas3 & MAS3_SX)))) {
+ pr_debug("%s: Instuction emulation from guest addres %08lx without execute permission\n",
+ __func__, geaddr);
+ return EMULATE_FAIL;
+ }
+
+ /*
+ * The real address will be mapped by a cacheable, memory coherent,
+ * write-back page. Check for mismatches when LRAT is used.
+ */
+ if (has_feature(vcpu, VCPU_FTR_MMU_V2) &&
+ unlikely((mas2 & MAS2_I) || (mas2 & MAS2_W) || !(mas2 & MAS2_M))) {
+ pr_debug("%s: Instuction emulation from guest addres %08lx mismatches storage attributes\n",
+ __func__, geaddr);
+ return EMULATE_FAIL;
+ }
+
+ /* Get page size */
+ psize_shift = MAS1_GET_TSIZE(mas1) + 10;
+
+ /* Map a page and get guest's instruction */
+ addr = (mas7_mas3 & (~0ULL << psize_shift)) |
+ (geaddr & ((1ULL << psize_shift) - 1ULL));
+ pfn = addr >> PAGE_SHIFT;
+
+ /* Guard us against emulation from devices area */
+ if (unlikely(!page_is_ram(pfn))) {
+ pr_debug("%s: Instruction emulation from non-RAM host addres %08llx is not supported\n",
+ __func__, addr);
+ return EMULATE_FAIL;
+ }
+
+ page = pfn_to_page(pfn);
+ eaddr = (unsigned long)kmap_atomic(page);
+ *instr = *(u32 *)(eaddr | (addr & ~PAGE_MASK));
+ kunmap_atomic((u32 *)eaddr);
+
+ return EMULATE_DONE;
+}
+#else
+int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type
+ u32 *instr)
+{
return EMULATE_FAIL;
}
+#endif
/************* MMU Notifiers *************/
--
1.7.11.7
^ permalink raw reply related
* [PATCH 4/5 v4] KVM: PPC: Alow kvmppc_get_last_inst() to fail
From: Mihai Caraman @ 2014-06-27 22:49 UTC (permalink / raw)
To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1403909347-31622-1-git-send-email-mihai.caraman@freescale.com>
On book3e, guest last instruction is read on the exit path using load
external pid (lwepx) dedicated instruction. This load operation may fail
due to TLB eviction and execute-but-not-read entries.
This patch lay down the path for an alternative solution to read the guest
last instruction, by allowing kvmppc_get_lat_inst() function to fail.
Architecture specific implmentations of kvmppc_load_last_inst() may read
last guest instruction and instruct the emulation layer to re-execute the
guest in case of failure.
Make kvmppc_get_last_inst() definition common between architectures.
Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v4:
- these changes compile on book3s, please validate the functionality and
do the necessary adaptations!
- common declaration and enum for kvmppc_load_last_inst()
- remove kvmppc_read_inst() in a preceding patch
v3:
- rework patch description
- add common definition for kvmppc_get_last_inst()
- check return values in book3s code
v2:
- integrated kvmppc_get_last_inst() in book3s code and checked build
- addressed cosmetic feedback
arch/powerpc/include/asm/kvm_book3s.h | 26 ------------------
arch/powerpc/include/asm/kvm_booke.h | 5 ----
arch/powerpc/include/asm/kvm_ppc.h | 24 +++++++++++++++++
arch/powerpc/kvm/book3s.c | 11 ++++++++
arch/powerpc/kvm/book3s_64_mmu_hv.c | 17 ++++--------
arch/powerpc/kvm/book3s_paired_singles.c | 38 +++++++++++++++++----------
arch/powerpc/kvm/book3s_pr.c | 45 ++++++++++++++++++++++++--------
arch/powerpc/kvm/booke.c | 3 +++
arch/powerpc/kvm/e500_mmu_host.c | 6 +++++
arch/powerpc/kvm/emulate.c | 18 ++++++++-----
arch/powerpc/kvm/powerpc.c | 11 ++++++--
11 files changed, 128 insertions(+), 76 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index ceb70aa..1300cd9 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -276,32 +276,6 @@ static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
return (kvmppc_get_msr(vcpu) & MSR_LE) != (MSR_KERNEL & MSR_LE);
}
-static inline u32 kvmppc_get_last_inst_internal(struct kvm_vcpu *vcpu, ulong pc)
-{
- /* Load the instruction manually if it failed to do so in the
- * exit path */
- if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
- kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false);
-
- return kvmppc_need_byteswap(vcpu) ? swab32(vcpu->arch.last_inst) :
- vcpu->arch.last_inst;
-}
-
-static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
-{
- return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu));
-}
-
-/*
- * Like kvmppc_get_last_inst(), but for fetching a sc instruction.
- * Because the sc instruction sets SRR0 to point to the following
- * instruction, we have to fetch from pc - 4.
- */
-static inline u32 kvmppc_get_last_sc(struct kvm_vcpu *vcpu)
-{
- return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu) - 4);
-}
-
static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
{
return vcpu->arch.fault_dar;
diff --git a/arch/powerpc/include/asm/kvm_booke.h b/arch/powerpc/include/asm/kvm_booke.h
index c7aed61..cbb1990 100644
--- a/arch/powerpc/include/asm/kvm_booke.h
+++ b/arch/powerpc/include/asm/kvm_booke.h
@@ -69,11 +69,6 @@ static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
return false;
}
-static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
-{
- return vcpu->arch.last_inst;
-}
-
static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
{
vcpu->arch.ctr = val;
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index e2fd5a1..ec326c8 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -47,6 +47,11 @@ enum emulation_result {
EMULATE_EXIT_USER, /* emulation requires exit to user-space */
};
+enum instruction_type {
+ INST_GENERIC,
+ INST_SC, /* system call */
+};
+
extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
extern void kvmppc_handler_highmem(void);
@@ -62,6 +67,9 @@ extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
u64 val, unsigned int bytes,
int is_default_endian);
+extern int kvmppc_load_last_inst(struct kvm_vcpu *vcpu,
+ enum instruction_type type, u32 *inst);
+
extern int kvmppc_emulate_instruction(struct kvm_run *run,
struct kvm_vcpu *vcpu);
extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
@@ -234,6 +242,22 @@ struct kvmppc_ops {
extern struct kvmppc_ops *kvmppc_hv_ops;
extern struct kvmppc_ops *kvmppc_pr_ops;
+static inline int kvmppc_get_last_inst(struct kvm_vcpu *vcpu,
+ enum instruction_type type, u32 *inst)
+{
+ int ret = EMULATE_DONE;
+
+ /* Load the instruction manually if it failed to do so in the
+ * exit path */
+ if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
+ ret = kvmppc_load_last_inst(vcpu, type, &vcpu->arch.last_inst);
+
+ *inst = kvmppc_need_byteswap(vcpu) ? swab32(vcpu->arch.last_inst) :
+ vcpu->arch.last_inst;
+
+ return ret;
+}
+
static inline bool is_kvmppc_hv_enabled(struct kvm *kvm)
{
return kvm->arch.kvm_ops == kvmppc_hv_ops;
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index bd75902..c17f101 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -467,6 +467,17 @@ mmio:
}
EXPORT_SYMBOL_GPL(kvmppc_ld);
+int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type,
+ u32 *inst)
+{
+ ulong pc = kvmppc_get_pc(vcpu);
+
+ if (type == INST_SC)
+ pc -= 4;
+ return kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false);
+}
+EXPORT_SYMBOL_GPL(kvmppc_load_last_inst);
+
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
return 0;
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 8056107..2c2b7ad 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -530,21 +530,14 @@ static int instruction_is_store(unsigned int instr)
static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned long gpa, gva_t ea, int is_store)
{
- int ret;
u32 last_inst;
- unsigned long srr0 = kvmppc_get_pc(vcpu);
- /* We try to load the last instruction. We don't let
- * emulate_instruction do it as it doesn't check what
- * kvmppc_ld returns.
+ /*
* If we fail, we just return to the guest and try executing it again.
*/
- if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) {
- ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
- if (ret != EMULATE_DONE || last_inst == KVM_INST_FETCH_FAILED)
- return RESUME_GUEST;
- vcpu->arch.last_inst = last_inst;
- }
+ if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst) !=
+ EMULATE_DONE)
+ return RESUME_GUEST;
/*
* WARNING: We do not know for sure whether the instruction we just
@@ -558,7 +551,7 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
* we just return and retry the instruction.
*/
- if (instruction_is_store(kvmppc_get_last_inst(vcpu)) != !!is_store)
+ if (instruction_is_store(last_inst) != !!is_store)
return RESUME_GUEST;
/*
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index 6c8011f..bfb8035 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -639,26 +639,36 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
{
- u32 inst = kvmppc_get_last_inst(vcpu);
+ u32 inst;
enum emulation_result emulated = EMULATE_DONE;
+ int ax_rd, ax_ra, ax_rb, ax_rc;
+ short full_d;
+ u64 *fpr_d, *fpr_a, *fpr_b, *fpr_c;
- int ax_rd = inst_get_field(inst, 6, 10);
- int ax_ra = inst_get_field(inst, 11, 15);
- int ax_rb = inst_get_field(inst, 16, 20);
- int ax_rc = inst_get_field(inst, 21, 25);
- short full_d = inst_get_field(inst, 16, 31);
-
- u64 *fpr_d = &VCPU_FPR(vcpu, ax_rd);
- u64 *fpr_a = &VCPU_FPR(vcpu, ax_ra);
- u64 *fpr_b = &VCPU_FPR(vcpu, ax_rb);
- u64 *fpr_c = &VCPU_FPR(vcpu, ax_rc);
-
- bool rcomp = (inst & 1) ? true : false;
- u32 cr = kvmppc_get_cr(vcpu);
+ bool rcomp;
+ u32 cr;
#ifdef DEBUG
int i;
#endif
+ emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst);
+ if (emulated != EMULATE_DONE)
+ return emulated;
+
+ ax_rd = inst_get_field(inst, 6, 10);
+ ax_ra = inst_get_field(inst, 11, 15);
+ ax_rb = inst_get_field(inst, 16, 20);
+ ax_rc = inst_get_field(inst, 21, 25);
+ full_d = inst_get_field(inst, 16, 31);
+
+ fpr_d = &VCPU_FPR(vcpu, ax_rd);
+ fpr_a = &VCPU_FPR(vcpu, ax_ra);
+ fpr_b = &VCPU_FPR(vcpu, ax_rb);
+ fpr_c = &VCPU_FPR(vcpu, ax_rc);
+
+ rcomp = (inst & 1) ? true : false;
+ cr = kvmppc_get_cr(vcpu);
+
if (!kvmppc_inst_is_paired_single(vcpu, inst))
return EMULATE_FAIL;
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index d247d88..7bbaeec 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -970,15 +970,24 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
{
enum emulation_result er;
ulong flags;
+ u32 last_inst;
+ int emul;
program_interrupt:
flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
+ emul = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
+ if (emul != EMULATE_DONE) {
+ r = RESUME_GUEST;
+ break;
+ }
+
if (kvmppc_get_msr(vcpu) & MSR_PR) {
#ifdef EXIT_DEBUG
- printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
+ pr_info("Userspace triggered 0x700 exception at\n 0x%lx (0x%x)\n",
+ kvmppc_get_pc(vcpu), last_inst);
#endif
- if ((kvmppc_get_last_inst(vcpu) & 0xff0007ff) !=
+ if ((last_inst & 0xff0007ff) !=
(INS_DCBZ & 0xfffffff7)) {
kvmppc_core_queue_program(vcpu, flags);
r = RESUME_GUEST;
@@ -997,7 +1006,7 @@ program_interrupt:
break;
case EMULATE_FAIL:
printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
- __func__, kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
+ __func__, kvmppc_get_pc(vcpu), last_inst);
kvmppc_core_queue_program(vcpu, flags);
r = RESUME_GUEST;
break;
@@ -1014,8 +1023,25 @@ program_interrupt:
break;
}
case BOOK3S_INTERRUPT_SYSCALL:
+ {
+ u32 last_sc;
+ int emul;
+
+ /* Get last sc for papr */
+ if (vcpu->arch.papr_enabled) {
+ /*
+ * The sc instuction sets SRR0 to point to the next inst
+ */
+ emul = kvmppc_get_last_inst(vcpu, INST_SC, &last_sc);
+ if (emul != EMULATE_DONE) {
+ kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) - 4);
+ r = RESUME_GUEST;
+ break;
+ }
+ }
+
if (vcpu->arch.papr_enabled &&
- (kvmppc_get_last_sc(vcpu) == 0x44000022) &&
+ (last_sc == 0x44000022) &&
!(kvmppc_get_msr(vcpu) & MSR_PR)) {
/* SC 1 papr hypercalls */
ulong cmd = kvmppc_get_gpr(vcpu, 3);
@@ -1060,13 +1086,13 @@ program_interrupt:
r = RESUME_GUEST;
}
break;
+ }
case BOOK3S_INTERRUPT_FP_UNAVAIL:
case BOOK3S_INTERRUPT_ALTIVEC:
case BOOK3S_INTERRUPT_VSX:
{
int ext_msr = 0;
int emul;
- ulong pc;
u32 last_inst;
if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)) {
@@ -1090,9 +1116,7 @@ program_interrupt:
break;
}
- pc = kvmppc_get_pc(vcpu);
- last_inst = kvmppc_get_last_inst(vcpu);
- emul = kvmppc_ld(vcpu, &pc, sizeof(u32), &last_inst, false);
+ emul = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
if (emul == EMULATE_DONE) {
/* we need to emulate this instruction */
goto program_interrupt;
@@ -1105,9 +1129,8 @@ program_interrupt:
}
case BOOK3S_INTERRUPT_ALIGNMENT:
{
- ulong pc = kvmppc_get_pc(vcpu);
- u32 last_inst = kvmppc_get_last_inst(vcpu);
- int emul = kvmppc_ld(vcpu, &pc, sizeof(u32), &last_inst, false);
+ u32 last_inst;
+ int emul = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
if (emul == EMULATE_DONE) {
u32 dsisr;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index ab62109..34a42b9 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -752,6 +752,9 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
* they were actually modified by emulation. */
return RESUME_GUEST_NV;
+ case EMULATE_AGAIN:
+ return RESUME_GUEST;
+
case EMULATE_DO_DCR:
run->exit_reason = KVM_EXIT_DCR;
return RESUME_HOST;
diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
index dd2cc03..4b4e8d6 100644
--- a/arch/powerpc/kvm/e500_mmu_host.c
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -606,6 +606,12 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
}
}
+int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type,
+ u32 *instr)
+{
+ return EMULATE_FAIL;
+}
+
/************* MMU Notifiers *************/
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index da86d9b..c5c64b6 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -224,19 +224,25 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
* from opcode tables in the future. */
int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
{
- u32 inst = kvmppc_get_last_inst(vcpu);
- int ra = get_ra(inst);
- int rs = get_rs(inst);
- int rt = get_rt(inst);
- int sprn = get_sprn(inst);
- enum emulation_result emulated = EMULATE_DONE;
+ u32 inst;
+ int ra, rs, rt, sprn;
+ enum emulation_result emulated;
int advance = 1;
/* this default type might be overwritten by subcategories */
kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
+ emulated = kvmppc_get_last_inst(vcpu, false, &inst);
+ if (emulated != EMULATE_DONE)
+ return emulated;
+
pr_debug("Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
+ ra = get_ra(inst);
+ rs = get_rs(inst);
+ rt = get_rt(inst);
+ sprn = get_sprn(inst);
+
switch (get_op(inst)) {
case OP_TRAP:
#ifdef CONFIG_PPC_BOOK3S
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 7efc2b7..da54e4b 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -261,6 +261,9 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
* actually modified. */
r = RESUME_GUEST_NV;
break;
+ case EMULATE_AGAIN:
+ r = RESUME_GUEST;
+ break;
case EMULATE_DO_MMIO:
run->exit_reason = KVM_EXIT_MMIO;
/* We must reload nonvolatiles because "update" load/store
@@ -270,11 +273,15 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
r = RESUME_HOST_NV;
break;
case EMULATE_FAIL:
+ {
+ u32 last_inst;
+
+ kvmppc_get_last_inst(vcpu, false, &last_inst);
/* XXX Deliver Program interrupt to guest. */
- printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__,
- kvmppc_get_last_inst(vcpu));
+ pr_emerg("%s: emulation failed (%08x)\n", __func__, last_inst);
r = RESUME_HOST;
break;
+ }
default:
WARN_ON(1);
r = RESUME_GUEST;
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH v2 1/2] powerpc: bpf: Use correct mask while accessing the VLAN tag
From: David Miller @ 2014-06-27 23:14 UTC (permalink / raw)
To: kda; +Cc: netdev, linuxppc-dev
In-Reply-To: <1403717697-3911-1-git-send-email-kda@linux-powerpc.org>
From: Denis Kirjanov <kda@linux-powerpc.org>
Date: Wed, 25 Jun 2014 21:34:56 +0400
> To get a full tag (and not just a VID) we should access the TCI
> except the VLAN_TAG_PRESENT field (which means that 802.1q header
> is present). Also ensure that the VLAN_TAG_PRESENT stay on its place
>
> Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
Applied.
^ permalink raw reply
* Re: [PATCH v2 2/2] powerpc: bpf: Fix the broken LD_VLAN_TAG_PRESENT test
From: David Miller @ 2014-06-27 23:14 UTC (permalink / raw)
To: kda; +Cc: netdev, linuxppc-dev
In-Reply-To: <1403717697-3911-2-git-send-email-kda@linux-powerpc.org>
From: Denis Kirjanov <kda@linux-powerpc.org>
Date: Wed, 25 Jun 2014 21:34:57 +0400
> We have to return the boolean here if the tag presents
> or not, not just ANDing the TCI with the mask which results to:
>
> [ 709.412097] test_bpf: #18 LD_VLAN_TAG_PRESENT
> [ 709.412245] ret 4096 != 1
> [ 709.412332] ret 4096 != 1
> [ 709.412333] FAIL (2 times)
>
> Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
Applied.
^ permalink raw reply
* [PATCH -trivial 1/4] powerpc/simpleboot: Spelling s/trucate/truncate/
From: Geert Uytterhoeven @ 2014-06-29 10:21 UTC (permalink / raw)
To: Jiri Kosina; +Cc: linuxppc-dev, Geert Uytterhoeven, linux-kernel
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: linuxppc-dev@lists.ozlabs.org
---
arch/powerpc/boot/simpleboot.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/boot/simpleboot.c b/arch/powerpc/boot/simpleboot.c
index 21cd48074ec8..9f8c678f0d9a 100644
--- a/arch/powerpc/boot/simpleboot.c
+++ b/arch/powerpc/boot/simpleboot.c
@@ -61,7 +61,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
if (*reg++ != 0)
fatal("Memory range is not based at address 0\n");
- /* get the memsize and trucate it to under 4G on 32 bit machines */
+ /* get the memsize and truncate it to under 4G on 32 bit machines */
memsize64 = 0;
for (i = 0; i < *ns; i++)
memsize64 = (memsize64 << 32) | *reg++;
--
1.9.1
^ permalink raw reply related
* [PATCH 1/6] KVM: PPC: BOOK3S: HV: Clear hash pte bits from do_h_enter callers
From: Aneesh Kumar K.V @ 2014-06-29 11:17 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
In-Reply-To: <1404040655-12076-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
We will use this to set HPTE_V_VRMA bit in the later patch. This also
make sure we clear the hpte bits only when called via hcall.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/kvm/book3s_64_mmu_hv.c | 15 +++++++++++++--
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 8 ++++++--
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 09a47aeb5b63..1c137f45dd55 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -371,8 +371,6 @@ long kvmppc_virtmode_do_h_enter(struct kvm *kvm, unsigned long flags,
if (!psize)
return H_PARAMETER;
- pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
-
/* Find the memslot (if any) for this address */
gpa = (ptel & HPTE_R_RPN) & ~(psize - 1);
gfn = gpa >> PAGE_SHIFT;
@@ -408,6 +406,12 @@ long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
long pte_index, unsigned long pteh,
unsigned long ptel)
{
+ /*
+ * Clear few bits, when called via hcall
+ */
+ pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+ ptel &= ~(HPTE_R_KEY_HI | HPTE_R_KEY_LO | HPTE_GR_RESERVED);
+
return kvmppc_virtmode_do_h_enter(vcpu->kvm, flags, pte_index,
pteh, ptel, &vcpu->arch.gpr[4]);
}
@@ -1560,6 +1564,13 @@ static ssize_t kvm_htab_write(struct file *file, const char __user *buf,
if (be64_to_cpu(hptp[0]) & (HPTE_V_VALID | HPTE_V_ABSENT))
kvmppc_do_h_remove(kvm, 0, i, 0, tmp);
err = -EIO;
+ /*
+ * Clear few bits we got via read_htab which we
+ * don't need to carry forward.
+ */
+ v &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+ r &= ~(HPTE_R_KEY_HI | HPTE_R_KEY_LO | HPTE_GR_RESERVED);
+
ret = kvmppc_virtmode_do_h_enter(kvm, H_EXACT, i, v, r,
tmp);
if (ret != H_SUCCESS) {
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 084ad54c73cd..157a5f35edfa 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -182,8 +182,6 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
if (!psize)
return H_PARAMETER;
writing = hpte_is_writable(ptel);
- pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
- ptel &= ~HPTE_GR_RESERVED;
g_ptel = ptel;
/* used later to detect if we might have been invalidated */
@@ -367,6 +365,12 @@ EXPORT_SYMBOL_GPL(kvmppc_do_h_enter);
long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
long pte_index, unsigned long pteh, unsigned long ptel)
{
+ /*
+ * Clear few bits. when called via hcall.
+ */
+ pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+ ptel &= ~(HPTE_R_KEY_HI | HPTE_R_KEY_LO | HPTE_GR_RESERVED);
+
return kvmppc_do_h_enter(vcpu->kvm, flags, pte_index, pteh, ptel,
vcpu->arch.pgdir, true, &vcpu->arch.gpr[4]);
}
--
1.9.1
^ permalink raw reply related
* [PATCH 0/6] Use virtual page class key protection mechanism for speeding up guest page fault
From: Aneesh Kumar K.V @ 2014-06-29 11:17 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
Hi,
With the current code we do an expensive hash page table lookup on every
page fault resulting from a missing hash page table entry. A NO_HPTE
page fault can happen due to the below reasons:
1) Missing hash pte as per guest. This should be forwarded to the guest
2) MMIO hash pte. The address against which the load/store is performed
should be emulated as a MMIO operation.
3) Missing hash pte because host swapped out the guest page.
We want to differentiate (1) from (2) and (3) so that we can speed up
page fault due to (1). Optimizing (1) will help in improving
the overall performance because that covers a large percentage of
the page faults.
To achieve the above we use virtual page calss protection mechanism for
covering (2) and (3). For both the above case we mark the hpte
valid, but associate the page with virtual page class index 30 and 31.
The authority mask register is configured such that class index 30 and 31
will have read/write denied. The above change results in a key fault
for (2) and (3). This allows us to forward a NO_HPTE fault directly to guest
without doing the expensive hash pagetable lookup.
For the test below:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#define PAGES (40*1024)
int main()
{
unsigned long size = getpagesize();
unsigned long length = size * PAGES;
unsigned long i, j, k = 0;
for (j = 0; j < 10; j++) {
char *c = mmap(NULL, length, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (c == MAP_FAILED) {
perror("mmap");
exit(1);
}
for (i = 0; i < length; i += size)
c[i] = 0;
/* flush hptes */
mprotect(c, length, PROT_WRITE);
for (i = 0; i < length; i += size)
c[i] = 10;
mprotect(c, length, PROT_READ);
for (i = 0; i < length; i += size)
k += c[i];
munmap(c, length);
}
}
Without Fix:
----------
[root@qemu-pr-host ~]# time ./pfault
real 0m8.438s
user 0m0.855s
sys 0m7.540s
[root@qemu-pr-host ~]#
With Fix:
--------
[root@qemu-pr-host ~]# time ./pfault
real 0m7.833s
user 0m0.782s
sys 0m7.038s
[root@qemu-pr-host ~]#
Aneesh Kumar K.V (6):
KVM: PPC: BOOK3S: HV: Clear hash pte bits from do_h_enter callers
KVM: PPC: BOOK3S: HV: Deny virtual page class key update via h_protect
KVM: PPC: BOOK3S: HV: Remove dead code
KVM: PPC: BOOK3S: HV: Use new functions for mapping/unmapping hpte in
host
KVM: PPC: BOOK3S: Use hpte_update_in_progress to track invalid hpte
during an hpte update
KVM: PPC: BOOK3S: HV: Use virtual page class protection mechanism for
host fault and mmio
arch/powerpc/include/asm/kvm_book3s_64.h | 97 +++++++++++++++++-
arch/powerpc/include/asm/kvm_host.h | 1 +
arch/powerpc/include/asm/reg.h | 1 +
arch/powerpc/kernel/asm-offsets.c | 1 +
arch/powerpc/kvm/book3s_64_mmu_hv.c | 99 ++++++++++++------
arch/powerpc/kvm/book3s_hv.c | 1 +
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 166 +++++++++++++++++++++----------
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 100 +++++++++++++++++--
8 files changed, 371 insertions(+), 95 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH] KVM: PPC: BOOK3S: HV: Update compute_tlbie_rb to handle 16MB base page
From: Aneesh Kumar K.V @ 2014-06-29 11:17 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
In-Reply-To: <1404040655-12076-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
When calculating the lower bits of AVA field, use the shift
count based on the base page size. Also add the missing segment
size and remove stale comment.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/kvm_book3s_64.h | 6 ++++--
arch/powerpc/kvm/book3s_hv.c | 6 ------
2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index 66a0a44b62a8..ca7c1688a7b6 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -158,6 +158,8 @@ static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
*/
/* This covers 14..54 bits of va*/
rb = (v & ~0x7fUL) << 16; /* AVA field */
+
+ rb |= v >> (62 - 8); /* B field */
/*
* AVA in v had cleared lower 23 bits. We need to derive
* that from pteg index
@@ -188,10 +190,10 @@ static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
{
int aval_shift;
/*
- * remaining 7bits of AVA/LP fields
+ * remaining bits of AVA/LP fields
* Also contain the rr bits of LP
*/
- rb |= (va_low & 0x7f) << 16;
+ rb |= (va_low << mmu_psize_defs[b_psize].shift) & 0x7ff000;
/*
* Now clear not needed LP bits based on actual psize
*/
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index cbf46eb3f59c..328416f28a55 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1917,12 +1917,6 @@ static void kvmppc_add_seg_page_size(struct kvm_ppc_one_seg_page_size **sps,
(*sps)->page_shift = def->shift;
(*sps)->slb_enc = def->sllp;
(*sps)->enc[0].page_shift = def->shift;
- /*
- * Only return base page encoding. We don't want to return
- * all the supporting pte_enc, because our H_ENTER doesn't
- * support MPSS yet. Once they do, we can start passing all
- * support pte_enc here
- */
(*sps)->enc[0].pte_enc = def->penc[linux_psize];
/*
* Add 16MB MPSS support if host supports it
--
1.9.1
^ permalink raw reply related
* [PATCH 2/6] KVM: PPC: BOOK3S: HV: Deny virtual page class key update via h_protect
From: Aneesh Kumar K.V @ 2014-06-29 11:17 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
In-Reply-To: <1404040655-12076-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
This makes it consistent with h_enter where we clear the key
bits. We also want to use virtual page class key protection mechanism
for indicating host page fault. For that we will be using key class
index 30 and 31. So prevent the guest from updating key bits until
we add proper support for virtual page class protection mechanism for
the guest. This will not have any impact for PAPR linux guest because
Linux guest currently don't use virtual page class key protection model
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 157a5f35edfa..f908845f7379 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -658,13 +658,17 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
}
v = pte;
+ /*
+ * We ignore key bits here. We use class 31 and 30 for
+ * hypervisor purpose. We still don't track the page
+ * class seperately. Until then don't allow h_protect
+ * to change key bits.
+ */
bits = (flags << 55) & HPTE_R_PP0;
- bits |= (flags << 48) & HPTE_R_KEY_HI;
- bits |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
+ bits |= flags & (HPTE_R_PP | HPTE_R_N);
/* Update guest view of 2nd HPTE dword */
- mask = HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
- HPTE_R_KEY_HI | HPTE_R_KEY_LO;
+ mask = HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N;
rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
if (rev) {
r = (rev->guest_rpte & ~mask) | bits;
--
1.9.1
^ permalink raw reply related
* [PATCH 3/6] KVM: PPC: BOOK3S: HV: Remove dead code
From: Aneesh Kumar K.V @ 2014-06-29 11:17 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
In-Reply-To: <1404040655-12076-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
Since we do don't support virtual page class key protection mechanism in
the guest, we should not find a keyfault that needs to be forwarded to
the guest. So remove the dead code.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/kvm/book3s_64_mmu_hv.c | 9 ---------
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 9 ---------
2 files changed, 18 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 1c137f45dd55..590e07b1a43f 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -499,15 +499,6 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
gpte->may_write = hpte_write_permission(pp, key);
gpte->may_execute = gpte->may_read && !(gr & (HPTE_R_N | HPTE_R_G));
- /* Storage key permission check for POWER7 */
- if (data && virtmode && cpu_has_feature(CPU_FTR_ARCH_206)) {
- int amrfield = hpte_get_skey_perm(gr, vcpu->arch.amr);
- if (amrfield & 1)
- gpte->may_read = 0;
- if (amrfield & 2)
- gpte->may_write = 0;
- }
-
/* Get the guest physical address */
gpte->raddr = kvmppc_mmu_get_real_addr(v, gr, eaddr);
return 0;
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index f908845f7379..1884bff3122c 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -925,15 +925,6 @@ long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
return status | DSISR_PROTFAULT;
}
- /* Check storage key, if applicable */
- if (data && (vcpu->arch.shregs.msr & MSR_DR)) {
- unsigned int perm = hpte_get_skey_perm(gr, vcpu->arch.amr);
- if (status & DSISR_ISSTORE)
- perm >>= 1;
- if (perm & 1)
- return status | DSISR_KEYFAULT;
- }
-
/* Save HPTE info for virtual-mode handler */
vcpu->arch.pgfault_addr = addr;
vcpu->arch.pgfault_index = index;
--
1.9.1
^ permalink raw reply related
* [PATCH 4/6] KVM: PPC: BOOK3S: HV: Use new functions for mapping/unmapping hpte in host
From: Aneesh Kumar K.V @ 2014-06-29 11:17 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
In-Reply-To: <1404040655-12076-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
We want to use virtual page class key protection mechanism for
indicating a MMIO mapped hpte entry or a guest hpte entry that is swapped out
in the host. Those hptes will be marked valid, but have virtual page
class key set to 30 or 31. These virtual page class numbers are
configured in AMR to deny read/write. To accomodate such a change, add
new functions that map, unmap and check whether a hpte is mapped in the
host. This patch still use HPTE_V_VALID and HPTE_V_ABSENT and don't use
virtual page class keys. But we want to differentiate in the code
where we explicitly check for HPTE_V_VALID with places where we want to
check whether the hpte is host mapped. This patch enables a closer
review for such a change.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/kvm_book3s_64.h | 36 ++++++++++++++++++++++++++++++++
arch/powerpc/kvm/book3s_64_mmu_hv.c | 24 +++++++++++----------
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 30 ++++++++++++++------------
3 files changed, 66 insertions(+), 24 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index 0aa817933e6a..da00b1f05ea1 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -400,6 +400,42 @@ static inline int is_vrma_hpte(unsigned long hpte_v)
(HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)));
}
+static inline void __kvmppc_unmap_host_hpte(struct kvm *kvm,
+ unsigned long *hpte_v,
+ unsigned long *hpte_r,
+ bool mmio)
+{
+ *hpte_v |= HPTE_V_ABSENT;
+ if (mmio)
+ *hpte_r |= HPTE_R_KEY_HI | HPTE_R_KEY_LO;
+}
+
+static inline void kvmppc_unmap_host_hpte(struct kvm *kvm, __be64 *hptep)
+{
+ /*
+ * We will never call this for MMIO
+ */
+ hptep[0] |= cpu_to_be64(HPTE_V_ABSENT);
+}
+
+static inline void kvmppc_map_host_hpte(struct kvm *kvm, unsigned long *hpte_v,
+ unsigned long *hpte_r)
+{
+ *hpte_v |= HPTE_V_VALID;
+ *hpte_v &= ~HPTE_V_ABSENT;
+}
+
+static inline bool kvmppc_is_host_mapped_hpte(struct kvm *kvm, __be64 *hpte)
+{
+ unsigned long v;
+
+ v = be64_to_cpu(hpte[0]);
+ if (v & HPTE_V_VALID)
+ return true;
+ return false;
+}
+
+
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
/*
* Note modification of an HPTE; set the HPTE modified bit
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 590e07b1a43f..8ce5e95613f8 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -752,7 +752,8 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
if (be64_to_cpu(hptep[0]) & HPTE_V_VALID) {
/* HPTE was previously valid, so we need to invalidate it */
unlock_rmap(rmap);
- hptep[0] |= cpu_to_be64(HPTE_V_ABSENT);
+ /* Always mark HPTE_V_ABSENT before invalidating */
+ kvmppc_unmap_host_hpte(kvm, hptep);
kvmppc_invalidate_hpte(kvm, hptep, index);
/* don't lose previous R and C bits */
r |= be64_to_cpu(hptep[1]) & (HPTE_R_R | HPTE_R_C);
@@ -897,11 +898,12 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
/* Now check and modify the HPTE */
ptel = rev[i].guest_rpte;
psize = hpte_page_size(be64_to_cpu(hptep[0]), ptel);
- if ((be64_to_cpu(hptep[0]) & HPTE_V_VALID) &&
+ if (kvmppc_is_host_mapped_hpte(kvm, hptep) &&
hpte_rpn(ptel, psize) == gfn) {
if (kvm->arch.using_mmu_notifiers)
- hptep[0] |= cpu_to_be64(HPTE_V_ABSENT);
+ kvmppc_unmap_host_hpte(kvm, hptep);
kvmppc_invalidate_hpte(kvm, hptep, i);
+
/* Harvest R and C */
rcbits = be64_to_cpu(hptep[1]) & (HPTE_R_R | HPTE_R_C);
*rmapp |= rcbits << KVMPPC_RMAP_RC_SHIFT;
@@ -990,7 +992,7 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
}
/* Now check and modify the HPTE */
- if ((be64_to_cpu(hptep[0]) & HPTE_V_VALID) &&
+ if (kvmppc_is_host_mapped_hpte(kvm, hptep) &&
(be64_to_cpu(hptep[1]) & HPTE_R_R)) {
kvmppc_clear_ref_hpte(kvm, hptep, i);
if (!(rev[i].guest_rpte & HPTE_R_R)) {
@@ -1121,11 +1123,12 @@ static int kvm_test_clear_dirty_npages(struct kvm *kvm, unsigned long *rmapp)
}
/* Now check and modify the HPTE */
- if (!(hptep[0] & cpu_to_be64(HPTE_V_VALID)))
+ if (!kvmppc_is_host_mapped_hpte(kvm, hptep))
continue;
-
- /* need to make it temporarily absent so C is stable */
- hptep[0] |= cpu_to_be64(HPTE_V_ABSENT);
+ /*
+ * need to make it temporarily absent so C is stable
+ */
+ kvmppc_unmap_host_hpte(kvm, hptep);
kvmppc_invalidate_hpte(kvm, hptep, i);
v = be64_to_cpu(hptep[0]);
r = be64_to_cpu(hptep[1]);
@@ -1141,9 +1144,8 @@ static int kvm_test_clear_dirty_npages(struct kvm *kvm, unsigned long *rmapp)
npages_dirty = n;
eieio();
}
- v &= ~(HPTE_V_ABSENT | HPTE_V_HVLOCK);
- v |= HPTE_V_VALID;
- hptep[0] = cpu_to_be64(v);
+ kvmppc_map_host_hpte(kvm, &v, &r);
+ hptep[0] = cpu_to_be64(v & ~HPTE_V_HVLOCK);
} while ((i = j) != head);
unlock_rmap(rmapp);
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 1884bff3122c..e8458c0d1336 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -177,6 +177,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
unsigned int writing;
unsigned long mmu_seq;
unsigned long rcbits;
+ unsigned int host_unmapped_hpte = 0;
psize = hpte_page_size(pteh, ptel);
if (!psize)
@@ -199,9 +200,10 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
/* PPC970 can't do emulated MMIO */
if (!cpu_has_feature(CPU_FTR_ARCH_206))
return H_PARAMETER;
- /* Emulated MMIO - mark this with key=31 */
- pteh |= HPTE_V_ABSENT;
- ptel |= HPTE_R_KEY_HI | HPTE_R_KEY_LO;
+ /*
+ * Mark the hpte as host unmapped
+ */
+ host_unmapped_hpte = 2;
goto do_insert;
}
@@ -241,7 +243,8 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
pa = pte_pfn(pte) << PAGE_SHIFT;
pa |= hva & (pte_size - 1);
pa |= gpa & ~PAGE_MASK;
- }
+ } else
+ host_unmapped_hpte = 1;
}
if (pte_size < psize)
@@ -252,8 +255,6 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
if (pa)
pteh |= HPTE_V_VALID;
- else
- pteh |= HPTE_V_ABSENT;
/* Check WIMG */
if (is_io != ~0ul && !hpte_cache_flags_ok(ptel, is_io)) {
@@ -330,16 +331,17 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
}
/* Link HPTE into reverse-map chain */
- if (pteh & HPTE_V_VALID) {
+ if (!host_unmapped_hpte) {
if (realmode)
rmap = real_vmalloc_addr(rmap);
lock_rmap(rmap);
/* Check for pending invalidations under the rmap chain lock */
if (kvm->arch.using_mmu_notifiers &&
mmu_notifier_retry(kvm, mmu_seq)) {
- /* inval in progress, write a non-present HPTE */
- pteh |= HPTE_V_ABSENT;
- pteh &= ~HPTE_V_VALID;
+ /*
+ * inval in progress in host, write host unmapped pte.
+ */
+ host_unmapped_hpte = 1;
unlock_rmap(rmap);
} else {
kvmppc_add_revmap_chain(kvm, rev, rmap, pte_index,
@@ -350,8 +352,10 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
}
}
+ if (host_unmapped_hpte)
+ __kvmppc_unmap_host_hpte(kvm, &pteh, &ptel,
+ (host_unmapped_hpte == 2));
hpte[1] = cpu_to_be64(ptel);
-
/* Write the first HPTE dword, unlocking the HPTE and making it valid */
eieio();
hpte[0] = cpu_to_be64(pteh);
@@ -593,7 +597,7 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
note_hpte_modification(kvm, rev);
- if (!(hp0 & HPTE_V_VALID)) {
+ if (!kvmppc_is_host_mapped_hpte(kvm, hp)) {
/* insert R and C bits from PTE */
rcbits = rev->guest_rpte & (HPTE_R_R|HPTE_R_C);
args[j] |= rcbits << (56 - 5);
@@ -678,7 +682,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
r = (be64_to_cpu(hpte[1]) & ~mask) | bits;
/* Update HPTE */
- if (v & HPTE_V_VALID) {
+ if (kvmppc_is_host_mapped_hpte(kvm, hpte)) {
rb = compute_tlbie_rb(v, r, pte_index);
hpte[0] = cpu_to_be64(v & ~HPTE_V_VALID);
do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true);
--
1.9.1
^ permalink raw reply related
* [PATCH 5/6] KVM: PPC: BOOK3S: Use hpte_update_in_progress to track invalid hpte during an hpte update
From: Aneesh Kumar K.V @ 2014-06-29 11:17 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
In-Reply-To: <1404040655-12076-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
As per ISA, we first need to mark hpte invalid (V=0) before we update
the hpte lower half bits. With virtual page class key protection mechanism we want
to send any fault other than key fault to guest directly without
searching the hash page table. But then we can get NO_HPTE fault while
we are updating the hpte. To track that add a vm specific atomic
variable that we check in the fault path to always send the fault
to host.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/kvm_book3s_64.h | 1 +
arch/powerpc/include/asm/kvm_host.h | 1 +
arch/powerpc/kernel/asm-offsets.c | 1 +
arch/powerpc/kvm/book3s_64_mmu_hv.c | 19 ++++++----
arch/powerpc/kvm/book3s_hv.c | 1 +
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 40 +++++++++++++++++++--
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 60 +++++++++++++++++++++++++++++---
7 files changed, 109 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index da00b1f05ea1..a6bf41865a66 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -416,6 +416,7 @@ static inline void kvmppc_unmap_host_hpte(struct kvm *kvm, __be64 *hptep)
* We will never call this for MMIO
*/
hptep[0] |= cpu_to_be64(HPTE_V_ABSENT);
+ atomic_dec(&kvm->arch.hpte_update_in_progress);
}
static inline void kvmppc_map_host_hpte(struct kvm *kvm, unsigned long *hpte_v,
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index f9ae69682ce1..0a9ff60fae4c 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -254,6 +254,7 @@ struct kvm_arch {
atomic_t hpte_mod_interest;
spinlock_t slot_phys_lock;
cpumask_t need_tlb_flush;
+ atomic_t hpte_update_in_progress;
struct kvmppc_vcore *vcores[KVM_MAX_VCORES];
int hpt_cma_alloc;
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index f5995a912213..54a36110f8f2 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -496,6 +496,7 @@ int main(void)
DEFINE(KVM_LPCR, offsetof(struct kvm, arch.lpcr));
DEFINE(KVM_RMOR, offsetof(struct kvm, arch.rmor));
DEFINE(KVM_VRMA_SLB_V, offsetof(struct kvm, arch.vrma_slb_v));
+ DEFINE(KVM_HPTE_UPDATE, offsetof(struct kvm, arch.hpte_update_in_progress));
DEFINE(VCPU_DSISR, offsetof(struct kvm_vcpu, arch.shregs.dsisr));
DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 8ce5e95613f8..cb7a616aacb1 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -592,6 +592,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int writing, write_ok;
struct vm_area_struct *vma;
unsigned long rcbits;
+ bool hpte_invalidated = false;
/*
* Real-mode code has already searched the HPT and found the
@@ -750,13 +751,15 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
r &= rcbits | ~(HPTE_R_R | HPTE_R_C);
if (be64_to_cpu(hptep[0]) & HPTE_V_VALID) {
- /* HPTE was previously valid, so we need to invalidate it */
+ /*
+ * If we had mapped this hpte before, we now need to
+ * invalidate that.
+ */
unlock_rmap(rmap);
- /* Always mark HPTE_V_ABSENT before invalidating */
- kvmppc_unmap_host_hpte(kvm, hptep);
kvmppc_invalidate_hpte(kvm, hptep, index);
/* don't lose previous R and C bits */
r |= be64_to_cpu(hptep[1]) & (HPTE_R_R | HPTE_R_C);
+ hpte_invalidated = true;
} else {
kvmppc_add_revmap_chain(kvm, rev, rmap, index, 0);
}
@@ -765,6 +768,9 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
eieio();
hptep[0] = cpu_to_be64(hpte[0]);
asm volatile("ptesync" : : : "memory");
+ if (hpte_invalidated)
+ atomic_dec(&kvm->arch.hpte_update_in_progress);
+
preempt_enable();
if (page && hpte_is_writable(r))
SetPageDirty(page);
@@ -1128,10 +1134,9 @@ static int kvm_test_clear_dirty_npages(struct kvm *kvm, unsigned long *rmapp)
/*
* need to make it temporarily absent so C is stable
*/
- kvmppc_unmap_host_hpte(kvm, hptep);
- kvmppc_invalidate_hpte(kvm, hptep, i);
v = be64_to_cpu(hptep[0]);
r = be64_to_cpu(hptep[1]);
+ kvmppc_invalidate_hpte(kvm, hptep, i);
if (r & HPTE_R_C) {
hptep[1] = cpu_to_be64(r & ~HPTE_R_C);
if (!(rev[i].guest_rpte & HPTE_R_C)) {
@@ -1144,8 +1149,8 @@ static int kvm_test_clear_dirty_npages(struct kvm *kvm, unsigned long *rmapp)
npages_dirty = n;
eieio();
}
- kvmppc_map_host_hpte(kvm, &v, &r);
- hptep[0] = cpu_to_be64(v & ~HPTE_V_HVLOCK);
+ hptep[0] = cpu_to_be64(v & ~HPTE_V_LOCK);
+ atomic_dec(&kvm->arch.hpte_update_in_progress);
} while ((i = j) != head);
unlock_rmap(rmapp);
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 47d3f20ad10f..328416f28a55 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -2291,6 +2291,7 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
kvm->arch.using_mmu_notifiers = !!cpu_has_feature(CPU_FTR_ARCH_206);
spin_lock_init(&kvm->arch.slot_phys_lock);
+ atomic_set(&kvm->arch.hpte_update_in_progress, 0);
/*
* Track that we now have a HV mode VM active. This blocks secondary
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index e8458c0d1336..d628d2810c93 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -647,6 +647,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
struct revmap_entry *rev;
unsigned long v, r, rb, mask, bits;
u64 pte;
+ bool hpte_invalidated = false;
if (pte_index >= kvm->arch.hpt_npte)
return H_PARAMETER;
@@ -683,8 +684,26 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
/* Update HPTE */
if (kvmppc_is_host_mapped_hpte(kvm, hpte)) {
- rb = compute_tlbie_rb(v, r, pte_index);
+ /*
+ * We use this in the fault path to check whether a
+ * NO_HPTE fault should be send to guest. In this
+ * case we don't want to send it to guest.
+ */
+ atomic_inc(&kvm->arch.hpte_update_in_progress);
+ /*
+ * We want to ensure that other cpus see the hpte_update_in_progress
+ * change before taking a page fault due to us clearing the valid
+ * bit below
+ */
+ smp_wmb();
+ hpte_invalidated = true;
+ /*
+ * We need to mark V = 0 before doing a tlb invalidate.
+ * Refer Page table entry modifying section in ISA
+ */
hpte[0] = cpu_to_be64(v & ~HPTE_V_VALID);
+
+ rb = compute_tlbie_rb(v, r, pte_index);
do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true);
/*
* If the host has this page as readonly but the guest
@@ -714,6 +733,8 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
eieio();
hpte[0] = cpu_to_be64(v & ~HPTE_V_HVLOCK);
asm volatile("ptesync" : : : "memory");
+ if (hpte_invalidated)
+ atomic_dec(&kvm->arch.hpte_update_in_progress);
return H_SUCCESS;
}
@@ -755,7 +776,22 @@ void kvmppc_invalidate_hpte(struct kvm *kvm, __be64 *hptep,
unsigned long pte_index)
{
unsigned long rb;
-
+ /*
+ * We use this in the fault path to check whether a
+ * NO_HPTE fault should be send to guest. In this
+ * case we don't want to send it to guest.
+ */
+ atomic_inc(&kvm->arch.hpte_update_in_progress);
+ /*
+ * We want to ensure that other cpus see the hpte_update_in_progress
+ * change before taking a page fault due to us clearing the valid
+ * bit below
+ */
+ smp_wmb();
+ /*
+ * We need to mark V = 0 before doing a tlb invalidate.
+ * Refer Page table entry modifying section in ISA
+ */
hptep[0] &= ~cpu_to_be64(HPTE_V_VALID);
rb = compute_tlbie_rb(be64_to_cpu(hptep[0]), be64_to_cpu(hptep[1]),
pte_index);
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 1ff3ebdd2ab0..0b425da9f8db 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1790,11 +1790,33 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
kvmppc_hdsi:
mfspr r4, SPRN_HDAR
mfspr r6, SPRN_HDSISR
+ /*
+ * first check whether we have an hpte update in progress.
+ * If so, we go to host directly
+ */
+ ld r0, VCPU_KVM(r9)
+ lwz r0, KVM_HPTE_UPDATE(r0)
+ /*
+ * If update is in progress go to host directly
+ */
+ cmpwi r0, 0
+ bne 5f
+
+ andi. r0, r11, MSR_DR /* data relocation enabled? */
+ beq 3f
+
/* HPTE not found fault or protection fault? */
andis. r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h
beq 1f /* if not, send it to the guest */
- andi. r0, r11, MSR_DR /* data relocation enabled? */
- beq 3f
+ b 8f
+5:
+ /*
+ * real mode access to be sent to host. because
+ * of an hpte update in progress
+ */
+ andi. r0, r11, MSR_DR
+ beq 7f
+8:
clrrdi r0, r4, 28
PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */
bne 1f /* if no SLB entry found */
@@ -1833,7 +1855,14 @@ fast_interrupt_c_return:
mr r4, r9
b fast_guest_return
-3: ld r5, VCPU_KVM(r9) /* not relocated, use VRMA */
+3: /*
+ * Check whether we can send the fault directly to
+ * guest.
+ */
+ andis. r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h
+ beq 1b
+7:
+ ld r5, VCPU_KVM(r9) /* not relocated, use VRMA */
ld r5, KVM_VRMA_SLB_V(r5)
b 4b
@@ -1865,10 +1894,27 @@ fast_interrupt_c_return:
* it is an HPTE not found fault for a page that we have paged out.
*/
kvmppc_hisi:
+ /* first check whether we have an hpte update in progress.
+ * If so, we go to host directly
+ */
+ ld r0, VCPU_KVM(r9) /* not relocated, use VRMA */
+ lwz r0, KVM_HPTE_UPDATE(r0)
+ /*
+ * If update is in progress go to host directly
+ */
+ cmpwi r0, 0
+ bne 5f
+
+ andi. r0, r11, MSR_IR /* instruction relocation enabled? */
+ beq 3f
+
andis. r0, r11, SRR1_ISI_NOPT@h
beq 1f
+ b 8f
+5:
andi. r0, r11, MSR_IR /* instruction relocation enabled? */
- beq 3f
+ beq 7f
+8:
clrrdi r0, r10, 28
PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */
bne 1f /* if no SLB entry found */
@@ -1896,7 +1942,11 @@ kvmppc_hisi:
bl kvmppc_msr_interrupt
b fast_interrupt_c_return
-3: ld r6, VCPU_KVM(r9) /* not relocated, use VRMA */
+3: /* Check whether we should send this to guest */
+ andis. r0, r11, SRR1_ISI_NOPT@h
+ beq 1b
+7:
+ ld r6, VCPU_KVM(r9) /* not relocated, use VRMA */
ld r5, KVM_VRMA_SLB_V(r6)
b 4b
--
1.9.1
^ permalink raw reply related
* [PATCH 6/6] KVM: PPC: BOOK3S: HV: Use virtual page class protection mechanism for host fault and mmio
From: Aneesh Kumar K.V @ 2014-06-29 11:17 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
In-Reply-To: <1404040655-12076-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
With this patch we use AMR class 30 and 31 for indicating a page
fault that should be handled by host. This includes the MMIO access and
the page fault resulting from guest RAM swapout in the host. This
enables us to forward the fault to guest without doing the expensive
hash page table search for finding the hpte entry. With this patch, we
mark hash pte always valid and use class index 30 and 31 for key based
fault. These virtual class index are configured in AMR to deny
read/write. Since access class protection mechanism doesn't work with
VRMA region, we need to handle them separately. We mark those HPTEs
invalid and use the software defined bit, HPTE_V_VRMA, to differentiate
them.
NOTE: We still need to handle protection fault in host so that a
write to KSM shared page is handled in the host.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/kvm_book3s_64.h | 80 +++++++++++++++++++++++++++-----
arch/powerpc/include/asm/reg.h | 1 +
arch/powerpc/kvm/book3s_64_mmu_hv.c | 48 ++++++++++++++-----
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 69 ++++++++++++++++++---------
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 52 ++++++++++++++++-----
5 files changed, 194 insertions(+), 56 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index a6bf41865a66..4aa9c3601fe8 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -48,7 +48,18 @@ extern unsigned long kvm_rma_pages;
* HPTEs.
*/
#define HPTE_V_HVLOCK 0x40UL
-#define HPTE_V_ABSENT 0x20UL
+/*
+ * VRMA mapping
+ */
+#define HPTE_V_VRMA 0x20UL
+
+#define HPTE_R_HOST_UNMAP_KEY 0x3000000000000e00UL
+/*
+ * We use this to differentiate between an MMIO key fault and
+ * and a key fault resulting from host swapping out the page.
+ */
+#define HPTE_R_MMIO_UNMAP_KEY 0x3000000000000c00UL
+
/*
* We use this bit in the guest_rpte field of the revmap entry
@@ -405,35 +416,82 @@ static inline void __kvmppc_unmap_host_hpte(struct kvm *kvm,
unsigned long *hpte_r,
bool mmio)
{
- *hpte_v |= HPTE_V_ABSENT;
- if (mmio)
- *hpte_r |= HPTE_R_KEY_HI | HPTE_R_KEY_LO;
+ /*
+ * We unmap on host by adding the page to AMR class 31
+ * which have both read/write access denied.
+ *
+ * For VRMA area we mark them invalid.
+ *
+ * If we are not using mmu_notifiers we don't use Access
+ * class protection.
+ *
+ * Since we are not changing the hpt directly we don't
+ * Worry about update ordering.
+ */
+ if ((*hpte_v & HPTE_V_VRMA) || !kvm->arch.using_mmu_notifiers)
+ *hpte_v &= ~HPTE_V_VALID;
+ else if (!mmio) {
+ *hpte_r |= HPTE_R_HOST_UNMAP_KEY;
+ *hpte_v |= HPTE_V_VALID;
+ } else {
+ *hpte_r |= HPTE_R_MMIO_UNMAP_KEY;
+ *hpte_v |= HPTE_V_VALID;
+ }
}
static inline void kvmppc_unmap_host_hpte(struct kvm *kvm, __be64 *hptep)
{
+ unsigned long pte_v, pte_r;
+
+ pte_v = be64_to_cpu(hptep[0]);
+ pte_r = be64_to_cpu(hptep[1]);
/*
* We will never call this for MMIO
*/
- hptep[0] |= cpu_to_be64(HPTE_V_ABSENT);
+ __kvmppc_unmap_host_hpte(kvm, &pte_v, &pte_r, 0);
+ hptep[1] = cpu_to_be64(pte_r);
+ eieio();
+ hptep[0] = cpu_to_be64(pte_v);
+ asm volatile("ptesync" : : : "memory");
+ /*
+ * we have now successfully marked the hpte using key bits
+ */
atomic_dec(&kvm->arch.hpte_update_in_progress);
}
static inline void kvmppc_map_host_hpte(struct kvm *kvm, unsigned long *hpte_v,
unsigned long *hpte_r)
{
- *hpte_v |= HPTE_V_VALID;
- *hpte_v &= ~HPTE_V_ABSENT;
+ /*
+ * We will never try to map an MMIO region
+ */
+ if ((*hpte_v & HPTE_V_VRMA) || !kvm->arch.using_mmu_notifiers)
+ *hpte_v |= HPTE_V_VALID;
+ else {
+ /*
+ * When we allow guest keys we should set this with key
+ * for this page.
+ */
+ *hpte_r &= ~(HPTE_R_KEY_HI | HPTE_R_KEY_LO);
+ }
}
static inline bool kvmppc_is_host_mapped_hpte(struct kvm *kvm, __be64 *hpte)
{
- unsigned long v;
+ unsigned long v, r;
v = be64_to_cpu(hpte[0]);
- if (v & HPTE_V_VALID)
- return true;
- return false;
+ if ((v & HPTE_V_VRMA) || !kvm->arch.using_mmu_notifiers)
+ return v & HPTE_V_VALID;
+
+ r = be64_to_cpu(hpte[1]);
+ if (!(v & HPTE_V_VALID))
+ return false;
+ if ((r & (HPTE_R_KEY_HI | HPTE_R_KEY_LO)) == HPTE_R_HOST_UNMAP_KEY)
+ return false;
+ if ((r & (HPTE_R_KEY_HI | HPTE_R_KEY_LO)) == HPTE_R_MMIO_UNMAP_KEY)
+ return false;
+ return true;
}
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 1f34ef7ec4a8..ca9a7aebc9ce 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -605,6 +605,7 @@
#define SRR1_ISI_NOPT 0x40000000 /* ISI: Not found in hash */
#define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */
#define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */
+#define SRR1_ISI_KEYFAULT 0x00200000 /* Key fault */
#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */
#define SRR1_WAKESYSERR 0x00300000 /* System error */
#define SRR1_WAKEEE 0x00200000 /* External interrupt */
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index cb7a616aacb1..06f860d84d69 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -214,6 +214,11 @@ void kvmppc_map_vrma(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
hash = (hash << 3) + 7;
hp_v = hp0 | ((addr >> 16) & ~0x7fUL);
hp_r = hp1 | addr;
+ /*
+ * VRMA mapping doesn't work with access class protection
+ * mechanism, hence don't use keys for them
+ */
+ hp_v |= HPTE_V_VRMA;
ret = kvmppc_virtmode_do_h_enter(kvm, H_EXACT, hash, hp_v, hp_r,
&idx_ret);
if (ret != H_SUCCESS) {
@@ -409,7 +414,7 @@ long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
/*
* Clear few bits, when called via hcall
*/
- pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+ pteh &= ~(HPTE_V_HVLOCK | HPTE_V_VRMA | HPTE_V_VALID);
ptel &= ~(HPTE_R_KEY_HI | HPTE_R_KEY_LO | HPTE_GR_RESERVED);
return kvmppc_virtmode_do_h_enter(vcpu->kvm, flags, pte_index,
@@ -472,7 +477,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
preempt_disable();
/* Find the HPTE in the hash table */
index = kvmppc_hv_find_lock_hpte(kvm, eaddr, slb_v,
- HPTE_V_VALID | HPTE_V_ABSENT);
+ HPTE_V_VALID | HPTE_V_VRMA);
if (index < 0) {
preempt_enable();
return -ENOENT;
@@ -733,7 +738,13 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
rev->guest_rpte != hpte[2])
/* HPTE has been changed under us; let the guest retry */
goto out_unlock;
- hpte[0] = (hpte[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
+ /*
+ * mark this hpte host mapped. We will use this value
+ * to update actual hpte later. We don't need to clear
+ * clear key bits, because we use rev->guest_rpte values
+ * for the lower half.
+ */
+ hpte[0] |= HPTE_V_VALID;
/* Always put the HPTE in the rmap chain for the page base address */
rmap = &memslot->arch.rmap[gfn_base - memslot->base_gfn];
@@ -906,8 +917,9 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
psize = hpte_page_size(be64_to_cpu(hptep[0]), ptel);
if (kvmppc_is_host_mapped_hpte(kvm, hptep) &&
hpte_rpn(ptel, psize) == gfn) {
- if (kvm->arch.using_mmu_notifiers)
- kvmppc_unmap_host_hpte(kvm, hptep);
+ /*
+ * For hpte update always invalidate first
+ */
kvmppc_invalidate_hpte(kvm, hptep, i);
/* Harvest R and C */
@@ -917,6 +929,11 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
rev[i].guest_rpte = ptel | rcbits;
note_hpte_modification(kvm, &rev[i]);
}
+ /*
+ * Mark the hpte umapped so that host can
+ * handle the faults.
+ */
+ kvmppc_unmap_host_hpte(kvm, hptep);
}
unlock_rmap(rmapp);
hptep[0] &= ~cpu_to_be64(HPTE_V_HVLOCK);
@@ -1345,7 +1362,7 @@ static long record_hpte(unsigned long flags, __be64 *hptp,
return 0;
valid = 0;
- if (be64_to_cpu(hptp[0]) & (HPTE_V_VALID | HPTE_V_ABSENT)) {
+ if (be64_to_cpu(hptp[0]) & (HPTE_V_VALID | HPTE_V_VRMA)) {
valid = 1;
if ((flags & KVM_GET_HTAB_BOLTED_ONLY) &&
!(be64_to_cpu(hptp[0]) & HPTE_V_BOLTED))
@@ -1362,7 +1379,11 @@ static long record_hpte(unsigned long flags, __be64 *hptp,
cpu_relax();
v = be64_to_cpu(hptp[0]);
- /* re-evaluate valid and dirty from synchronized HPTE value */
+ /*
+ * re-evaluate valid and dirty from synchronized HPTE value
+ * We don't need to worry of host unmapped. We keep the valid
+ * bit set even if we move the hpte to class 31.
+ */
valid = !!(v & HPTE_V_VALID);
dirty = !!(revp->guest_rpte & HPTE_GR_MODIFIED);
@@ -1374,8 +1395,11 @@ static long record_hpte(unsigned long flags, __be64 *hptp,
dirty = 1;
}
- if (v & HPTE_V_ABSENT) {
- v &= ~HPTE_V_ABSENT;
+ if (v & HPTE_V_VRMA) {
+ /*
+ * unmapped vrma consider them mapped and also
+ * retain the HPTE_V_VRMA bit.
+ */
v |= HPTE_V_VALID;
valid = 1;
}
@@ -1559,14 +1583,14 @@ static ssize_t kvm_htab_write(struct file *file, const char __user *buf,
lbuf += 2;
nb += HPTE_SIZE;
- if (be64_to_cpu(hptp[0]) & (HPTE_V_VALID | HPTE_V_ABSENT))
+ if (be64_to_cpu(hptp[0]) & (HPTE_V_VALID | HPTE_V_VRMA))
kvmppc_do_h_remove(kvm, 0, i, 0, tmp);
err = -EIO;
/*
* Clear few bits we got via read_htab which we
* don't need to carry forward.
*/
- v &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+ v &= ~(HPTE_V_HVLOCK | HPTE_V_VALID);
r &= ~(HPTE_R_KEY_HI | HPTE_R_KEY_LO | HPTE_GR_RESERVED);
ret = kvmppc_virtmode_do_h_enter(kvm, H_EXACT, i, v, r,
@@ -1592,7 +1616,7 @@ static ssize_t kvm_htab_write(struct file *file, const char __user *buf,
}
for (j = 0; j < hdr.n_invalid; ++j) {
- if (be64_to_cpu(hptp[0]) & (HPTE_V_VALID | HPTE_V_ABSENT))
+ if (be64_to_cpu(hptp[0]) & (HPTE_V_VALID | HPTE_V_VRMA))
kvmppc_do_h_remove(kvm, 0, i, 0, tmp);
++i;
hptp += 2;
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index d628d2810c93..f907be908b28 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -252,7 +252,13 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
ptel &= ~(HPTE_R_PP0 - psize);
ptel |= pa;
-
+ /*
+ * We mark the pte valid, if it is valid from guest point of view
+ * For VRMA area we need to mark it still invalid, because access
+ * class protection mechanism doesn't work with guest real mode
+ * access.
+ * Non vrma area is always valid, and vram is valid only if pa is set.
+ */
if (pa)
pteh |= HPTE_V_VALID;
@@ -278,7 +284,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
for (i = 0; i < 8; ++i) {
if ((be64_to_cpu(*hpte) & HPTE_V_VALID) == 0 &&
try_lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID |
- HPTE_V_ABSENT))
+ HPTE_V_VRMA))
break;
hpte += 2;
}
@@ -295,7 +301,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
cpu_relax();
pte = be64_to_cpu(*hpte);
- if (!(pte & (HPTE_V_VALID | HPTE_V_ABSENT)))
+ if (!(pte & (HPTE_V_VALID | HPTE_V_VRMA)))
break;
*hpte &= ~cpu_to_be64(HPTE_V_HVLOCK);
hpte += 2;
@@ -307,14 +313,14 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
} else {
hpte = (__be64 *)(kvm->arch.hpt_virt + (pte_index << 4));
if (!try_lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID |
- HPTE_V_ABSENT)) {
+ HPTE_V_VRMA)) {
/* Lock the slot and check again */
u64 pte;
while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
cpu_relax();
pte = be64_to_cpu(*hpte);
- if (pte & (HPTE_V_VALID | HPTE_V_ABSENT)) {
+ if (pte & (HPTE_V_VALID | HPTE_V_VRMA)) {
*hpte &= ~cpu_to_be64(HPTE_V_HVLOCK);
return H_PTEG_FULL;
}
@@ -372,7 +378,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
/*
* Clear few bits. when called via hcall.
*/
- pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+ pteh &= ~(HPTE_V_HVLOCK | HPTE_V_VRMA | HPTE_V_VALID);
ptel &= ~(HPTE_R_KEY_HI | HPTE_R_KEY_LO | HPTE_GR_RESERVED);
return kvmppc_do_h_enter(vcpu->kvm, flags, pte_index, pteh, ptel,
@@ -492,7 +498,7 @@ long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
cpu_relax();
pte = be64_to_cpu(hpte[0]);
- if ((pte & (HPTE_V_ABSENT | HPTE_V_VALID)) == 0 ||
+ if ((pte & (HPTE_V_VRMA | HPTE_V_VALID)) == 0 ||
((flags & H_AVPN) && (pte & ~0x7fUL) != avpn) ||
((flags & H_ANDCOND) && (pte & avpn) != 0)) {
hpte[0] &= ~cpu_to_be64(HPTE_V_HVLOCK);
@@ -503,9 +509,12 @@ long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
v = pte & ~HPTE_V_HVLOCK;
if (v & HPTE_V_VALID) {
u64 pte1;
-
pte1 = be64_to_cpu(hpte[1]);
- hpte[0] &= ~cpu_to_be64(HPTE_V_VALID);
+ /*
+ * Remove the valid and VRMA bits
+ */
+ hpte[0] &= ~cpu_to_be64(HPTE_V_VALID | HPTE_V_VRMA);
+
rb = compute_tlbie_rb(v, pte1, pte_index);
do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true);
/* Read PTE low word after tlbie to get final R/C values */
@@ -572,7 +581,7 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
}
found = 0;
hp0 = be64_to_cpu(hp[0]);
- if (hp0 & (HPTE_V_ABSENT | HPTE_V_VALID)) {
+ if (hp0 & (HPTE_V_VRMA | HPTE_V_VALID)) {
switch (flags & 3) {
case 0: /* absolute */
found = 1;
@@ -606,7 +615,7 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
}
/* leave it locked */
- hp[0] &= ~cpu_to_be64(HPTE_V_VALID);
+ hp[0] &= ~cpu_to_be64(HPTE_V_VALID | HPTE_V_VRMA);
tlbrb[n] = compute_tlbie_rb(be64_to_cpu(hp[0]),
be64_to_cpu(hp[1]), pte_index);
indexes[n] = j;
@@ -656,7 +665,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
cpu_relax();
pte = be64_to_cpu(hpte[0]);
- if ((pte & (HPTE_V_ABSENT | HPTE_V_VALID)) == 0 ||
+ if ((pte & (HPTE_V_VRMA | HPTE_V_VALID)) == 0 ||
((flags & H_AVPN) && (pte & ~0x7fUL) != avpn)) {
hpte[0] &= ~cpu_to_be64(HPTE_V_HVLOCK);
return H_NOT_FOUND;
@@ -758,10 +767,17 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
hpte = (__be64 *)(kvm->arch.hpt_virt + (pte_index << 4));
v = be64_to_cpu(hpte[0]) & ~HPTE_V_HVLOCK;
r = be64_to_cpu(hpte[1]);
- if (v & HPTE_V_ABSENT) {
- v &= ~HPTE_V_ABSENT;
+ if (v & HPTE_V_VRMA) {
+ /*
+ * don't share vrma bits back to guest
+ */
+ v &= ~HPTE_V_VRMA;
v |= HPTE_V_VALID;
}
+ /*
+ * Clear the AMR class bits
+ */
+ r &= ~(HPTE_R_KEY_HI | HPTE_R_KEY_LO);
if (v & HPTE_V_VALID) {
r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C));
r &= ~HPTE_GR_RESERVED;
@@ -871,8 +887,13 @@ long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
/* Read the PTE racily */
v = be64_to_cpu(hpte[i]) & ~HPTE_V_HVLOCK;
- /* Check valid/absent, hash, segment size and AVPN */
- if (!(v & valid) || (v & mask) != val)
+ /*
+ * Check hash, segment size and AVPN.
+ * We can't check for valid here without lock. We do
+ * mark the hpte not valid while an hpte update is
+ * in progress.
+ */
+ if ((v & mask) != val)
continue;
/* Lock the PTE and read it under the lock */
@@ -927,7 +948,7 @@ long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
/* For protection fault, expect to find a valid HPTE */
valid = HPTE_V_VALID;
if (status & DSISR_NOHPTE)
- valid |= HPTE_V_ABSENT;
+ valid |= HPTE_V_VRMA;
index = kvmppc_hv_find_lock_hpte(kvm, addr, slb_v, valid);
if (index < 0) {
@@ -942,10 +963,17 @@ long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
gr = rev->guest_rpte;
unlock_hpte(hpte, v);
-
- /* For not found, if the HPTE is valid by now, retry the instruction */
+ /*
+ * For not found, if the HPTE is valid by now, retry the instruction
+ */
if ((status & DSISR_NOHPTE) && (v & HPTE_V_VALID))
return 0;
+ /*
+ * For key fault if HPTE is host mapped by now retry the instruction
+ */
+ if ((status & DSISR_KEYFAULT) &&
+ kvmppc_is_host_mapped_hpte(kvm, hpte))
+ return 0;
/* Check access permissions to the page */
pp = gr & (HPTE_R_PP0 | HPTE_R_PP);
@@ -973,8 +1001,7 @@ long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
/* Check the storage key to see if it is possibly emulated MMIO */
if (data && (vcpu->arch.shregs.msr & MSR_IR) &&
- (r & (HPTE_R_KEY_HI | HPTE_R_KEY_LO)) ==
- (HPTE_R_KEY_HI | HPTE_R_KEY_LO))
+ ((r & HPTE_R_MMIO_UNMAP_KEY) == HPTE_R_MMIO_UNMAP_KEY))
return -2; /* MMIO emulation - load instr word */
return -1; /* send fault up to host kernel mode */
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 0b425da9f8db..f1af0d24e2b5 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -834,7 +834,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
mtmsrd r8
/* Load up POWER8-specific registers */
+ /*
+ * Always disable read/write w.r.t to class index 31
+ */
ld r5, VCPU_IAMR(r4)
+ ori r5, r5, 0x3
lwz r6, VCPU_PSPB(r4)
ld r7, VCPU_FSCR(r4)
mtspr SPRN_IAMR, r5
@@ -901,10 +905,25 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
mtspr SPRN_DSISR, r6
BEGIN_FTR_SECTION
- /* Restore AMR and UAMOR, set AMOR to all 1s */
- ld r5,VCPU_AMR(r4)
+ /* Restore AMR and UAMOR */
+ /*
+ * Always disable read/write wr.t. to class index
+ * 30 and 31
+ */
+ ld r5, VCPU_AMR(r4)
+ ori r5, r5, 0xf
+ /*
+ * UAMOR set so that mask bits for class index 30
+ * and 31 cannot be updated
+ */
+
ld r6,VCPU_UAMOR(r4)
- li r7,-1
+ rldicr r6, r6, 0, 59
+ /*
+ * AMOR set so that mask bits for class index 30
+ * and 31 cannot be updated
+ */
+ li r7, ~0xf
mtspr SPRN_AMR,r5
mtspr SPRN_UAMOR,r6
mtspr SPRN_AMOR,r7
@@ -1801,13 +1820,22 @@ kvmppc_hdsi:
*/
cmpwi r0, 0
bne 5f
-
- andi. r0, r11, MSR_DR /* data relocation enabled? */
+ /*
+ * If data relocation is disabled, virtual page class
+ * key protection mechanis does not apply.
+ */
+ andi. r0, r11, MSR_DR
beq 3f
-
- /* HPTE not found fault or protection fault? */
- andis. r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h
- beq 1f /* if not, send it to the guest */
+ /*
+ * If access is not permitted by virtual page class
+ * key protection, handle it in the host. If not
+ * send it to the guest.
+ */
+ andis. r0, r6, (DSISR_KEYFAULT | DSISR_PROTFAULT)@h
+ beq 1f
+ /*
+ * skip the real mode check below
+ */
b 8f
5:
/*
@@ -1857,7 +1885,8 @@ fast_interrupt_c_return:
3: /*
* Check whether we can send the fault directly to
- * guest.
+ * guest. We don't need to worry about keyfault if
+ * the fault happens in real mode.
*/
andis. r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h
beq 1b
@@ -1907,8 +1936,7 @@ kvmppc_hisi:
andi. r0, r11, MSR_IR /* instruction relocation enabled? */
beq 3f
-
- andis. r0, r11, SRR1_ISI_NOPT@h
+ andis. r0, r11, SRR1_ISI_KEYFAULT@h
beq 1f
b 8f
5:
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 0/6] Use virtual page class key protection mechanism for speeding up guest page fault
From: Benjamin Herrenschmidt @ 2014-06-29 11:26 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: linuxppc-dev, paulus, agraf, kvm-ppc, kvm
In-Reply-To: <1404040655-12076-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On Sun, 2014-06-29 at 16:47 +0530, Aneesh Kumar K.V wrote:
> To achieve the above we use virtual page calss protection mechanism for
> covering (2) and (3). For both the above case we mark the hpte
> valid, but associate the page with virtual page class index 30 and 31.
> The authority mask register is configured such that class index 30 and 31
> will have read/write denied. The above change results in a key fault
> for (2) and (3). This allows us to forward a NO_HPTE fault directly to guest
> without doing the expensive hash pagetable lookup.
So we have a measurable performance benefit (about half a second out of
8) but you didn't explain the drawback here which is to essentially make
it impossible for guests to exploit virtual page class keys, or did you
find a way to still make that possible ?
As it-is, it's not a huge issue for Linux but we might have to care with
other OSes that do care...
Do we have a way in PAPR to signify to the guest that the keys are not
available ?
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH 0/6] Use virtual page class key protection mechanism for speeding up guest page fault
From: Aneesh Kumar K.V @ 2014-06-29 16:57 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, paulus, agraf, kvm-ppc, kvm
In-Reply-To: <1404041166.31323.2.camel@pasglop>
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> On Sun, 2014-06-29 at 16:47 +0530, Aneesh Kumar K.V wrote:
>
>> To achieve the above we use virtual page calss protection mechanism for
>> covering (2) and (3). For both the above case we mark the hpte
>> valid, but associate the page with virtual page class index 30 and 31.
>> The authority mask register is configured such that class index 30 and 31
>> will have read/write denied. The above change results in a key fault
>> for (2) and (3). This allows us to forward a NO_HPTE fault directly to guest
>> without doing the expensive hash pagetable lookup.
>
> So we have a measurable performance benefit (about half a second out of
> 8).
I was able to measure a performance benefit of 2 seconds earlier. But
once i get the below patch applied that got reduced. I am trying
to find how the patch is helping the performance. May be it is
avoiding some unnecessary invalidation ?
http://mid.gmane.org/1403876103-32459-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com
I also believe the benefit depends on how much impact a hash table
lookup have. I did try to access the addresses linearly so that I can make
sure we do take a cache miss for hash page table access.
>but you didn't explain the drawback here which is to essentially make
> it impossible for guests to exploit virtual page class keys, or did you
> find a way to still make that possible ?
I am now making PROTFAULT to go to host. That means, ksm sharing is
represented as read only page and an attempt to write to it will get to
host via PROTFAULT. Now with that we can implement keys for guest if we
want to. So irrespective of what restrictions guest has put in, if the
host swapout the page, we will deny read/write. Now if the key fault
need to go to guest, we will find that out looking at the key index.
>
> As it-is, it's not a huge issue for Linux but we might have to care with
> other OSes that do care...
>
> Do we have a way in PAPR to signify to the guest that the keys are not
> available ?
Right now Qemu doesn't provide the device tree node
ibm,processor-storage-keys. That means guest cannot use keys. So we are
good there. If we want to support guest keys, we need to fill that with
the value that indicate how many keys can be used for data and instruction.
-aneesh
^ permalink raw reply
* Re: [RFC PATCH v2 4/6] mmc: sdhci: host: add new f_sdh30
From: Vincent Yang @ 2014-06-30 2:10 UTC (permalink / raw)
To: Mark Rutland
Cc: devicetree@vger.kernel.org, andy.green@linaro.org,
patches@linaro.org, anton@enomsg.org, linux-mmc@vger.kernel.org,
chris@printf.net, jaswinder.singh@linaro.org,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20140627101248.GD7262@leverpostej>
2014-06-27 18:12 GMT+08:00 Mark Rutland <mark.rutland@arm.com>:
> On Fri, Jun 27, 2014 at 04:32:21AM +0100, Vincent Yang wrote:
>> 2014-06-26 19:03 GMT+08:00 Mark Rutland <mark.rutland@arm.com>:
>> > On Thu, Jun 26, 2014 at 07:23:30AM +0100, Vincent Yang wrote:
>> >> This patch adds new host controller driver for
>> >> Fujitsu SDHCI controller f_sdh30.
>> >>
>> >> Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
>> >> ---
>> >> .../devicetree/bindings/mmc/sdhci-fujitsu.txt | 35 +++
>> >> drivers/mmc/host/Kconfig | 7 +
>> >> drivers/mmc/host/Makefile | 1 +
>> >> drivers/mmc/host/sdhci_f_sdh30.c | 346 +++++++++++++++++++++
>> >> drivers/mmc/host/sdhci_f_sdh30.h | 40 +++
>> >> 5 files changed, 429 insertions(+)
>> >> create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt
>> >> create mode 100644 drivers/mmc/host/sdhci_f_sdh30.c
>> >> create mode 100644 drivers/mmc/host/sdhci_f_sdh30.h
>> >>
>> >> diff --git a/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt b/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt
>> >> new file mode 100644
>> >> index 0000000..40add438
>> >> --- /dev/null
>> >> +++ b/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt
>> >> @@ -0,0 +1,35 @@
>> >> +* Fujitsu SDHCI controller
>> >> +
>> >> +This file documents differences between the core properties in mmc.txt
>> >> +and the properties used by the sdhci_f_sdh30 driver.
>> >> +
>> >> +Required properties:
>> >> +- compatible: "fujitsu,f_sdh30"
>> >
>> > Please use '-' rather than '_' in compatible strings.
>>
>> Hi Mark,
>> Yes, I'll update it to '-' in next version.
>>
>> >
>> > This seems to be the name of the driver. What is the precise name of the
>> > IP block?
>>
>> The name of the IP block is "F_SDH30".
>> That's why it uses "fujitsu,f_sdh30"
>
> Hmm. I'd still be tempted to use "fujitsu,f-sdh30".
Hi Mark,
Sure, I'll update it to "fujitsu,f-sdh30" in next version.
>
>> >
>> > [...]
>> >
>> >> + if (!of_property_read_u32(pdev->dev.of_node, "vendor-hs200",
>> >> + &priv->vendor_hs200))
>> >> + dev_info(dev, "Applying vendor-hs200 setting\n");
>> >> + else
>> >> + priv->vendor_hs200 = 0;
>> >
>> > This wasn't in the binding document, and a grep for "vendor-hs200" in a
>> > v3.16-rc2 tree found me nothing.
>> >
>> > Please document this.
>>
>> Yes, it is a setting for a vendor specific register.
>> I'll update it in next version.
>
> It would be nice to know exactly what this is. We usually shy clear of
> placing register values in dt. I can wait until the next posting if
> you're goin to document that.
I'm thinking about removing this register value in dt.
I'll update it in next version.
>
>> >> + if (!of_property_read_u32(pdev->dev.of_node, "bus-width", &bus_width)) {
>> >> + if (bus_width == 8) {
>> >> + dev_info(dev, "Applying 8 bit bus width\n");
>> >> + host->mmc->caps |= MMC_CAP_8_BIT_DATA;
>> >> + }
>> >> + }
>> >
>> > What if bus-width is not 8, or is not present?
>>
>> In both cases, it will not touch host->mmc->caps at all. Then sdhci_add_host()
>> will handle it and set MMC_CAP_4_BIT_DATA as default:
>>
>> [...]
>> /*
>> * A controller may support 8-bit width, but the board itself
>> * might not have the pins brought out. Boards that support
>> * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in
>> * their platform code before calling sdhci_add_host(), and we
>> * won't assume 8-bit width for hosts without that CAP.
>> */
>> if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
>> mmc->caps |= MMC_CAP_4_BIT_DATA;
>
> Ok, but does it make sense for a dts to have:
>
> bus-width = <1>;
>
> If so, we should presumably do something.
>
> If not, we should at least print a warning that the dtb doesn't make
> sense.
I'll print a warning for invalid values in next version.
Thanks a lot for your review!
Best regards,
Vincent Yang
>
> Cheers,
> Mark.
^ permalink raw reply
* Re: [PATCH v4] [BUGFIX] kprobes: Fix "Failed to find blacklist" error on ia64 and ppc64
From: Masami Hiramatsu @ 2014-06-30 3:14 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Tony Luck
Cc: Jeremy Fitzhardinge, linux-ia64, sparse, H. Peter Anvin, akataria,
linux-tip-commits, anil.s.keshavamurthy, Ingo Molnar,
Suzuki K. Poulose, Fenghua Yu, Arnd Bergmann, Rusty Russell,
Chris Wright, yrl.pp-manager.tt, Thomas Gleixner, Tony Luck,
Kevin Hao, Linus Torvalds, rdunlap, Linux Kernel Mailing List,
dl9pf, Andrew Morton, linuxppc-dev, David S. Miller
In-Reply-To: <20140620022307.23075.55858.stgit@kbuild-fedora.novalocal>
Ping? :)
(2014/06/20 11:23), Masami Hiramatsu wrote:
> On ia64 and ppc64, the function pointer does not point the
> entry address of the function, but the address of function
> discriptor (which contains the entry address and misc
> data.) Since the kprobes passes the function pointer stored
> by NOKPROBE_SYMBOL() to kallsyms_lookup_size_offset() for
> initalizing its blacklist, it fails and reports many errors
> as below.
>
> Failed to find blacklist 0001013168300000
> Failed to find blacklist 0001013000f0a000
> Failed to find blacklist 000101315f70a000
> Failed to find blacklist 000101324c80a000
> Failed to find blacklist 0001013063f0a000
> Failed to find blacklist 000101327800a000
> Failed to find blacklist 0001013277f0a000
> Failed to find blacklist 000101315a70a000
> Failed to find blacklist 0001013277e0a000
> Failed to find blacklist 000101305a20a000
> Failed to find blacklist 0001013277d0a000
> Failed to find blacklist 00010130bdc0a000
> Failed to find blacklist 00010130dc20a000
> Failed to find blacklist 000101309a00a000
> Failed to find blacklist 0001013277c0a000
> Failed to find blacklist 0001013277b0a000
> Failed to find blacklist 0001013277a0a000
> Failed to find blacklist 000101327790a000
> Failed to find blacklist 000101303140a000
> Failed to find blacklist 0001013a3280a000
>
> To fix this bug, this introduces function_entry() macro to
> retrieve the entry address from the given function pointer,
> and uses for kallsyms_lookup_size_offset() while initializing
> blacklist.
>
> Changes in v4:
> - Add kernel_text_address() check for verifying the address.
> - Moved on the latest linus tree.
>
> Changes in v3:
> - Fix a bug to get blacklist address based on function entry
> instead of function descriptor. (Suzuki's work, Thanks!)
>
> Changes in V2:
> - Use function_entry() macro when lookin up symbols instead
> of storing it.
> - Update for the latest -next.
>
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Reported-by: Tony Luck <tony.luck@gmail.com>
> Tested-by: Tony Luck <tony.luck@intel.com>
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: Suzuki K. Poulose <suzuki@in.ibm.com>
> Cc: Tony Luck <tony.luck@intel.com>
> Cc: Fenghua Yu <fenghua.yu@intel.com>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
> Cc: Kevin Hao <haokexin@gmail.com>
> Cc: linux-ia64@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Cc: linuxppc-dev@lists.ozlabs.org
> ---
> arch/ia64/include/asm/types.h | 2 ++
> arch/powerpc/include/asm/types.h | 11 +++++++++++
> include/linux/types.h | 4 ++++
> kernel/kprobes.c | 15 ++++++++++-----
> 4 files changed, 27 insertions(+), 5 deletions(-)
>
> diff --git a/arch/ia64/include/asm/types.h b/arch/ia64/include/asm/types.h
> index 4c351b1..95279dd 100644
> --- a/arch/ia64/include/asm/types.h
> +++ b/arch/ia64/include/asm/types.h
> @@ -27,5 +27,7 @@ struct fnptr {
> unsigned long gp;
> };
>
> +#define function_entry(fn) (((struct fnptr *)(fn))->ip)
> +
> #endif /* !__ASSEMBLY__ */
> #endif /* _ASM_IA64_TYPES_H */
> diff --git a/arch/powerpc/include/asm/types.h b/arch/powerpc/include/asm/types.h
> index bfb6ded..8b89d65 100644
> --- a/arch/powerpc/include/asm/types.h
> +++ b/arch/powerpc/include/asm/types.h
> @@ -25,6 +25,17 @@ typedef struct {
> unsigned long env;
> } func_descr_t;
>
> +#if defined(CONFIG_PPC64) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
> +/*
> + * On PPC64 ABIv1 the function pointer actually points to the
> + * function's descriptor. The first entry in the descriptor is the
> + * address of the function text.
> + */
> +#define function_entry(fn) (((func_descr_t *)(fn))->entry)
> +#else
> +#define function_entry(fn) ((unsigned long)(fn))
> +#endif
> +
> #endif /* __ASSEMBLY__ */
>
> #endif /* _ASM_POWERPC_TYPES_H */
> diff --git a/include/linux/types.h b/include/linux/types.h
> index a0bb704..3b95369 100644
> --- a/include/linux/types.h
> +++ b/include/linux/types.h
> @@ -213,5 +213,9 @@ struct callback_head {
> };
> #define rcu_head callback_head
>
> +#ifndef function_entry
> +#define function_entry(fn) ((unsigned long)(fn))
> +#endif
> +
> #endif /* __ASSEMBLY__ */
> #endif /* _LINUX_TYPES_H */
> diff --git a/kernel/kprobes.c b/kernel/kprobes.c
> index 3214289..7412535 100644
> --- a/kernel/kprobes.c
> +++ b/kernel/kprobes.c
> @@ -32,6 +32,7 @@
> * <prasanna@in.ibm.com> added function-return probes.
> */
> #include <linux/kprobes.h>
> +#include <linux/types.h>
> #include <linux/hash.h>
> #include <linux/init.h>
> #include <linux/slab.h>
> @@ -2037,19 +2038,23 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
> {
> unsigned long *iter;
> struct kprobe_blacklist_entry *ent;
> - unsigned long offset = 0, size = 0;
> + unsigned long entry, offset = 0, size = 0;
>
> for (iter = start; iter < end; iter++) {
> - if (!kallsyms_lookup_size_offset(*iter, &size, &offset)) {
> - pr_err("Failed to find blacklist %p\n", (void *)*iter);
> + entry = function_entry(*iter);
> +
> + if (!kernel_text_address(entry) ||
> + !kallsyms_lookup_size_offset(entry, &size, &offset)) {
> + pr_err("Failed to find blacklist at %p\n",
> + (void *)entry);
> continue;
> }
>
> ent = kmalloc(sizeof(*ent), GFP_KERNEL);
> if (!ent)
> return -ENOMEM;
> - ent->start_addr = *iter;
> - ent->end_addr = *iter + size;
> + ent->start_addr = entry;
> + ent->end_addr = entry + size;
> INIT_LIST_HEAD(&ent->list);
> list_add_tail(&ent->list, &kprobe_blacklist);
> }
>
>
>
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com
^ permalink raw reply
* [PATCH] Fixes return issues in uic_init_one
From: Nicholas Krause @ 2014-06-30 4:02 UTC (permalink / raw)
To: paulus; +Cc: linuxppc-dev, linux-kernel
This patch fixes the FIXME messages for returning a ENOMEM error
if uic is not allocated and if uic->irqhost is not allocated a
IRQ domain that is linear returns EIO.
Signed-off-by: Nicholas Krause <xerofoify@gmail.com>
---
arch/powerpc/sysdev/uic.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 9203393..f95010a 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -239,7 +239,7 @@ static struct uic * __init uic_init_one(struct device_node *node)
uic = kzalloc(sizeof(*uic), GFP_KERNEL);
if (! uic)
- return NULL; /* FIXME: panic? */
+ return -ENOMEM;
raw_spin_lock_init(&uic->lock);
indexp = of_get_property(node, "cell-index", &len);
@@ -261,7 +261,7 @@ static struct uic * __init uic_init_one(struct device_node *node)
uic->irqhost = irq_domain_add_linear(node, NR_UIC_INTS, &uic_host_ops,
uic);
if (! uic->irqhost)
- return NULL; /* FIXME: panic? */
+ return -EIO;
/* Start with all interrupts disabled, level and non-critical */
mtdcr(uic->dcrbase + UIC_ER, 0);
--
1.9.1
^ permalink raw reply related
* RE: [RESEND PATCH] memory: Freescale CoreNet Coherency Fabric error reporting driver
From: Bharat.Bhushan @ 2014-06-30 4:58 UTC (permalink / raw)
To: Scott Wood
Cc: Greg Kroah-Hartman, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org
In-Reply-To: <1401901656.6603.327.camel@snotra.buserror.net>
DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogV29vZCBTY290dC1CMDc0
MjENCj4gU2VudDogV2VkbmVzZGF5LCBKdW5lIDA0LCAyMDE0IDEwOjM4IFBNDQo+IFRvOiBCaHVz
aGFuIEJoYXJhdC1SNjU3NzcNCj4gQ2M6IEdyZWcgS3JvYWgtSGFydG1hbjsgbGludXhwcGMtZGV2
QGxpc3RzLm96bGFicy5vcmc7IGxpbnV4LQ0KPiBrZXJuZWxAdmdlci5rZXJuZWwub3JnDQo+IFN1
YmplY3Q6IFJlOiBbUkVTRU5EIFBBVENIXSBtZW1vcnk6IEZyZWVzY2FsZSBDb3JlTmV0IENvaGVy
ZW5jeSBGYWJyaWMgZXJyb3INCj4gcmVwb3J0aW5nIGRyaXZlcg0KPiANCj4gT24gV2VkLCAyMDE0
LTA2LTA0IGF0IDEyOjA0IC0wNTAwLCBCaHVzaGFuIEJoYXJhdC1SNjU3Nzcgd3JvdGU6DQo+ID4N
Cj4gPiA+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+ID4gPiBGcm9tOiBXb29kIFNjb3R0
LUIwNzQyMQ0KPiA+ID4gU2VudDogV2VkbmVzZGF5LCBKdW5lIDA0LCAyMDE0IDEwOjEyIFBNDQo+
ID4gPiBUbzogQmh1c2hhbiBCaGFyYXQtUjY1Nzc3DQo+ID4gPiBDYzogR3JlZyBLcm9haC1IYXJ0
bWFuOyBsaW51eHBwYy1kZXZAbGlzdHMub3psYWJzLm9yZzsgbGludXgtDQo+ID4gPiBrZXJuZWxA
dmdlci5rZXJuZWwub3JnDQo+ID4gPiBTdWJqZWN0OiBSZTogW1JFU0VORCBQQVRDSF0gbWVtb3J5
OiBGcmVlc2NhbGUgQ29yZU5ldCBDb2hlcmVuY3kNCj4gPiA+IEZhYnJpYyBlcnJvciByZXBvcnRp
bmcgZHJpdmVyDQo+ID4gPg0KPiA+ID4gT24gV2VkLCAyMDE0LTA2LTA0IGF0IDAzOjE3IC0wNTAw
LCBCaHVzaGFuIEJoYXJhdC1SNjU3Nzcgd3JvdGU6DQo+ID4gPiA+ID4gK3N0YXRpYyBpbnQgY2Nm
X3JlbW92ZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KSB7DQo+ID4gPiA+ID4gKwlzdHJ1
Y3QgY2NmX3ByaXZhdGUgKmNjZiA9IGRldl9nZXRfZHJ2ZGF0YSgmcGRldi0+ZGV2KTsNCj4gPiA+
ID4gPiArDQo+ID4gPiA+ID4gKwlzd2l0Y2ggKGNjZi0+aW5mby0+dmVyc2lvbikgew0KPiA+ID4g
PiA+ICsJY2FzZSBDQ0YxOg0KPiA+ID4gPiA+ICsJCWlvd3JpdGUzMmJlKDAsICZjY2YtPmVycl9y
ZWdzLT5lcnJkaXMpOw0KPiA+ID4gPiA+ICsJCWJyZWFrOw0KPiA+ID4gPiA+ICsNCj4gPiA+ID4g
PiArCWNhc2UgQ0NGMjoNCj4gPiA+ID4gPiArCQlpb3dyaXRlMzJiZSgwLCAmY2NmLT5lcnJfcmVn
cy0+ZXJyaW50ZW4pOw0KPiA+ID4gPg0KPiA+ID4gPiBEbyB5b3UgdGhpbmsgaXQgaXMgc2FtZSB0
byBkaXNhYmxlIGRldGVjdGlvbiBiaXRzIGluIGNjZi0+ZXJyX3JlZ3MtDQo+ID5lcnJkaXM/DQo+
ID4gPg0KPiA+ID4gRGlzYWJsaW5nIHRoZSBpbnRlcnJ1cHQgaXMgd2hhdCB3ZSdyZSBhaW1pbmcg
Zm9yIGhlcmUsIGJ1dCBjY2YxDQo+ID4gPiBkb2Vzbid0IHByb3ZpZGUgYSB3YXkgdG8gZG8gdGhh
dCBzZXBhcmF0ZSBmcm9tIGRpc2FibGluZyBkZXRlY3Rpb24uDQo+ID4NCj4gPiBXaGF0IEkgd2Fu
dGVkIHRvIHNheSB0aGF0IGRvIHdlIGFsc28gbmVlZCB0byBkaXNhYmxlIGRldGVjdGlvbiAoc2V0
DQo+ID4gRVJSREVUX0xBRSB8IEVSUkRFVF9DViBiaXRzIGluIGVycmRpcykgYXBhcnQgZnJvbSBj
bGVhcmluZyBlcnJpbnRlbiBvbg0KPiA+IGNjZjIgPw0KPiANCj4gSSBkb24ndCB0aGluayB3ZSAi
bmVlZCIgdG8uICBZb3UgY291bGQgYXJndWUgdGhhdCB3ZSBzaG91bGQgZm9yIGNvbnNpc3RlbmN5
LA0KPiB0aG91Z2ggSSB0aGluayB0aGVyZSdzIHZhbHVlIGluIGVycm9ycyBjb250aW51aW5nIHRv
IGJlIGRldGVjdGVkIGV2ZW4gd2l0aG91dA0KPiB0aGUgZHJpdmVyIChlLmcuIGNhbiBkdW1wIHRo
ZSByZWdpc3RlcnMgaW4gYSBkZWJ1Z2dlcikuDQoNClllcyB0aGlzIGNvbW1lbnQgd2FzIGZvciBj
b25zaXN0ZW5jeS4gQWxzbyBJSVVDLCB0aGUgc3RhdGUgd2hpY2ggaXMgbGVmdCB3aGVuIHRoZSBk
cml2ZXIgaXMgcmVtb3ZlZCBpcyBub3QgZGVmYXVsdCByZXNldCBiZWhhdmlvci4NCklmIHdlIHdh
bnQgZXJyb3JzIHRvIGJlIGRldGVjdGVkIHRoZW4gc2hvdWxkIG5vdCB3ZSBoYXZlIGEgc3lzZnMg
aW50ZXJmYWNlPw0KDQpUaGFua3MNCi1CaGFyYXQNCg0KPiANCj4gLVNjb3R0DQo+IA0KDQo=
^ permalink raw reply
* [PATCH] powerpc/powernv: Check for IRQHAPPENED before sleeping
From: Preeti U Murthy @ 2014-06-30 6:24 UTC (permalink / raw)
To: benh, mikey, mpe; +Cc: shreyas, linuxppc-dev, linux-kernel
Commit 8d6f7c5a: "powerpc/powernv: Make it possible to skip the IRQHAPPENED
check in power7_nap()" added code that prevents even cores which enter sleep
on idle, from checking for pending interrupts. Fix this.
Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
---
arch/powerpc/kernel/idle_power7.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 2480256..5cf3d36 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -131,7 +131,7 @@ _GLOBAL(power7_nap)
_GLOBAL(power7_sleep)
li r3,1
- li r4,0
+ li r4,1
b power7_powersave_common
/* No return */
^ permalink raw reply related
* Regression in 3.15 on POWER8 with multipath SCSI
From: Paul Mackerras @ 2014-06-30 10:30 UTC (permalink / raw)
To: dm-devel, linux-kernel, linuxppc-dev
Cc: Vladimir Davydov, Andrew Morton, Linus Torvalds, Hannes Reinecke
I have a machine on which 3.15 usually fails to boot, and 3.14 boots
every time. The machine is a POWER8 2-socket server with 20 cores
(thus 160 CPUs), 128GB of RAM, and 7 SCSI disks connected via a
hardware-RAID-capable adapter which appears as two IPR controllers
which are both connected to each disk. I am booting from a disk that
has Fedora 20 installed on it.
After over two weeks of bisections, I can finally point to the commits
that cause the problems. The culprits are:
3e9f1be1 dm mpath: remove process_queued_ios()
e8099177 dm mpath: push back requests instead of queueing
bcccff93 kobject: don't block for each kobject_uevent
The interesting thing is that neither e8099177 nor bcccff93 cause
failures on their own, but with both commits in there are failures
where the system will fail to find /home on some occasions.
With 3e9f1be1 included, the system appears to be prone to a deadlock
condition which typically causes the boot process to hang with this
message showing:
A start job is running for Monitoring of LVM2 mirror...rogress polling
(with a [*** ] thing before it where the asterisks move back and
forth).
If I revert 63d832c3 ("dm mpath: really fix lockdep warning") ,
4cdd2ad7 ("dm mpath: fix lock order inconsistency in
multipath_ioctl"), 3e9f1be1 and bcccff93, in that order, I get a
kernel that will boot every time. The first two are later commits
that fix some problems with 3e9f1be1 (though not the problems I am
seeing).
Can anyone see any reason why e8099177 and bcccff93 would interfere
with each other?
-----
The rest of this email outlines the steps I took to identify these
commits. I first identified that 3.15-rc1 would sometimes fail to
boot, and did a bisection between 3.15 and 3.15-rc1 that identified
3e9f1be1 as the bad commit. I then took 3.15-rc8 and reverted
63d832c3, 4cdd2ad7 and 3e9f1be1, and tested that. That didn't fail
with the deadlock, but was still prone to fail to find root or /home
and thus fail to boot.
To debug this second problem, I tested the commit before Linus merged
in the dm modifications: 3f583bc2 ("Merge tag 'iommu-updates-v3.15' of
git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu"). It was
fine. I then took 0596661f ("dm cache: fix a lock-inversion"), which
is what Linus merged in during the 3.15 merge window, reverted
3e9f1be1 on top of that, and tested that, and it also was fine.
The ID of that revert commit was 9cfd3fe8 (that ID doesn't appear in
any public tree, of course).
Interestingly, the merge of 3f583bc2 with 9cfd3fe8 was bad. To track
this down, I first rebased the commits from the dm-3.15-changes branch
except for 3e9f1be1 on top of 3f583bc2, and bisected between 3f583bc2
and the tip of that branch. That bisection pointed to e8099177. I
tried reverting that from 3.15-rc8, but it doesn't revert cleanly, and
was too complex for me to work out how to manually revert it.
Next I did a git bisection between 3.14 and 3f583bc2, merging in
9cfd3fe8 at each point before testing. That identified bcccff93 as
the first bad commit, and indeed 3.15 with bcccff93 reverted was not
prone to failing to find root or /home.
Paul.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox