]> rtime.felk.cvut.cz Git - l4.git/blobdiff - kernel/fiasco/src/kern/ia32/thread-ia32.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / thread-ia32.cpp
index 3066221ef6ee021aa8d6cbbf55f265784d1d63f9..079f9999608bbb1b4580bdc26c159dca9150944e 100644 (file)
@@ -8,7 +8,7 @@ INTERFACE [ia32,amd64,ux]:
 
 class Idt_entry;
 
-EXTENSION class Thread 
+EXTENSION class Thread
 {
 private:
   /**
@@ -17,9 +17,6 @@ private:
   static Mword exception_cs();
 
 protected:
-  Idt_entry *_idt;
-  Unsigned16 _idt_limit;
-
   static Trap_state::Handler nested_trap_handler FIASCO_FASTCALL;
 };
 
@@ -54,29 +51,27 @@ IMPLEMENTATION [ia32,amd64,ux]:
 #include "thread.h"
 #include "timer.h"
 #include "trap_state.h"
-#include "vmem_alloc.h"
 
 Trap_state::Handler Thread::nested_trap_handler FIASCO_FASTCALL;
 
 IMPLEMENT
 Thread::Thread()
-: Receiver(&_thread_lock),
+: Receiver(),
   Sender(0),   // select optimized version of constructor
   _pager(Thread_ptr::Invalid),
   _exc_handler(Thread_ptr::Invalid),
   _del_observer(0)
 {
-  //assert (current() == thread_lock()->lock_owner());
-  assert (state() == Thread_invalid);
+  assert (state(false) == Thread_invalid);
 
   inc_ref();
+  _space.space(Kernel_task::kernel_task());
 
-  if (Config::stack_depth)
+  if (Config::Stack_depth)
     std::memset((char*)this + sizeof(Thread), '5',
-               Config::thread_block_size-sizeof(Thread)-64);
+               Thread::Size-sizeof(Thread)-64);
 
   _magic          = magic;
-  _idt_limit      = 0;
   _recover_jmpbuf = 0;
   _timeout        = 0;
 
@@ -84,7 +79,7 @@ Thread::Thread()
 
   arch_init();
 
-  state_add_dirty(Thread_dead | Thread_suspended);
+  state_add_dirty(Thread_dead, false);
 
   // ok, we're ready to go!
 }
@@ -99,19 +94,6 @@ Mword
 Thread::user_flags() const
 { return regs()->flags(); }
 
-
-
-PRIVATE inline
-int
-Thread::is_privileged_for_debug(Trap_state * /*ts*/)
-{
-#if 0
-  return ((ts->flags() & EFLAGS_IOPL) == EFLAGS_IOPL_U);
-#else
-  return 1;
-#endif
-}
-
 /** Check if the pagefault occured at a special place: At some places in the
     kernel we want to ensure that a specific address is mapped. The regular
     case is "mapped", the exception or slow case is "not mapped". The fastest
@@ -176,7 +158,7 @@ thread_restore_exc_state()
   current_thread()->restore_exc_state();
 }
 
-PRIVATE static 
+PRIVATE static
 void
 Thread::print_page_fault_error(Mword e)
 {
@@ -196,18 +178,27 @@ Thread::print_page_fault_error(Mword e)
 PUBLIC
 int
 Thread::handle_slow_trap(Trap_state *ts)
-{ 
+{
   Address ip;
   int from_user = ts->cs() & 3;
 
   if (EXPECT_FALSE(ts->_trapno == 0xee)) //debug IPI
     {
-      Ipi::eoi(Ipi::Debug);
+      Ipi::eoi(Ipi::Debug, cpu());
       goto generic_debug;
     }
 
-  if (from_user && (state() & Thread_vcpu_user_mode) && send_exception(ts))
-    goto success;
+  if (from_user && _space.user_mode())
+    {
+      if (ts->_trapno == 14 && Kmem::is_io_bitmap_page_fault(ts->_cr2))
+        {
+         ts->_trapno = 13;
+         ts->_err    = 0;
+        }
+
+      if (send_exception(ts))
+       goto success;
+    }
 
   // XXX We might be forced to raise an excepton. In this case, our return
   // CS:IP points to leave_by_trigger_exception() which will trigger the
@@ -217,14 +208,6 @@ Thread::handle_slow_trap(Trap_state *ts)
   if (ts->_trapno == 13 && (ts->_err & 6) == 6)
     goto check_exception;
 
-
-  // XXX: need to do in a different way, if on debug stack e.g.
-#if 0
-  if (EXPECT_FALSE(!in_context_area((void*)Proc::stack_pointer())))
-    goto generic_debug;                // we're in the GDB stub or in jdb
-                                // -- let generic handler handle it
-#endif
-
   LOG_TRAP;
 
   if (!check_trap13_kernel (ts))
@@ -248,122 +231,35 @@ Thread::handle_slow_trap(Trap_state *ts)
   check_f00f_bug(ts);
 
   // so we were in user mode -- look for something to emulate
-  
+
   // We continue running with interrupts off -- no sti() here. But
   // interrupts may be enabled by the pagefault handler if we get a
   // pagefault in peek_user().
 
   // Set up exception handling.  If we suffer an un-handled user-space
   // page fault, kill the thread.
-  jmp_buf pf_recovery; 
+  jmp_buf pf_recovery;
   unsigned error;
   if (EXPECT_FALSE ((error = setjmp(pf_recovery)) != 0) )
     {
-      WARN ("%p killed:\n"
-           "\033[1mUnhandled page fault, code=%08x\033[m\n",
-           this, error);
+      WARN("%p killed:\n"
+           "\033[1mUnhandled page fault, code=%08x\033[m\n", this, error);
       goto fail_nomsg;
     }
 
   _recover_jmpbuf = &pf_recovery;
 
-  switch (handle_io_page_fault(ts, from_user))
+  switch (handle_io_page_fault(ts))
     {
     case 1: goto success;
     case 2: goto fail;
+    default: break;
     }
-  
-  ip = ts->ip();
 
-  // check for "invalid opcode" exception
-  if (EXPECT_FALSE (Config::Kip_syscalls && ts->_trapno == 6))
-    {
-#if 0
-      // Check "lock; nop" opcode
-      if (mem_space()->peek ((Unsigned16*) ip, from_user) == 0x90f0)
-        {
-         ts->consume_instruction(2);
-         ts->value(task()->map_kip());
-          goto success;
-        }
-#endif
-    }
+  ip = ts->ip();
 
   // just print out some warning, we do the normal exception handling
   handle_sysenter_trap(ts, ip, from_user);
-
-  // check for general protection exception
-  if (ts->_trapno == 13 && (ts->_err & 0xffff) == 0)
-    {
-      // find out if we are a privileged task
-      bool is_privileged = trap_is_privileged (ts);
-
-      // check for "lidt (%eax)"
-      if (EXPECT_FALSE
-         (ip < Kmem::mem_user_max - 4 &&
-          (mem_space()->peek((Mword*) ip, from_user) & 0xffffff) == 0x18010f))
-       {
-          // emulate "lidt (%eax)"
-
-          // read descriptor
-          if (ts->value() >= Kmem::mem_user_max - 6)
-            goto fail;
-
-          Idt_entry *idt
-           = mem_space()->peek((Idt_entry**)(ts->value() + 2), from_user);
-          Unsigned16 limit = mem_space()->peek ((Unsigned16*) ts->value(), from_user);
-
-          if ((Address)idt >= (Address)Kmem::mem_user_max-limit-1)
-            goto fail;
-
-          // OK; store descriptor
-          _idt = idt;
-          _idt_limit = (limit + 1) / sizeof(Idt_entry);
-
-          // consume instruction and continue
-         ts->consume_instruction(3);
-          // ignore errors
-          goto success;
-        }
-
-      // check for "wrmsr (%eax)"
-      if (EXPECT_FALSE
-         (is_privileged
-          && (ip < Kmem::mem_user_max - 2)
-          && (mem_space()->peek((Unsigned16*) ip, from_user)) == 0x300f
-          && (Cpu::cpus.cpu(cpu()).can_wrmsr())))
-        {
-         printf("Detected wrmsr at %lx\n", ip);
-         if (0)
-            {
-              do_wrmsr_in_kernel (ts);
-
-              // consume instruction and continue
-              ts->consume_instruction(2);
-              // ignore errors
-              goto success;
-            }
-        }
-
-      // check for "rdmsr (%eax)"
-      if (EXPECT_FALSE
-         (is_privileged
-          && (ip < Kmem::mem_user_max - 2)
-          && (mem_space()->peek((Unsigned16*) ip, from_user)) == 0x320f
-          && (Cpu::cpus.cpu(cpu()).can_wrmsr())))
-        {
-          printf("Detected rdmsr at %lx\n", ip);
-          if (0)
-            {
-              do_rdmsr_in_kernel(ts);
-
-              // consume instruction and continue
-              ts->consume_instruction(2);
-              // ignore errors
-              goto success;
-            }
-        }
-    }
   _recover_jmpbuf = 0;
 
 check_exception:
@@ -372,37 +268,9 @@ check_exception:
   if (send_exception(ts))
     goto success;
 
-  // let's see if we have a trampoline to invoke
-  if (ts->_trapno < 0x20 && ts->_trapno < _idt_limit)
-    {
-      Idt_entry e = mem_space()->peek(_idt + ts->_trapno, 1);
-
-      if ((e.ist() & 0xe0) == 0x00
-          && (e.access() & 0x1f) == 0x0f) // gate descriptor ok?
-        {
-          Address handler = e.offset();
-
-          if (handler
-              && handler  <  Kmem::mem_user_max // in user space?
-              && ts->sp() <= Kmem::mem_user_max
-              && ts->sp() > 5 * sizeof (Mword)) // enough space on user stack?
-            {
-             // OK, reflect the trap to user mode
-             if (1 /* !raise_exception (ts, handler) */)
-                {
-                  // someone interfered and changed our state
-                 assert (state() & Thread_cancel);
-                  state_del(Thread_cancel);
-                }
-
-              goto success;     // we've consumed the trap
-            }
-        }
-    }
-
   // backward compatibility cruft: check for those insane "int3" debug
   // messaging command sequences
