[PATCH] lhype: Add TLS support

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

 



This is queued for when Rusty returns, but may be generally useful now to 
people playing with lhype.

TLS support is required for some binaries (notably, Fedora & co), and also 
any binary which explicitly uses __thread variables (which all segfault 
without this patch).

It works well enough to bring FC6 up as far as it goes without an initrd, 
although there may be some further work required.  e.g.

o Need to ensure fixup_gdt() doesn't stomp on TLS segement descriptors.
o In some cases, a binary may fall back to calling modify_ldt(2) instead 
  of get_thread_area(2), and this needs to be handled.

---

Virtualize thread local storage for guests.  A new hypercall,
LHCALL_LOAD_TLS, is implemented, mapping to the load_tls()
paravirt op.  The virtualized GDT is now updated correctly
from the guest's per-thread TLS array.

Signed-off-by: James Morris <jmorris at namei.org>
---
 arch/i386/kernel/lhype.c   |    6 ++++++
 drivers/lhype/hypercalls.c |   22 +++++++++++++++++++++-
 include/asm-i386/lhype.h   |    1 +
 3 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/arch/i386/kernel/lhype.c b/arch/i386/kernel/lhype.c
index d4376c5..35c4616 100644
--- a/arch/i386/kernel/lhype.c
+++ b/arch/i386/kernel/lhype.c
@@ -221,6 +221,11 @@ static fastcall void lhype_set_ldt(const
 	BUG_ON(entries);
 }
 
+static fastcall void lhype_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+	hcall(LHCALL_LOAD_TLS, __pa(t), cpu, 0);
+}
+
 static fastcall void lhype_set_debugreg(int regno, unsigned long value)
 {
 	/* FIXME: Implement */
@@ -385,6 +390,7 @@ #endif
 	paravirt_ops.load_esp0 = lhype_load_esp0;
 	paravirt_ops.load_tr_desc = lhype_load_tr_desc;
 	paravirt_ops.set_ldt = lhype_set_ldt;
+	paravirt_ops.load_tls = lhype_load_tls;
 	paravirt_ops.set_debugreg = lhype_set_debugreg;
 	paravirt_ops.clts = lhype_clts;
 	paravirt_ops.read_cr0 = lhype_read_cr0;
diff --git a/drivers/lhype/hypercalls.c b/drivers/lhype/hypercalls.c
index bc8639c..f3ff693 100644
--- a/drivers/lhype/hypercalls.c
+++ b/drivers/lhype/hypercalls.c
@@ -178,13 +178,29 @@ static int guest_set_stack(struct lhype_
 	return 1;
 }
 
+static void guest_load_tls(struct lhype_dom_info *info,
+			   const struct thread_struct __user *t)
+{
+	int i;
+	struct desc_struct *gdt = info->domain->gdt_table;
+	
+	for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++) {
+		struct desc_struct d;
+
+		lhread(info, &d, (u32)&t->tls_array[i - GDT_ENTRY_TLS_MIN],
+		       sizeof(d));
+		gdt[i] = d;
+	}
+}
+
 void hypercall(struct lhype_dom_info *linfo, struct lhype_regs *regs)
 {
 	static unsigned long last_jifs;
 	/* These three happen regularly, so we limit them... */
 	if ((regs->eax != LHCALL_IRET
 	     && regs->eax != LHCALL_HALT
-	     && regs->eax != LHCALL_TIMER_READ)
+	     && regs->eax != LHCALL_TIMER_READ
+	     && regs->eax != LHCALL_LOAD_TLS)
 	    || printk_timed_ratelimit(&last_jifs, 10000)) {
 		printk(KERN_DEBUG "%i: %s\n", linfo->domid,
 		       regs->eax == LHCALL_LHYPE_PAGE ? "LHYPE_PAGE" :
@@ -208,6 +224,7 @@ void hypercall(struct lhype_dom_info *li
 		       regs->eax == LHCALL_SET_PTE ? "SET_PTE" :
 		       regs->eax == LHCALL_SET_SOME_PTE ? "SET_SOME_PTE" :
 		       regs->eax == LHCALL_SET_PUD ? "SET_PUD" :
+		       regs->eax == LHCALL_LOAD_TLS ? "LOAD_TLS" :
 		       "UNKNOWN");
 	}
 
@@ -325,6 +342,9 @@ void hypercall(struct lhype_dom_info *li
 	case LHCALL_SET_PUD:
 		guest_set_pud(linfo, regs->edx);
 		break;
+	case LHCALL_LOAD_TLS:
+		guest_load_tls(linfo, (struct thread_struct __user*)regs->edx);
+		break;
 	}
 	return;
 }
diff --git a/include/asm-i386/lhype.h b/include/asm-i386/lhype.h
index df86d97..af0c03b 100644
--- a/include/asm-i386/lhype.h
+++ b/include/asm-i386/lhype.h
@@ -26,6 +26,7 @@ #define LHCALL_SEND_DMA		18
 #define LHCALL_SET_PTE		19
 #define LHCALL_SET_SOME_PTE	20
 #define LHCALL_SET_PUD		21
+#define LHCALL_LOAD_TLS		22
 
 #define LHYPE_TRAP_ENTRY 0x81
 
-- 
1.4.2.1







[Index of Archives]     [KVM Development]     [Libvirt Development]     [Libvirt Users]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux