]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/thread-ia32.cpp
9a5428a074adc38f3eb61cb2ead917fb41b422a0
[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 PUBLIC inline
561 Utcb *
562 Thread::access_utcb() const
563 { return utcb(); }
564
565 PRIVATE static inline
566 void
567 Thread::save_fpu_state_to_utcb(Trap_state *, Utcb *)
568 {}
569
570 /* return 1 if this exception should be sent, return 0 if not
571  */
572 PUBLIC inline NEEDS["trap_state.h"]
573 int
574 Thread::send_exception_arch(Trap_state *ts)
575 {
576   // Do not send exception IPC but return 'not for us' if thread is a normal
577   // thread (not alien) and it's a debug trap,
578   // debug traps for aliens are always reflected as exception IPCs
579   if (!(state() & Thread_alien)
580       && (ts->_trapno == 1 || ts->_trapno == 3))
581     return 0; // we do not handle this
582
583   if (ts->_trapno == 3)
584     {
585       if (state() & Thread_dis_alien)
586         {
587           state_del(Thread_dis_alien);
588           return 0; // no exception
589         }
590
591       // set IP back on the int3 instruction
592       ts->ip(ts->ip() - 1);
593     }
594
595   return 1; // make it an exception
596 }
597
598
599 //----------------------------------------------------------------------------
600 IMPLEMENTATION [ia32 || amd64]:
601
602 PRIVATE inline
603 void
604 Thread::vcpu_resume_user_arch()
605 {}
606
607 //----------------------------------------------------------------------------
608 IMPLEMENTATION [ux]:
609
610 PRIVATE inline
611 void
612 Thread::vcpu_resume_user_arch()
613 {
614   switch_gdt_user_entries(this);
615 }
616
617 //----------------------------------------------------------------------------
618 IMPLEMENTATION [ux || amd64]:
619
620 IMPLEMENT inline NEEDS[Thread::exception_triggered]
621 void
622 Thread::user_ip(Mword ip)
623 {
624   if (exception_triggered())
625     _exc_cont.ip(ip);
626   else
627     {
628       Entry_frame *r = regs();
629       r->ip(ip);
630     }
631 }
632
633
634 //----------------------------------------------------------------------------
635 IMPLEMENTATION [(ia32,amd64,ux) && !io]:
636
637 PRIVATE inline
638 int
639 Thread::handle_io_page_fault (Trap_state *, bool)
640 { return 0; }
641
642 PRIVATE inline
643 bool
644 Thread::get_ioport(Address /*eip*/, Trap_state * /*ts*/,
645                    unsigned * /*port*/, unsigned * /*size*/)
646 { return false; }
647
648
649 //---------------------------------------------------------------------------
650 IMPLEMENTATION[ia32 || amd64]:
651
652 #include "fpu.h"
653 #include "fpu_alloc.h"
654 #include "fpu_state.h"
655 #include "gdt.h"
656 #include "globalconfig.h"
657 #include "idt.h"
658 #include "simpleio.h"
659 #include "static_init.h"
660 #include "terminate.h"
661 #include "utcb_init.h"
662
663 int (*Thread::int3_handler)(Trap_state*);
664 Per_cpu<Thread::Dbg_stack> DEFINE_PER_CPU Thread::dbg_stack;
665
666 STATIC_INITIALIZER_P (int3_handler_init, KDB_INIT_PRIO);
667
668 static
669 void
670 int3_handler_init()
671 {
672   Thread::set_int3_handler (Thread::handle_int3);
673 }
674
675 IMPLEMENT static inline NEEDS ["gdt.h"]
676 Mword
677 Thread::exception_cs()
678 {
679   return Gdt::gdt_code_user | Gdt::Selector_user;
680 }
681
682 /**
683  * The ia32 specific part of the thread constructor.
684  */
685 PRIVATE inline NEEDS ["gdt.h"]
686 void
687 Thread::arch_init()
688 {
689   // clear out user regs that can be returned from the thread_ex_regs
690   // system call to prevent covert channel
691   Entry_frame *r = regs();
692   if (Config::enable_io_protection)
693     r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2);    // ei
694   else
695     r->flags(EFLAGS_IOPL_U | EFLAGS_IF | 2);    // XXX iopl=kernel
696   r->cs(Gdt::gdt_code_user | Gdt::Selector_user);
697   r->ss(Gdt::gdt_data_user | Gdt::Selector_user);
698
699   r->sp(0);
700   // after cs initialisation as ip() requires proper cs
701   r->ip(0);
702
703 #ifdef CONFIG_HANDLE_SEGMENTS
704   _gs = _fs = Utcb_init::utcb_segment();
705 #else
706   Cpu::set_gs(Utcb_init::utcb_segment());
707   Cpu::set_fs(Utcb_init::utcb_segment());
708 #endif
709 }
710
711
712 /** A C interface for Context::handle_fpu_trap, callable from assembly code.
713     @relates Context
714  */
715 // The "FPU not available" trap entry point
716 extern "C"
717 int
718 thread_handle_fputrap()
719 {
720   LOG_TRAP_N(7);
721
722   return current_thread()->switchin_fpu();
723 }
724
725 PUBLIC static inline
726 void
727 Thread::set_int3_handler(int (*handler)(Trap_state *ts))
728 {
729   int3_handler = handler;
730 }
731
732 /**
733  * Default handle for int3 extensions if JDB is disabled. If the JDB is
734  * available, Jdb::handle_int3_threadctx is called instead.
735  * @return 0 not handled, wait for user response
736  *         1 successfully handled
737  */
738 PUBLIC static
739 int
740 Thread::handle_int3 (Trap_state *ts)
741 {
742   Mem_space *s   = current_mem_space();
743   int from_user  = ts->cs() & 3;
744   Address   ip   = ts->ip();
745   Unsigned8 todo = s->peek((Unsigned8*)ip, from_user);
746   Unsigned8 *str;
747   int len;
748   char c;
749
750   switch (todo)
751     {
752     case 0xeb: // jmp == enter_kdebug()
753       len = s->peek((Unsigned8*)(ip+1), from_user);
754       str = (Unsigned8*)(ip + 2);
755
756       putstr("KDB: ");
757       if (len > 0)
758         {
759           for (; len; len--)
760             putchar(s->peek(str++, from_user));
761         }
762       putchar('\n');
763       return 0; // => Jdb
764
765     case 0x90: // nop == l4kd_display()
766       if (          s->peek((Unsigned8*)(ip+1), from_user)  != 0xeb /*jmp*/
767           || (len = s->peek((Unsigned8*)(ip+2), from_user)) <= 0)
768         return 0; // => Jdb
769
770       str = (Unsigned8*)(ip + 3);
771       for (; len; len--)
772         putchar(s->peek(str++, from_user));
773       break;
774
775     case 0x3c: // cmpb
776       todo = s->peek((Unsigned8*)(ip+1), from_user);
777       switch (todo)
778         {
779         case  0: // l4kd_outchar
780           putchar(ts->value() & 0xff);
781           break;
782         case  1: // l4kd_outnstring
783           str = (Unsigned8*)ts->value();
784           len = ts->value4();
785           for(; len > 0; len--)
786             putchar(s->peek(str++, from_user));
787           break;
788         case  2: // l4kd_outstr
789           str = (Unsigned8*)ts->value();
790           for (; (c=s->peek(str++, from_user)); )
791             putchar(c);
792           break;
793         case  5: // l4kd_outhex32
794           printf("%08lx", ts->value() & 0xffffffff);
795           break;
796         case  6: // l4kd_outhex20
797           printf("%05lx", ts->value() & 0xfffff);
798           break;
799         case  7: // l4kd_outhex16
800           printf("%04lx", ts->value() & 0xffff);
801           break;
802         case  8: // l4kd_outhex12
803           printf("%03lx", ts->value() & 0xfff);
804           break;
805         case  9: // l4kd_outhex8
806           printf("%02lx", ts->value() & 0xff);
807           break;
808         case 11: // l4kd_outdec
809           printf("%ld", ts->value());
810           break;
811         case 31: // Watchdog
812           switch (ts->value2())
813             {
814             case 1:
815               // enable watchdog
816               Watchdog::user_enable();
817               break;
818             case 2:
819               // disable watchdog
820               Watchdog::user_disable();
821               break;
822             case 3:
823               // user takes over the control of watchdog and is from now on
824               // responsible for calling "I'm still alive" events (function 5)
825               Watchdog::user_takeover_control();
826               break;
827             case 4:
828               // user returns control of watchdog to kernel
829               Watchdog::user_giveback_control();
830               break;
831             case 5:
832               // I'm still alive
833               Watchdog::touch();
834               break;
835             }
836           break;
837
838         default: // ko
839           if (todo < ' ')
840             return 0; // => Jdb
841
842           putchar(todo);
843           break;
844         }
845       break;
846
847     default:
848       return 0; // => Jdb
849     }
850
851   return 1;
852 }
853
854
855 PRIVATE inline
856 void
857 Thread::check_f00f_bug (Trap_state *ts)
858 {
859   // If we page fault on the IDT, it must be because of the F00F bug.
860   // Figure out exception slot and raise the corresponding exception.
861   // XXX: Should we also modify the error code?
862   if (ts->_trapno == 14         // page fault?
863       && ts->_cr2 >= Idt::idt()
864       && ts->_cr2 <  Idt::idt() + Idt::_idt_max * 8)
865     ts->_trapno = (ts->_cr2 - Idt::idt()) / 8;
866 }
867
868
869 PRIVATE inline
870 unsigned
871 Thread::check_io_bitmap_delimiter_fault(Trap_state *ts)
872 {
873   // check for page fault at the byte following the IO bitmap
874   if (ts->_trapno == 14           // page fault?
875       && (ts->_err & 4) == 0         // in supervisor mode?
876       && ts->ip() < Kmem::mem_user_max   // delimiter byte accessed?
877       && (ts->_cr2 == Mem_layout::Io_bitmap + Mem_layout::Io_port_max / 8))
878     {
879       // page fault in the first byte following the IO bitmap
880       // map in the cpu_page read_only at the place
881       Mem_space::Status result =
882         mem_space()->v_insert (
883             Mem_space::Phys_addr(mem_space()->virt_to_phys_s0
884               ((void*)Kmem::io_bitmap_delimiter_page())),
885             Mem_space::Addr::create(Mem_layout::Io_bitmap + Mem_layout::Io_port_max / 8),
886             Mem_space::Size::create(Config::PAGE_SIZE),
887             Pt_entry::global());
888
889       switch (result)
890         {
891         case Mem_space::Insert_ok:
892           return 1; // success
893         case Mem_space::Insert_err_nomem:
894           // kernel failure, translate this into a general protection
895           // violation and hope that somebody handles it
896           ts->_trapno = 13;
897           ts->_err    =  0;
898           return 0; // fail
899         default:
900           // no other error code possible
901           assert (false);
902         }
903     }
904
905   return 1;
906 }
907
908 PRIVATE inline
909 bool
910 Thread::handle_sysenter_trap (Trap_state *ts, Address eip, bool from_user)
911 {
912   if (EXPECT_FALSE
913       ((ts->_trapno == 6 || ts->_trapno == 13)
914        && (ts->_err & 0xffff) == 0
915        && (eip < Kmem::mem_user_max - 2)
916        && (mem_space()->peek ((Unsigned16*) eip, from_user)) == 0x340f))
917     {
918       // somebody tried to do sysenter on a machine without support for it
919       WARN ("tcb=%p killed:\n"
920             "\033[1;31mSYSENTER not supported on this machine\033[0m",
921             this);
922
923       if (Cpu::have_sysenter())
924         // GP exception if sysenter is not correctly set up..
925         WARN ("MSR_SYSENTER_CS: %llx", Cpu::rdmsr (MSR_SYSENTER_CS));
926       else
927         // We get UD exception on processors without SYSENTER/SYSEXIT.
928         WARN ("SYSENTER/EXIT not available.");
929
930       return false;
931     }
932
933   return true;
934 }
935
936 PRIVATE inline
937 bool
938 Thread::trap_is_privileged (Trap_state *)
939 { return space()->has_io_privileges(); }
940
941 PRIVATE inline
942 void
943 Thread::do_wrmsr_in_kernel (Trap_state *ts)
944 {
945   // do "wrmsr (msr[ecx], edx:eax)" in kernel
946   Cpu::wrmsr (ts->value(), ts->value3(), ts->value2());
947 }
948
949 PRIVATE inline
950 void
951 Thread::do_rdmsr_in_kernel (Trap_state *ts)
952 {
953   // do "rdmsr (msr[ecx], edx:eax)" in kernel
954   Unsigned64 msr = Cpu::rdmsr (ts->value2());
955   ts->value((Unsigned32) msr);
956   ts->value3((Unsigned32) (msr >> 32));
957 }
958
959 PRIVATE inline
960 int
961 Thread::handle_not_nested_trap (Trap_state *ts)
962 {
963   // no kernel debugger present
964   printf (" %p IP="L4_PTR_FMT" Trap=%02lx [Ret/Esc]\n",
965           this, ts->ip(), ts->_trapno);
966
967   int r;
968   // cannot use normal getchar because it may block with hlt and irq's
969   // are off here
970   while ((r=Kconsole::console()->getchar (false)) == -1)
971     Proc::pause();
972
973   if (r == '\033')
974     terminate (1);
975
976   return 0;
977 }
978
979 PRIVATE inline
980 int
981 Thread::sys_control_arch(Utcb *)
982 {
983   return 0;
984 }
985
986
987 //---------------------------------------------------------------------------
988 IMPLEMENTATION [(ia32 |amd64) & !(debug | kdb)]:
989
990 /** There is no nested trap handler if both jdb and kdb are disabled.
991  * Important: We don't need the nested_handler_stack here.
992  */
993 PRIVATE static inline
994 int
995 Thread::call_nested_trap_handler(Trap_state *)
996 { return -1; }