]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-upstream' of https://github.com/agraf/linux-2.6 into queue
authorMarcelo Tosatti <mtosatti@redhat.com>
Sun, 9 Dec 2012 20:44:10 +0000 (18:44 -0200)
committerMarcelo Tosatti <mtosatti@redhat.com>
Sun, 9 Dec 2012 20:44:10 +0000 (18:44 -0200)
* 'for-upstream' of https://github.com/agraf/linux-2.6: (28 commits)
  KVM: PPC: booke: Get/set guest EPCR register using ONE_REG interface
  KVM: PPC: bookehv: Add EPCR support in mtspr/mfspr emulation
  KVM: PPC: bookehv: Add guest computation mode for irq delivery
  KVM: PPC: Make EPCR a valid field for booke64 and bookehv
  KVM: PPC: booke: Extend MAS2 EPN mask for 64-bit
  KVM: PPC: e500: Mask MAS2 EPN high 32-bits in 32/64 tlbwe emulation
  KVM: PPC: Mask ea's high 32-bits in 32/64 instr emulation
  KVM: PPC: e500: Add emulation helper for getting instruction ea
  KVM: PPC: bookehv64: Add support for interrupt handling
  KVM: PPC: bookehv: Remove GET_VCPU macro from exception handler
  KVM: PPC: booke: Fix get_tb() compile error on 64-bit
  KVM: PPC: e500: Silence bogus GCC warning in tlb code
  KVM: PPC: Book3S HV: Handle guest-caused machine checks on POWER7 without panicking
  KVM: PPC: Book3S HV: Improve handling of local vs. global TLB invalidations
  MAINTAINERS: Add git tree link for PPC KVM
  KVM: PPC: Book3S PR: MSR_DE doesn't exist on Book 3S
  KVM: PPC: Book3S PR: Fix VSX handling
  KVM: PPC: Book3S PR: Emulate PURR, SPURR and DSCR registers
  KVM: PPC: Book3S HV: Don't give the guest RW access to RO pages
  KVM: PPC: Book3S HV: Report correct HPT entry index when reading HPT
  ...

34 files changed:
Documentation/virtual/kvm/api.txt
MAINTAINERS
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/include/asm/kvm_booke_hv_asm.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/include/asm/mmu-hash64.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/uapi/asm/kvm.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kvm/Kconfig
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_emulate.c
arch/powerpc/kvm/book3s_exports.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_ras.c [new file with mode: 0644]
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/book3s_rmhandlers.S
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/booke.h
arch/powerpc/kvm/booke_emulate.c
arch/powerpc/kvm/bookehv_interrupts.S
arch/powerpc/kvm/e500.h
arch/powerpc/kvm/e500_emulate.c
arch/powerpc/kvm/e500_tlb.c
arch/powerpc/kvm/powerpc.c
include/linux/kvm_host.h
include/uapi/linux/kvm.h
virt/kvm/eventfd.c

index 6671fdc0afb1171920976b841da0f968a90f70cb..a4df5535996b9bca097d65a7c7a2851d9ab46dfe 100644 (file)
@@ -1773,6 +1773,7 @@ registers, find a list below:
   PPC   | KVM_REG_PPC_VPA_ADDR  | 64
   PPC   | KVM_REG_PPC_VPA_SLB   | 128
   PPC   | KVM_REG_PPC_VPA_DTL   | 128
+  PPC   | KVM_REG_PPC_EPCR     | 32
 
 4.69 KVM_GET_ONE_REG
 
@@ -2071,6 +2072,60 @@ KVM_S390_INT_EXTERNAL_CALL (vcpu) - sigp external call; source cpu in parm
 
 Note that the vcpu ioctl is asynchronous to vcpu execution.
 