-  if (ts->_trapno == 3 && is_privileged_for_debug(ts))
+  if (ts->_trapno == 3)
     {
       if (int3_handler && int3_handler(ts))
        goto success;
@@ -412,23 +280,19 @@ check_exception:
 
   // privileged tasks also may invoke the kernel debugger with a debug
   // exception
-  if (ts->_trapno == 1 && is_privileged_for_debug (ts))
+  if (ts->_trapno == 1)
     goto generic_debug;
 
 
 fail:
   // can't handle trap -- kill the thread
-  WARN ("%p killed:\n"
-       "\033[1mUnhandled trap \033[m\n",
-       this);
+  WARN("%p killed:\n"
+       "\033[1mUnhandled trap \033[m\n", this);
 
 fail_nomsg:
-  if (Config::warn_level >= Warning)
+  if ((int)Config::Warn_level >= Warning)
     ts->dump();
 
-  if (Config::conservative)
-    kdb_ke("thread killed");
-
   halt();
 
 success:
@@ -478,7 +342,7 @@ thread_page_fault(Address pfa, Mword error_code, Address ip, Mword flags,
     Proc::sti();
 
   // Pagefault in kernel mode and interrupts were disabled
-  else 
+  else
     {
       // page fault in kernel memory region
       if (Kmem::is_kmem_page_fault(pfa, error_code))
@@ -490,15 +354,14 @@ thread_page_fault(Address pfa, Mword error_code, Address ip, Mword flags,
          // just not in the currently active page directory)
          // Remain cli'd !!!
        }
-      else if (!Config::conservative &&
-              !Kmem::is_kmem_page_fault(pfa, error_code))
+      else if (!Kmem::is_kmem_page_fault(pfa, error_code))
        {
           // No error -- just enable interrupts.
          Proc::sti();
        }
-      else 
+      else
        {
-                 // Error: We interrupted a cli'd kernel context touching kernel space
+          // Error: We interrupted a cli'd kernel context touching kernel space
          if (!Thread::log_page_fault())
            printf("*P[%lx,%lx,%lx] ", pfa, error_code & 0xffff, ip);
 
@@ -532,36 +395,24 @@ IMPLEMENT inline
 bool
 Thread::handle_sigma0_page_fault(Address pfa)
 {
-  size_t size;
+  Mem_space::Page_order size = mem_space()->largest_page_size(); // take a page size less than 16MB (1<<24)
+  auto f = mem_space()->fitting_sizes();
+  Virt_addr va = Virt_addr(pfa);
 
   // Check if mapping a superpage doesn't exceed the size of physical memory
-  if (Cpu::have_superpages()
-     // Some distributions do not allow to mmap below a certain threshold
-     // (like 64k on Ubuntu 8.04) so we cannot map a superpage at 0 if
-     // we're Fiasco-UX
-      && (!Config::Is_ux || !(pfa < Config::SUPERPAGE_SIZE)))
-    {
-      pfa &= Config::SUPERPAGE_MASK;
-      size = Config::SUPERPAGE_SIZE;
-    }
-  else
-    {
-      pfa &= Config::PAGE_MASK;
-      size = Config::PAGE_SIZE;
-    }
+  // Some distributions do not allow to mmap below a certain threshold
+  // (like 64k on Ubuntu 8.04) so we cannot map a superpage at 0 if
+  // we're Fiasco-UX
+  while (Config::Is_ux && (va < (Virt_addr(1) << size)))
+    size = f(--size);
+
+  va = cxx::mask_lsb(va, size);
 
-  return mem_space()->v_insert(Mem_space::Phys_addr(pfa), Mem_space::Addr(pfa),
-                               Mem_space::Size(size),
-                               Mem_space::Page_writable
-                               | Mem_space::Page_user_accessible)
+  return mem_space()->v_insert(Mem_space::Phys_addr(va), va, size,
+                               Page::Attr(L4_fpage::Rights::URWX()))
     != Mem_space::Insert_err_nomem;
 }
 
-PUBLIC inline
-Utcb *
-Thread::access_utcb() const
-{ return utcb(); }
-
 PRIVATE static inline
 void
 Thread::save_fpu_state_to_utcb(Trap_state *, Utcb *)
@@ -596,10 +447,29 @@ Thread::send_exception_arch(Trap_state *ts)
 }
 
 
+//----------------------------------------------------------------------------
+IMPLEMENTATION [(vmx || svm) && (ia32 || amd64)]:
+
+#include "vmx.h"
+#include "svm.h"
+
+IMPLEMENT inline NEEDS["vmx.h", "svm.h"]
+void
+Thread::arch_init_vcpu_state(Vcpu_state *vcpu_state, bool ext)
+{
+  if (!ext)
+    return;
+
+  if (Vmx::cpus.current().vmx_enabled())
+    Vmx::cpus.current().init_vmcs_infos(vcpu_state);
+
+  // currently we do nothing for SVM here
+}
+
 //----------------------------------------------------------------------------
 IMPLEMENTATION [ia32 || amd64]:
 
-PRIVATE inline
+PROTECTED inline
 void
 Thread::vcpu_resume_user_arch()
 {}
@@ -607,7 +477,7 @@ Thread::vcpu_resume_user_arch()
 //----------------------------------------------------------------------------
 IMPLEMENTATION [ux]:
 
-PRIVATE inline
+PROTECTED inline
 void
 Thread::vcpu_resume_user_arch()
 {
@@ -630,13 +500,12 @@ Thread::user_ip(Mword ip)
     }
 }
 
-
 //----------------------------------------------------------------------------
 IMPLEMENTATION [(ia32,amd64,ux) && !io]:
 
 PRIVATE inline
 int
-Thread::handle_io_page_fault(Trap_state *, bool)
+Thread::handle_io_page_fault(Trap_state *)
 { return 0; }
 
 PRIVATE inline
@@ -658,10 +527,9 @@ IMPLEMENTATION[ia32 || amd64]:
 #include "simpleio.h"
 #include "static_init.h"
 #include "terminate.h"
-#include "utcb_init.h"
 
 int (*Thread::int3_handler)(Trap_state*);
-Per_cpu<Thread::Dbg_stack> DEFINE_PER_CPU Thread::dbg_stack;
+DEFINE_PER_CPU Per_cpu<Thread::Dbg_stack> Thread::dbg_stack;
 
 STATIC_INITIALIZER_P (int3_handler_init, KDB_INIT_PRIO);
 
@@ -689,23 +557,13 @@ Thread::arch_init()
   // clear out user regs that can be returned from the thread_ex_regs
   // system call to prevent covert channel
   Entry_frame *r = regs();
-  if (Config::enable_io_protection)
-    r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2);   // ei
-  else
-    r->flags(EFLAGS_IOPL_U | EFLAGS_IF | 2);   // XXX iopl=kernel
+  r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2);     // ei
   r->cs(Gdt::gdt_code_user | Gdt::Selector_user);
   r->ss(Gdt::gdt_data_user | Gdt::Selector_user);
 
   r->sp(0);
   // after cs initialisation as ip() requires proper cs
   r->ip(0);
-
-#ifdef CONFIG_HANDLE_SEGMENTS
-  _gs = _fs = Utcb_init::utcb_segment();
-#else
-  Cpu::set_gs(Utcb_init::utcb_segment());
-  Cpu::set_fs(Utcb_init::utcb_segment());
-#endif
 }
 
 
@@ -739,7 +597,7 @@ PUBLIC static
 int
 Thread::handle_int3(Trap_state *ts)
 {
-  Mem_space *s   = current_mem_space();
+  Mem_space *s   = current()->mem_space();
   int from_user  = ts->cs() & 3;
   Address   ip   = ts->ip();
   Unsigned8 todo = s->peek((Unsigned8*)ip, from_user);
@@ -881,9 +739,9 @@ Thread::check_io_bitmap_delimiter_fault(Trap_state *ts)
       Mem_space::Status result =
        mem_space()->v_insert(
            Mem_space::Phys_addr(mem_space()->virt_to_phys_s0((void*)Kmem::io_bitmap_delimiter_page())),
-           Mem_space::Addr::create(Mem_layout::Io_bitmap + Mem_layout::Io_port_max / 8),
-           Mem_space::Size::create(Config::PAGE_SIZE),
-           Pt_entry::global());
+           Virt_addr(Mem_layout::Io_bitmap + Mem_layout::Io_port_max / 8),
+           Mem_space::Page_order(Config::PAGE_SHIFT),
+           Page::Attr(Page::Rights::R(), Page::Type::Normal(), Page::Kern::Global()));
 
       switch (result)
        {
@@ -932,41 +790,18 @@ Thread::handle_sysenter_trap(Trap_state *ts, Address eip, bool from_user)
   return true;
 }
 
