[PATCH] Map guest (ts,tid) to individual shadow tid

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

 



Hi guys,

Thanks to Hollis's idea.
This patch help to make KVMPPC be more friendly to OSes other than Linux.

Any (ts,tid) combination will be mapped to an individual shadow tid(stid).
Whenever the stid is exhausted, it needs to reset of stid and flush host TLB.

To simplify the code, guest tid=0 will always be mapped to stid=0.
And I don't think any OS uses tid=0 in userspace, does it?

In the case that run Linux in guest, the stid won't be exhausted.
So that there is no extra overhead comparing to old code.

Any comment?

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

diff --git a/arch/powerpc/include/asm/kvm_e500.h b/arch/powerpc/include/asm/kvm_e500.h
index 9d497ce..a62dd27 100644
--- a/arch/powerpc/include/asm/kvm_e500.h
+++ b/arch/powerpc/include/asm/kvm_e500.h
@@ -37,6 +37,9 @@ struct kvmppc_vcpu_e500 {
 	/* Pages which are referenced in the shadow TLB. */
 	struct page **shadow_pages[E500_TLB_NUM];
 
+	/* tid mapping table */
+	void *tid_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 0e773fc..ab077e3 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_tlb.c
@@ -106,6 +106,53 @@ static inline u32 e500_shadow_mas2_attrib(u32 mas2, int usermode)
 #endif
 }
 
+struct tid_mapping {
+	unsigned char tid[2][256];
+};
+
+static inline struct tid_mapping *kvmppc_e500_alloc_stid(void)
+{
+	return (struct tid_mapping *)kzalloc(sizeof(struct tid_mapping), GFP_KERNEL);
+}
+
+static inline void kvmppc_e500_free_stid(struct tid_mapping *tid)
+{
+	kfree(tid);
+	return;
+}
+
+/*
+ * Map guest (ts,tid) to individual shadow tid.
+ * XXX Always map tid=0 to stid=0,
+ * and suppose that guest won't use tid=0 in userspace(ts=1).
+ */
+static inline int kvmppc_e500_get_stid(struct tid_mapping *tid, int gts, int gtid)
+{
+	int ret;
+
+	if (unlikely(gtid == 0)) {
+		WARN_ON(gts == 1);
+		return 0;
+	}
+
+	ret = tid->tid[gts][gtid];
+
+	if (ret == 0) {
+		/* None mapping yet */
+		ret = ++tid->tid[0][0];
+		if(unlikely(ret == 0))
+			return -1;
+
+		tid->tid[gts][gtid] = ret;
+	}
+	return ret;
+}
+
+static inline void kvmppc_e500_reset_stid(struct tid_mapping *tid)
+{
+	memset(tid, 0, sizeof(struct tid_mapping));
+}
+
 /*
  * writing shadow tlb entry to host TLB
  */
@@ -291,6 +338,7 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
 	struct page *new_page;
 	struct tlbe *stlbe;
 	hpa_t hpaddr;
+	int stid = -1;
 
 	stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel];
 
@@ -308,9 +356,19 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
 
 	vcpu_e500->shadow_pages[tlbsel][esel] = new_page;
 
+	while (stid < 0) {
+		stid = kvmppc_e500_get_stid(vcpu_e500->tid_mapping,
+					    get_tlb_ts(gtlbe),
+					    get_tlb_tid(gtlbe));
+		if (unlikely(stid < 0)) {
+			kvmppc_e500_reset_stid(vcpu_e500->tid_mapping);
+			_tlbil_all();
+		}
+	}
+
 	/* Force TS=1 IPROT=0 TSIZE=4KB for all guest mappings. */
 	stlbe->mas1 = MAS1_TSIZE(BOOKE_PAGESZ_4K)
-		| MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID;
+		| MAS1_TID(stid) | MAS1_TS | MAS1_VALID;
 	stlbe->mas2 = (gvaddr & MAS2_EPN)
 		| e500_shadow_mas2_attrib(gtlbe->mas2,
 				vcpu_e500->vcpu.arch.msr & MSR_PR);
@@ -730,8 +788,14 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
 	if (vcpu_e500->shadow_pages[1] == NULL)
 		goto err_out_page0;
 
+	vcpu_e500->tid_mapping = kvmppc_e500_alloc_stid();
+	if (vcpu_e500->tid_mapping == NULL)
+		goto err_out_page1;
+
 	return 0;
 
+err_out_page1:
+	kfree(vcpu_e500->shadow_pages[1]);
 err_out_page0:
 	kfree(vcpu_e500->shadow_pages[0]);
 err_out_shadow1:
@@ -748,6 +812,7 @@ err_out:
 
 void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
+	kvmppc_e500_free_stid(vcpu_e500->tid_mapping);
 	kfree(vcpu_e500->shadow_pages[1]);
 	kfree(vcpu_e500->shadow_pages[0]);
 	kfree(vcpu_e500->shadow_tlb[1]);
-- 
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