]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/jdb_tbuf.cpp
update
[l4.git] / kernel / fiasco / src / jdb / jdb_tbuf.cpp
1 INTERFACE:
2
3 #include "jdb_ktrace.h"
4 #include "l4_types.h"
5 #include "std_macros.h"
6 #include "tb_entry.h"
7 #include "spin_lock.h"
8
9 class Context;
10 class Log_event;
11 struct Tracebuffer_status;
12
13 class Jdb_tbuf
14 {
15 public:
16   static void (*direct_log_entry)(Tb_entry*, const char*);
17
18   enum
19   {
20     Event  = 1,
21     Result = 2
22   };
23
24 protected:
25   static Tb_entry_union *_tbuf_act;     // current entry
26   static Tb_entry_union *_tbuf_max;
27   static Mword          _entries;       // number of occupied entries
28   static Mword          _max_entries;   // maximum number of entries
29   static Mword          _filter_enabled;// !=0 if filter is active
30   static Mword          _number;        // current event number
31   static Mword          _count_mask1;
32   static Mword          _count_mask2;
33   static Address        _size;          // size of memory area for tbuffer
34   static Spin_lock<>    _lock;
35 };
36
37 #ifdef CONFIG_JDB_LOGGING
38
39 #ifdef CONFIG_PF_UX
40
41 // We don't want to patch the text segment of Fiasco-UX.
42
43 #define BEGIN_LOG_EVENT(name, sc, fmt)                          \
44   do                                                            \
45     {                                                           \
46       register Unsigned8 __do_log__;                            \
47       asm volatile (".pushsection \".data\"     \n\t"           \
48                     "1:  .byte   0              \n\t"           \
49                     ".section \".debug.jdb.log_table\" \n\t"    \
50                     ".long 2f                   \n\t"           \
51                     ".long 1b                   \n\t"           \
52                     ".long %c[xfmt]             \n\t"           \
53                     ".section \".rodata.log.str\" \n\t"         \
54                     "2: .asciz "#name"          \n\t"           \
55                     "   .asciz "#sc"            \n\t"           \
56                     ".popsection                \n\t"           \
57                     "movb    1b,%0              \n\t"           \
58                     : "=q"(__do_log__)                  \
59                     : [xfmt] "i" (&Tb_entry_formatter_t<fmt>::singleton));  \
60       if (EXPECT_FALSE( __do_log__ ))                           \
61         {
62
63 #elif defined(CONFIG_ARM)
64
65 #define BEGIN_LOG_EVENT(name, sc, fmt)                          \
66   do                                                            \
67     {                                                           \
68       register Mword __do_log__;                                \
69       asm volatile ("1:  mov    %0, #0          \n\t"           \
70                     ".pushsection \".debug.jdb.log_table\" \n\t"        \
71                     "3: .long 2f                \n\t"           \
72                     "   .long 1b                \n\t"           \
73                     "   .long %c[xfmt]          \n\t"           \
74                     ".section \".rodata.log.str\" \n\t"         \
75                     "2: .asciz "#name"          \n\t"           \
76                     "   .asciz "#sc"            \n\t"           \
77                     ".popsection                \n\t"           \
78                     : "=r"(__do_log__)                          \
79                     : [xfmt] "i" (&Tb_entry_formatter_t<fmt>::singleton));  \
80       if (EXPECT_FALSE( __do_log__ ))                           \
81         {
82
83 #elif defined(CONFIG_IA32) // IA32
84
85 #define BEGIN_LOG_EVENT(name, sc, fmt)                          \
86   do                                                            \
87     {                                                           \
88       register Unsigned8 __do_log__;                            \
89       asm volatile ("1:   movb $0,%0                    \n\t"   \
90                     ".pushsection \".debug.jdb.log_table\"      \n\t"   \
91                     "3:  .long 2f                       \n\t"   \
92                     "    .long 1b + 1                   \n\t"   \
93                     "    .long %a[xfmt]                 \n\t"   \
94                     ".section \".rodata.log.str\"       \n\t"   \
95                     "2:  .asciz "#name"                 \n\t"   \
96                     "    .asciz "#sc"                   \n\t"   \
97                     ".popsection                        \n\t"   \
98                     : "=b"(__do_log__)                          \
99                     : [xfmt] "i" (&Tb_entry_formatter_t<fmt>::singleton));  \
100       if (EXPECT_FALSE( __do_log__ ))                           \
101         {
102
103 #elif defined(CONFIG_AMD64)
104 #define BEGIN_LOG_EVENT(name, sc, fmt)                          \
105   do                                                            \
106     {                                                           \
107       register Unsigned8 __do_log__;                            \
108       asm volatile ("1:   movb $0,%0                    \n\t"   \
109                     ".pushsection \".debug.jdb.log_table\"      \n\t"   \
110                     "3:  .quad 2f                       \n\t"   \
111                     "    .quad 1b + 1                   \n\t"   \
112                     "    .quad %c[xfmt]                 \n\t"   \
113                     ".section \".rodata.log.str\"       \n\t"   \
114                     "2:  .asciz "#name"                 \n\t"   \
115                     "    .asciz "#sc"                   \n\t"   \
116                     ".popsection                        \n\t"   \
117                     : "=b"(__do_log__)                          \
118                     : [xfmt] "i"(&Tb_entry_formatter_t<fmt>::singleton) );   \
119       if (EXPECT_FALSE( __do_log__ ))                           \
120         {
121
122 #elif defined(CONFIG_PPC32)
123 //#warning TODO: Dummy implementation for PPC32
124 #define BEGIN_LOG_EVENT(name, sc, fmt)                          \
125   do                                                            \
126     {                                                           \
127       register Unsigned8 __do_log__ = 0;                        \
128       if (EXPECT_FALSE( __do_log__ ))                           \
129         {
130
131 #else
132 #error Unknown Arch for LOG macros
133 #endif
134
135 #define END_LOG_EVENT                                           \
136         }                                                       \
137     } while (0)
138
139 #else // ! CONFIG_JDB_LOGGING
140
141 #define BEGIN_LOG_EVENT(name, sc, fmt)                          \
142   if (0)                                                        \
143     { char __do_log__ = 0; (void)__do_log__;
144
145 #define END_LOG_EVENT                                           \
146     }
147
148 #endif // ! CONFIG_JDB_LOGGING
149
150
151 IMPLEMENTATION:
152
153 #include "config.h"
154 #include "cpu_lock.h"
155 #include "initcalls.h"
156 #include "lock_guard.h"
157 #include "mem_layout.h"
158 #include "std_macros.h"
159
160 Tb_entry_union *Jdb_tbuf::_tbuf_act;
161 Tb_entry_union *Jdb_tbuf::_tbuf_max;
162 Mword Jdb_tbuf::_entries;
163 Mword Jdb_tbuf::_max_entries;
164 Mword Jdb_tbuf::_filter_enabled;
165 Mword Jdb_tbuf::_number;
166 Mword Jdb_tbuf::_count_mask1;
167 Mword Jdb_tbuf::_count_mask2;
168 Address Jdb_tbuf::_size;
169 Spin_lock<> Jdb_tbuf::_lock;
170
171 static void direct_log_dummy(Tb_entry*, const char*)
172 {}
173
174 void (*Jdb_tbuf::direct_log_entry)(Tb_entry*, const char*) = &direct_log_dummy;
175
176 PUBLIC static inline NEEDS["mem_layout.h"]
177 Tracebuffer_status *
178 Jdb_tbuf::status()
179 {
180   return (Tracebuffer_status *)Mem_layout::Tbuf_status_page;
181 }
182
183 PROTECTED static inline NEEDS["mem_layout.h"]
184 Tb_entry_union *
185 Jdb_tbuf::buffer()
186 {
187   return (Tb_entry_union *)Mem_layout::Tbuf_buffer_area;
188 }
189
190 PUBLIC static inline
191 Address
192 Jdb_tbuf::size()
193 {
194   return _size;
195 }
196
197 /** Clear tracebuffer. */
198 PUBLIC static
199 void
200 Jdb_tbuf::clear_tbuf()
201 {
202   Mword i;
203
204   for (i = 0; i < _max_entries; i++)
205     buffer()[i].clear();
206
207   _tbuf_act = buffer();
208   _entries = 0;
209 }
210
211 /** Return pointer to new tracebuffer entry. */
212 PUBLIC static
213 Tb_entry*
214 Jdb_tbuf::new_entry()
215 {
216   Tb_entry *tb;
217   {
218     auto guard = lock_guard(_lock);
219
220     tb = _tbuf_act;
221
222     status()->current = (Address)tb;
223
224     if (++_tbuf_act >= _tbuf_max)
225       _tbuf_act = buffer();
226
227     if (_entries < _max_entries)
228       _entries++;
229
230     tb->number(++_number);
231   }
232
233   tb->rdtsc();
234   tb->rdpmc1();
235   tb->rdpmc2();
236
237   return tb;
238 }
239
240 PUBLIC template<typename T> static inline
241 T*
242 Jdb_tbuf::new_entry()
243 {
244   static_assert(sizeof(T) <= sizeof(Tb_entry_union), "tb entry T too big");
245   return static_cast<T*>(new_entry());
246 }
247
248 /** Commit tracebuffer entry. */
249 PUBLIC static
250 void
251 Jdb_tbuf::commit_entry()
252 {
253   if (EXPECT_FALSE((_number & _count_mask2) == 0))
254     {
255       if (_number & _count_mask1)
256         status()->window[0].version++; // 64-bit value!
257       else
258         status()->window[1].version++; // 64-bit value!
259
260 #if 0 // disbale Tbuf vIRQ for the time beeing (see bug #357)
261       // fire the virtual 'buffer full' irq
262       if (_observer)
263         {
264           auto guard = lock_guard(cpu_lock);
265           _observer->notify();
266         }
267 #endif
268     }
269 }
270
271 /** Return number of entries currently allocated in tracebuffer.
272  * @return number of entries */
273 PUBLIC static inline
274 Mword
275 Jdb_tbuf::unfiltered_entries()
276 {
277   return _entries;
278 }
279
280 PUBLIC static
281 Mword
282 Jdb_tbuf::entries()
283 {
284   if (!_filter_enabled)
285     return unfiltered_entries();
286
287   Mword cnt = 0;
288
289   for (Mword idx = 0; idx<unfiltered_entries(); idx++)
290     if (!buffer()[idx].hidden())
291       cnt++;
292
293   return cnt;
294 }
295
296 /** Return maximum number of entries in tracebuffer.
297  * @return number of entries */
298 PUBLIC static inline
299 Mword
300 Jdb_tbuf::max_entries()
301 {
302   return _max_entries;
303 }
304
305 /** Set maximum number of entries in tracebuffer. */
306 PUBLIC static inline
307 void
308 Jdb_tbuf::max_entries (Mword num)
309 {
310   _max_entries = num;
311 }
312
313 /** Check if event is valid.
314  * @param idx position of event in tracebuffer
315  * @return 0 if not valid, 1 if valid */
316 PUBLIC static inline
317 int
318 Jdb_tbuf::event_valid(Mword idx)
319 {
320   return idx < _entries;
321 }
322
323 /** Return pointer to tracebuffer event.
324  * @param  position of event in tracebuffer:
325  *         0 is last event, 1 the event before and so on
326  * @return pointer to tracebuffer event
327  *
328  * event with idx == 0 is the last event queued in
329  * event with idx == 1 is the event before */
330 PUBLIC static
331 Tb_entry*
332 Jdb_tbuf::unfiltered_lookup(Mword idx)
333 {
334   if (!event_valid(idx))
335     return 0;
336
337   Tb_entry_union *e = _tbuf_act - idx - 1;
338
339   if (e < buffer())
340     e += _max_entries;
341
342   return e;
343 }
344
345 /** Return pointer to tracebuffer event.
346  * Don't count hidden events.
347  * @param  position of event in tracebuffer:
348  *         0 is last event, 1 the event before and so on
349  * @return pointer to tracebuffer event
350  *
351  * event with idx == 0 is the last event queued in
352  * event with idx == 1 is the event before */
353 PUBLIC static
354 Tb_entry*
355 Jdb_tbuf::lookup(Mword look_idx)
356 {
357   if (!_filter_enabled)
358     return unfiltered_lookup(look_idx);
359
360   for (Mword idx = 0;; idx++)
361     {
362       Tb_entry *e = unfiltered_lookup(idx);
363
364       if (!e)
365         return 0;
366       if (e->hidden())
367         continue;
368       if (!look_idx--)
369         return e;
370     }
371 }
372
373 PUBLIC static
374 Mword
375 Jdb_tbuf::unfiltered_idx(Tb_entry const *e)
376 {
377   Tb_entry_union const *ef = static_cast<Tb_entry_union const *>(e);
378   Mword idx = _tbuf_act - ef - 1;
379
380   if (idx > _max_entries)
381     idx += _max_entries;
382
383   return idx;
384 }
385
386 /** Tb_entry => tracebuffer index. */
387 PUBLIC static
388 Mword
389 Jdb_tbuf::idx(Tb_entry const *e)
390 {
391   if (!_filter_enabled)
392     return unfiltered_idx(e);
393
394   Tb_entry_union const *ef = static_cast<Tb_entry_union const*>(e);
395   Mword idx = (Mword) - 1;
396
397   for (;;)
398     {
399       if (!ef->hidden())
400         idx++;
401       ef++;
402       if (ef >= buffer() + _max_entries)
403         ef -= _max_entries;
404       if (ef == _tbuf_act)
405         break;
406     }
407
408   return idx;
409 }
410
411 /** Event number => Tb_entry. */
412 PUBLIC static inline
413 Tb_entry*
414 Jdb_tbuf::search(Mword nr)
415 {
416   Tb_entry *e;
417
418   for (Mword idx = 0; (e = unfiltered_lookup(idx)); idx++)
419     if (e->number() == nr)
420       return e;
421
422   return 0;
423 }
424
425 /** Event number => tracebuffer index.
426  * @param  nr  number of event
427  * @return tracebuffer index of event which has the number nr or
428  *         -1 if there is no event with this number or
429  *         -2 if the event is currently hidden. */
430 PUBLIC static
431 Mword
432 Jdb_tbuf::search_to_idx(Mword nr)
433 {
434   if (nr == (Mword) - 1)
435     return (Mword) - 1;
436
437   Tb_entry *e;
438
439   if (!_filter_enabled)
440     {
441       e = search(nr);
442       if (!e)
443         return (Mword) - 1;
444       return unfiltered_idx(e);
445     }
446
447   for (Mword idx_u = 0, idx_f = 0; (e = unfiltered_lookup(idx_u)); idx_u++)
448     {
449       if (e->number() == nr)
450         return e->hidden() ? (Mword) - 2 : idx_f;
451
452       if (!e->hidden())
453         idx_f++;
454     }
455
456   return (Mword)-1;
457 }
458
459 /** Return some information about log event.
460  * @param idx number of event to determine the info
461  * @retval number event number
462  * @retval tsc event value of CPU cycles
463  * @retval pmc event value of perf counter cycles
464  * @return 0 if something wrong, 1 if everything ok */
465 PUBLIC static
466 int
467 Jdb_tbuf::event(Mword idx, Mword *number, Unsigned32 *kclock,
468                 Unsigned64 *tsc, Unsigned32 *pmc1, Unsigned32 *pmc2)
469 {
470   Tb_entry *e = lookup(idx);
471
472   if (!e)
473     return false;
474
475   *number = e->number();
476   if (kclock)
477     *kclock = e->kclock();
478   if (tsc)
479     *tsc = e->tsc();
480   if (pmc1)
481     *pmc1 = e->pmc1();
482   if (pmc2)
483     *pmc2 = e->pmc2();
484   return true;
485 }
486
487 /** Get difference CPU cycles between event idx and event idx+1.
488  * @param idx position of first event in tracebuffer
489  * @retval difference in CPU cycles
490  * @return 0 if something wrong, 1 if everything ok */
491 PUBLIC static
492 int
493 Jdb_tbuf::diff_tsc(Mword idx, Signed64 *delta)
494 {
495   Tb_entry *e      = lookup(idx);
496   Tb_entry *e_prev = lookup(idx + 1);
497
498   if (!e || !e_prev)
499     return false;
500
501   *delta = e->tsc() - e_prev->tsc();
502   return true;
503 }
504
505 /** Get difference perfcnt cycles between event idx and event idx+1.
506  * @param idx position of first event in tracebuffer
507  * @param nr  number of perfcounter (0=first, 1=second)
508  * @retval difference in perfcnt cycles
509  * @return 0 if something wrong, 1 if everything ok */
510 PUBLIC static
511 int
512 Jdb_tbuf::diff_pmc(Mword idx, Mword nr, Signed32 *delta)
513 {
514   Tb_entry *e      = lookup(idx);
515   Tb_entry *e_prev = lookup(idx + 1);
516
517   if (!e || !e_prev)
518     return false;
519
520   switch (nr)
521     {
522     case 0: *delta = e->pmc1() - e_prev->pmc1(); break;
523     case 1: *delta = e->pmc2() - e_prev->pmc2(); break;
524     }
525
526   return true;
527 }
528
529 PUBLIC static inline
530 void
531 Jdb_tbuf::enable_filter()
532 {
533   _filter_enabled = 1;
534 }
535
536 PUBLIC static inline
537 void
538 Jdb_tbuf::disable_filter()
539 {
540   _filter_enabled = 0;
541 }