-PRIVATE inline
-bool
-Thread::trap_is_privileged(Trap_state *)
-{ return space()->has_io_privileges(); }
-
-PRIVATE inline
-void
-Thread::do_wrmsr_in_kernel(Trap_state *ts)
-{
-  // do "wrmsr (msr[ecx], edx:eax)" in kernel
-  Cpu::wrmsr (ts->value(), ts->value3(), ts->value2());
-}
-
-PRIVATE inline
-void
-Thread::do_rdmsr_in_kernel(Trap_state *ts)
-{
-  // do "rdmsr (msr[ecx], edx:eax)" in kernel
-  Unsigned64 msr = Cpu::rdmsr(ts->value2());
-  ts->value((Unsigned32) msr);
-  ts->value3((Unsigned32) (msr >> 32));
-}
-
 PRIVATE inline
 int
 Thread::handle_not_nested_trap(Trap_state *ts)
 {
   // no kernel debugger present
-  printf(" %p IP="L4_PTR_FMT" Trap=%02lx [Ret/Esc]\n",
+  printf(" %p IP=" L4_PTR_FMT " Trap=%02lx [Ret/Esc]\n",
         this, ts->ip(), ts->_trapno);
 
   int r;
   // cannot use normal getchar because it may block with hlt and irq's
   // are off here
-  while ((r=Kconsole::console()->getchar(false)) == -1)
+  while ((r = Kconsole::console()->getchar(false)) == -1)
     Proc::pause();
 
   if (r == '\033')
@@ -975,13 +810,37 @@ Thread::handle_not_nested_trap(Trap_state *ts)
   return 0;
 }
 
-PRIVATE inline
+PROTECTED inline
 int
 Thread::sys_control_arch(Utcb *)
 {
   return 0;
 }
 
+//---------------------------------------------------------------------------
+IMPLEMENTATION [(ia32 | amd64) & (debug | kdb) & !mp]:
+
+PRIVATE static inline Cpu_number Thread::dbg_find_cpu() { return Cpu_number::boot_cpu(); }
+
+//---------------------------------------------------------------------------
+IMPLEMENTATION [(ia32 | amd64) & (debug | kdb) & mp]:
+
+#include "apic.h"
+
+PRIVATE static inline NEEDS["apic.h"]
+Cpu_number
+Thread::dbg_find_cpu()
+{
+  unsigned long phys_cpu = Apic::get_id();
+  Cpu_number log_cpu = Apic::find_cpu(phys_cpu);
+  if (log_cpu == Cpu_number::nil())
+    {
+      printf("Trap on unknown CPU phys_id=%lx\n", phys_cpu);
+      log_cpu = Cpu_number::boot_cpu();
+    }
+  return log_cpu;
+}
+
 
 //---------------------------------------------------------------------------
 IMPLEMENTATION [(ia32 |amd64) & !(debug | kdb)]: