]> rtime.felk.cvut.cz Git - l4.git/blobdiff - kernel/fiasco/src/kern/ux/emulation.cpp
update
[l4.git] / kernel / fiasco / src / kern / ux / emulation.cpp
index b27c4f683470fcafddacbc11e95f5a8144f023f5..ecec83c32fa7b8cc4c1933bd64fb4a1ff9a7f9db 100644 (file)
@@ -12,15 +12,15 @@ class Idt_entry;
 
 struct Ldt_user_desc                   // work around glibc naming mess
 {
- unsigned int  entry_number;
- unsigned long base_addr;   
- unsigned int  limit;
- unsigned int  seg_32bit:1;
- unsigned int  contents:2; 
- unsigned int  read_exec_only:1;
- unsigned int  limit_in_pages:1;
- unsigned int  seg_not_present:1;
- unsigned int  useable:1;
 unsigned int  entry_number;
+  unsigned long base_addr;
 unsigned int  limit;
 unsigned int  seg_32bit:1;
+  unsigned int  contents:2;
 unsigned int  read_exec_only:1;
 unsigned int  limit_in_pages:1;
 unsigned int  seg_not_present:1;
 unsigned int  useable:1;
 };
 
 class Pseudo_descriptor;
@@ -32,6 +32,7 @@ private:
   static Address       _page_fault_addr        asm ("PAGE_FAULT_ADDR");
   static Idt_entry const *_idt_base;
   static unsigned short        _idt_limit;
+  static unsigned       _host_tls_base;
 };
 
 IMPLEMENTATION:
@@ -41,10 +42,11 @@ IMPLEMENTATION:
 #include <sched.h>
 #include "x86desc.h"
 
-Address        Emulation::_page_dir_addr;
-Address        Emulation::_page_fault_addr;
+Address         Emulation::_page_dir_addr;
+Address         Emulation::_page_fault_addr;
 Idt_entry const *Emulation::_idt_base;
 unsigned short Emulation::_idt_limit;
+unsigned        Emulation::_host_tls_base;
 
 /**
  * Return page directory base address (register cr3)
@@ -56,10 +58,10 @@ Emulation::pdir_addr()
 {
   return _page_dir_addr;
 }
+
 /**
  * Set page directory base address (register cr3)
- * @param addr New Page Directory Base Address   
+ * @param addr New Page Directory Base Address
  */
 PUBLIC static inline
 void
@@ -67,10 +69,10 @@ Emulation::set_pdir_addr (Address addr)
 {
   _page_dir_addr = addr;
 }
+
 /**
  * Set page fault address (register cr2)
- * @param addr Page Fault Address   
+ * @param addr Page Fault Address
  */
 PUBLIC static inline
 void
@@ -173,39 +175,59 @@ Emulation::modify_ldt (unsigned entry, unsigned long base_addr, unsigned limit)
                                 "d" (sizeof (ldt)));
 }
 
+PUBLIC static
+void
+Emulation::set_host_tls_base(unsigned b)
+{
+  _host_tls_base = b;
+}
+
+PUBLIC static inline
+unsigned
+Emulation::host_tls_base()
+{ return _host_tls_base; }
+
+PUBLIC static inline
+int
+Emulation::get_thread_area(Ldt_user_desc *desc, unsigned entry_number)
+{
+  int result;
+  desc->entry_number = entry_number;
+
+#ifndef __NR_get_thread_area
+#define __NR_get_thread_area 244
+#endif
+  asm volatile ("int $0x80" : "=a" (result)
+                            : "0" (__NR_get_thread_area),
+                              "b" (desc), "m" (*desc));
+
+  if (EXPECT_FALSE(result == -38)) // -ENOSYS
+    printf("Your kernel does not support the get/set_thread_area system calls!\n"
+           "The requested feature will not work.\n");
+  return result;
+}
+
 PUBLIC static inline NEEDS [<asm/unistd.h>, <cassert>]
 void
 Emulation::thread_area_host (unsigned entry)
 {
   Ldt_user_desc desc;
   int result;
-  static int called = 0;
+  enum { NUM_TLS = 3 };
+  static int called[NUM_TLS];
 
 #ifndef __NR_set_thread_area
 #define __NR_set_thread_area 243
 #endif
-#ifndef __NR_get_thread_area
-#define __NR_get_thread_area 244
-#endif
-
-  if (called)
-    return;
-
-  called = 1;
 
-  desc.entry_number    = entry;
+  assert(_host_tls_base <= entry && entry < (_host_tls_base + NUM_TLS));
 
-  asm volatile ("int $0x80" : "=a" (result)
-                            : "0" (__NR_get_thread_area),
-                              "b" (&desc), "m" (desc));
+  if (called[entry - _host_tls_base])
+    return;
 
-  if (EXPECT_FALSE(result == -38)) // -ENOSYS
-    {
-      printf("Your kernel does not support the get/set_thread_area system calls!\n"
-            "The requested feature will not work.\n");
-      return;
-    }
+  called[entry - _host_tls_base] = 1;
 
+  result = get_thread_area(&desc, entry);
   assert(!result);
 
   if (!desc.base_addr || !desc.limit)