]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/thread-ia32.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / thread-ia32.cpp
1 /*
2  * Fiasco Thread Code
3  * Shared between UX and native IA32.
4  */
5 INTERFACE [ia32,amd64,ux]:
6
7 #include "trap_state.h"
8
9 class Idt_entry;
10
11 EXTENSION class Thread
12 {
13 private:
14   /**
15    * Return code segment used for exception reflection to user mode
16    */
17   static Mword exception_cs();
18
19 protected:
20   Idt_entry *_idt;
21   Unsigned16 _idt_limit;
22
23   static Trap_state::Handler nested_trap_handler FIASCO_FASTCALL;
24 };
25
26
27 //----------------------------------------------------------------------------
28 INTERFACE [ia32,amd64]:
29
30 class Trap_state;
31
32 EXTENSION class Thread
33 {
34 private:
35   static int  (*int3_handler)(Trap_state*);
36 };
37
38
39 //----------------------------------------------------------------------------
40 IMPLEMENTATION [ia32,amd64,ux]:
41
42 #include "config.h"
43 #include "cpu.h"
44 #include "cpu_lock.h"
45 #include "gdt.h"
46 #include "idt.h"
47 #include "ipi.h"
48 #include "mem_layout.h"
49 #include "logdefs.h"
50 #include "paging.h"
51 #include "processor.h"          // for cli/sti
52 #include "regdefs.h"
53 #include "std_macros.h"
54 #include "thread.h"
55 #include "timer.h"
56 #include "trap_state.h"
57 #include "vmem_alloc.h"
58
59 Trap_state::Handler Thread::nested_trap_handler FIASCO_FASTCALL;
60
61 IMPLEMENT
62 Thread::Thread()
63 : Receiver(&_thread_lock),
64   Sender(0),   // select optimized version of constructor
65   _pager(Thread_ptr::Invalid),
66   _exc_handler(Thread_ptr::Invalid),
67   _del_observer(0)
68 {
69   //assert (current() == thread_lock()->lock_owner());
70   assert (state() == Thread_invalid);
71
72   inc_ref();
73
74   if (Config::stack_depth)
75     std::memset((char*)this + sizeof(Thread), '5',
76                 Config::thread_block_size-sizeof(Thread)-64);
77
78   _magic          = magic;
79   _idt_limit      = 0;
80   _recover_jmpbuf = 0;
81   _timeout        = 0;
82
83   *reinterpret_cast<void(**)()> (--_kernel_sp) = user_invoke;
84
85   arch_init();
86
87   state_add_dirty(Thread_dead | Thread_suspended);
88
89   // ok, we're ready to go!
90 }
91
92 IMPLEMENT inline NEEDS[Thread::exception_triggered]
93 Mword
94 Thread::user_ip() const
95 { return exception_triggered()?_exc_cont.ip():regs()->ip(); }
96
97 IMPLEMENT inline
98 Mword
99 Thread::user_flags() const
100 { return regs()->flags(); }
101
102
103
104 PRIVATE inline
105 int
106 Thread::is_privileged_for_debug(Trap_state * /*ts*/)
107 {
108 #if 0
109   return ((ts->flags() & EFLAGS_IOPL) == EFLAGS_IOPL_U);
110 #else
111   return 1;
112 #endif
113 }
114
115 /** Check if the pagefault occured at a special place: At some places in the
116     kernel we want to ensure that a specific address is mapped. The regular
117     case is "mapped", the exception or slow case is "not mapped". The fastest
118     way to check this is to touch into the memory. If there is no mapping for
119     the address we get a pagefault. Now the pagefault exception handler can
120     recognize that situation by scanning the code. The trick is that the
121     assembler instruction "andl $0xffffffff, %ss:(%ecx)" _clears_ the carry
122     flag normally (see Intel reference manual). The pager wants to inform the
123     code that there was a pagefault and therefore _sets_ the carry flag. So
124     the code has only to check if the carry flag is set. If yes, there was
125     a pagefault at this instruction.
126     @param ip pagefault address */
127 IMPLEMENT inline
128 bool
129 Thread::pagein_tcb_request(Return_frame *regs)
130 {
131   unsigned long new_ip = regs->ip();
132   if (*(Unsigned8*)new_ip == 0x48) // REX.W
133     new_ip += 1;
134
135   register Unsigned16 op = *(Unsigned16*)new_ip;
136   //LOG_MSG_3VAL(current(),"TCB", op, new_ip, 0);
137   if ((op & 0xc0ff) == 0x8b) // Context::is_tcb_mapped() and Context::state()
138     {
139       regs->ip(new_ip + 2);
140       // stack layout:
141       //         user eip
142       //         PF error code
143       // reg =>  eax/rax
144       //         ecx/rcx
145       //         edx/rdx
146       //         ...
147       Mword *reg = ((Mword*)regs) - 2 - Return_frame::Pf_ax_offset;
148 #if 0
149       LOG_MSG_3VAL(current(),"TCB", op, regs->ip(), (Mword)reg);
150       LOG_MSG_3VAL(current(),"TCBX", reg[-3], reg[-4], reg[-5]);
151       LOG_MSG_3VAL(current(),"TCB0", reg[0], reg[-1], reg[-2]);
152       LOG_MSG_3VAL(current(),"TCB1", reg[1], reg[2], reg[3]);
153 #endif
154       assert((op >> 11) <= 2);
155       reg[-(op>>11)] = 0; // op==0 => eax, op==1 => ecx, op==2 => edx
156
157       // tell program that a pagefault occured we cannot handle
158       regs->flags(regs->flags() | 0x41); // set carry and zero flag in EFLAGS
159       return true;
160     }
161   else if (*(Unsigned32*)regs->ip() == 0xff01f636) // used in shortcut.S
162     {
163       regs->ip(regs->ip() + 4);
164       regs->flags(regs->flags() | 1);  // set carry flag in EFLAGS
165       return true;
166     }
167
168   return false;
169 }
170
171
172 extern "C" FIASCO_FASTCALL
173 void
174 thread_restore_exc_state()
175 {
176   current_thread()->restore_exc_state();
177 }
178
179 PRIVATE static 
180 void
181 Thread::print_page_fault_error(Mword e)
182 {
183   printf("%lx", e);
184 }
185
186 /**
187  * The global trap handler switch.
188  * This function handles CPU-exception reflection, emulation of CPU 
189  * instructions (LIDT, WRMSR, RDMSR), int3 debug messages, 
190  * kernel-debugger invocation, and thread crashes (if a trap cannot be 
191  * handled).
192  * @param state trap state
193  * @return 0 if trap has been consumed by handler;
194  *          -1 if trap could not be handled.
195  */
196 PUBLIC
197 int
198 Thread::handle_slow_trap(Trap_state *ts)
199 {
200   Address ip;
201   int from_user = ts->cs() & 3;
202
203   if (EXPECT_FALSE(ts->_trapno == 0xee)) //debug IPI
204     {
205       Ipi::eoi(Ipi::Debug);
206       goto generic_debug;
207     }
208
209   if (from_user && (state() & Thread_vcpu_user_mode) && send_exception(ts))
210     goto success;
211
212   // XXX We might be forced to raise an excepton. In this case, our return
213   // CS:IP points to leave_by_trigger_exception() which will trigger the
214   // exception just before returning to userland. But if we were inside an
215   // IPC while we was ex-regs'd, we will generate the 'exception after the
216   // syscall' _before_ we leave the kernel.
217   if (ts->_trapno == 13 && (ts->_err & 6) == 6)
218     goto check_exception;
219
220
221   // XXX: need to do in a different way, if on debug stack e.g.
222 #if 0
223   if (EXPECT_FALSE(!in_context_area((void*)Proc::stack_pointer())))
224     goto generic_debug;         // we're in the GDB stub or in jdb
225                                 // -- let generic handler handle it
226 #endif
227
228   LOG_TRAP;
229
230   if (!check_trap13_kernel (ts))
231     return 0;
232
233   if (EXPECT_FALSE(!from_user))
234     {
235       // get also here if a pagefault was not handled by the user level pager
236       if (ts->_trapno == 14)
237         goto check_exception;
238
239       goto generic_debug;      // we were in kernel mode -- nothing to emulate
240     }
241
242   if (EXPECT_FALSE(ts->_trapno == 2))
243     goto generic_debug;        // NMI always enters kernel debugger
244
245   if (EXPECT_FALSE(ts->_trapno == 0xffffffff))
246     goto generic_debug;        // debugger interrupt
247
248   check_f00f_bug(ts);
249
250   // so we were in user mode -- look for something to emulate
251   
252   // We continue running with interrupts off -- no sti() here. But
253   // interrupts may be enabled by the pagefault handler if we get a
254   // pagefault in peek_user().
255
256   // Set up exception handling.  If we suffer an un-handled user-space
257   // page fault, kill the thread.
258   jmp_buf pf_recovery; 
259   unsigned error;
260   if (EXPECT_FALSE ((error = setjmp(pf_recovery)) != 0) )
261     {
262       WARN ("%p killed:\n"
263             "\033[1mUnhandled page fault, code=%08x\033[m\n",
264             this, error);
265       goto fail_nomsg;
266     }
267
268   _recover_jmpbuf = &pf_recovery;
269
270   switch (handle_io_page_fault(ts, from_user))
271     {
272     case 1: goto success;
273     case 2: goto fail;
274     }
275   
276   ip = ts->ip();
277
278   // check for "invalid opcode" exception
279   if (EXPECT_FALSE (Config::Kip_syscalls && ts->_trapno == 6))
280     {
281 #if 0
282       // Check "lock; nop" opcode
283       if (mem_space()->peek ((Unsigned16*) ip, from_user) == 0x90f0)
284         {
285           ts->consume_instruction(2);
286           ts->value(task()->map_kip());
287           goto success;
288         }
289 #endif
290     }
291
292   // just print out some warning, we do the normal exception handling
293   handle_sysenter_trap(ts, ip, from_user);
294
295   // check for general protection exception
296   if (ts->_trapno == 13 && (ts->_err & 0xffff) == 0)
297     {
298       // find out if we are a privileged task
299       bool is_privileged = trap_is_privileged (ts);
300
301       // check for "lidt (%eax)"
302       if (EXPECT_FALSE
303           (ip < Kmem::mem_user_max - 4 &&
304            (mem_space()->peek((Mword*) ip, from_user) & 0xffffff) == 0x18010f))
305         {
306           // emulate "lidt (%eax)"
307
308           // read descriptor
309           if (ts->value() >= Kmem::mem_user_max - 6)
310             goto fail;
311
312           Idt_entry *idt
313             = mem_space()->peek((Idt_entry**)(ts->value() + 2), from_user);
314           Unsigned16 limit = mem_space()->peek ((Unsigned16*) ts->value(), from_user);
315
316           if ((Address)idt >= (Address)Kmem::mem_user_max-limit-1)
317             goto fail;
318
319           // OK; store descriptor
320           _idt = idt;
321           _idt_limit = (limit + 1) / sizeof(Idt_entry);
322
323           // consume instruction and continue
324           ts->consume_instruction(3);
325           // ignore errors
326           goto success;
327         }
328
329       // check for "wrmsr (%eax)"
330       if (EXPECT_FALSE
331           (is_privileged
332            && (ip < Kmem::mem_user_max - 2)
333            && (mem_space()->peek((Unsigned16*) ip, from_user)) == 0x300f
334            && (Cpu::cpus.cpu(cpu()).can_wrmsr())))
335         {
336           printf("Detected wrmsr at %lx\n", ip);
337           if (0)
338             {
339               do_wrmsr_in_kernel (ts);
340
341               // consume instruction and continue
342               ts->consume_instruction(2);
343               // ignore errors
344               goto success;
345             }
346         }
347
348       // check for "rdmsr (%eax)"
349       if (EXPECT_FALSE
350           (is_privileged
351            && (ip < Kmem::mem_user_max - 2)
352            && (mem_space()->peek((Unsigned16*) ip, from_user)) == 0x320f
353            && (Cpu::cpus.cpu(cpu()).can_wrmsr())))
354         {
355           printf("Detected rdmsr at %lx\n", ip);
356           if (0)
357             {
358               do_rdmsr_in_kernel(ts);
359
360               // consume instruction and continue
361               ts->consume_instruction(2);
362               // ignore errors
363               goto success;
364             }
365         }
366     }
367   _recover_jmpbuf = 0;
368
369 check_exception:
370
371   // send exception IPC if requested
372   if (send_exception(ts))
373     goto success;
374
375   // let's see if we have a trampoline to invoke
376   if (ts->_trapno < 0x20 && ts->_trapno < _idt_limit)
377     {
378       Idt_entry e = mem_space()->peek(_idt + ts->_trapno, 1);
379
380       if ((e.ist() & 0xe0) == 0x00
381           && (e.access() & 0x1f) == 0x0f) // gate descriptor ok?
382         {
383           Address handler = e.offset();
384
385           if (handler
386               && handler  <  Kmem::mem_user_max // in user space?
387               && ts->sp() <= Kmem::mem_user_max
388               && ts->sp() > 5 * sizeof (Mword)) // enough space on user stack?
389             {
390               // OK, reflect the trap to user mode
391               if (1 /* !raise_exception (ts, handler) */)
392                 {
393                   // someone interfered and changed our state
394                   assert (state() & Thread_cancel);
395                   state_del(Thread_cancel);
396                 }
397
398               goto success;     // we've consumed the trap
399             }
400         }
401     }
402
403   // backward compatibility cruft: check for those insane "int3" debug
404   // messaging command sequences
405   if (ts->_trapno == 3 && is_privileged_for_debug(ts))
406     {
407       if (int3_handler && int3_handler(ts))
408         goto success;
409
410       goto generic_debug;
411     }
412
413   // privileged tasks also may invoke the kernel debugger with a debug
414   // exception
415   if (ts->_trapno == 1 && is_privileged_for_debug (ts))
416     goto generic_debug;
417
418
419 fail:
420   // can't handle trap -- kill the thread
421   WARN ("%p killed:\n"
422         "\033[1mUnhandled trap \033[m\n",
423         this);
424
425 fail_nomsg:
426   if (Config::warn_level >= Warning)
427     ts->dump();
428
429   if (Config::conservative)
430     kdb_ke("thread killed");
431
432   halt();
433
434 success:
435   _recover_jmpbuf = 0;
436   return 0;
437
438 generic_debug:
439   _recover_jmpbuf = 0;
440
441   if (!nested_trap_handler)
442     return handle_not_nested_trap(ts);
443
444   return call_nested_trap_handler(ts);
445 }
446
447 /**
448  * The low-level page fault handler called from entry.S.  We're invoked with
449  * interrupts turned off.  Apart from turning on interrupts in almost
450  * all cases (except for kernel page faults in TCB area), just forwards
451  * the call to Thread::handle_page_fault().
452  * @param pfa page-fault virtual address
453  * @param error_code CPU error code
454  * @return true if page fault could be resolved, false otherwise
455  */
456 extern "C" FIASCO_FASTCALL
457 int
458 thread_page_fault(Address pfa, Mword error_code, Address ip, Mword flags,
459                   Return_frame *regs)
460 {
461
462   // XXX: need to do in a different way, if on debug stack e.g.
463 #if 0
464   // If we're in the GDB stub -- let generic handler handle it
465   if (EXPECT_FALSE (!in_context_area((void*)Proc::stack_pointer())))
466     return false;
467 #endif
468
469   // Pagefault in user mode or interrupts were enabled
470   if (PF::is_usermode_error(error_code))
471     {
472       if (current_thread()->vcpu_pagefault(pfa, error_code, ip))
473         return 1;
474
475       Proc::sti();
476     }
477   else if(flags & EFLAGS_IF)
478     Proc::sti();
479
480   // Pagefault in kernel mode and interrupts were disabled
481   else 
482     {
483       // page fault in kernel memory region
484       if (Kmem::is_kmem_page_fault(pfa, error_code))
485         {
486           // We've interrupted a context in the kernel with disabled interrupts,
487           // the page fault address is in the kernel region, the error code is
488           // "not mapped" (as opposed to "access error"), and the region is
489           // actually valid (that is, mapped in Kmem's shared page directory,
490           // just not in the currently active page directory)
491           // Remain cli'd !!!
492         }
493       else if (!Config::conservative &&
494                !Kmem::is_kmem_page_fault(pfa, error_code))
495         {
496           // No error -- just enable interrupts.
497           Proc::sti();
498         }
499       else 
500         {
501           // Error: We interrupted a cli'd kernel context touching kernel space
502           if (!Thread::log_page_fault())
503             printf("*P[%lx,%lx,%lx] ", pfa, error_code & 0xffff, ip);
504
505           kdb_ke ("page fault in cli mode");
506         }
507     }
508
509   return current_thread()->handle_page_fault(pfa, error_code, ip, regs);
510 }
511
512 /** The catch-all trap entry point.  Called by assembly code when a 
513     CPU trap (that's not specially handled, such as system calls) occurs.
514     Just forwards the call to Thread::handle_slow_trap().
515     @param state trap state
516     @return 0 if trap has been consumed by handler;
517            -1 if trap could not be handled.
518  */
519 extern "C" FIASCO_FASTCALL
520 int
521 thread_handle_trap(Trap_state *ts, unsigned)
522 {
523   return current_thread()->handle_slow_trap(ts);
524 }
525
526
527 //
528 // Public services
529 //
530
531 IMPLEMENT inline
532 bool
533 Thread::handle_sigma0_page_fault(Address pfa)
534 {
535   size_t size;
536
537   // Check if mapping a superpage doesn't exceed the size of physical memory
538   if (Cpu::have_superpages()
539      // Some distributions do not allow to mmap below a certain threshold
540      // (like 64k on Ubuntu 8.04) so we cannot map a superpage at 0 if
541      // we're Fiasco-UX
542       && (!Config::Is_ux || !(pfa < Config::SUPERPAGE_SIZE)))
543     {
544       pfa &= Config::SUPERPAGE_MASK;
545       size = Config::SUPERPAGE_SIZE;
546     }
547   else
548     {
549       pfa &= Config::PAGE_MASK;
550       size = Config::PAGE_SIZE;
551     }
552
553   return mem_space()->v_insert(Mem_space::Phys_addr(pfa), Mem_space::Addr(pfa),
554                                Mem_space::Size(size),
555                                Mem_space::Page_writable
556                                | Mem_space::Page_user_accessible)
557     != Mem_space::Insert_err_nomem;
558 }
559
560 PRIVATE static inline
561 void
562 Thread::save_fpu_state_to_utcb(Trap_state *, Utcb *)
563 {}
564
565 /* return 1 if this exception should be sent, return 0 if not
566  */
567 PUBLIC inline NEEDS["trap_state.h"]
568 int
569 Thread::send_exception_arch(Trap_state *ts)
570 {
571   // Do not send exception IPC but return 'not for us' if thread is a normal
572   // thread (not alien) and it's a debug trap,
573   // debug traps for aliens are always reflected as exception IPCs
574   if (!(state() & Thread_alien)
575       && (ts->_trapno == 1 || ts->_trapno == 3))
576     return 0; // we do not handle this
577
578   if (ts->_trapno == 3)
579     {
580       if (state() & Thread_dis_alien)
581         {
582           state_del(Thread_dis_alien);
583           return 0; // no exception
584         }
585
586       // set IP back on the int3 instruction
587       ts->ip(ts->ip() - 1);
588     }
589
590   return 1; // make it an exception
591 }
592
593
594 //----------------------------------------------------------------------------
595 IMPLEMENTATION [ia32 || amd64]:
596
597 PROTECTED inline
598 void
599 Thread::vcpu_resume_user_arch()
600 {}
601
602 //----------------------------------------------------------------------------
603 IMPLEMENTATION [ux]:
604
605 PROTECTED inline
606 void
607 Thread::vcpu_resume_user_arch()
608 {
609   switch_gdt_user_entries(this);
610 }
611
612 //----------------------------------------------------------------------------
613 IMPLEMENTATION [ux || amd64]:
614
615 IMPLEMENT inline NEEDS[Thread::exception_triggered]
616 void
617 Thread::user_ip(Mword ip)
618 {
619   if (exception_triggered())
620     _exc_cont.ip(ip);
621   else
622     {
623       Entry_frame *r = regs();
624       r->ip(ip);
625     }
626 }
627
628 //----------------------------------------------------------------------------
629 IMPLEMENTATION [ia32]:
630
631 #include "utcb_init.h"
632
633 PROTECTED inline NEEDS["utcb_init.h"]
634 void
635 Thread::arch_init_seg()
636 {
637   _gs = _fs = Utcb_init::utcb_segment();
638 }
639
640 //----------------------------------------------------------------------------
641 IMPLEMENTATION [amd64]:
642
643 PROTECTED inline
644 void
645 Thread::arch_init_seg()
646 {}
647
648
649 //----------------------------------------------------------------------------
650 IMPLEMENTATION [(ia32,amd64,ux) && !io]:
651
652 PRIVATE inline
653 int
654 Thread::handle_io_page_fault(Trap_state *, bool)
655 { return 0; }
656
657 PRIVATE inline
658 bool
659 Thread::get_ioport(Address /*eip*/, Trap_state * /*ts*/,
660                    unsigned * /*port*/, unsigned * /*size*/)
661 { return false; }
662
663
664 //---------------------------------------------------------------------------
665 IMPLEMENTATION[ia32 || amd64]:
666
667 #include "fpu.h"
668 #include "fpu_alloc.h"
669 #include "fpu_state.h"
670 #include "gdt.h"
671 #include "globalconfig.h"
672 #include "idt.h"
673 #include "simpleio.h"
674 #include "static_init.h"
675 #include "terminate.h"
676
677 int (*Thread::int3_handler)(Trap_state*);
678 Per_cpu<Thread::Dbg_stack> DEFINE_PER_CPU Thread::dbg_stack;
679
680 STATIC_INITIALIZER_P (int3_handler_init, KDB_INIT_PRIO);
681
682 static
683 void
684 int3_handler_init()
685 {
686   Thread::set_int3_handler(Thread::handle_int3);
687 }
688
689 IMPLEMENT static inline NEEDS ["gdt.h"]
690 Mword
691 Thread::exception_cs()
692 {
693   return Gdt::gdt_code_user | Gdt::Selector_user;
694 }
695
696 /**
697  * The ia32 specific part of the thread constructor.
698  */
699 PRIVATE inline NEEDS ["gdt.h"]
700 void
701 Thread::arch_init()
702 {
703   // clear out user regs that can be returned from the thread_ex_regs
704   // system call to prevent covert channel
705   Entry_frame *r = regs();
706   if (Config::enable_io_protection)
707     r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2);    // ei
708   else
709     r->flags(EFLAGS_IOPL_U | EFLAGS_IF | 2);    // XXX iopl=kernel
710   r->cs(Gdt::gdt_code_user | Gdt::Selector_user);
711   r->ss(Gdt::gdt_data_user | Gdt::Selector_user);
712
713   r->sp(0);
714   // after cs initialisation as ip() requires proper cs
715   r->ip(0);
716
717   arch_init_seg();
718 }
719
720
721 /** A C interface for Context::handle_fpu_trap, callable from assembly code.
722     @relates Context
723  */
724 // The "FPU not available" trap entry point
725 extern "C"
726 int
727 thread_handle_fputrap()
728 {
729   LOG_TRAP_N(7);
730
731   return current_thread()->switchin_fpu();
732 }
733
734 PUBLIC static inline
735 void
736 Thread::set_int3_handler(int (*handler)(Trap_state *ts))
737 {
738   int3_handler = handler;
739 }
740
741 /**
742  * Default handle for int3 extensions if JDB is disabled. If the JDB is
743  * available, Jdb::handle_int3_threadctx is called instead.
744  * @return 0 not handled, wait for user response
745  *         1 successfully handled
746  */
747 PUBLIC static
748 int
749 Thread::handle_int3(Trap_state *ts)
750 {
751   Mem_space *s   = current_mem_space();
752   int from_user  = ts->cs() & 3;
753   Address   ip   = ts->ip();
754   Unsigned8 todo = s->peek((Unsigned8*)ip, from_user);
755   Unsigned8 *str;
756   int len;
757   char c;
758
759   switch (todo)
760     {
761     case 0xeb: // jmp == enter_kdebug()
762       len = s->peek((Unsigned8*)(ip+1), from_user);
763       str = (Unsigned8*)(ip + 2);
764
765       putstr("KDB: ");
766       if (len > 0)
767         {
768           for (; len; len--)
769             putchar(s->peek(str++, from_user));
770         }
771       putchar('\n');
772       return 0; // => Jdb
773
774     case 0x90: // nop == l4kd_display()
775       if (          s->peek((Unsigned8*)(ip+1), from_user)  != 0xeb /*jmp*/
776           || (len = s->peek((Unsigned8*)(ip+2), from_user)) <= 0)
777         return 0; // => Jdb
778
779       str = (Unsigned8*)(ip + 3);
780       for (; len; len--)
781         putchar(s->peek(str++, from_user));
782       break;
783
784     case 0x3c: // cmpb
785       todo = s->peek((Unsigned8*)(ip+1), from_user);
786       switch (todo)
787         {
788         case  0: // l4kd_outchar
789           putchar(ts->value() & 0xff);
790           break;
791         case  1: // l4kd_outnstring
792           str = (Unsigned8*)ts->value();
793           len = ts->value4();
794           for(; len > 0; len--)
795             putchar(s->peek(str++, from_user));
796           break;
797         case  2: // l4kd_outstr
798           str = (Unsigned8*)ts->value();
799           for (; (c=s->peek(str++, from_user)); )
800             putchar(c);
801           break;
802         case  5: // l4kd_outhex32
803           printf("%08lx", ts->value() & 0xffffffff);
804           break;
805         case  6: // l4kd_outhex20
806           printf("%05lx", ts->value() & 0xfffff);
807           break;
808         case  7: // l4kd_outhex16
809           printf("%04lx", ts->value() & 0xffff);
810           break;
811         case  8: // l4kd_outhex12
812           printf("%03lx", ts->value() & 0xfff);
813           break;
814         case  9: // l4kd_outhex8
815           printf("%02lx", ts->value() & 0xff);
816           break;
817         case 11: // l4kd_outdec
818           printf("%ld", ts->value());
819           break;
820         case 31: // Watchdog
821           switch (ts->value2())
822             {
823             case 1:
824               // enable watchdog
825               Watchdog::user_enable();
826               break;
827             case 2:
828               // disable watchdog
829               Watchdog::user_disable();
830               break;
831             case 3:
832               // user takes over the control of watchdog and is from now on
833               // responsible for calling "I'm still alive" events (function 5)
834               Watchdog::user_takeover_control();
835               break;
836             case 4:
837               // user returns control of watchdog to kernel
838               Watchdog::user_giveback_control();
839               break;
840             case 5:
841               // I'm still alive
842               Watchdog::touch();
843               break;
844             }
845           break;
846
847         default: // ko
848           if (todo < ' ')
849             return 0; // => Jdb
850
851           putchar(todo);
852           break;
853         }
854       break;
855
856     default:
857       return 0; // => Jdb
858     }
859
860   return 1;
861 }
862
863
864 PRIVATE inline
865 void
866 Thread::check_f00f_bug(Trap_state *ts)
867 {
868   // If we page fault on the IDT, it must be because of the F00F bug.
869   // Figure out exception slot and raise the corresponding exception.
870   // XXX: Should we also modify the error code?
871   if (ts->_trapno == 14         // page fault?
872       && ts->_cr2 >= Idt::idt()
873       && ts->_cr2 <  Idt::idt() + Idt::_idt_max * 8)
874     ts->_trapno = (ts->_cr2 - Idt::idt()) / 8;
875 }
876
877
878 PRIVATE inline
879 unsigned
880 Thread::check_io_bitmap_delimiter_fault(Trap_state *ts)
881 {
882   // check for page fault at the byte following the IO bitmap
883   if (ts->_trapno == 14           // page fault?
884       && (ts->_err & 4) == 0         // in supervisor mode?
885       && ts->ip() < Kmem::mem_user_max   // delimiter byte accessed?
886       && (ts->_cr2 == Mem_layout::Io_bitmap + Mem_layout::Io_port_max / 8))
887     {
888       // page fault in the first byte following the IO bitmap
889       // map in the cpu_page read_only at the place
890       Mem_space::Status result =
891         mem_space()->v_insert(
892             Mem_space::Phys_addr(mem_space()->virt_to_phys_s0((void*)Kmem::io_bitmap_delimiter_page())),
893             Mem_space::Addr::create(Mem_layout::Io_bitmap + Mem_layout::Io_port_max / 8),
894             Mem_space::Size::create(Config::PAGE_SIZE),
895             Pt_entry::global());
896
897       switch (result)
898         {
899         case Mem_space::Insert_ok:
900           return 1; // success
901         case Mem_space::Insert_err_nomem:
902           // kernel failure, translate this into a general protection
903           // violation and hope that somebody handles it
904           ts->_trapno = 13;
905           ts->_err    =  0;
906           return 0; // fail
907         default:
908           // no other error code possible
909           assert (false);
910         }
911     }
912
913   return 1;
914 }
915
916 PRIVATE inline
917 bool
918 Thread::handle_sysenter_trap(Trap_state *ts, Address eip, bool from_user)
919 {
920   if (EXPECT_FALSE
921       ((ts->_trapno == 6 || ts->_trapno == 13)
922        && (ts->_err & 0xffff) == 0
923        && (eip < Kmem::mem_user_max - 2)
924        && (mem_space()->peek((Unsigned16*) eip, from_user)) == 0x340f))
925     {
926       // somebody tried to do sysenter on a machine without support for it
927       WARN("tcb=%p killed:\n"
928            "\033[1;31mSYSENTER not supported on this machine\033[0m",
929            this);
930
931       if (Cpu::have_sysenter())
932         // GP exception if sysenter is not correctly set up..
933         WARN("MSR_SYSENTER_CS: %llx", Cpu::rdmsr(MSR_SYSENTER_CS));
934       else
935         // We get UD exception on processors without SYSENTER/SYSEXIT.
936         WARN("SYSENTER/EXIT not available.");
937
938       return false;
939     }
940
941   return true;
942 }
943
944 PRIVATE inline
945 bool
946 Thread::trap_is_privileged(Trap_state *)
947 { return space()->has_io_privileges(); }
948
949 PRIVATE inline
950 void
951 Thread::do_wrmsr_in_kernel(Trap_state *ts)
952 {
953   // do "wrmsr (msr[ecx], edx:eax)" in kernel
954   Cpu::wrmsr (ts->value(), ts->value3(), ts->value2());
955 }
956
957 PRIVATE inline
958 void
959 Thread::do_rdmsr_in_kernel(Trap_state *ts)
960 {
961   // do "rdmsr (msr[ecx], edx:eax)" in kernel
962   Unsigned64 msr = Cpu::rdmsr(ts->value2());
963   ts->value((Unsigned32) msr);
964   ts->value3((Unsigned32) (msr >> 32));
965 }
966
967 PRIVATE inline
968 int
969 Thread::handle_not_nested_trap(Trap_state *ts)
970 {
971   // no kernel debugger present
972   printf(" %p IP="L4_PTR_FMT" Trap=%02lx [Ret/Esc]\n",
973          this, ts->ip(), ts->_trapno);
974
975   int r;
976   // cannot use normal getchar because it may block with hlt and irq's
977   // are off here
978   while ((r=Kconsole::console()->getchar(false)) == -1)
979     Proc::pause();
980
981   if (r == '\033')
982     terminate (1);
983
984   return 0;
985 }
986
987 PROTECTED inline
988 int
989 Thread::sys_control_arch(Utcb *)
990 {
991   return 0;
992 }
993
994
995 //---------------------------------------------------------------------------
996 IMPLEMENTATION [(ia32 |amd64) & !(debug | kdb)]:
997
998 /** There is no nested trap handler if both jdb and kdb are disabled.
999  * Important: We don't need the nested_handler_stack here.
1000  */
1001 PRIVATE static inline
1002 int
1003 Thread::call_nested_trap_handler(Trap_state *)
1004 { return -1; }