[PATCH 2/5] kvm/e500: Add shadow ID mapping support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Based on Hollis's idea,
this patch map (vcpu, as, pid) to individual shadow id.

Every vcpu has a mapping table,
which keep the mapping from guest (as, id) to shadow id.

Every hardware core has a shadow id reference table,
which keep the mapping from shadow id to (vcpu, as, pid).

When mapping is created, both vcpu and core need to update their tables.
But they can destroy the mapping one-sided.

When shadow id get exhausted,
a flush is needed for shadow id reference table.

Signed-off-by: Liu Yu <yu.liu@xxxxxxxxxxxxx>
---
 arch/powerpc/include/asm/kvm_e500.h |    3 +
 arch/powerpc/kvm/e500_tlb.c         |   96 +++++++++++++++++++++++++++++++++++
 arch/powerpc/kvm/e500_tlb.h         |    4 +-
 3 files changed, 102 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_e500.h b/arch/powerpc/include/asm/kvm_e500.h
index b248f31..bc73abe 100644
--- a/arch/powerpc/include/asm/kvm_e500.h
+++ b/arch/powerpc/include/asm/kvm_e500.h
@@ -42,6 +42,9 @@ struct kvmppc_vcpu_e500 {
 	/* Pages which are referenced in the shadow TLB. */
 	struct kvmppc_e500_shadow_ref *shadow_refs[E500_TLB_NUM];
 
+	/* MMU id mapping */
+	void *id_mapping;
+
 	unsigned int guest_tlb_size[E500_TLB_NUM];
 	unsigned int shadow_tlb_size[E500_TLB_NUM];
 	unsigned int guest_tlb_nv[E500_TLB_NUM];
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c
index 4952dba..e5c9211 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_tlb.c
@@ -27,6 +27,96 @@
 
 static unsigned int tlb1_entry_num;
 
+struct id_mapping {
+	unsigned char id[2][256];
+};
+
+struct shadow_id_ref {
+	void *entry[256];
+};
+
+static DEFINE_PER_CPU(struct shadow_id_ref, host_sid);
+
+static inline int e500_id_create_mapping(unsigned char *entry)
+{
+	unsigned long sid;
+	int ret = -1;
+
+	preempt_disable();
+	sid = (unsigned long)++(__get_cpu_var(host_sid).entry[0]);
+	if (sid < 256) {
+		*entry = (unsigned char)sid;
+		__get_cpu_var(host_sid).entry[sid] = entry;
+		ret = sid;
+	}
+	preempt_enable();
+
+	return ret;
+}
+
+static inline void e500_id_destroy_all(void)
+{
+	preempt_disable();
+	memset(&__get_cpu_var(host_sid), 0, sizeof(__get_cpu_var(host_sid)));
+	preempt_enable();
+}
+
+static inline int e500_id_find_mapping(unsigned char *entry)
+{
+	if (*entry && __get_cpu_var(host_sid).entry[*entry] == entry)
+		return *entry;
+	return -1;
+}
+
+static void *kvmppc_e500_alloc_idm(void)
+{
+	return kzalloc(sizeof(struct id_mapping), GFP_KERNEL);
+}
+
+static void kvmppc_e500_free_idm(void *idm)
+{
+	kfree(idm);
+	return;
+}
+
+static inline void kvmppc_e500_reset_idm(void *idm)
+{
+	memset(idm, 0, sizeof(struct id_mapping));
+}
+
+static void inline kvmppc_e500_update_spid(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+	unsigned int as = !!(vcpu_e500->vcpu.arch.msr & (MSR_IS | MSR_DS));
+
+	vcpu_e500->vcpu.arch.shadow_pid = kvmppc_e500_get_sid(vcpu_e500, as,
+			get_cur_pid(&vcpu_e500->vcpu));
+	vcpu_e500->vcpu.arch.swap_pid = kvmppc_e500_get_sid(vcpu_e500, as, 0);
+}
+
+/*
+ * Map guest (vcpu,as,id) to individual shadow id.
+ */
+unsigned int kvmppc_e500_get_sid(struct kvmppc_vcpu_e500 *vcpu_e500,
+				  int as, int gid)
+{
+	struct id_mapping *idm = vcpu_e500->id_mapping;
+	int sid;
+
+	sid = e500_id_find_mapping(&idm->id[as][gid]);
+
+	while (sid <= 0) {
+		/* None mapping yet */
+		sid = e500_id_create_mapping(&idm->id[as][gid]);
+		if(sid <= 0) {
+			BUG_ON(sid == 0);
+			e500_id_destroy_all();
+			kvmppc_e500_update_spid(vcpu_e500);
+		}
+	}
+
+	return sid;
+}
+
 void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
@@ -653,8 +743,13 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
 	if (vcpu_e500->shadow_refs[1] == NULL)
 		goto err_out_ref0;
 
+	if((vcpu_e500->id_mapping = kvmppc_e500_alloc_idm()) == NULL)
+		goto err_out_ref1;
+
 	return 0;
 
+err_out_ref1:
+	kfree(vcpu_e500->shadow_refs[1]);
 err_out_ref0:
 	kfree(vcpu_e500->shadow_refs[0]);
 err_out_guest1:
@@ -667,6 +762,7 @@ err_out:
 
 void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
+	kvmppc_e500_free_idm(vcpu_e500->id_mapping);
 	kfree(vcpu_e500->shadow_refs[1]);
 	kfree(vcpu_e500->shadow_refs[0]);
 	kfree(vcpu_e500->guest_tlb[1]);
diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h
index 45b064b..eb36514 100644
--- a/arch/powerpc/kvm/e500_tlb.h
+++ b/arch/powerpc/kvm/e500_tlb.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2008 - 2009 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Author: Yu Liu, yu.liu@xxxxxxxxxxxxx
  *
@@ -55,6 +55,8 @@ extern void kvmppc_e500_tlb_load(struct kvm_vcpu *, int);
 extern int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *);
 extern void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *);
 extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *);
+extern unsigned int kvmppc_e500_get_sid(struct kvmppc_vcpu_e500 *vcpu_e500,
+					int as, int gid);
 
 /* TLB helper functions */
 static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
-- 
1.5.4

--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [KVM Development]     [KVM ARM]     [KVM ia64]     [Linux Virtualization]     [Linux USB Devel]     [Linux Video]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux