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