]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/arm/jdb-arm.cpp
Some minor fixes.
[l4.git] / kernel / fiasco / src / jdb / arm / jdb-arm.cpp
1 INTERFACE [arm]:
2
3 EXTENSION class Jdb
4 {
5 public:
6   static int (*bp_test_log_only)(Cpu_number);
7   static int (*bp_test_break)(Cpu_number, String_buffer *);
8 };
9
10 IMPLEMENTATION [arm]:
11
12 #include "globals.h"
13 #include "kernel_task.h"
14 #include "kmem_alloc.h"
15 #include "kmem_space.h"
16 #include "space.h"
17 #include "mem_layout.h"
18 #include "mem_unit.h"
19 #include "static_init.h"
20 #include "timer_tick.h"
21 #include "watchdog.h"
22 #include "cxx/cxx_int"
23
24 STATIC_INITIALIZE_P(Jdb, JDB_INIT_PRIO);
25
26 DEFINE_PER_CPU static Per_cpu<Proc::Status> jdb_irq_state;
27
28 int (*Jdb::bp_test_log_only)(Cpu_number);
29 int (*Jdb::bp_test_break)(Cpu_number, String_buffer *buf);
30
31 // ------------------------------------------------------------------------
32 IMPLEMENTATION [arm && !pic_gic]:
33
34 PRIVATE static inline
35 void
36 Jdb::wfi_enter()
37 {}
38
39 PRIVATE static inline
40 void
41 Jdb::wfi_leave()
42 {}
43
44 // ------------------------------------------------------------------------
45 IMPLEMENTATION [arm && pic_gic]:
46
47 #include "gic.h"
48
49 struct Jdb_wfi_gic
50 {
51   unsigned orig_tt_prio;
52   unsigned orig_pmr;
53 };
54 static Jdb_wfi_gic wfi_gic;
55
56 PRIVATE static
57 void
58 Jdb::wfi_enter()
59 {
60   Jdb_core::wait_for_input = _wait_for_input;
61
62   Timer_tick *tt = Timer_tick::boot_cpu_timer_tick();
63   Gic *g = static_cast<Gic*>(tt->chip());
64
65   wfi_gic.orig_tt_prio = g->irq_prio(tt->pin());
66   wfi_gic.orig_pmr     = g->pmr();
67   g->pmr(0x20);
68   g->irq_prio(tt->pin(), 0x10);
69
70   Timer_tick::enable(Cpu_number::boot_cpu());
71 }
72
73 PRIVATE static
74 void
75 Jdb::wfi_leave()
76 {
77   Timer_tick *tt = Timer_tick::boot_cpu_timer_tick();
78   Gic *g = static_cast<Gic*>(tt->chip());
79   g->irq_prio(tt->pin(), wfi_gic.orig_tt_prio);
80   g->pmr(wfi_gic.orig_pmr);
81 }
82
83 PRIVATE static
84 void
85 Jdb::_wait_for_input()
86 {
87   Proc::halt();
88
89   Timer_tick *tt = Timer_tick::boot_cpu_timer_tick();
90   unsigned i = static_cast<Gic*>(tt->chip())->pending();
91   if (i == tt->pin())
92     {
93       tt->chip()->ack(i);
94       tt->ack();
95     }
96   else
97     printf("JDB: Unexpected interrupt %d\n", i);
98 }
99
100 // ------------------------------------------------------------------------
101 IMPLEMENTATION [arm]:
102
103 // disable interrupts before entering the kernel debugger
104 IMPLEMENT
105 void
106 Jdb::save_disable_irqs(Cpu_number cpu)
107 {
108   jdb_irq_state.cpu(cpu) = Proc::cli_save();
109   if (cpu == Cpu_number::boot_cpu())
110     Watchdog::disable();
111
112   Timer_tick::disable(cpu);
113
114   if (cpu == Cpu_number::boot_cpu())
115     wfi_enter();
116 }
117
118 // restore interrupts after leaving the kernel debugger
119 IMPLEMENT
120 void
121 Jdb::restore_irqs(Cpu_number cpu)
122 {
123   if (cpu == Cpu_number::boot_cpu())
124     wfi_leave();
125
126   Timer_tick::enable(cpu);
127
128   if (cpu == Cpu_number::boot_cpu())
129     Watchdog::enable();
130   Proc::sti_restore(jdb_irq_state.cpu(cpu));
131 }
132
133 IMPLEMENT inline
134 void
135 Jdb::enter_trap_handler(Cpu_number)
136 {}
137
138 IMPLEMENT inline
139 void
140 Jdb::leave_trap_handler(Cpu_number)
141 {}
142
143 IMPLEMENT inline
144 bool
145 Jdb::handle_conditional_breakpoint(Cpu_number cpu, Jdb_entry_frame *e)
146 {
147   return Thread::is_debug_exception(e->error_code)
148          && bp_test_log_only && bp_test_log_only(cpu);
149 }
150
151 IMPLEMENT
152 void
153 Jdb::handle_nested_trap(Jdb_entry_frame *e)
154 {
155   printf("Trap in JDB: IP:%08lx PSR=%08lx ERR=%08lx\n",
156          e->ip(), e->psr, e->error_code);
157 }
158
159 IMPLEMENT
160 bool
161 Jdb::handle_debug_traps(Cpu_number cpu)
162 {
163   Jdb_entry_frame *ef = entry_frame.cpu(cpu);
164   error_buffer.cpu(cpu).clear();
165
166   if (Thread::is_debug_exception(ef->error_code)
167       && bp_test_break)
168     return bp_test_break(cpu, &error_buffer.cpu(cpu));
169
170   if (ef->error_code == (0x33UL << 26))
171     error_buffer.cpu(cpu).printf("%s",(char const *)ef->r[0]);
172   else if (ef->debug_ipi())
173     error_buffer.cpu(cpu).printf("IPI ENTRY");
174   else
175     error_buffer.cpu(cpu).printf("ENTRY");
176
177   return true;
178 }
179
180 IMPLEMENT inline
181 bool
182 Jdb::handle_user_request(Cpu_number cpu)
183 {
184   Jdb_entry_frame *ef = Jdb::entry_frame.cpu(cpu);
185   const char *str = (char const *)ef->r[0];
186   Space * task = get_task(cpu);
187   char tmp;
188
189   if (ef->debug_ipi())
190     return cpu != Cpu_number::boot_cpu();
191
192   if (ef->error_code == ((0x33UL << 26) | 1))
193     return execute_command_ni(task, str);
194
195   if (!peek(str, task, tmp) || tmp != '*')
196     return false;
197   if (!peek(str+1, task, tmp) || tmp != '#')
198     return false;
199
200   return execute_command_ni(task, str+2);
201 }
202
203 IMPLEMENT inline
204 bool
205 Jdb::test_checksums()
206 { return true; }
207
208 static
209 bool
210 Jdb::handle_special_cmds(int)
211 { return 1; }
212
213 PUBLIC static
214 FIASCO_INIT FIASCO_NOINLINE void
215 Jdb::init()
216 {
217   static Jdb_handler enter(at_jdb_enter);
218   static Jdb_handler leave(at_jdb_leave);
219
220   Jdb::jdb_enter.add(&enter);
221   Jdb::jdb_leave.add(&leave);
222
223   Thread::nested_trap_handler = (Trap_state::Handler)enter_jdb;
224
225   Kconsole::console()->register_console(push_cons());
226 }
227
228
229 PRIVATE static
230 void *
231 Jdb::access_mem_task(Address virt, Space * task)
232 {
233   // align
234   virt &= ~0x03;
235
236   Address phys;
237
238   if (!task)
239     {
240       if (Mem_layout::in_kernel(virt))
241         {
242           auto p = Kmem_space::kdir()->walk(Virt_addr(virt));
243           if (!p.is_valid())
244             return 0;
245
246           phys = p.page_addr() | cxx::get_lsb(virt, p.page_order());
247         }
248       else
249         phys = virt;
250     }
251   else
252     {
253       phys = Address(task->virt_to_phys(virt));
254
255
256       if (phys == (Address)-1)
257         phys = task->virt_to_phys_s0((void *)virt);
258
259       if (phys == (Address)-1)
260         return 0;
261     }
262
263   unsigned long addr = Mem_layout::phys_to_pmem(phys);
264   if (addr == (Address)-1)
265     {
266       Mem_unit::flush_vdcache();
267       auto pte = Kmem_space::kdir()
268         ->walk(Virt_addr(Mem_layout::Jdb_tmp_map_area), Pdir::Super_level);
269
270       if (!pte.is_valid() || pte.page_addr() != cxx::mask_lsb(phys, pte.page_order()))
271         {
272           pte.create_page(Phys_mem_addr(cxx::mask_lsb(phys, pte.page_order())),
273                           Page::Attr(Page::Rights::RW()));
274           pte.write_back_if(true, Mem_unit::Asid_kernel);
275         }
276
277       Mem_unit::kernel_tlb_flush();
278
279       addr = Mem_layout::Jdb_tmp_map_area + (phys & (Config::SUPERPAGE_SIZE - 1));
280     }
281
282   return (Mword*)addr;
283 }
284
285 PUBLIC static
286 Space *
287 Jdb::translate_task(Address addr, Space * task)
288 {
289   return (Kmem::is_kmem_page_fault(addr, 0)) ? 0 : task;
290 }
291
292 PUBLIC static
293 int
294 Jdb::peek_task(Address virt, Space * task, void *value, int width)
295 {
296   void const *mem = access_mem_task(virt, task);
297   if (!mem)
298     return -1;
299
300   switch (width)
301     {
302     case 1:
303         {
304           Mword dealign = (virt & 0x3) * 8;
305           *(Mword*)value = (*(Mword*)mem & (0xff << dealign)) >> dealign;
306         }
307         break;
308     case 2:
309         {
310           Mword dealign = ((virt & 0x2) >> 1) * 16;
311           *(Mword*)value = (*(Mword*)mem & (0xffff << dealign)) >> dealign;
312         }
313         break;
314     case 4:
315       memcpy(value, mem, width);
316     }
317
318   return 0;
319 }
320
321 PUBLIC static
322 int
323 Jdb::is_adapter_memory(Address, Space *)
324 {
325   return 0;
326 }
327
328 PUBLIC static
329 int
330 Jdb::poke_task(Address virt, Space * task, void const *val, int width)
331 {
332   void *mem = access_mem_task(virt, task);
333   if (!mem)
334     return -1;
335
336   memcpy(mem, val, width);
337   return 0;
338 }
339
340
341 PRIVATE static
342 void
343 Jdb::at_jdb_enter()
344 {
345   Mem_unit::clean_vdcache();
346 }
347
348 PRIVATE static
349 void
350 Jdb::at_jdb_leave()
351 {
352   Mem_unit::flush_vcache();
353 }
354
355 PUBLIC static inline
356 void
357 Jdb::enter_getchar()
358 {}
359
360 PUBLIC static inline
361 void
362 Jdb::leave_getchar()
363 {}
364
365 PUBLIC static
366 void
367 Jdb::write_tsc_s(String_buffer *buf, Signed64 tsc, bool sign)
368 {
369   if (sign)
370     buf->printf("%c", (tsc < 0) ? '-' : (tsc == 0) ? ' ' : '+');
371   buf->printf("%lld c", tsc);
372 }
373
374 PUBLIC static
375 void
376 Jdb::write_tsc(String_buffer *buf, Signed64 tsc, bool sign)
377 {
378   write_tsc_s(buf, tsc, sign);
379 }
380
381
382 //----------------------------------------------------------------------------
383 IMPLEMENTATION [arm && mp]:
384
385 #include <cstdio>
386
387 static
388 void
389 Jdb::send_nmi(Cpu_number cpu)
390 {
391   printf("NMI to %d, what's that?\n",
392          cxx::int_value<Cpu_number>(cpu));
393 }
394
395 IMPLEMENT_OVERRIDE inline template< typename T >
396 void
397 Jdb::set_monitored_address(T *dest, T val)
398 {
399   *const_cast<T volatile *>(dest) = val;
400   Mem::dsb();
401   asm volatile("sev");
402 }
403
404 IMPLEMENT_OVERRIDE inline template< typename T >
405 T
406 Jdb::monitor_address(Cpu_number, T volatile const *addr)
407 {
408   asm volatile("wfe");
409   return *addr;
410 }