+4.78 KVM_PPC_GET_HTAB_FD
+
+Capability: KVM_CAP_PPC_HTAB_FD
+Architectures: powerpc
+Type: vm ioctl
+Parameters: Pointer to struct kvm_get_htab_fd (in)
+Returns: file descriptor number (>= 0) on success, -1 on error
+
+This returns a file descriptor that can be used either to read out the
+entries in the guest's hashed page table (HPT), or to write entries to
+initialize the HPT.  The returned fd can only be written to if the
+KVM_GET_HTAB_WRITE bit is set in the flags field of the argument, and
+can only be read if that bit is clear.  The argument struct looks like
+this:
+
+/* For KVM_PPC_GET_HTAB_FD */
+struct kvm_get_htab_fd {
+       __u64   flags;
+       __u64   start_index;
+       __u64   reserved[2];
+};
+
+/* Values for kvm_get_htab_fd.flags */
+#define KVM_GET_HTAB_BOLTED_ONLY       ((__u64)0x1)
+#define KVM_GET_HTAB_WRITE             ((__u64)0x2)
+
+The `start_index' field gives the index in the HPT of the entry at
+which to start reading.  It is ignored when writing.
+
+Reads on the fd will initially supply information about all
+"interesting" HPT entries.  Interesting entries are those with the
+bolted bit set, if the KVM_GET_HTAB_BOLTED_ONLY bit is set, otherwise
+all entries.  When the end of the HPT is reached, the read() will
+return.  If read() is called again on the fd, it will start again from
+the beginning of the HPT, but will only return HPT entries that have
+changed since they were last read.
+
+Data read or written is structured as a header (8 bytes) followed by a
+series of valid HPT entries (16 bytes) each.  The header indicates how
+many valid HPT entries there are and how many invalid entries follow
+the valid entries.  The invalid entries are not represented explicitly
+in the stream.  The header format is:
+
+struct kvm_get_htab_header {
+       __u32   index;
+       __u16   n_valid;
+       __u16   n_invalid;
+};
+
+Writes to the fd create HPT entries starting at the index given in the
+header; first `n_valid' valid entries with contents from the data
+written, then `n_invalid' invalid entries, invalidating any previously
+valid entries found.
+
 
 5. The kvm_run structure
 ------------------------
index 4376c528f75b106cb709fecc32cc366fa88ece09..703446720a26827e70a79ab679013ccde862a2f6 100644 (file)
@@ -4253,6 +4253,7 @@ KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
 M:     Alexander Graf <agraf@suse.de>
 L:     kvm-ppc@vger.kernel.org
 W:     http://kvm.qumranet.com
+T:     git git://github.com/agraf/linux-2.6.git
 S:     Supported
 F:     arch/powerpc/include/asm/kvm*
 F:     arch/powerpc/kvm/
index 36fcf41904613cf442bd07338887bb492735213a..5a56e1c5f8517fde0b4005c0c456d14a0b4ce7bc 100644 (file)
@@ -81,6 +81,8 @@ struct kvmppc_vcpu_book3s {
        u64 sdr1;
        u64 hior;
        u64 msr_mask;
+       u64 purr_offset;
+       u64 spurr_offset;
 #ifdef CONFIG_PPC_BOOK3S_32
        u32 vsid_pool[VSID_POOL_SIZE];
        u32 vsid_next;
@@ -157,8 +159,12 @@ extern void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long addr,
 extern void kvmppc_unpin_guest_page(struct kvm *kvm, void *addr);
 extern long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
                        long pte_index, unsigned long pteh, unsigned long ptel);
-extern long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
-                       long pte_index, unsigned long pteh, unsigned long ptel);
+extern long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
+                       long pte_index, unsigned long pteh, unsigned long ptel,
+                       pgd_t *pgdir, bool realmode, unsigned long *idx_ret);
+extern long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
+                       unsigned long pte_index, unsigned long avpn,
+                       unsigned long *hpret);
 extern long kvmppc_hv_get_dirty_log(struct kvm *kvm,
                        struct kvm_memory_slot *memslot, unsigned long *map);
 
index 1472a5b4e4e3fc785563d58a15adb3684e552a1d..38bec1dc99281f682ddf13209c296be0a8da056b 100644 (file)
@@ -50,6 +50,15 @@ extern int kvm_hpt_order;            /* order of preallocated HPTs */
 #define HPTE_V_HVLOCK  0x40UL
 #define HPTE_V_ABSENT  0x20UL
 
+/*
+ * We use this bit in the guest_rpte field of the revmap entry
+ * to indicate a modified HPTE.
+ */
+#define HPTE_GR_MODIFIED       (1ul << 62)
+
+/* These bits are reserved in the guest view of the HPTE */
+#define HPTE_GR_RESERVED       HPTE_GR_MODIFIED
+
 static inline long try_lock_hpte(unsigned long *hpte, unsigned long bits)
 {
        unsigned long tmp, old;
@@ -237,4 +246,26 @@ static inline bool slot_is_aligned(struct kvm_memory_slot *memslot,
        return !(memslot->base_gfn & mask) && !(memslot->npages & mask);
 }
 
+/*
+ * This works for 4k, 64k and 16M pages on POWER7,
+ * and 4k and 16M pages on PPC970.
+ */
+static inline unsigned long slb_pgsize_encoding(unsigned long psize)
+{
+       unsigned long senc = 0;
+
+       if (psize > 0x1000) {
+               senc = SLB_VSID_L;
+               if (psize == 0x10000)
+                       senc |= SLB_VSID_LP_01;
+       }
+       return senc;
+}
+
+static inline int is_vrma_hpte(unsigned long hpte_v)
+{
+       return (hpte_v & ~0xffffffUL) ==
+               (HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)));
+}
+
 #endif /* __ASM_KVM_BOOK3S_64_H__ */
index a37a12a9a7d720374304b8460f59b690f24c2556..3a79f53257125a4daf05e5546893eb8821606c3d 100644 (file)
@@ -17,6 +17,7 @@
  * there are no exceptions for which we fall through directly to
  * the normal host handler.
  *
+ * 32-bit host
  * Expected inputs (normal exceptions):
  *   SCRATCH0 = saved r10
  *   r10 = thread struct
  *   *(r8 + GPR9) = saved r9
  *   *(r8 + GPR10) = saved r10 (r10 not yet clobbered)
  *   *(r8 + GPR11) = saved r11
+ *
+ * 64-bit host
+ * Expected inputs (GEN/GDBELL/DBG/MC exception types):
+ *  r10 = saved CR
+ *  r13 = PACA_POINTER
+ *  *(r13 + PACA_EX##type + EX_R10) = saved r10
+ *  *(r13 + PACA_EX##type + EX_R11) = saved r11
+ *  SPRN_SPRG_##type##_SCRATCH = saved r13
+ *
+  * Expected inputs (CRIT exception type):
+ *  r10 = saved CR
+ *  r13 = PACA_POINTER
+ *  *(r13 + PACA_EX##type + EX_R10) = saved r10
+ *  *(r13 + PACA_EX##type + EX_R11) = saved r11
+ *  *(r13 + PACA_EX##type + EX_R13) = saved r13
+ *
+ * Expected inputs (TLB exception type):
+ *  r10 = saved CR
+ *  r13 = PACA_POINTER
+ *  *(r13 + PACA_EX##type + EX_TLB_R10) = saved r10
+ *  *(r13 + PACA_EX##type + EX_TLB_R11) = saved r11
+ *  SPRN_SPRG_GEN_SCRATCH = saved r13
+ *
+ * Only the bolted version of TLB miss exception handlers is supported now.
  */
 .macro DO_KVM intno srr1
 #ifdef CONFIG_KVM_BOOKE_HV
index 3093896015f0d8cb70ad4f8335de243a90d780bd..ca9bf459db6a56e2bb7d1e450a7b5c4d6026a3ae 100644 (file)
@@ -246,10 +246,12 @@ struct kvm_arch {
        int using_mmu_notifiers;
        u32 hpt_order;
        atomic_t vcpus_running;
+       u32 online_vcores;
        unsigned long hpt_npte;
        unsigned long hpt_mask;
+       atomic_t hpte_mod_interest;
        spinlock_t slot_phys_lock;
-       unsigned short last_vcpu[NR_CPUS];
+       cpumask_t need_tlb_flush;
        struct kvmppc_vcore *vcores[KVM_MAX_VCORES];
        struct kvmppc_linear_info *hpt_li;
 #endif /* CONFIG_KVM_BOOK3S_64_HV */
@@ -274,6 +276,7 @@ struct kvmppc_vcore {
        int nap_count;
        int napping_threads;
        u16 pcpu;
+       u16 last_cpu;
        u8 vcore_state;
        u8 in_guest;
        struct list_head runnable_threads;
@@ -403,13 +406,18 @@ struct kvm_vcpu_arch {
        u32 host_mas4;
        u32 host_mas6;
        u32 shadow_epcr;
-       u32 epcr;
        u32 shadow_msrp;
        u32 eplc;
        u32 epsc;
        u32 oldpir;
 #endif
 
+#if defined(CONFIG_BOOKE)
+#if defined(CONFIG_KVM_BOOKE_HV) || defined(CONFIG_64BIT)
+       u32 epcr;
+#endif
+#endif
+
 #ifdef CONFIG_PPC_BOOK3S
        /* For Gekko paired singles */
        u32 qpr[32];
@@ -522,7 +530,6 @@ struct kvm_vcpu_arch {
        u64 dec_jiffies;
        u64 dec_expires;
        unsigned long pending_exceptions;
-       u16 last_cpu;
        u8 ceded;
        u8 prodded;
        u32 last_inst;
index 609cca3e942621a7380c79724cd6e72d2e6d9b5c..572aa75306191272c684a8263a5900cd876352c2 100644 (file)
@@ -164,6 +164,8 @@ extern void kvmppc_bookehv_exit(void);
 
 extern int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu);
 
+extern int kvm_vm_ioctl_get_htab_fd(struct kvm *kvm, struct kvm_get_htab_fd *);
+
 /*
  * Cuts out inst bits with ordering according to spec.
  * That means the leftmost bit is zero. All given bits are included.
@@ -293,4 +295,25 @@ static inline void kvmppc_lazy_ee_enable(void)
 #endif
 }
 
+static inline ulong kvmppc_get_ea_indexed(struct kvm_vcpu *vcpu, int ra, int rb)
+{
+       ulong ea;
+       ulong msr_64bit = 0;
+
+       ea = kvmppc_get_gpr(vcpu, rb);
+       if (ra)
+               ea += kvmppc_get_gpr(vcpu, ra);
+
+#if defined(CONFIG_PPC_BOOK3E_64)
+       msr_64bit = MSR_CM;
+#elif defined(CONFIG_PPC_BOOK3S_64)
+       msr_64bit = MSR_SF;
+#endif
+
+       if (!(vcpu->arch.shared->msr & msr_64bit))
+               ea = (uint32_t)ea;
+
+       return ea;
+}
+
 #endif /* __POWERPC_KVM_PPC_H__ */
index eeabcdbc30f7ab00bd7856983e020e70db8a7045..99d43e0c1e4af1198ea4fd07ad3834d0eb4c8f82 100644 (file)
@@ -59,7 +59,7 @@
 #define MAS1_TSIZE_SHIFT       7
 #define MAS1_TSIZE(x)          (((x) << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
 
-#define MAS2_EPN               0xFFFFF000
+#define MAS2_EPN               (~0xFFFUL)
 #define MAS2_X0                        0x00000040
 #define MAS2_X1                        0x00000020
 #define MAS2_W                 0x00000010
index 9673f73eb8db2294159a3356266b97c7df6734c2..2fdb47a19efda298b8ddc3749f174be75e1e7a63 100644 (file)
@@ -121,6 +121,16 @@ extern char initial_stab[];
 #define PP_RXRX 3      /* Supervisor read,       User read */
 #define PP_RXXX        (HPTE_R_PP0 | 2)        /* Supervisor read, user none */
 
+/* Fields for tlbiel instruction in architecture 2.06 */
+#define TLBIEL_INVAL_SEL_MASK  0xc00   /* invalidation selector */
+#define  TLBIEL_INVAL_PAGE     0x000   /* invalidate a single page */
+#define  TLBIEL_INVAL_SET_LPID 0x800   /* invalidate a set for current LPID */
+#define  TLBIEL_INVAL_SET      0xc00   /* invalidate a set for all LPIDs */
+#define TLBIEL_INVAL_SET_MASK  0xfff000        /* set number to inval. */
+#define TLBIEL_INVAL_SET_SHIFT 12
+
+#define POWER7_TLB_SETS                128     /* # sets in POWER7 TLB */
+
 #ifndef __ASSEMBLY__
 
 struct hash_pte {
index d24c14163966599ed3a78f559f80191f7cd53693..97d37278ea2da4f978bbf5b5967b5ed22912ee7d 100644 (file)
 #define          SRR1_WS_DEEPER        0x00020000 /* Some resources not maintained */
 #define          SRR1_WS_DEEP          0x00010000 /* All resources maintained */
 #define   SRR1_PROGFPE         0x00100000 /* Floating Point Enabled */
+#define   SRR1_PROGILL         0x00080000 /* Illegal instruction */
 #define   SRR1_PROGPRIV                0x00040000 /* Privileged instruction */
 #define   SRR1_PROGTRAP                0x00020000 /* Trap */
 #define   SRR1_PROGADDR                0x00010000 /* SRR0 contains subsequent addr */
index b89ae4db45ced4523e101c18a5477c62c928fd0a..2fba8a66fb10f8a609d2e95e3b97174bbd70a6a6 100644 (file)
@@ -331,6 +331,31 @@ struct kvm_book3e_206_tlb_params {
        __u32 reserved[8];
 };
 
+/* For KVM_PPC_GET_HTAB_FD */
+struct kvm_get_htab_fd {
+       __u64   flags;
+       __u64   start_index;
+       __u64   reserved[2];
+};
+
+/* Values for kvm_get_htab_fd.flags */
+#define KVM_GET_HTAB_BOLTED_ONLY       ((__u64)0x1)
+#define KVM_GET_HTAB_WRITE             ((__u64)0x2)
+
+/*
+ * Data read on the file descriptor is formatted as a series of
+ * records, each consisting of a header followed by a series of
+ * `n_valid' HPTEs (16 bytes each), which are all valid.  Following
+ * those valid HPTEs there are `n_invalid' invalid HPTEs, which
+ * are not represented explicitly in the stream.  The same format
+ * is used for writing.
+ */
+struct kvm_get_htab_header {
+       __u32   index;
+       __u16   n_valid;
+       __u16   n_invalid;
+};
+
 #define KVM_REG_PPC_HIOR       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
 #define KVM_REG_PPC_IAC1       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2)
 #define KVM_REG_PPC_IAC2       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3)
@@ -386,4 +411,6 @@ struct kvm_book3e_206_tlb_params {
 #define KVM_REG_PPC_VPA_SLB    (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x83)
 #define KVM_REG_PPC_VPA_DTL    (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84)
 
+#define KVM_REG_PPC_EPCR       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85)
+
 #endif /* __LINUX_KVM_POWERPC_H */
index 7523539cfe9f88e0a49e4b8a5715e8dff7a64fc7..4e23ba2f3ca7622d7f2fe66f6d0925bae26f0cf1 100644 (file)
@@ -441,8 +441,7 @@ int main(void)
        DEFINE(KVM_HOST_LPCR, offsetof(struct kvm, arch.host_lpcr));
        DEFINE(KVM_HOST_SDR1, offsetof(struct kvm, arch.host_sdr1));
        DEFINE(KVM_TLBIE_LOCK, offsetof(struct kvm, arch.tlbie_lock));
-       DEFINE(KVM_ONLINE_CPUS, offsetof(struct kvm, online_vcpus.counter));
-       DEFINE(KVM_LAST_VCPU, offsetof(struct kvm, arch.last_vcpu));
+       DEFINE(KVM_NEED_FLUSH, offsetof(struct kvm, arch.need_tlb_flush.bits));
        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));
@@ -470,7 +469,6 @@ int main(void)
        DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb));
        DEFINE(VCPU_SLB_MAX, offsetof(struct kvm_vcpu, arch.slb_max));
        DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr));
-       DEFINE(VCPU_LAST_CPU, offsetof(struct kvm_vcpu, arch.last_cpu));
        DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr));
        DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar));
        DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
index 71f0cd9edf335a4751895c16f6b3069e5f872950..4730c953f4357f41df6bf87a8a5a590c53c6f2e1 100644 (file)
@@ -20,6 +20,7 @@ config KVM
        bool
        select PREEMPT_NOTIFIERS
        select ANON_INODES
+       select HAVE_KVM_EVENTFD
 
 config KVM_BOOK3S_HANDLER
        bool
index c2a08636e6d4294a12e5148fd4a8dd8fe07dbe7d..1e473d46322cd977e5948ec0012ee3563d04ba8b 100644 (file)
@@ -6,7 +6,8 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
 ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm
 
-common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
+common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o \
+                                               eventfd.o)
 
 CFLAGS_44x_tlb.o  := -I.
 CFLAGS_e500_tlb.o := -I.
@@ -72,10 +73,12 @@ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
        book3s_hv_rmhandlers.o \
        book3s_hv_rm_mmu.o \
        book3s_64_vio_hv.o \
+       book3s_hv_ras.o \
        book3s_hv_builtin.o
 
 kvm-book3s_64-module-objs := \
        ../../../virt/kvm/kvm_main.o \
+       ../../../virt/kvm/eventfd.o \
        powerpc.o \
        emulate.o \
        book3s.o \
index 2a89a36e726344dadd5e065b12f49e234c2aa8f7..8cc18abd6dde6b486996bf9f4719fdeb12e0c65e 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/hugetlb.h>
 #include <linux/vmalloc.h>
 #include <linux/srcu.h>
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
 
 #include <asm/tlbflush.h>
 #include <asm/kvm_ppc.h>
 /* Power architecture requires HPT is at least 256kB */
 #define PPC_MIN_HPT_ORDER      18
 
+static long kvmppc_virtmode_do_h_enter(struct kvm *kvm, unsigned long flags,
+                               long pte_index, unsigned long pteh,
+                               unsigned long ptel, unsigned long *pte_idx_ret);
+static void kvmppc_rmap_reset(struct kvm *kvm);
+
 long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
 {
        unsigned long hpt;
@@ -138,10 +145,11 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp)
                /* Set the entire HPT to 0, i.e. invalid HPTEs */
                memset((void *)kvm->arch.hpt_virt, 0, 1ul << order);
                /*
-                * Set the whole last_vcpu array to an invalid vcpu number.
-                * This ensures that each vcpu will flush its TLB on next entry.
+                * Reset all the reverse-mapping chains for all memslots
                 */
-               memset(kvm->arch.last_vcpu, 0xff, sizeof(kvm->arch.last_vcpu));
+               kvmppc_rmap_reset(kvm);
+               /* Ensure that each vcpu will flush its TLB on next entry. */
+               cpumask_setall(&kvm->arch.need_tlb_flush);
                *htab_orderp = order;
                err = 0;
        } else {
@@ -185,6 +193,7 @@ void kvmppc_map_vrma(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
        unsigned long addr, hash;
        unsigned long psize;
        unsigned long hp0, hp1;
+       unsigned long idx_ret;
        long ret;
        struct kvm *kvm = vcpu->kvm;
 
@@ -216,7 +225,8 @@ 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;
-               ret = kvmppc_virtmode_h_enter(vcpu, H_EXACT, hash, hp_v, hp_r);
+               ret = kvmppc_virtmode_do_h_enter(kvm, H_EXACT, hash, hp_v, hp_r,
+                                                &idx_ret);
                if (ret != H_SUCCESS) {
                        pr_err("KVM: map_vrma at %lx failed, ret=%ld\n",
                               addr, ret);
@@ -354,15 +364,10 @@ static long kvmppc_get_guest_page(struct kvm *kvm, unsigned long gfn,
        return err;
 }
 
-/*
- * We come here on a H_ENTER call from the guest when we are not
- * using mmu notifiers and we don't have the requested page pinned
- * already.
- */
-long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
-                       long pte_index, unsigned long pteh, unsigned long ptel)
+long kvmppc_virtmode_do_h_enter(struct kvm *kvm, unsigned long flags,
+                               long pte_index, unsigned long pteh,
+                               unsigned long ptel, unsigned long *pte_idx_ret)
 {
-       struct kvm *kvm = vcpu->kvm;
        unsigned long psize, gpa, gfn;
        struct kvm_memory_slot *memslot;
        long ret;
@@ -390,8 +395,8 @@ long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
  do_insert:
        /* Protect linux PTE lookup from page table destruction */
        rcu_read_lock_sched();  /* this disables preemption too */
-       vcpu->arch.pgdir = current->mm->pgd;
-       ret = kvmppc_h_enter(vcpu, flags, pte_index, pteh, ptel);
+       ret = kvmppc_do_h_enter(kvm, flags, pte_index, pteh, ptel,
+                               current->mm->pgd, false, pte_idx_ret);
        rcu_read_unlock_sched();
        if (ret == H_TOO_HARD) {
                /* this can't happen */
@@ -402,6 +407,19 @@ long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 
 }
 
+/*
+ * We come here on a H_ENTER call from the guest when we are not
+ * using mmu notifiers and we don't have the requested page pinned
+ * already.
+ */
+long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
+                            long pte_index, unsigned long pteh,
+                            unsigned long ptel)
+{
+       return kvmppc_virtmode_do_h_enter(vcpu->kvm, flags, pte_index,
+                                         pteh, ptel, &vcpu->arch.gpr[4]);
+}
+
 static struct kvmppc_slb *kvmppc_mmu_book3s_hv_find_slbe(struct kvm_vcpu *vcpu,
                                                         gva_t eaddr)
 {
@@ -756,6 +774,25 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
        goto out_put;
 }
 
+static void kvmppc_rmap_reset(struct kvm *kvm)
+{
+       struct kvm_memslots *slots;
+       struct kvm_memory_slot *memslot;
+       int srcu_idx;
+
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       slots = kvm->memslots;
+       kvm_for_each_memslot(memslot, slots) {
+               /*
+                * This assumes it is acceptable to lose reference and
+                * change bits across a reset.
+                */
+               memset(memslot->arch.rmap, 0,
+                      memslot->npages * sizeof(*memslot->arch.rmap));
+       }
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+}
+
 static int kvm_handle_hva_range(struct kvm *kvm,
                                unsigned long start,
                                unsigned long end,
@@ -1131,6 +1168,348 @@ void kvmppc_unpin_guest_page(struct kvm *kvm, void *va)
        put_page(page);
 }
 
+/*
+ * Functions for reading and writing the hash table via reads and
+ * writes on a file descriptor.
+ *
+ * Reads return the guest view of the hash table, which has to be
+ * pieced together from the real hash table and the guest_rpte
+ * values in the revmap array.
+ *
+ * On writes, each HPTE written is considered in turn, and if it
+ * is valid, it is written to the HPT as if an H_ENTER with the
+ * exact flag set was done.  When the invalid count is non-zero
+ * in the header written to the stream, the kernel will make
+ * sure that that many HPTEs are invalid, and invalidate them
+ * if not.
+ */
+
+struct kvm_htab_ctx {
+       unsigned long   index;
+       unsigned long   flags;
+       struct kvm      *kvm;
+       int             first_pass;
+};
+
+#define HPTE_SIZE      (2 * sizeof(unsigned long))
+
+static long record_hpte(unsigned long flags, unsigned long *hptp,
+                       unsigned long *hpte, struct revmap_entry *revp,
+                       int want_valid, int first_pass)
+{
+       unsigned long v, r;
+       int ok = 1;
+       int valid, dirty;
+
+       /* Unmodified entries are uninteresting except on the first pass */
+       dirty = !!(revp->guest_rpte & HPTE_GR_MODIFIED);
+       if (!first_pass && !dirty)
+               return 0;
+
+       valid = 0;
+       if (hptp[0] & (HPTE_V_VALID | HPTE_V_ABSENT)) {
+               valid = 1;
+               if ((flags & KVM_GET_HTAB_BOLTED_ONLY) &&
+                   !(hptp[0] & HPTE_V_BOLTED))
+                       valid = 0;
+       }
+       if (valid != want_valid)
+               return 0;
+
+       v = r = 0;
+       if (valid || dirty) {
+               /* lock the HPTE so it's stable and read it */
+               preempt_disable();
+               while (!try_lock_hpte(hptp, HPTE_V_HVLOCK))
+                       cpu_relax();
+               v = hptp[0];
+               if (v & HPTE_V_ABSENT) {
+                       v &= ~HPTE_V_ABSENT;
+                       v |= HPTE_V_VALID;
+               }
+               /* re-evaluate valid and dirty from synchronized HPTE value */
+               valid = !!(v & HPTE_V_VALID);
+               if ((flags & KVM_GET_HTAB_BOLTED_ONLY) && !(v & HPTE_V_BOLTED))
+                       valid = 0;
+               r = revp->guest_rpte | (hptp[1] & (HPTE_R_R | HPTE_R_C));
+               dirty = !!(revp->guest_rpte & HPTE_GR_MODIFIED);
+               /* only clear modified if this is the right sort of entry */
+               if (valid == want_valid && dirty) {
+                       r &= ~HPTE_GR_MODIFIED;
+                       revp->guest_rpte = r;
+               }
+               asm volatile(PPC_RELEASE_BARRIER "" : : : "memory");
+               hptp[0] &= ~HPTE_V_HVLOCK;
+               preempt_enable();
+               if (!(valid == want_valid && (first_pass || dirty)))
+                       ok = 0;
+       }
+       hpte[0] = v;
+       hpte[1] = r;
+       return ok;
+}
+
+static ssize_t kvm_htab_read(struct file *file, char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       struct kvm_htab_ctx *ctx = file->private_data;
+       struct kvm *kvm = ctx->kvm;
+       struct kvm_get_htab_header hdr;
+       unsigned long *hptp;
+       struct revmap_entry *revp;
+       unsigned long i, nb, nw;
+       unsigned long __user *lbuf;
+       struct kvm_get_htab_header __user *hptr;
+       unsigned long flags;
+       int first_pass;
+       unsigned long hpte[2];
+
+       if (!access_ok(VERIFY_WRITE, buf, count))
+               return -EFAULT;
+
+       first_pass = ctx->first_pass;
+       flags = ctx->flags;
+
+       i = ctx->index;
+       hptp = (unsigned long *)(kvm->arch.hpt_virt + (i * HPTE_SIZE));
+       revp = kvm->arch.revmap + i;
+       lbuf = (unsigned long __user *)buf;
+
+       nb = 0;
+       while (nb + sizeof(hdr) + HPTE_SIZE < count) {
+               /* Initialize header */
+               hptr = (struct kvm_get_htab_header __user *)buf;
+               hdr.n_valid = 0;
+               hdr.n_invalid = 0;
+               nw = nb;
+               nb += sizeof(hdr);
+               lbuf = (unsigned long __user *)(buf + sizeof(hdr));
+
+               /* Skip uninteresting entries, i.e. clean on not-first pass */
+               if (!first_pass) {
+                       while (i < kvm->arch.hpt_npte &&
+                              !(revp->guest_rpte & HPTE_GR_MODIFIED)) {
+                               ++i;
+                               hptp += 2;
+                               ++revp;
+                       }
+               }
+               hdr.index = i;
+
+               /* Grab a series of valid entries */
+               while (i < kvm->arch.hpt_npte &&
+                      hdr.n_valid < 0xffff &&
+                      nb + HPTE_SIZE < count &&
+                      record_hpte(flags, hptp, hpte, revp, 1, first_pass)) {
+                       /* valid entry, write it out */
+                       ++hdr.n_valid;
+                       if (__put_user(hpte[0], lbuf) ||
+                           __put_user(hpte[1], lbuf + 1))
+                               return -EFAULT;
+                       nb += HPTE_SIZE;
+                       lbuf += 2;
+                       ++i;
+                       hptp += 2;
+                       ++revp;
+               }
+               /* Now skip invalid entries while we can */
+               while (i < kvm->arch.hpt_npte &&
+                      hdr.n_invalid < 0xffff &&
+                      record_hpte(flags, hptp, hpte, revp, 0, first_pass)) {
+                       /* found an invalid entry */
+                       ++hdr.n_invalid;
+                       ++i;
+                       hptp += 2;
+                       ++revp;
+               }
+
+               if (hdr.n_valid || hdr.n_invalid) {
+                       /* write back the header */
+                       if (__copy_to_user(hptr, &hdr, sizeof(hdr)))
+                               return -EFAULT;
+                       nw = nb;
+                       buf = (char __user *)lbuf;
+               } else {
+                       nb = nw;
+               }
+
+               /* Check if we've wrapped around the hash table */
+               if (i >= kvm->arch.hpt_npte) {
+                       i = 0;
+                       ctx->first_pass = 0;
+                       break;
+               }
+       }
+
+       ctx->index = i;
+
+       return nb;
+}
+
+static ssize_t kvm_htab_write(struct file *file, const char __user *buf,
+                             size_t count, loff_t *ppos)
+{
+       struct kvm_htab_ctx *ctx = file->private_data;
+       struct kvm *kvm = ctx->kvm;
+       struct kvm_get_htab_header hdr;
+       unsigned long i, j;
+       unsigned long v, r;
+       unsigned long __user *lbuf;
+       unsigned long *hptp;
+       unsigned long tmp[2];
+       ssize_t nb;
+       long int err, ret;
+       int rma_setup;
+
+       if (!access_ok(VERIFY_READ, buf, count))
+               return -EFAULT;
+
+       /* lock out vcpus from running while we're doing this */
+       mutex_lock(&kvm->lock);
+       rma_setup = kvm->arch.rma_setup_done;
+       if (rma_setup) {
+               kvm->arch.rma_setup_done = 0;   /* temporarily */
+               /* order rma_setup_done vs. vcpus_running */
+               smp_mb();
+               if (atomic_read(&kvm->arch.vcpus_running)) {
+                       kvm->arch.rma_setup_done = 1;
+                       mutex_unlock(&kvm->lock);
+                       return -EBUSY;
+               }
+       }
+
+       err = 0;
+       for (nb = 0; nb + sizeof(hdr) <= count; ) {
+               err = -EFAULT;
+               if (__copy_from_user(&hdr, buf, sizeof(hdr)))
+                       break;
+
+               err = 0;
+               if (nb + hdr.n_valid * HPTE_SIZE > count)
+                       break;
+
+               nb += sizeof(hdr);
+               buf += sizeof(hdr);
+
+               err = -EINVAL;
+               i = hdr.index;
+               if (i >= kvm->arch.hpt_npte ||
+                   i + hdr.n_valid + hdr.n_invalid > kvm->arch.hpt_npte)
+                       break;
+
+               hptp = (unsigned long *)(kvm->arch.hpt_virt + (i * HPTE_SIZE));
+               lbuf = (unsigned long __user *)buf;
+               for (j = 0; j < hdr.n_valid; ++j) {
+                       err = -EFAULT;
+                       if (__get_user(v, lbuf) || __get_user(r, lbuf + 1))
+                               goto out;
+                       err = -EINVAL;
+                       if (!(v & HPTE_V_VALID))
+                               goto out;
+                       lbuf += 2;
+                       nb += HPTE_SIZE;
+
+                       if (hptp[0] & (HPTE_V_VALID | HPTE_V_ABSENT))
+                               kvmppc_do_h_remove(kvm, 0, i, 0, tmp);
+                       err = -EIO;
+                       ret = kvmppc_virtmode_do_h_enter(kvm, H_EXACT, i, v, r,
+                                                        tmp);
+                       if (ret != H_SUCCESS) {
+                               pr_err("kvm_htab_write ret %ld i=%ld v=%lx "
+                                      "r=%lx\n", ret, i, v, r);
+                               goto out;
+                       }
+                       if (!rma_setup && is_vrma_hpte(v)) {
+                               unsigned long psize = hpte_page_size(v, r);
+                               unsigned long senc = slb_pgsize_encoding(psize);
+                               unsigned long lpcr;
+
+                               kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T |
+                                       (VRMA_VSID << SLB_VSID_SHIFT_1T);
+                               lpcr = kvm->arch.lpcr & ~LPCR_VRMASD;
+                               lpcr |= senc << (LPCR_VRMASD_SH - 4);
+                               kvm->arch.lpcr = lpcr;
+                               rma_setup = 1;
+                       }
+                       ++i;
+                       hptp += 2;
+               }
+
+               for (j = 0; j < hdr.n_invalid; ++j) {
+                       if (hptp[0] & (HPTE_V_VALID | HPTE_V_ABSENT))
+                               kvmppc_do_h_remove(kvm, 0, i, 0, tmp);
+                       ++i;
+                       hptp += 2;
+               }
+               err = 0;
+       }
+
+ out:
+       /* Order HPTE updates vs. rma_setup_done */
+       smp_wmb();
+       kvm->arch.rma_setup_done = rma_setup;
+       mutex_unlock(&kvm->lock);
+
+       if (err)
+               return err;
+       return nb;
+}
+
+static int kvm_htab_release(struct inode *inode, struct file *filp)
+{
+       struct kvm_htab_ctx *ctx = filp->private_data;
+
+       filp->private_data = NULL;
+       if (!(ctx->flags & KVM_GET_HTAB_WRITE))
+               atomic_dec(&ctx->kvm->arch.hpte_mod_interest);
+       kvm_put_kvm(ctx->kvm);
+       kfree(ctx);
+       return 0;
+}
+
+static struct file_operations kvm_htab_fops = {
+       .read           = kvm_htab_read,
+       .write          = kvm_htab_write,
+       .llseek         = default_llseek,
+       .release        = kvm_htab_release,
+};
+
+int kvm_vm_ioctl_get_htab_fd(struct kvm *kvm, struct kvm_get_htab_fd *ghf)
+{
+       int ret;
+       struct kvm_htab_ctx *ctx;
+       int rwflag;
+
+       /* reject flags we don't recognize */
+       if (ghf->flags & ~(KVM_GET_HTAB_BOLTED_ONLY | KVM_GET_HTAB_WRITE))
+               return -EINVAL;
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+       kvm_get_kvm(kvm);
+       ctx->kvm = kvm;
+       ctx->index = ghf->start_index;
+       ctx->flags = ghf->flags;
+       ctx->first_pass = 1;
+
+       rwflag = (ghf->flags & KVM_GET_HTAB_WRITE) ? O_WRONLY : O_RDONLY;
+       ret = anon_inode_getfd("kvm-htab", &kvm_htab_fops, ctx, rwflag);
+       if (ret < 0) {
+               kvm_put_kvm(kvm);
+               return ret;
+       }
+
+       if (rwflag == O_RDONLY) {
+               mutex_lock(&kvm->slots_lock);
+               atomic_inc(&kvm->arch.hpte_mod_interest);
+               /* make sure kvmppc_do_h_enter etc. see the increment */
+               synchronize_srcu_expedited(&kvm->srcu);
+               mutex_unlock(&kvm->slots_lock);
+       }
+
+       return ret;
+}
+
 void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_mmu *mmu = &vcpu->arch.mmu;
index b9a989dc76ccff5cd739f22910c4201c0dafb4e2..d31a716f7f2bc1d06b0a2021a422b1f69e8257e5 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/kvm_book3s.h>
 #include <asm/reg.h>
 #include <asm/switch_to.h>
+#include <asm/time.h>
 
 #define OP_19_XOP_RFID         18
 #define OP_19_XOP_RFI          50
@@ -395,6 +396,12 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
                    (mfmsr() & MSR_HV))
                        vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;
                break;
+       case SPRN_PURR:
+               to_book3s(vcpu)->purr_offset = spr_val - get_tb();
+               break;
+       case SPRN_SPURR:
+               to_book3s(vcpu)->spurr_offset = spr_val - get_tb();
+               break;
        case SPRN_GQR0:
        case SPRN_GQR1:
        case SPRN_GQR2:
@@ -412,6 +419,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
        case SPRN_CTRLF:
        case SPRN_CTRLT:
        case SPRN_L2CR:
+       case SPRN_DSCR:
        case SPRN_MMCR0_GEKKO:
        case SPRN_MMCR1_GEKKO:
        case SPRN_PMC1_GEKKO:
@@ -483,9 +491,15 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
                *spr_val = to_book3s(vcpu)->hid[5];
                break;
        case SPRN_CFAR:
-       case SPRN_PURR:
+       case SPRN_DSCR:
                *spr_val = 0;
                break;
+       case SPRN_PURR:
+               *spr_val = get_tb() + to_book3s(vcpu)->purr_offset;
+               break;
+       case SPRN_SPURR:
+               *spr_val = get_tb() + to_book3s(vcpu)->purr_offset;
+               break;
        case SPRN_GQR0:
        case SPRN_GQR1:
        case SPRN_GQR2:
index a150817d6d4c7f9d03763542dacad5cf45ada096..7057a02f0906b2545540d92bef5ae2f45b6c527a 100644 (file)
@@ -28,8 +28,5 @@ EXPORT_SYMBOL_GPL(kvmppc_load_up_fpu);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL_GPL(kvmppc_load_up_altivec);
 #endif
-#ifdef CONFIG_VSX
-EXPORT_SYMBOL_GPL(kvmppc_load_up_vsx);
-#endif
 #endif
 
index 843eb754a1d593493d56fe5a61728d985ed9419a..71d0c90b62bf6dfe5c2a512bdda80ed60963b3f2 100644 (file)
@@ -545,6 +545,17 @@ static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        case BOOK3S_INTERRUPT_PERFMON:
                r = RESUME_GUEST;
                break;
+       case BOOK3S_INTERRUPT_MACHINE_CHECK:
+               /*
+                * Deliver a machine check interrupt to the guest.
+                * We have to do this, even if the host has handled the
+                * machine check, because machine checks use SRR0/1 and
+                * the interrupt might have trashed guest state in them.
+                */
+               kvmppc_book3s_queue_irqprio(vcpu,
+                                           BOOK3S_INTERRUPT_MACHINE_CHECK);
+               r = RESUME_GUEST;
+               break;
        case BOOK3S_INTERRUPT_PROGRAM:
        {
                ulong flags;
@@ -853,7 +864,6 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
                goto free_vcpu;
 
        vcpu->arch.shared = &vcpu->arch.shregs;
-       vcpu->arch.last_cpu = -1;
        vcpu->arch.mmcr[0] = MMCR0_FC;
        vcpu->arch.ctrl = CTRL_RUNLATCH;
        /* default to host PVR, since we can't spoof it */
@@ -880,6 +890,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
                        vcore->preempt_tb = TB_NIL;
                }
                kvm->arch.vcores[core] = vcore;
+               kvm->arch.online_vcores++;
        }
        mutex_unlock(&kvm->lock);
 
@@ -1563,18 +1574,6 @@ out:
        return r;
 }
 
-static unsigned long slb_pgsize_encoding(unsigned long psize)
-{
-       unsigned long senc = 0;
-
-       if (psize > 0x1000) {
-               senc = SLB_VSID_L;
-               if (psize == 0x10000)
-                       senc |= SLB_VSID_LP_01;
-       }
-       return senc;
-}
-
 static void unpin_slot(struct kvm_memory_slot *memslot)
 {
        unsigned long *physp;
@@ -1814,6 +1813,13 @@ int kvmppc_core_init_vm(struct kvm *kvm)
                return -ENOMEM;
        kvm->arch.lpid = lpid;
 
+       /*
+        * Since we don't flush the TLB when tearing down a VM,
+        * and this lpid might have previously been used,
+        * make sure we flush on each core before running the new VM.
+        */
+       cpumask_setall(&kvm->arch.need_tlb_flush);
+
        INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
 
        kvm->arch.rma = NULL;
diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c
new file mode 100644 (file)
index 0000000..35f3cf0
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * Copyright 2012 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/kernel.h>
+#include <asm/opal.h>
+
+/* SRR1 bits for machine check on POWER7 */
+#define SRR1_MC_LDSTERR                (1ul << (63-42))
+#define SRR1_MC_IFETCH_SH      (63-45)
+#define SRR1_MC_IFETCH_MASK    0x7
+#define SRR1_MC_IFETCH_SLBPAR          2       /* SLB parity error */
+#define SRR1_MC_IFETCH_SLBMULTI                3       /* SLB multi-hit */
+#define SRR1_MC_IFETCH_SLBPARMULTI     4       /* SLB parity + multi-hit */
+#define SRR1_MC_IFETCH_TLBMULTI                5       /* I-TLB multi-hit */
+
+/* DSISR bits for machine check on POWER7 */
+#define DSISR_MC_DERAT_MULTI   0x800           /* D-ERAT multi-hit */
+#define DSISR_MC_TLB_MULTI     0x400           /* D-TLB multi-hit */
+#define DSISR_MC_SLB_PARITY    0x100           /* SLB parity error */
+#define DSISR_MC_SLB_MULTI     0x080           /* SLB multi-hit */
+#define DSISR_MC_SLB_PARMULTI  0x040           /* SLB parity + multi-hit */
+
+/* POWER7 SLB flush and reload */
+static void reload_slb(struct kvm_vcpu *vcpu)
+{
+       struct slb_shadow *slb;
+       unsigned long i, n;
+
+       /* First clear out SLB */
+       asm volatile("slbmte %0,%0; slbia" : : "r" (0));
+
+       /* Do they have an SLB shadow buffer registered? */
+       slb = vcpu->arch.slb_shadow.pinned_addr;
+       if (!slb)
+               return;
+
+       /* Sanity check */
+       n = min_t(u32, slb->persistent, SLB_MIN_SIZE);
+       if ((void *) &slb->save_area[n] > vcpu->arch.slb_shadow.pinned_end)
+               return;
+
+       /* Load up the SLB from that */
+       for (i = 0; i < n; ++i) {
+               unsigned long rb = slb->save_area[i].esid;
+               unsigned long rs = slb->save_area[i].vsid;
+
+               rb = (rb & ~0xFFFul) | i;       /* insert entry number */
+               asm volatile("slbmte %0,%1" : : "r" (rs), "r" (rb));
+       }
+}
+
+/* POWER7 TLB flush */
+static void flush_tlb_power7(struct kvm_vcpu *vcpu)
+{
+       unsigned long i, rb;
+
+       rb = TLBIEL_INVAL_SET_LPID;
+       for (i = 0; i < POWER7_TLB_SETS; ++i) {
+               asm volatile("tlbiel %0" : : "r" (rb));
+               rb += 1 << TLBIEL_INVAL_SET_SHIFT;
+       }
+}
+
+/*
+ * On POWER7, see if we can handle a machine check that occurred inside
+ * the guest in real mode, without switching to the host partition.
+ *
+ * Returns: 0 => exit guest, 1 => deliver machine check to guest
+ */
+static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
+{
+       unsigned long srr1 = vcpu->arch.shregs.msr;
+       struct opal_machine_check_event *opal_evt;
+       long handled = 1;
+
+       if (srr1 & SRR1_MC_LDSTERR) {
+               /* error on load/store */
+               unsigned long dsisr = vcpu->arch.shregs.dsisr;
+
+               if (dsisr & (DSISR_MC_SLB_PARMULTI | DSISR_MC_SLB_MULTI |
+                            DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI)) {
+                       /* flush and reload SLB; flushes D-ERAT too */
+                       reload_slb(vcpu);
+                       dsisr &= ~(DSISR_MC_SLB_PARMULTI | DSISR_MC_SLB_MULTI |
+                                  DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI);
+               }
+               if (dsisr & DSISR_MC_TLB_MULTI) {
+                       flush_tlb_power7(vcpu);
+                       dsisr &= ~DSISR_MC_TLB_MULTI;
+               }
+               /* Any other errors we don't understand? */
+               if (dsisr & 0xffffffffUL)
+                       handled = 0;
+       }
+
+       switch ((srr1 >> SRR1_MC_IFETCH_SH) & SRR1_MC_IFETCH_MASK) {
+       case 0:
+               break;
+       case SRR1_MC_IFETCH_SLBPAR:
+       case SRR1_MC_IFETCH_SLBMULTI:
+       case SRR1_MC_IFETCH_SLBPARMULTI:
+               reload_slb(vcpu);
+               break;
+       case SRR1_MC_IFETCH_TLBMULTI:
+               flush_tlb_power7(vcpu);
+               break;
+       default:
+               handled = 0;
+       }
+
+       /*
+        * See if OPAL has already handled the condition.
+        * We assume that if the condition is recovered then OPAL
+        * will have generated an error log event that we will pick
+        * up and log later.
+        */
+       opal_evt = local_paca->opal_mc_evt;
+       if (opal_evt->version == OpalMCE_V1 &&
+           (opal_evt->severity == OpalMCE_SEV_NO_ERROR ||
+            opal_evt->disposition == OpalMCE_DISPOSITION_RECOVERED))
+               handled = 1;
+
+       if (handled)
+               opal_evt->in_use = 0;
+
+       return handled;
+}
+
+long kvmppc_realmode_machine_check(struct kvm_vcpu *vcpu)
+{
+       if (cpu_has_feature(CPU_FTR_ARCH_206))
+               return kvmppc_realmode_mc_power7(vcpu);
+
+       return 0;
+}
index 5e06e3153888f6c3dd2affcdd2ae0e414eea7e6e..19c93bae1aea5781a421957c3ff941d39427f7f5 100644 (file)
@@ -35,6 +35,37 @@ static void *real_vmalloc_addr(void *x)
        return __va(addr);
 }
 
+/* Return 1 if we need to do a global tlbie, 0 if we can use tlbiel */
+static int global_invalidates(struct kvm *kvm, unsigned long flags)
+{
+       int global;
+
+       /*
+        * If there is only one vcore, and it's currently running,
+        * we can use tlbiel as long as we mark all other physical
+        * cores as potentially having stale TLB entries for this lpid.
+        * If we're not using MMU notifiers, we never take pages away
+        * from the guest, so we can use tlbiel if requested.
+        * Otherwise, don't use tlbiel.
+        */
+       if (kvm->arch.online_vcores == 1 && local_paca->kvm_hstate.kvm_vcore)
+               global = 0;
+       else if (kvm->arch.using_mmu_notifiers)
+               global = 1;
+       else
+               global = !(flags & H_LOCAL);
+
+       if (!global) {
+               /* any other core might now have stale TLB entries... */
+               smp_wmb();
+               cpumask_setall(&kvm->arch.need_tlb_flush);
+               cpumask_clear_cpu(local_paca->kvm_hstate.kvm_vcore->pcpu,
+                                 &kvm->arch.need_tlb_flush);
+       }
+
+       return global;
+}
+
 /*
  * Add this HPTE into the chain for the real page.
  * Must be called with the chain locked; it unlocks the chain.
@@ -59,13 +90,24 @@ void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
                head->back = pte_index;
        } else {
                rev->forw = rev->back = pte_index;
-               i = pte_index;
+               *rmap = (*rmap & ~KVMPPC_RMAP_INDEX) |
+                       pte_index | KVMPPC_RMAP_PRESENT;
        }
-       smp_wmb();
-       *rmap = i | KVMPPC_RMAP_REFERENCED | KVMPPC_RMAP_PRESENT; /* unlock */
+       unlock_rmap(rmap);
 }
 EXPORT_SYMBOL_GPL(kvmppc_add_revmap_chain);
 
+/*
+ * Note modification of an HPTE; set the HPTE modified bit
+ * if anyone is interested.
+ */
+static inline void note_hpte_modification(struct kvm *kvm,
+                                         struct revmap_entry *rev)
+{
+       if (atomic_read(&kvm->arch.hpte_mod_interest))
+               rev->guest_rpte |= HPTE_GR_MODIFIED;
+}
+
 /* Remove this HPTE from the chain for a real page */
 static void remove_revmap_chain(struct kvm *kvm, long pte_index,
                                struct revmap_entry *rev,
@@ -103,14 +145,14 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
        unlock_rmap(rmap);
 }
 
-static pte_t lookup_linux_pte(struct kvm_vcpu *vcpu, unsigned long hva,
+static pte_t lookup_linux_pte(pgd_t *pgdir, unsigned long hva,
                              int writing, unsigned long *pte_sizep)
 {
        pte_t *ptep;
        unsigned long ps = *pte_sizep;
        unsigned int shift;
 
-       ptep = find_linux_pte_or_hugepte(vcpu->arch.pgdir, hva, &shift);
+       ptep = find_linux_pte_or_hugepte(pgdir, hva, &shift);
        if (!ptep)
                return __pte(0);
        if (shift)
@@ -130,15 +172,15 @@ static inline void unlock_hpte(unsigned long *hpte, unsigned long hpte_v)
        hpte[0] = hpte_v;
 }
 
-long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
-                   long pte_index, unsigned long pteh, unsigned long ptel)
+long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
+                      long pte_index, unsigned long pteh, unsigned long ptel,
+                      pgd_t *pgdir, bool realmode, unsigned long *pte_idx_ret)
 {
-       struct kvm *kvm = vcpu->kvm;
        unsigned long i, pa, gpa, gfn, psize;
        unsigned long slot_fn, hva;
        unsigned long *hpte;
        struct revmap_entry *rev;
-       unsigned long g_ptel = ptel;
+       unsigned long g_ptel;
        struct kvm_memory_slot *memslot;
        unsigned long *physp, pte_size;
        unsigned long is_io;
@@ -147,13 +189,14 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
        unsigned int writing;
        unsigned long mmu_seq;
        unsigned long rcbits;
-       bool realmode = vcpu->arch.vcore->vcore_state == VCORE_RUNNING;
 
        psize = hpte_page_size(pteh, ptel);
        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 */
        mmu_seq = kvm->mmu_notifier_seq;
@@ -201,7 +244,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 
                /* Look up the Linux PTE for the backing page */
                pte_size = psize;
-               pte = lookup_linux_pte(vcpu, hva, writing, &pte_size);
+               pte = lookup_linux_pte(pgdir, hva, writing, &pte_size);
                if (pte_present(pte)) {
                        if (writing && !pte_write(pte))
                                /* make the actual HPTE be read-only */
@@ -210,6 +253,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
                        pa = pte_pfn(pte) << PAGE_SHIFT;
                }
        }
+
        if (pte_size < psize)
                return H_PARAMETER;
        if (pa && pte_size > psize)
@@ -287,8 +331,10 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
        rev = &kvm->arch.revmap[pte_index];
        if (realmode)
                rev = real_vmalloc_addr(rev);
-       if (rev)
+       if (rev) {
                rev->guest_rpte = g_ptel;
+               note_hpte_modification(kvm, rev);
+       }
 
        /* Link HPTE into reverse-map chain */
        if (pteh & HPTE_V_VALID) {
@@ -297,7 +343,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
                lock_rmap(rmap);
                /* Check for pending invalidations under the rmap chain lock */
                if (kvm->arch.using_mmu_notifiers &&
-                   mmu_notifier_retry(vcpu->kvm, mmu_seq)) {
+                   mmu_notifier_retry(kvm, mmu_seq)) {
                        /* inval in progress, write a non-present HPTE */
                        pteh |= HPTE_V_ABSENT;
                        pteh &= ~HPTE_V_VALID;
@@ -318,10 +364,17 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
        hpte[0] = pteh;
        asm volatile("ptesync" : : : "memory");
 
-       vcpu->arch.gpr[4] = pte_index;
+       *pte_idx_ret = pte_index;
        return H_SUCCESS;
 }
-EXPORT_SYMBOL_GPL(kvmppc_h_enter);
+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)
+{
+       return kvmppc_do_h_enter(vcpu->kvm, flags, pte_index, pteh, ptel,
+                                vcpu->arch.pgdir, true, &vcpu->arch.gpr[4]);
+}
 
 #define LOCK_TOKEN     (*(u32 *)(&get_paca()->lock_token))
 
@@ -343,11 +396,10 @@ static inline int try_lock_tlbie(unsigned int *lock)
        return old == 0;
 }
 
-long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
-                    unsigned long pte_index, unsigned long avpn,
-                    unsigned long va)
+long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
+                       unsigned long pte_index, unsigned long avpn,
+                       unsigned long *hpret)
 {
-       struct kvm *kvm = vcpu->kvm;
        unsigned long *hpte;
        unsigned long v, r, rb;
        struct revmap_entry *rev;
@@ -369,7 +421,7 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
        if (v & HPTE_V_VALID) {
                hpte[0] &= ~HPTE_V_VALID;
                rb = compute_tlbie_rb(v, hpte[1], pte_index);
-               if (!(flags & H_LOCAL) && atomic_read(&kvm->online_vcpus) > 1) {
+               if (global_invalidates(kvm, flags)) {
                        while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
                                cpu_relax();
                        asm volatile("ptesync" : : : "memory");
@@ -385,13 +437,22 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
                /* Read PTE low word after tlbie to get final R/C values */
                remove_revmap_chain(kvm, pte_index, rev, v, hpte[1]);
        }
-       r = rev->guest_rpte;
+       r = rev->guest_rpte & ~HPTE_GR_RESERVED;
+       note_hpte_modification(kvm, rev);
        unlock_hpte(hpte, 0);
 
-       vcpu->arch.gpr[4] = v;
-       vcpu->arch.gpr[5] = r;
+       hpret[0] = v;
+       hpret[1] = r;
        return H_SUCCESS;
 }
+EXPORT_SYMBOL_GPL(kvmppc_do_h_remove);
+
+long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
+                    unsigned long pte_index, unsigned long avpn)
+{
+       return kvmppc_do_h_remove(vcpu->kvm, flags, pte_index, avpn,
+                                 &vcpu->arch.gpr[4]);
+}
 
 long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 {
@@ -459,6 +520,7 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 
                        args[j] = ((0x80 | flags) << 56) + pte_index;
                        rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
+                       note_hpte_modification(kvm, rev);
 
                        if (!(hp[0] & HPTE_V_VALID)) {
                                /* insert R and C bits from PTE */
@@ -534,8 +596,6 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
                return H_NOT_FOUND;
        }
 
-       if (atomic_read(&kvm->online_vcpus) == 1)
-               flags |= H_LOCAL;
        v = hpte[0];
        bits = (flags << 55) & HPTE_R_PP0;
        bits |= (flags << 48) & HPTE_R_KEY_HI;
@@ -548,6 +608,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
        if (rev) {
                r = (rev->guest_rpte & ~mask) | bits;
                rev->guest_rpte = r;
+               note_hpte_modification(kvm, rev);
        }
        r = (hpte[1] & ~mask) | bits;
 
@@ -555,7 +616,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
        if (v & HPTE_V_VALID) {
                rb = compute_tlbie_rb(v, r, pte_index);
                hpte[0] = v & ~HPTE_V_VALID;
-               if (!(flags & H_LOCAL)) {
+               if (global_invalidates(kvm, flags)) {
                        while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
                                cpu_relax();
                        asm volatile("ptesync" : : : "memory");
@@ -568,6 +629,28 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
                        asm volatile("tlbiel %0" : : "r" (rb));
                        asm volatile("ptesync" : : : "memory");
                }
+               /*
+                * If the host has this page as readonly but the guest
+                * wants to make it read/write, reduce the permissions.
+                * Checking the host permissions involves finding the
+                * memslot and then the Linux PTE for the page.
+                */
+               if (hpte_is_writable(r) && kvm->arch.using_mmu_notifiers) {
+                       unsigned long psize, gfn, hva;
+                       struct kvm_memory_slot *memslot;
+                       pgd_t *pgdir = vcpu->arch.pgdir;
+                       pte_t pte;
+
+                       psize = hpte_page_size(v, r);
+                       gfn = ((r & HPTE_R_RPN) & ~(psize - 1)) >> PAGE_SHIFT;
+                       memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+                       if (memslot) {
+                               hva = __gfn_to_hva_memslot(memslot, gfn);
+                               pte = lookup_linux_pte(pgdir, hva, 1, &psize);
+                               if (pte_present(pte) && !pte_write(pte))
+                                       r = hpte_make_readonly(r);
+                       }
+               }
        }
        hpte[1] = r;
        eieio();
@@ -599,8 +682,10 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
                        v &= ~HPTE_V_ABSENT;
                        v |= HPTE_V_VALID;
                }
-               if (v & HPTE_V_VALID)
+               if (v & HPTE_V_VALID) {
                        r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C));
+                       r &= ~HPTE_GR_RESERVED;
+               }
                vcpu->arch.gpr[4 + i * 2] = v;
                vcpu->arch.gpr[5 + i * 2] = r;
        }
index 690d1120402dc3f995ccd4e5bf1dda1e51c29bf2..10b6c358dd770cf7c3c0083aebfdecc321631985 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/exception-64s.h>
 #include <asm/kvm_book3s_asm.h>
+#include <asm/mmu-hash64.h>
 
 /*****************************************************************************
  *                                                                           *
@@ -313,7 +314,33 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        mtspr   SPRN_SDR1,r6            /* switch to partition page table */
        mtspr   SPRN_LPID,r7
        isync
+
+       /* See if we need to flush the TLB */
+       lhz     r6,PACAPACAINDEX(r13)   /* test_bit(cpu, need_tlb_flush) */
+       clrldi  r7,r6,64-6              /* extract bit number (6 bits) */
+       srdi    r6,r6,6                 /* doubleword number */
+       sldi    r6,r6,3                 /* address offset */
+       add     r6,r6,r9
+       addi    r6,r6,KVM_NEED_FLUSH    /* dword in kvm->arch.need_tlb_flush */
        li      r0,1
+       sld     r0,r0,r7
+       ld      r7,0(r6)
+       and.    r7,r7,r0
+       beq     22f
+23:    ldarx   r7,0,r6                 /* if set, clear the bit */
+       andc    r7,r7,r0
+       stdcx.  r7,0,r6
+       bne     23b
+       li      r6,128                  /* and flush the TLB */
+       mtctr   r6
+       li      r7,0x800                /* IS field = 0b10 */
+       ptesync
+28:    tlbiel  r7
+       addi    r7,r7,0x1000
+       bdnz    28b
+       ptesync
+
+22:    li      r0,1
        stb     r0,VCORE_IN_GUEST(r5)   /* signal secondaries to continue */
        b       10f
 
@@ -336,36 +363,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        mr      r9,r4
        blt     hdec_soon
 
-       /*
-        * Invalidate the TLB if we could possibly have stale TLB
-        * entries for this partition on this core due to the use
-        * of tlbiel.
-        * XXX maybe only need this on primary thread?
-        */
-       ld      r9,VCPU_KVM(r4)         /* pointer to struct kvm */
-       lwz     r5,VCPU_VCPUID(r4)
-       lhz     r6,PACAPACAINDEX(r13)
-       rldimi  r6,r5,0,62              /* XXX map as if threads 1:1 p:v */
-       lhz     r8,VCPU_LAST_CPU(r4)
-       sldi    r7,r6,1                 /* see if this is the same vcpu */
-       add     r7,r7,r9                /* as last ran on this pcpu */
-       lhz     r0,KVM_LAST_VCPU(r7)
-       cmpw    r6,r8                   /* on the same cpu core as last time? */
-       bne     3f
-       cmpw    r0,r5                   /* same vcpu as this core last ran? */
-       beq     1f
-3:     sth     r6,VCPU_LAST_CPU(r4)    /* if not, invalidate partition TLB */
-       sth     r5,KVM_LAST_VCPU(r7)
-       li      r6,128
-       mtctr   r6
-       li      r7,0x800                /* IS field = 0b10 */
-       ptesync
-2:     tlbiel  r7
-       addi    r7,r7,0x1000
-       bdnz    2b
-       ptesync
-1:
-
        /* Save purr/spurr */
        mfspr   r5,SPRN_PURR
        mfspr   r6,SPRN_SPURR
@@ -682,8 +679,7 @@ BEGIN_FTR_SECTION
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
-nohpte_cont:
-hcall_real_cont:               /* r9 = vcpu, r12 = trap, r13 = paca */
+guest_exit_cont:               /* r9 = vcpu, r12 = trap, r13 = paca */
        /* Save DEC */
        mfspr   r5,SPRN_DEC
        mftb    r6
@@ -704,6 +700,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
        std     r6, VCPU_FAULT_DAR(r9)
        stw     r7, VCPU_FAULT_DSISR(r9)
 
+       /* See if it is a machine check */
+       cmpwi   r12, BOOK3S_INTERRUPT_MACHINE_CHECK
+       beq     machine_check_realmode
+mc_cont:
+
        /* Save guest CTRL register, set runlatch to 1 */
 6:     mfspr   r6,SPRN_CTRLF
        stw     r6,VCPU_CTRL(r9)
@@ -1116,38 +1117,41 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        /*
         * For external and machine check interrupts, we need
         * to call the Linux handler to process the interrupt.
-        * We do that by jumping to the interrupt vector address
-        * which we have in r12.  The [h]rfid at the end of the
+        * We do that by jumping to absolute address 0x500 for
+        * external interrupts, or the machine_check_fwnmi label
+        * for machine checks (since firmware might have patched
+        * the vector area at 0x200).  The [h]rfid at the end of the
         * handler will return to the book3s_hv_interrupts.S code.
         * For other interrupts we do the rfid to get back
-        * to the book3s_interrupts.S code here.
+        * to the book3s_hv_interrupts.S code here.
         */
        ld      r8, HSTATE_VMHANDLER(r13)
        ld      r7, HSTATE_HOST_MSR(r13)
 
+       cmpwi   cr1, r12, BOOK3S_INTERRUPT_MACHINE_CHECK
        cmpwi   r12, BOOK3S_INTERRUPT_EXTERNAL
+BEGIN_FTR_SECTION
        beq     11f
-       cmpwi   r12, BOOK3S_INTERRUPT_MACHINE_CHECK
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
        /* RFI into the highmem handler, or branch to interrupt handler */
-12:    mfmsr   r6
-       mtctr   r12
+       mfmsr   r6
        li      r0, MSR_RI
        andc    r6, r6, r0
        mtmsrd  r6, 1                   /* Clear RI in MSR */
        mtsrr0  r8
        mtsrr1  r7
-       beqctr
+       beqa    0x500                   /* external interrupt (PPC970) */
+       beq     cr1, 13f                /* machine check */
        RFI
 
-11:
-BEGIN_FTR_SECTION
-       b       12b
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
-       mtspr   SPRN_HSRR0, r8
+       /* On POWER7, we have external interrupts set to use HSRR0/1 */
+11:    mtspr   SPRN_HSRR0, r8
        mtspr   SPRN_HSRR1, r7
        ba      0x500
 
+13:    b       machine_check_fwnmi
+
 /*
  * Check whether an HDSI is an HPTE not found fault or something else.
  * If it is an HPTE not found fault that is due to the guest accessing
@@ -1180,7 +1184,7 @@ kvmppc_hdsi:
        cmpdi   r3, 0                   /* retry the instruction */
        beq     6f
        cmpdi   r3, -1                  /* handle in kernel mode */
-       beq     nohpte_cont
+       beq     guest_exit_cont
        cmpdi   r3, -2                  /* MMIO emulation; need instr word */
        beq     2f
 
@@ -1194,6 +1198,7 @@ kvmppc_hdsi:
        li      r10, BOOK3S_INTERRUPT_DATA_STORAGE
        li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
        rotldi  r11, r11, 63
+fast_interrupt_c_return:
 6:     ld      r7, VCPU_CTR(r9)
        lwz     r8, VCPU_XER(r9)
        mtctr   r7
@@ -1226,7 +1231,7 @@ kvmppc_hdsi:
        /* Unset guest mode. */
        li      r0, KVM_GUEST_MODE_NONE
        stb     r0, HSTATE_IN_GUEST(r13)
-       b       nohpte_cont
+       b       guest_exit_cont
 
 /*
  * Similarly for an HISI, reflect it to the guest as an ISI unless
@@ -1252,9 +1257,9 @@ kvmppc_hisi:
        ld      r11, VCPU_MSR(r9)
        li      r12, BOOK3S_INTERRUPT_H_INST_STORAGE
        cmpdi   r3, 0                   /* retry the instruction */
-       beq     6f
+       beq     fast_interrupt_c_return
        cmpdi   r3, -1                  /* handle in kernel mode */
-       beq     nohpte_cont
+       beq     guest_exit_cont
 
        /* Synthesize an ISI for the guest */
        mr      r11, r3
@@ -1263,12 +1268,7 @@ kvmppc_hisi:
        li      r10, BOOK3S_INTERRUPT_INST_STORAGE
        li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
        rotldi  r11, r11, 63
-6:     ld      r7, VCPU_CTR(r9)
-       lwz     r8, VCPU_XER(r9)
-       mtctr   r7
-       mtxer   r8
-       mr      r4, r9
-       b       fast_guest_return
+       b       fast_interrupt_c_return
 
 3:     ld      r6, VCPU_KVM(r9)        /* not relocated, use VRMA */
        ld      r5, KVM_VRMA_SLB_V(r6)
@@ -1284,14 +1284,14 @@ kvmppc_hisi:
 hcall_try_real_mode:
        ld      r3,VCPU_GPR(R3)(r9)
        andi.   r0,r11,MSR_PR
-       bne     hcall_real_cont
+       bne     guest_exit_cont
        clrrdi  r3,r3,2
        cmpldi  r3,hcall_real_table_end - hcall_real_table
-       bge     hcall_real_cont
+       bge     guest_exit_cont
        LOAD_REG_ADDR(r4, hcall_real_table)
        lwzx    r3,r3,r4
        cmpwi   r3,0
-       beq     hcall_real_cont
+       beq     guest_exit_cont
        add     r3,r3,r4
        mtctr   r3
        mr      r3,r9           /* get vcpu pointer */
@@ -1312,7 +1312,7 @@ hcall_real_fallback:
        li      r12,BOOK3S_INTERRUPT_SYSCALL
        ld      r9, HSTATE_KVM_VCPU(r13)
 
-       b       hcall_real_cont
+       b       guest_exit_cont
 
        .globl  hcall_real_table
 hcall_real_table:
@@ -1571,6 +1571,21 @@ kvm_cede_exit:
        li      r3,H_TOO_HARD
        blr
 
+       /* Try to handle a machine check in real mode */
+machine_check_realmode:
+       mr      r3, r9          /* get vcpu pointer */
+       bl      .kvmppc_realmode_machine_check
+       nop
+       cmpdi   r3, 0           /* continue exiting from guest? */
+       ld      r9, HSTATE_KVM_VCPU(r13)
+       li      r12, BOOK3S_INTERRUPT_MACHINE_CHECK
+       beq     mc_cont
+       /* If not, deliver a machine check.  SRR0/1 are already set */
+       li      r10, BOOK3S_INTERRUPT_MACHINE_CHECK
+       li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
+       rotldi  r11, r11, 63
+       b       fast_interrupt_c_return
+
 secondary_too_late:
        ld      r5,HSTATE_KVM_VCORE(r13)
        HMT_LOW
index b853696b6d8e30ad63ce3ef2d3db1bc07c67c1af..28d38adeca73af0658785a79f94da7a7865ec854 100644 (file)
@@ -81,9 +81,7 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
        svcpu_put(svcpu);
 #endif
 
-       kvmppc_giveup_ext(vcpu, MSR_FP);
-       kvmppc_giveup_ext(vcpu, MSR_VEC);
-       kvmppc_giveup_ext(vcpu, MSR_VSX);
+       kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX);
        vcpu->cpu = -1;
 }
 
@@ -147,7 +145,7 @@ static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
        ulong smsr = vcpu->arch.shared->msr;
 
        /* Guest MSR values */
-       smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_DE;
+       smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE;
        /* Process MSR values */
        smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
        /* External providers the guest reserved */
@@ -433,10 +431,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
 static inline int get_fpr_index(int i)
 {
-#ifdef CONFIG_VSX
-       i *= 2;
-#endif
-       return i;
+       return i * TS_FPRWIDTH;
 }
 
 /* Give up external provider (FPU, Altivec, VSX) */
@@ -450,41 +445,49 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
        u64 *thread_fpr = (u64*)t->fpr;
        int i;
 
-       if (!(vcpu->arch.guest_owned_ext & msr))
+       /*
+        * VSX instructions can access FP and vector registers, so if
+        * we are giving up VSX, make sure we give up FP and VMX as well.
+        */
+       if (msr & MSR_VSX)
+               msr |= MSR_FP | MSR_VEC;
+
+       msr &= vcpu->arch.guest_owned_ext;
+       if (!msr)
                return;
 
 #ifdef DEBUG_EXT
        printk(KERN_INFO "Giving up ext 0x%lx\n", msr);
 #endif
 
-       switch (msr) {
-       case MSR_FP:
+       if (msr & MSR_FP) {
+               /*
+                * Note that on CPUs with VSX, giveup_fpu stores
+                * both the traditional FP registers and the added VSX
+                * registers into thread.fpr[].
+                */
                giveup_fpu(current);
                for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
                        vcpu_fpr[i] = thread_fpr[get_fpr_index(i)];
 
                vcpu->arch.fpscr = t->fpscr.val;
-               break;
-       case MSR_VEC:
+
+#ifdef CONFIG_VSX
+               if (cpu_has_feature(CPU_FTR_VSX))
+                       for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr) / 2; i++)
+                               vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1];
+#endif
+       }
+
 #ifdef CONFIG_ALTIVEC
+       if (msr & MSR_VEC) {
                giveup_altivec(current);
                memcpy(vcpu->arch.vr, t->vr, sizeof(vcpu->arch.vr));
                vcpu->arch.vscr = t->vscr;
-#endif
-               break;
-       case MSR_VSX:
-#ifdef CONFIG_VSX
-               __giveup_vsx(current);
-               for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++)
-                       vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1];
-#endif
-               break;
-       default:
-               BUG();
        }
+#endif
 
-       vcpu->arch.guest_owned_ext &= ~msr;
-       current->thread.regs->msr &= ~msr;
+       vcpu->arch.guest_owned_ext &= ~(msr | MSR_VSX);
        kvmppc_recalc_shadow_msr(vcpu);
 }
 
@@ -544,47 +547,56 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
                return RESUME_GUEST;
        }
 
-       /* We already own the ext */
-       if (vcpu->arch.guest_owned_ext & msr) {
-               return RESUME_GUEST;
+       if (msr == MSR_VSX) {
+               /* No VSX?  Give an illegal instruction interrupt */
+#ifdef CONFIG_VSX
+               if (!cpu_has_feature(CPU_FTR_VSX))
+#endif
+               {
+                       kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+                       return RESUME_GUEST;
+               }
+
+               /*
+                * We have to load up all the FP and VMX registers before
+                * we can let the guest use VSX instructions.
+                */
+               msr = MSR_FP | MSR_VEC | MSR_VSX;
        }
 
+       /* See if we already own all the ext(s) needed */
+       msr &= ~vcpu->arch.guest_owned_ext;
+       if (!msr)
+               return RESUME_GUEST;
+
 #ifdef DEBUG_EXT
        printk(KERN_INFO "Loading up ext 0x%lx\n", msr);
 #endif
 
        current->thread.regs->msr |= msr;
 
-       switch (msr) {
-       case MSR_FP:
+       if (msr & MSR_FP) {
                for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
                        thread_fpr[get_fpr_index(i)] = vcpu_fpr[i];
-
+#ifdef CONFIG_VSX
+               for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr) / 2; i++)
+                       thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i];
+#endif
                t->fpscr.val = vcpu->arch.fpscr;
                t->fpexc_mode = 0;
                kvmppc_load_up_fpu();
-               break;
-       case MSR_VEC:
+       }
+
+       if (msr & MSR_VEC) {
 #ifdef CONFIG_ALTIVEC
                memcpy(t->vr, vcpu->arch.vr, sizeof(vcpu->arch.vr));
                t->vscr = vcpu->arch.vscr;
                t->vrsave = -1;
                kvmppc_load_up_altivec();
 #endif
-               break;
-       case MSR_VSX:
-#ifdef CONFIG_VSX
-               for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++)
-                       thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i];
-               kvmppc_load_up_vsx();
-#endif
-               break;
-       default:
-               BUG();
        }
 
        vcpu->arch.guest_owned_ext |= msr;
-
        kvmppc_recalc_shadow_msr(vcpu);
 
        return RESUME_GUEST;
@@ -1134,7 +1146,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        /* Save VSX state in stack */
        used_vsr = current->thread.used_vsr;
        if (used_vsr && (current->thread.regs->msr & MSR_VSX))
-                       __giveup_vsx(current);
+               __giveup_vsx(current);
 #endif
 
        /* Remember the MSR with disabled extensions */
@@ -1151,14 +1163,12 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        /* No need for kvm_guest_exit. It's done in handle_exit.
           We also get here with interrupts enabled. */
 
-       current->thread.regs->msr = ext_msr;
-
        /* Make sure we save the guest FPU/Altivec/VSX state */
-       kvmppc_giveup_ext(vcpu, MSR_FP);
-       kvmppc_giveup_ext(vcpu, MSR_VEC);
-       kvmppc_giveup_ext(vcpu, MSR_VSX);
+       kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX);
+
+       current->thread.regs->msr = ext_msr;
 
-       /* Restore FPU state from stack */
+       /* Restore FPU/VSX state from stack */
        memcpy(current->thread.fpr, fpr, sizeof(current->thread.fpr));
        current->thread.fpscr.val = fpscr;
        current->thread.fpexc_mode = fpexc_mode;
index b2f8258b545ae9e7a5530d2c73e204dc7b8d3db8..8f7633e3afb8112b0123a298211a31c82240dcf0 100644 (file)
@@ -234,8 +234,5 @@ define_load_up(fpu)
 #ifdef CONFIG_ALTIVEC
 define_load_up(altivec)
 #endif
-#ifdef CONFIG_VSX
-define_load_up(vsx)
-#endif
 
 #include "book3s_segment.S"
index 3d1f35dc786281f5640ebf825a752f5ae19c2231..69f1140157807c7df83c33541975e799563ed865 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/dbell.h>
 #include <asm/hw_irq.h>
 #include <asm/irq.h>
+#include <asm/time.h>
 
 #include "timing.h"
 #include "booke.h"
@@ -311,6 +312,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
        bool crit;
        bool keep_irq = false;
        enum int_class int_class;
+       ulong new_msr = vcpu->arch.shared->msr;
 
        /* Truncate crit indicators in 32 bit mode */
        if (!(vcpu->arch.shared->msr & MSR_SF)) {
@@ -406,7 +408,13 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                        set_guest_esr(vcpu, vcpu->arch.queued_esr);
                if (update_dear == true)
                        set_guest_dear(vcpu, vcpu->arch.queued_dear);
-               kvmppc_set_msr(vcpu, vcpu->arch.shared->msr & msr_mask);
+
+               new_msr &= msr_mask;
+#if defined(CONFIG_64BIT)
+               if (vcpu->arch.epcr & SPRN_EPCR_ICM)
+                       new_msr |= MSR_CM;
+#endif
+               kvmppc_set_msr(vcpu, new_msr);
 
                if (!keep_irq)
                        clear_bit(priority, &vcpu->arch.pending_exceptions);
@@ -1380,6 +1388,11 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                                 &vcpu->arch.dbg_reg.dac[dac], sizeof(u64));
                break;
        }
+#if defined(CONFIG_64BIT)
+       case KVM_REG_PPC_EPCR:
+               r = put_user(vcpu->arch.epcr, (u32 __user *)(long)reg->addr);
+               break;
+#endif
        default:
                break;
        }
@@ -1407,6 +1420,15 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                             (u64 __user *)(long)reg->addr, sizeof(u64));
                break;
        }
+#if defined(CONFIG_64BIT)
+       case KVM_REG_PPC_EPCR: {
+               u32 new_epcr;
+               r = get_user(new_epcr, (u32 __user *)(long)reg->addr);
+               if (r == 0)
+                       kvmppc_set_epcr(vcpu, new_epcr);
+               break;
+       }
+#endif
        default:
                break;
        }
@@ -1465,6 +1487,18 @@ void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot)
 {
 }
 
+void kvmppc_set_epcr(struct kvm_vcpu *vcpu, u32 new_epcr)
+{
+#if defined(CONFIG_64BIT)
+       vcpu->arch.epcr = new_epcr;
+#ifdef CONFIG_KVM_BOOKE_HV
+       vcpu->arch.shadow_epcr &= ~SPRN_EPCR_GICM;
+       if (vcpu->arch.epcr  & SPRN_EPCR_ICM)
+               vcpu->arch.shadow_epcr |= SPRN_EPCR_GICM;
+#endif
+#endif
+}
+
 void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr)
 {
        vcpu->arch.tcr = new_tcr;
index ba61974c1e20839f454ebb9e33cc8f46e4949d9e..e9b88e433f64a3d835d8b8970ab6ff6a6d0ebf56 100644 (file)
@@ -69,6 +69,7 @@ extern unsigned long kvmppc_booke_handlers;
 void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr);
 void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr);
 
+void kvmppc_set_epcr(struct kvm_vcpu *vcpu, u32 new_epcr);
 void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr);
 void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits);
 void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits);
index 514790f41abafa9c752ebdaa90bde9f1e961423f..4685b8cf224959a29d1c6e774109e31f47f5c2e6 100644 (file)
@@ -240,7 +240,14 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
        case SPRN_MCSR:
                vcpu->arch.mcsr &= ~spr_val;
                break;
-
+#if defined(CONFIG_64BIT)
+       case SPRN_EPCR:
+               kvmppc_set_epcr(vcpu, spr_val);
+#ifdef CONFIG_KVM_BOOKE_HV
+               mtspr(SPRN_EPCR, vcpu->arch.shadow_epcr);
+#endif
+               break;
+#endif
        default:
                emulated = EMULATE_FAIL;
        }
@@ -335,6 +342,11 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
        case SPRN_MCSR:
                *spr_val = vcpu->arch.mcsr;
                break;
+#if defined(CONFIG_64BIT)
+       case SPRN_EPCR:
+               *spr_val = vcpu->arch.epcr;
+               break;
+#endif
 
        default:
                emulated = EMULATE_FAIL;
index 099fe8272b57fdd7fdfb9de56ff1beb53dd36e53..e8ed7d659c55f8cbcdc341c07ea58a8bc26b744d 100644 (file)
@@ -16,6 +16,7 @@
  *
  * Author: Varun Sethi <varun.sethi@freescale.com>
  * Author: Scott Wood <scotwood@freescale.com>
+ * Author: Mihai Caraman <mihai.caraman@freescale.com>
  *
  * This file is derived from arch/powerpc/kvm/booke_interrupts.S
  */
 #include <asm/bitsperlong.h>
 #include <asm/thread_info.h>
 
+#ifdef CONFIG_64BIT
+#include <asm/exception-64e.h>
+#else
 #include "../kernel/head_booke.h" /* for THREAD_NORMSAVE() */
-
-#define GET_VCPU(vcpu, thread) \
-       PPC_LL  vcpu, THREAD_KVM_VCPU(thread)
+#endif
 
 #define LONGBYTES              (BITS_PER_LONG / 8)
 
 #define VCPU_GUEST_SPRG(n)     (VCPU_GUEST_SPRGS + (n * LONGBYTES))
 
 /* The host stack layout: */
-#define HOST_R1         (0 * LONGBYTES) /* Implied by stwu. */
-#define HOST_CALLEE_LR  (1 * LONGBYTES)
-#define HOST_RUN        (2 * LONGBYTES) /* struct kvm_run */
+#define HOST_R1         0 /* Implied by stwu. */
+#define HOST_CALLEE_LR  PPC_LR_STKOFF
+#define HOST_RUN        (HOST_CALLEE_LR + LONGBYTES)
 /*
  * r2 is special: it holds 'current', and it made nonvolatile in the
  * kernel with the -ffixed-r2 gcc option.
  */
-#define HOST_R2         (3 * LONGBYTES)
-#define HOST_CR         (4 * LONGBYTES)
-#define HOST_NV_GPRS    (5 * LONGBYTES)
+#define HOST_R2         (HOST_RUN + LONGBYTES)
+#define HOST_CR         (HOST_R2 + LONGBYTES)
+#define HOST_NV_GPRS    (HOST_CR + LONGBYTES)
 #define __HOST_NV_GPR(n)  (HOST_NV_GPRS + ((n - 14) * LONGBYTES))
 #define HOST_NV_GPR(n)  __HOST_NV_GPR(__REG_##n)
 #define HOST_MIN_STACK_SIZE (HOST_NV_GPR(R31) + LONGBYTES)
 #define HOST_STACK_SIZE ((HOST_MIN_STACK_SIZE + 15) & ~15) /* Align. */
-#define HOST_STACK_LR   (HOST_STACK_SIZE + LONGBYTES) /* In caller stack frame. */
+/* LR in caller stack frame. */
+#define HOST_STACK_LR  (HOST_STACK_SIZE + PPC_LR_STKOFF)
 
 #define NEED_EMU               0x00000001 /* emulation -- save nv regs */
 #define NEED_DEAR              0x00000002 /* save faulting DEAR */
        b       kvmppc_resume_host
 .endm
 
+#ifdef CONFIG_64BIT
+/* Exception types */
+#define EX_GEN                 1
+#define EX_GDBELL              2
+#define EX_DBG                 3
+#define EX_MC                  4
+#define EX_CRIT                        5
+#define EX_TLB                 6
+
+/*
+ * For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h
+ */
+.macro kvm_handler intno type scratch, paca_ex, ex_r10, ex_r11, srr0, srr1, flags
+ _GLOBAL(kvmppc_handler_\intno\()_\srr1)
+       mr      r11, r4
+       /*
+        * Get vcpu from Paca: paca->__current.thread->kvm_vcpu
+        */
+       PPC_LL  r4, PACACURRENT(r13)
+       PPC_LL  r4, (THREAD + THREAD_KVM_VCPU)(r4)
+       stw     r10, VCPU_CR(r4)
+       PPC_STL r11, VCPU_GPR(R4)(r4)
+       PPC_STL r5, VCPU_GPR(R5)(r4)
+       .if \type == EX_CRIT
+       PPC_LL  r5, (\paca_ex + EX_R13)(r13)
+       .else
+       mfspr   r5, \scratch
+       .endif
+       PPC_STL r6, VCPU_GPR(R6)(r4)
+       PPC_STL r8, VCPU_GPR(R8)(r4)
+       PPC_STL r9, VCPU_GPR(R9)(r4)
+       PPC_STL r5, VCPU_GPR(R13)(r4)
+       PPC_LL  r6, (\paca_ex + \ex_r10)(r13)
+       PPC_LL  r8, (\paca_ex + \ex_r11)(r13)
+       PPC_STL r3, VCPU_GPR(R3)(r4)
+       PPC_STL r7, VCPU_GPR(R7)(r4)
+       PPC_STL r12, VCPU_GPR(R12)(r4)
+       PPC_STL r6, VCPU_GPR(R10)(r4)
+       PPC_STL r8, VCPU_GPR(R11)(r4)
+       mfctr   r5
+       PPC_STL r5, VCPU_CTR(r4)
+       mfspr   r5, \srr0
+       mfspr   r6, \srr1
+       kvm_handler_common \intno, \srr0, \flags
+.endm
+
+#define EX_PARAMS(type) \
+       EX_##type, \
+       SPRN_SPRG_##type##_SCRATCH, \
+       PACA_EX##type, \
+       EX_R10, \
+       EX_R11
+
+#define EX_PARAMS_TLB \
+       EX_TLB, \
+       SPRN_SPRG_GEN_SCRATCH, \
+       PACA_EXTLB, \
+       EX_TLB_R10, \
+       EX_TLB_R11
+
+kvm_handler BOOKE_INTERRUPT_CRITICAL, EX_PARAMS(CRIT), \
+       SPRN_CSRR0, SPRN_CSRR1, 0
+kvm_handler BOOKE_INTERRUPT_MACHINE_CHECK, EX_PARAMS(MC), \
+       SPRN_MCSRR0, SPRN_MCSRR1, 0
+kvm_handler BOOKE_INTERRUPT_DATA_STORAGE, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1,(NEED_EMU | NEED_DEAR | NEED_ESR)
+kvm_handler BOOKE_INTERRUPT_INST_STORAGE, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, NEED_ESR
+kvm_handler BOOKE_INTERRUPT_EXTERNAL, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_ALIGNMENT, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1,(NEED_DEAR | NEED_ESR)
+kvm_handler BOOKE_INTERRUPT_PROGRAM, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1,NEED_ESR
+kvm_handler BOOKE_INTERRUPT_FP_UNAVAIL, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_AP_UNAVAIL, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_DECREMENTER, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_FIT, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_WATCHDOG, EX_PARAMS(CRIT),\
+       SPRN_CSRR0, SPRN_CSRR1, 0
+/*
+ * Only bolted TLB miss exception handlers are supported for now
+ */
+kvm_handler BOOKE_INTERRUPT_DTLB_MISS, EX_PARAMS_TLB, \
+       SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR)
+kvm_handler BOOKE_INTERRUPT_ITLB_MISS, EX_PARAMS_TLB, \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_DOORBELL, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_DOORBELL_CRITICAL, EX_PARAMS(CRIT), \
+       SPRN_CSRR0, SPRN_CSRR1, 0
+kvm_handler BOOKE_INTERRUPT_HV_PRIV, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, NEED_EMU
+kvm_handler BOOKE_INTERRUPT_HV_SYSCALL, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, 0
+kvm_handler BOOKE_INTERRUPT_GUEST_DBELL, EX_PARAMS(GDBELL), \
+       SPRN_GSRR0, SPRN_GSRR1, 0
+kvm_handler BOOKE_INTERRUPT_GUEST_DBELL_CRIT, EX_PARAMS(CRIT), \
+       SPRN_CSRR0, SPRN_CSRR1, 0
+kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(DBG), \
+       SPRN_DSRR0, SPRN_DSRR1, 0
+kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(CRIT), \
+       SPRN_CSRR0, SPRN_CSRR1, 0
+#else
 /*
  * For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h
  */
 .macro kvm_handler intno srr0, srr1, flags
 _GLOBAL(kvmppc_handler_\intno\()_\srr1)
-       GET_VCPU(r11, r10)
+       PPC_LL  r11, THREAD_KVM_VCPU(r10)
        PPC_STL r3, VCPU_GPR(R3)(r11)
        mfspr   r3, SPRN_SPRG_RSCRATCH0
        PPC_STL r4, VCPU_GPR(R4)(r11)
@@ -233,7 +352,7 @@ _GLOBAL(kvmppc_handler_\intno\()_\srr1)
 .macro kvm_lvl_handler intno scratch srr0, srr1, flags
 _GLOBAL(kvmppc_handler_\intno\()_\srr1)
        mfspr   r10, SPRN_SPRG_THREAD
-       GET_VCPU(r11, r10)
+       PPC_LL  r11, THREAD_KVM_VCPU(r10)
        PPC_STL r3, VCPU_GPR(R3)(r11)
        mfspr   r3, \scratch
        PPC_STL r4, VCPU_GPR(R4)(r11)
@@ -295,7 +414,7 @@ kvm_lvl_handler BOOKE_INTERRUPT_DEBUG, \
        SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, 0
 kvm_lvl_handler BOOKE_INTERRUPT_DEBUG, \
        SPRN_SPRG_RSCRATCH_DBG, SPRN_DSRR0, SPRN_DSRR1, 0
-
+#endif
 
 /* Registers:
  *  SPRG_SCRATCH0: guest r10
index d1622864549ecc6b03c26bb1bde194a9ce691237..c70d37ed770a33c4d844ccbaca59f7c3e8e413e6 100644 (file)
@@ -129,9 +129,9 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500,
                                ulong value);
 int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu);
 int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu);
-int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb);
-int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int rt, int ra, int rb);
-int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb);
+int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, gva_t ea);
+int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int type, gva_t ea);
+int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, gva_t ea);
 int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500);
 void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500);
 
@@ -154,7 +154,7 @@ get_tlb_size(const struct kvm_book3e_206_tlb_entry *tlbe)
 
 static inline gva_t get_tlb_eaddr(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
-       return tlbe->mas2 & 0xfffff000;
+       return tlbe->mas2 & MAS2_EPN;
 }
 
 static inline u64 get_tlb_bytes(const struct kvm_book3e_206_tlb_entry *tlbe)
index e04b0ef55ce0e131df45cdadd06d95d004129bbb..e78f353a836a0731d96217546598a93b2ae22dfd 100644 (file)
@@ -89,6 +89,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
        int ra = get_ra(inst);
        int rb = get_rb(inst);
        int rt = get_rt(inst);
+       gva_t ea;
 
        switch (get_op(inst)) {
        case 31:
@@ -113,15 +114,20 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        break;
 
                case XOP_TLBSX:
-                       emulated = kvmppc_e500_emul_tlbsx(vcpu,rb);
+                       ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
+                       emulated = kvmppc_e500_emul_tlbsx(vcpu, ea);
                        break;
 
-               case XOP_TLBILX:
-                       emulated = kvmppc_e500_emul_tlbilx(vcpu, rt, ra, rb);
+               case XOP_TLBILX: {
+                       int type = rt & 0x3;
+                       ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
+                       emulated = kvmppc_e500_emul_tlbilx(vcpu, type, ea);
                        break;
+               }
 
                case XOP_TLBIVAX:
-                       emulated = kvmppc_e500_emul_tlbivax(vcpu, ra, rb);
+                       ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
+                       emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
                        break;
 
                default:
index 6305ee692ef76ff0a58d6f0f944ea4adf84d86ae..cf3f180123717cb8e7439f6460c537ec24d0523b 100644 (file)
@@ -415,7 +415,8 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        struct tlbe_ref *ref)
 {
        struct kvm_memory_slot *slot;
-       unsigned long pfn, hva;
+       unsigned long pfn = 0; /* silence GCC warning */
+       unsigned long hva;
        int pfnmap = 0;
        int tsize = BOOK3E_PAGESZ_4K;
 
@@ -688,14 +689,11 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value)
        return EMULATE_DONE;
 }
 
-int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb)
+int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, gva_t ea)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
        unsigned int ia;
        int esel, tlbsel;
-       gva_t ea;
-
-       ea = ((ra) ? kvmppc_get_gpr(vcpu, ra) : 0) + kvmppc_get_gpr(vcpu, rb);
 
        ia = (ea >> 2) & 0x1;
 
@@ -722,7 +720,7 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb)
 }
 
 static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
-                      int pid, int rt)
+                      int pid, int type)
 {
        struct kvm_book3e_206_tlb_entry *tlbe;
        int tid, esel;
@@ -731,7 +729,7 @@ static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
        for (esel = 0; esel < vcpu_e500->gtlb_params[tlbsel].entries; esel++) {
                tlbe = get_entry(vcpu_e500, tlbsel, esel);
                tid = get_tlb_tid(tlbe);
-               if (rt == 0 || tid == pid) {
+               if (type == 0 || tid == pid) {
                        inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
                        kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
                }
@@ -739,14 +737,9 @@ static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
 }
 
 static void tlbilx_one(struct kvmppc_vcpu_e500 *vcpu_e500, int pid,
-                      int ra, int rb)
+                      gva_t ea)
 {
        int tlbsel, esel;
-       gva_t ea;
-
-       ea = kvmppc_get_gpr(&vcpu_e500->vcpu, rb);
-       if (ra)
-               ea += kvmppc_get_gpr(&vcpu_e500->vcpu, ra);
 
        for (tlbsel = 0; tlbsel < 2; tlbsel++) {
                esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, -1);
@@ -758,16 +751,16 @@ static void tlbilx_one(struct kvmppc_vcpu_e500 *vcpu_e500, int pid,
        }
 }
 
-int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int rt, int ra, int rb)
+int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int type, gva_t ea)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
        int pid = get_cur_spid(vcpu);
 
-       if (rt == 0 || rt == 1) {
-               tlbilx_all(vcpu_e500, 0, pid, rt);
-               tlbilx_all(vcpu_e500, 1, pid, rt);
-       } else if (rt == 3) {
-               tlbilx_one(vcpu_e500, pid, ra, rb);
+       if (type == 0 || type == 1) {
+               tlbilx_all(vcpu_e500, 0, pid, type);
+               tlbilx_all(vcpu_e500, 1, pid, type);
+       } else if (type == 3) {
+               tlbilx_one(vcpu_e500, pid, ea);
        }
 
        return EMULATE_DONE;
@@ -792,16 +785,13 @@ int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu)
        return EMULATE_DONE;
 }
 
-int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb)
+int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, gva_t ea)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
        int as = !!get_cur_sas(vcpu);
        unsigned int pid = get_cur_spid(vcpu);
        int esel, tlbsel;
        struct kvm_book3e_206_tlb_entry *gtlbe = NULL;
-       gva_t ea;
-
-       ea = kvmppc_get_gpr(vcpu, rb);
 
        for (tlbsel = 0; tlbsel < 2; tlbsel++) {
                esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as);
@@ -881,6 +871,8 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
 
        gtlbe->mas1 = vcpu->arch.shared->mas1;
        gtlbe->mas2 = vcpu->arch.shared->mas2;
+       if (!(vcpu->arch.shared->msr & MSR_CM))
+               gtlbe->mas2 &= 0xffffffffUL;
        gtlbe->mas7_3 = vcpu->arch.shared->mas7_3;
 
        trace_kvm_booke206_gtlb_write(vcpu->arch.shared->mas0, gtlbe->mas1,
index f9ab12aea829de64a61b7e066769121dd8b57f36..70739a08956044b875d4c98cbbeec27d74643c75 100644 (file)
@@ -314,6 +314,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PPC_IRQ_LEVEL:
        case KVM_CAP_ENABLE_CAP:
        case KVM_CAP_ONE_REG:
+       case KVM_CAP_IOEVENTFD:
                r = 1;
                break;
 #ifndef CONFIG_KVM_BOOK3S_64_HV
@@ -353,6 +354,12 @@ int kvm_dev_ioctl_check_extension(long ext)
                r = 1;
 #else
                r = 0;
+               break;
+#endif
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+       case KVM_CAP_PPC_HTAB_FD:
+               r = 1;
+               break;
 #endif
                break;
        case KVM_CAP_NR_VCPUS:
@@ -618,6 +625,13 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
        vcpu->mmio_is_write = 0;
        vcpu->arch.mmio_sign_extend = 0;
 
+       if (!kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr,
+                            bytes, &run->mmio.data)) {
+               kvmppc_complete_mmio_load(vcpu, run);
+               vcpu->mmio_needed = 0;
+               return EMULATE_DONE;
+       }
+
        return EMULATE_DO_MMIO;
 }
 
@@ -627,8 +641,8 @@ int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
 {
        int r;
 
-       r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian);
        vcpu->arch.mmio_sign_extend = 1;
+       r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian);
 
        return r;
 }
@@ -666,6 +680,13 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
                }
        }
 
+       if (!kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr,
+                             bytes, &run->mmio.data)) {
+               kvmppc_complete_mmio_load(vcpu, run);
+               vcpu->mmio_needed = 0;
+               return EMULATE_DONE;
+       }
+
        return EMULATE_DO_MMIO;
 }
 
@@ -939,6 +960,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
                r = 0;
                break;
        }
+
+       case KVM_PPC_GET_HTAB_FD: {
+               struct kvm *kvm = filp->private_data;
+               struct kvm_get_htab_fd ghf;
+
+               r = -EFAULT;
+               if (copy_from_user(&ghf, argp, sizeof(ghf)))
+                       break;
+               r = kvm_vm_ioctl_get_htab_fd(kvm, &ghf);
+               break;
+       }
 #endif /* CONFIG_KVM_BOOK3S_64_HV */
 
 #ifdef CONFIG_PPC_BOOK3S_64
index 36c3704bfa7cd7eaaeb69f9976b3d44baec150b3..91ae127f4ac57ba5dd08da48095b906f526bad4b 100644 (file)
@@ -901,10 +901,20 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {}
 #ifdef CONFIG_HAVE_KVM_EVENTFD
 
 void kvm_eventfd_init(struct kvm *kvm);
+int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
+
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
 int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args);
 void kvm_irqfd_release(struct kvm *kvm);
 void kvm_irq_routing_update(struct kvm *, struct kvm_irq_routing_table *);
-int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
+#else
+static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
+{
+       return -EINVAL;
+}
+
+static inline void kvm_irqfd_release(struct kvm *kvm) {}
+#endif
 
 #else
 
index 494a84c37c3eee49b27e657c057096cd2b0ae88d..e6e5d4b1370826328cee8771d523e2a1043c0889 100644 (file)
@@ -634,6 +634,7 @@ struct kvm_ppc_smmu_info {
 #endif
 #define KVM_CAP_IRQFD_RESAMPLE 82
 #define KVM_CAP_PPC_BOOKE_WATCHDOG 83
+#define KVM_CAP_PPC_HTAB_FD 84
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -859,6 +860,8 @@ struct kvm_s390_ucas_mapping {
 #define KVM_CREATE_SPAPR_TCE     _IOW(KVMIO,  0xa8, struct kvm_create_spapr_tce)
 /* Available with KVM_CAP_RMA */
 #define KVM_ALLOCATE_RMA         _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
+/* Available with KVM_CAP_PPC_HTAB_FD */
+#define KVM_PPC_GET_HTAB_FD      _IOW(KVMIO,  0xaa, struct kvm_get_htab_fd)
 
 /*
  * ioctls for vcpu fds
index 9718e98d6d2a84956d113bd43f55d804bd30d049..d7424c8c138ae47248b2ca4567d4a56a1fee4140 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "iodev.h"
 
+#ifdef __KVM_HAVE_IOAPIC
 /*
  * --------------------------------------------------------------------
  * irqfd: Allows an fd to be used to inject an interrupt to the guest
@@ -425,17 +426,21 @@ fail:
        kfree(irqfd);
        return ret;
 }
+#endif
 
 void
 kvm_eventfd_init(struct kvm *kvm)
 {
+#ifdef __KVM_HAVE_IOAPIC
        spin_lock_init(&kvm->irqfds.lock);
        INIT_LIST_HEAD(&kvm->irqfds.items);
        INIT_LIST_HEAD(&kvm->irqfds.resampler_list);
        mutex_init(&kvm->irqfds.resampler_lock);
+#endif
        INIT_LIST_HEAD(&kvm->ioeventfds);
 }
 
+#ifdef __KVM_HAVE_IOAPIC
 /*
  * shutdown any irqfd's that match fd+gsi
  */
@@ -555,6 +560,7 @@ static void __exit irqfd_module_exit(void)
 
 module_init(irqfd_module_init);
 module_exit(irqfd_module_exit);
+#endif
 
 /*
  * --------------------------------------------------------------------