KVM: PPC: e500: Expose MMU registers via ONE_REG
authorMihai Caraman <mihai.caraman@freescale.com>
Thu, 11 Apr 2013 00:03:08 +0000 (00:03 +0000)
committerAlexander Graf <agraf@suse.de>
Fri, 26 Apr 2013 18:27:06 +0000 (20:27 +0200)
MMU registers were exposed to user-space using sregs interface. Add them
to ONE_REG interface using kvmppc_get_one_reg/kvmppc_set_one_reg delegation
mechanism.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Documentation/virtual/kvm/api.txt
arch/powerpc/include/uapi/asm/kvm.h
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/e500.h
arch/powerpc/kvm/e500_mmu.c
arch/powerpc/kvm/e500mc.c

index 976eb65..1a76663 100644 (file)
@@ -1792,6 +1792,17 @@ registers, find a list below:
   PPC   | KVM_REG_PPC_TSR      | 32
   PPC   | KVM_REG_PPC_OR_TSR   | 32
   PPC   | KVM_REG_PPC_CLEAR_TSR        | 32
+  PPC   | KVM_REG_PPC_MAS0     | 32
+  PPC   | KVM_REG_PPC_MAS1     | 32
+  PPC   | KVM_REG_PPC_MAS2     | 64
+  PPC   | KVM_REG_PPC_MAS7_3   | 64
+  PPC   | KVM_REG_PPC_MAS4     | 32
+  PPC   | KVM_REG_PPC_MAS6     | 32
+  PPC   | KVM_REG_PPC_MMUCFG   | 32
+  PPC   | KVM_REG_PPC_TLB0CFG  | 32
+  PPC   | KVM_REG_PPC_TLB1CFG  | 32
+  PPC   | KVM_REG_PPC_TLB2CFG  | 32
+  PPC   | KVM_REG_PPC_TLB3CFG  | 32
 
 ARM registers are mapped using the lower 32 bits.  The upper 16 of that
 is the register group type, or coprocessor number:
index c0c38ed..0c5cffb 100644 (file)
@@ -449,4 +449,21 @@ struct kvm_get_htab_header {
 /* Debugging: Special instruction for software breakpoint */
 #define KVM_REG_PPC_DEBUG_INST (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8b)
 
+/* MMU registers */
+#define KVM_REG_PPC_MAS0       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8c)
+#define KVM_REG_PPC_MAS1       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8d)
+#define KVM_REG_PPC_MAS2       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8e)
+#define KVM_REG_PPC_MAS7_3     (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8f)
+#define KVM_REG_PPC_MAS4       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x90)
+#define KVM_REG_PPC_MAS6       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x91)
+#define KVM_REG_PPC_MMUCFG     (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x92)
+/*
+ * TLBnCFG fields TLBnCFG_N_ENTRY and TLBnCFG_ASSOC can be changed only using
+ * KVM_CAP_SW_TLB ioctl
+ */
+#define KVM_REG_PPC_TLB0CFG    (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x93)
+#define KVM_REG_PPC_TLB1CFG    (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x94)
+#define KVM_REG_PPC_TLB2CFG    (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x95)
+#define KVM_REG_PPC_TLB3CFG    (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x96)
+
 #endif /* __LINUX_KVM_POWERPC_H */
index 576010f..ce6b73c 100644 (file)
@@ -428,13 +428,15 @@ int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
 int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
                        union kvmppc_one_reg *val)
 {
-       return -EINVAL;
+       int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
+       return r;
 }
 
 int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
                       union kvmppc_one_reg *val)
 {
-       return -EINVAL;
+       int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
+       return r;
 }
 
 struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
