]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/ux/jdb-ux.cpp
update
[l4.git] / kernel / fiasco / src / jdb / ux / jdb-ux.cpp
1 INTERFACE [ux]:
2
3 #include "types.h"
4 #include "l4_types.h"
5
6 class Trap_state;
7 class Thread;
8 class Context;
9 class Jdb_entry_frame;
10 class Mem_space;
11
12 EXTENSION class Jdb
13 {
14 public:
15   typedef enum
16     {
17       s_unknown, s_ipc, s_syscall, s_pagefault, s_fputrap,
18       s_interrupt, s_timer_interrupt, s_slowtrap, s_user_invoke,
19     } Guessed_thread_state;
20
21   enum { MIN_SCREEN_HEIGHT = 20, MIN_SCREEN_WIDTH = 80 };
22
23   template < typename T > static T peek(T const *addr, Address_type user);
24
25   static int (*bp_test_log_only)();
26   static int (*bp_test_break)(String_buffer *buf);
27
28 private:
29   static unsigned short rows, cols;
30
31 };
32
33 IMPLEMENTATION [ux]:
34
35 #include <cstdio>
36 #include <cstdlib>
37 #include <sys/ioctl.h>
38 #include <termios.h>
39 #include <unistd.h>
40
41 #include "globals.h"
42 #include "initcalls.h"
43 #include "jdb_core.h"
44 #include "jdb_dbinfo.h"
45 #include "jdb_screen.h"
46 #include "kernel_console.h"
47 #include "kernel_task.h"
48 #include "kernel_thread.h"
49 #include "keycodes.h"
50 #include "kmem.h"
51 #include "libc_support.h"
52 #include "logdefs.h"
53 #include "mem_layout.h"
54 #include "push_console.h"
55 #include "simpleio.h"
56 #include "space.h"
57 #include "static_init.h"
58 #include "thread.h"
59 #include "thread_state.h"
60 #include "trap_state.h"
61 #include "usermode.h"
62 #include "vkey.h"
63
64 int (*Jdb::bp_test_log_only)();
65 int (*Jdb::bp_test_break)(String_buffer *buf);
66
67 unsigned short Jdb::rows, Jdb::cols;
68
69 static Proc::Status jdb_irq_state;
70
71 IMPLEMENT inline
72 void
73 Jdb::enter_trap_handler(Cpu_number)
74 {
75   conf_screen();
76
77   // Set terminal raw mode
78   enter_getchar();
79
80   // Flush all output streams
81   fflush (NULL);
82 }
83
84 IMPLEMENT inline
85 void
86 Jdb::leave_trap_handler(Cpu_number)
87 {
88   // Restore terminal mode
89   leave_getchar();
90
91   // Flush all output streams
92   fflush (NULL);
93
94 }
95
96 IMPLEMENT inline
97 bool
98 Jdb::handle_user_request(Cpu_number)
99 { return false; }
100
101 IMPLEMENT inline
102 bool
103 Jdb::test_checksums()
104 { return true; }
105
106
107 // disable interrupts before entering the kernel debugger
108 IMPLEMENT
109 void
110 Jdb::save_disable_irqs(Cpu_number cpu)
111 {
112   assert(cpu == Cpu_number::boot_cpu());
113   jdb_irq_state = Proc::cli_save();
114 }
115
116 // restore interrupts after leaving the kernel debugger
117 IMPLEMENT
118 void
119 Jdb::restore_irqs(Cpu_number cpu)
120 {
121   assert(cpu == Cpu_number::boot_cpu());
122   Proc::sti_restore(jdb_irq_state);
123 }
124
125 STATIC_INITIALIZE_P(Jdb,JDB_INIT_PRIO);
126
127 PUBLIC static FIASCO_INIT
128 void
129 Jdb::init()
130 {
131   // Install JDB handler
132   Trap_state::base_handler = (Trap_state::Handler)enter_jdb;
133
134   // be sure that Push_console comes very first
135   Kconsole::console()->register_console(push_cons()),
136
137   register_libc_atexit(leave_getchar);
138   atexit(leave_getchar);
139
140   Thread::set_int3_handler(handle_int3_threadctx);
141 }
142
143 PRIVATE
144 static void
145 Jdb::conf_screen()
146 {
147   struct winsize win;
148   ioctl (fileno (stdin), TIOCGWINSZ, &win);
149   rows = win.ws_row;
150   cols = win.ws_col;
151
152   if (rows < MIN_SCREEN_HEIGHT || cols < MIN_SCREEN_WIDTH)
153     printf ("%sTerminal probably too small, should be at least %dx%d!\033[0m\n",
154             esc_emph, MIN_SCREEN_WIDTH, MIN_SCREEN_HEIGHT);
155
156   Jdb_screen::set_height(rows);
157   Jdb_screen::set_width(cols);
158 }
159
160 /** handle int3 debug extension */
161 PUBLIC static inline NOEXPORT
162 int
163 Jdb::int3_extension()
164 {
165   Jdb_entry_frame *entry_frame = Jdb::entry_frame.cpu(Cpu_number::boot_cpu());
166   Address      addr = entry_frame->ip();
167   Address_type user = (entry_frame->cs() & 3) ? ADDR_USER : ADDR_KERNEL;
168   Unsigned8    todo = peek ((Unsigned8 *) addr, user);
169   Space *space = NULL; //get_task_id(0);
170   error_buffer.cpu(Cpu_number::boot_cpu()).clear();
171
172   if (todo == 0x3c && peek ((Unsigned8 *) (addr+1), user) == 13)
173     {
174       enter_getchar();
175       entry_frame->_ax = Vkey::get();
176       Vkey::clear();
177       leave_getchar();
178       return 1;
179     }
180   else if (todo != 0xeb)
181     {
182       error_buffer.cpu(Cpu_number::boot_cpu()).printf("INT 3");
183       return 0;
184     }
185
186   // todo == 0xeb => enter_kdebug()
187   Mword i;
188   Mword len = peek ((Unsigned8 *) ++addr, user);
189
190   if (len > 2 &&
191       peek (((Unsigned8 *) addr + 1), user) == '*' &&
192       peek (((Unsigned8 *) addr + 2), user) == '#')
193     {
194       char c = peek (((Unsigned8 *) addr + 3), user);
195
196       if ((c == '#')
197           ? execute_command_ni(space, (char const *) entry_frame->_ax)
198           : execute_command_ni(space, (char const *)(addr + 3), len-2))
199         return 1; // => leave Jdb
200     }
201
202   for (i = 0; i < len; i++)
203     error_buffer.cpu(Cpu_number::boot_cpu()).append(peek ((Unsigned8 *) ++addr, user));
204   error_buffer.cpu(Cpu_number::boot_cpu()).terminate();
205   return 0;
206 }
207
208 static
209 bool
210 Jdb::handle_special_cmds(int)
211 { return 1; }
212
213 IMPLEMENT
214 bool
215 Jdb::handle_debug_traps(Cpu_number cpu)
216 {
217   error_buffer.cpu(cpu).clear();
218   switch (entry_frame.cpu(cpu)->_trapno)
219     {
220       case 1:
221         error_buffer.cpu(cpu).printf("Interception");
222         break;
223       case 3:
224         if (int3_extension())
225           return false;
226 #ifdef FIXME
227         if (get_thread(cpu)->d_taskno())
228           {
229             if (bp_test_log_only && bp_test_log_only())
230               return false;
231             if (bp_test_break
232                 && bp_test_break(&error_buffer.cpu(cpu)))
233               break;
234           }
235 #endif
236     }
237
238   return true;
239 }
240
241 IMPLEMENT
242 void
243 Jdb::handle_nested_trap(Jdb_entry_frame *e)
244 {
245   printf("Trap in JDB: IP:%08lx\n", e->ip());
246 }
247
248 IMPLEMENT inline
249 bool
250 Jdb::handle_conditional_breakpoint(Cpu_number, Jdb_entry_frame *)
251 { return false; }
252
253
254 PUBLIC
255 static Space *
256 Jdb::translate_task(Address /*addr*/, Space *task)
257 {
258   // we have no idea if addr belongs to kernel or user space
259   // since kernel and user occupy different address spaces
260   return task;
261 }
262
263 PUBLIC
264 static Address
265 Jdb::virt_to_kvirt(Address virt, Mem_space* space)
266 {
267   Mem_space::Phys_addr phys;
268   Mem_space::Page_order size;
269
270   if (!space)
271     {
272       // Kernel address.
273       // We can directly access it via virtual addresses if it's kernel code
274       // (which is always mapped, but doesn't appear in the kernel pagetable)
275       //  or if we find a mapping for it in the kernel's master pagetable.
276       return (virt >= (Address)&Mem_layout::load && 
277               virt <  (Kernel_thread::init_done() 
278                                 ? (Address)&Mem_layout::end
279                                 : (Address)&Mem_layout::initcall_end)
280               || (Kernel_task::kernel_task()->virt_to_phys(virt) != ~0UL))
281         ? virt
282         : (Address) -1;
283     }
284   else
285     {
286       // User address.
287       // We can't directly access it because it's in a different host process
288       // but if the task's pagetable has a mapping for it, we can translate
289       // task-virtual -> physical -> kernel-virtual address and then access.
290       Virt_addr va(virt);
291       return (space->v_lookup(va, &phys, &size, 0))
292         ? (Address) Kmem::phys_to_virt(Mem_space::Phys_addr::val(phys) + Virt_size::val(cxx::get_lsb(va, size)))
293         : (Address) -1;
294     }
295 }
296
297 IMPLEMENT inline NEEDS ["space.h"]
298 template <typename T>
299 T
300 Jdb::peek (T const *addr, Address_type user)
301 {
302   // FIXME: assume UP here (current_meme_space(0))
303   return Mem_space::current_mem_space(Cpu_number::boot_cpu())->peek(addr, user);
304 }
305
306 PUBLIC static
307 int
308 Jdb::peek_task(Address virt, Space *space, void *value, int width)
309 {
310   // make sure we don't cross a page boundary
311   if (virt & (width-1))
312     return -1;
313
314   Address kvirt = virt_to_kvirt(virt, space);
315   if (kvirt == (Address)-1)
316     return -1;
317
318   memcpy(value, (void*)kvirt, width);
319   return 0;
320 }
321
322 PUBLIC static
323 int
324 Jdb::poke_task(Address virt, Space *space, void const *value, int width)
325 {
326   // make sure we don't cross a page boundary
327   if (virt & (width-1))
328     return -1;
329
330   Address kvirt = virt_to_kvirt(virt, space);
331
332   if (kvirt == (Address)-1)
333     return -1;
334
335   memcpy((void*)kvirt, value, width);
336   return 0;
337 }
338
339 PUBLIC
340 static int
341 Jdb::is_adapter_memory(Address /*addr*/, Space * /*task*/)
342 {
343   return 0;
344 }
345
346 #define WEAK __attribute__((weak))
347 extern "C" char in_slowtrap, in_page_fault, in_handle_fputrap;
348 extern "C" char in_interrupt, in_timer_interrupt, in_timer_interrupt_slow;
349 extern "C" char i30_ret_switch WEAK, in_slow_ipc1 WEAK;
350 extern "C" char in_slow_ipc2 WEAK, in_slow_ipc4;
351 extern "C" char in_sc_ipc1 WEAK, in_sc_ipc2 WEAK, in_syscall WEAK;
352 #undef WEAK
353
354 /** Try to guess the thread state of t by walking down the kernel stack and
355  * locking at the first return address we find. */
356 PUBLIC
357 static Jdb::Guessed_thread_state
358 Jdb::guess_thread_state(Thread *t)
359 {
360   Guessed_thread_state state = s_unknown;
361   Mword *ktop = (Mword*)((Mword)context_of(t->get_kernel_sp()) +
362                          Context::Size);
363
364   for (int i=-1; i>-26; i--)
365     {
366       if (ktop[i] != 0)
367         {
368           if (ktop[i] == (Mword)&in_page_fault)
369             state = s_pagefault;
370           if ((ktop[i] == (Mword)&i30_ret_switch) ||// shortcut.S, int 0x30
371               (ktop[i] == (Mword)&in_slow_ipc1) ||  // shortcut.S, int 0x30
372               (ktop[i] == (Mword)&in_slow_ipc4) ||  // entry.S, int 0x30
373 #if !defined(CONFIG_ASSEMBLER_IPC_SHORTCUT)
374               (ktop[i] == (Mword)&in_sc_ipc1)   ||  // entry.S, int 0x30
375               (ktop[i] == (Mword)&in_sc_ipc2)   ||  // entry.S, sysenter
376 #endif
377              0)
378             state = s_ipc;
379           else if (ktop[i] == (Mword)&in_syscall)
380             state = s_syscall;
381           else if (ktop[i] == (Mword)&Thread::user_invoke)
382             state = s_user_invoke;
383           else if (ktop[i] == (Mword)&in_handle_fputrap)
384             state = s_fputrap;
385           else if (ktop[i] == (Mword)&in_interrupt)
386             state = s_interrupt;
387           else if ((ktop[i] == (Mword)&in_timer_interrupt) ||
388                    (ktop[i] == (Mword)&in_timer_interrupt_slow))
389             state = s_timer_interrupt;
390           else if (ktop[i] == (Mword)&in_slowtrap)
391             state = s_slowtrap;
392           if (state != s_unknown)
393             break;
394         }
395     }
396
397   if (state == s_unknown && (t->state() & Thread_ipc_mask))
398     state = s_ipc;
399
400   return state;
401 }
402
403 // Don't make these members of Jdb else we have to include <termios.h>
404 // into the Jdb interface ...
405 static struct termios raw, new_raw;
406 static int    getchar_entered;
407
408 /** prepare Linux console for raw input */
409 PUBLIC static
410 void
411 Jdb::enter_getchar()
412 {
413   if (!getchar_entered++)
414     {
415       tcgetattr (fileno (stdin), &raw);
416       memcpy(&new_raw, &raw, sizeof(new_raw));
417       new_raw.c_lflag    &= ~(ICANON|ECHO);
418       new_raw.c_cc[VMIN]  = 0;
419       new_raw.c_cc[VTIME] = 1;
420       tcsetattr (fileno (stdin), TCSAFLUSH, &new_raw);
421     }
422 }
423
424 /** restore Linux console. */
425 PUBLIC static
426 void
427 Jdb::leave_getchar()
428 {
429   if (!--getchar_entered)
430     tcsetattr (fileno (stdin), TCSAFLUSH, &raw);
431 }
432
433 //----------------------------------------------------------------------------
434 IMPLEMENTATION [ux && mp]:
435
436 static
437 void
438 Jdb::send_nmi(Cpu_number)
439 {
440 }