index 33db48a..b73ca7a 100644 (file)
@@ -131,6 +131,10 @@ void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500);
 void kvmppc_get_sregs_e500_tlb(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
 int kvmppc_set_sregs_e500_tlb(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
 
+int kvmppc_get_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id,
+                               union kvmppc_one_reg *val);
+int kvmppc_set_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id,
+                              union kvmppc_one_reg *val);
 
 #ifdef CONFIG_KVM_E500V2
 unsigned int kvmppc_e500_get_sid(struct kvmppc_vcpu_e500 *vcpu_e500,
index 5c44759..44f7762 100644 (file)
@@ -596,6 +596,100 @@ int kvmppc_set_sregs_e500_tlb(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
        return 0;
 }
 
+int kvmppc_get_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id,
+                               union kvmppc_one_reg *val)
+{
+       int r = 0;
+       long int i;
+
+       switch (id) {
+       case KVM_REG_PPC_MAS0:
+               *val = get_reg_val(id, vcpu->arch.shared->mas0);
+               break;
+       case KVM_REG_PPC_MAS1:
+               *val = get_reg_val(id, vcpu->arch.shared->mas1);
+               break;
+       case KVM_REG_PPC_MAS2:
+               *val = get_reg_val(id, vcpu->arch.shared->mas2);
+               break;
+       case KVM_REG_PPC_MAS7_3:
+               *val = get_reg_val(id, vcpu->arch.shared->mas7_3);
+               break;
+       case KVM_REG_PPC_MAS4:
+               *val = get_reg_val(id, vcpu->arch.shared->mas4);
+               break;
+       case KVM_REG_PPC_MAS6:
+               *val = get_reg_val(id, vcpu->arch.shared->mas6);
+               break;
+       case KVM_REG_PPC_MMUCFG:
+               *val = get_reg_val(id, vcpu->arch.mmucfg);
+               break;
+       case KVM_REG_PPC_TLB0CFG:
+       case KVM_REG_PPC_TLB1CFG:
+       case KVM_REG_PPC_TLB2CFG:
+       case KVM_REG_PPC_TLB3CFG:
+               i = id - KVM_REG_PPC_TLB0CFG;
+               *val = get_reg_val(id, vcpu->arch.tlbcfg[i]);
+               break;
+       default:
+               r = -EINVAL;
+               break;
+       }
+
+       return r;
+}
+
+int kvmppc_set_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id,
+                              union kvmppc_one_reg *val)
+{
+       int r = 0;
+       long int i;
+
+       switch (id) {
+       case KVM_REG_PPC_MAS0:
+               vcpu->arch.shared->mas0 = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_MAS1:
+               vcpu->arch.shared->mas1 = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_MAS2:
+               vcpu->arch.shared->mas2 = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_MAS7_3:
+               vcpu->arch.shared->mas7_3 = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_MAS4:
+               vcpu->arch.shared->mas4 = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_MAS6:
+               vcpu->arch.shared->mas6 = set_reg_val(id, *val);
+               break;
+       /* Only allow MMU registers to be set to the config supported by KVM */
+       case KVM_REG_PPC_MMUCFG: {
+               u32 reg = set_reg_val(id, *val);
+               if (reg != vcpu->arch.mmucfg)
+                       r = -EINVAL;
+               break;
+       }
+       case KVM_REG_PPC_TLB0CFG:
+       case KVM_REG_PPC_TLB1CFG:
+       case KVM_REG_PPC_TLB2CFG:
+       case KVM_REG_PPC_TLB3CFG: {
+               /* MMU geometry (N_ENTRY/ASSOC) can be set only using SW_TLB */
+               u32 reg = set_reg_val(id, *val);
+               i = id - KVM_REG_PPC_TLB0CFG;
+               if (reg != vcpu->arch.tlbcfg[i])
+                       r = -EINVAL;
+               break;
+       }
+       default:
+               r = -EINVAL;
+               break;
+       }
+
+       return r;
+}
+
 int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
                              struct kvm_config_tlb *cfg)
 {
index b071bdc..ab073a8 100644 (file)
@@ -258,13 +258,15 @@ int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
 int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
                        union kvmppc_one_reg *val)
 {
-       return -EINVAL;
+       int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
+       return r;
 }
 
 int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
                       union kvmppc_one_reg *val)
 {
-       return -EINVAL;
+       int r = kvmppc_set_one_reg_e500_tlb(vcpu, id, val);
+       return r;
 }
 
 struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)