3 #include "jdb_ktrace.h"
5 #include "std_macros.h"
11 struct Tracebuffer_status;
16 static void (*direct_log_entry)(Tb_entry*, const char*);
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;
37 #ifdef CONFIG_JDB_LOGGING
41 // We don't want to patch the text segment of Fiasco-UX.
43 #define BEGIN_LOG_EVENT(name, sc, fmt) \
46 register Unsigned8 __do_log__; \
47 asm volatile (".pushsection \".data\" \n\t" \
49 ".section \".debug.jdb.log_table\" \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" \
59 : [xfmt] "i" (&Tb_entry_formatter_t<fmt>::singleton)); \
60 if (EXPECT_FALSE( __do_log__ )) \
63 #elif defined(CONFIG_ARM)
65 #define BEGIN_LOG_EVENT(name, sc, fmt) \
68 register Mword __do_log__; \
69 asm volatile ("1: mov %0, #0 \n\t" \
70 ".pushsection \".debug.jdb.log_table\" \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" \
79 : [xfmt] "i" (&Tb_entry_formatter_t<fmt>::singleton)); \
80 if (EXPECT_FALSE( __do_log__ )) \
83 #elif defined(CONFIG_IA32) // IA32
85 #define BEGIN_LOG_EVENT(name, sc, fmt) \
88 register Unsigned8 __do_log__; \
89 asm volatile ("1: movb $0,%0 \n\t" \
90 ".pushsection \".debug.jdb.log_table\" \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" \
99 : [xfmt] "i" (&Tb_entry_formatter_t<fmt>::singleton)); \
100 if (EXPECT_FALSE( __do_log__ )) \
103 #elif defined(CONFIG_AMD64)
104 #define BEGIN_LOG_EVENT(name, sc, fmt) \
107 register Unsigned8 __do_log__; \
108 asm volatile ("1: movb $0,%0 \n\t" \
109 ".pushsection \".debug.jdb.log_table\" \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" \
118 : [xfmt] "i"(&Tb_entry_formatter_t<fmt>::singleton) ); \
119 if (EXPECT_FALSE( __do_log__ )) \
122 #elif defined(CONFIG_PPC32)
123 //#warning TODO: Dummy implementation for PPC32
124 #define BEGIN_LOG_EVENT(name, sc, fmt) \
127 register Unsigned8 __do_log__ = 0; \
128 if (EXPECT_FALSE( __do_log__ )) \
132 #error Unknown Arch for LOG macros
135 #define END_LOG_EVENT \
139 #else // ! CONFIG_JDB_LOGGING
141 #define BEGIN_LOG_EVENT(name, sc, fmt) \
143 { char __do_log__ = 0; (void)__do_log__;
145 #define END_LOG_EVENT \
148 #endif // ! CONFIG_JDB_LOGGING
154 #include "cpu_lock.h"
155 #include "initcalls.h"
156 #include "lock_guard.h"
157 #include "mem_layout.h"
158 #include "std_macros.h"
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;
171 static void direct_log_dummy(Tb_entry*, const char*)
174 void (*Jdb_tbuf::direct_log_entry)(Tb_entry*, const char*) = &direct_log_dummy;
176 PUBLIC static inline NEEDS["mem_layout.h"]
180 return (Tracebuffer_status *)Mem_layout::Tbuf_status_page;
183 PROTECTED static inline NEEDS["mem_layout.h"]
187 return (Tb_entry_union *)Mem_layout::Tbuf_buffer_area;
197 /** Clear tracebuffer. */
200 Jdb_tbuf::clear_tbuf()
204 for (i = 0; i < _max_entries; i++)
207 _tbuf_act = buffer();
211 /** Return pointer to new tracebuffer entry. */
214 Jdb_tbuf::new_entry()
218 auto guard = lock_guard(_lock);
222 status()->current = (Address)tb;
224 if (++_tbuf_act >= _tbuf_max)
225 _tbuf_act = buffer();
227 if (_entries < _max_entries)
230 tb->number(++_number);
240 PUBLIC template<typename T> static inline
242 Jdb_tbuf::new_entry()
244 static_assert(sizeof(T) <= sizeof(Tb_entry_union), "tb entry T too big");
245 return static_cast<T*>(new_entry());
248 /** Commit tracebuffer entry. */
251 Jdb_tbuf::commit_entry()
253 if (EXPECT_FALSE((_number & _count_mask2) == 0))
255 if (_number & _count_mask1)
256 status()->window[0].version++; // 64-bit value!
258 status()->window[1].version++; // 64-bit value!
260 #if 0 // disbale Tbuf vIRQ for the time beeing (see bug #357)
261 // fire the virtual 'buffer full' irq
264 auto guard = lock_guard(cpu_lock);
271 /** Return number of entries currently allocated in tracebuffer.
272 * @return number of entries */
275 Jdb_tbuf::unfiltered_entries()
284 if (!_filter_enabled)
285 return unfiltered_entries();
289 for (Mword idx = 0; idx<unfiltered_entries(); idx++)
290 if (!buffer()[idx].hidden())
296 /** Return maximum number of entries in tracebuffer.
297 * @return number of entries */
300 Jdb_tbuf::max_entries()
305 /** Set maximum number of entries in tracebuffer. */
308 Jdb_tbuf::max_entries (Mword num)
313 /** Check if event is valid.
314 * @param idx position of event in tracebuffer
315 * @return 0 if not valid, 1 if valid */
318 Jdb_tbuf::event_valid(Mword idx)
320 return idx < _entries;
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
328 * event with idx == 0 is the last event queued in
329 * event with idx == 1 is the event before */
332 Jdb_tbuf::unfiltered_lookup(Mword idx)
334 if (!event_valid(idx))
337 Tb_entry_union *e = _tbuf_act - idx - 1;
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
351 * event with idx == 0 is the last event queued in
352 * event with idx == 1 is the event before */
355 Jdb_tbuf::lookup(Mword look_idx)
357 if (!_filter_enabled)
358 return unfiltered_lookup(look_idx);
360 for (Mword idx = 0;; idx++)
362 Tb_entry *e = unfiltered_lookup(idx);
375 Jdb_tbuf::unfiltered_idx(Tb_entry const *e)
377 Tb_entry_union const *ef = static_cast<Tb_entry_union const *>(e);
378 Mword idx = _tbuf_act - ef - 1;
380 if (idx > _max_entries)
386 /** Tb_entry => tracebuffer index. */
389 Jdb_tbuf::idx(Tb_entry const *e)
391 if (!_filter_enabled)
392 return unfiltered_idx(e);
394 Tb_entry_union const *ef = static_cast<Tb_entry_union const*>(e);
395 Mword idx = (Mword) - 1;
402 if (ef >= buffer() + _max_entries)
411 /** Event number => Tb_entry. */
414 Jdb_tbuf::search(Mword nr)
418 for (Mword idx = 0; (e = unfiltered_lookup(idx)); idx++)
419 if (e->number() == nr)
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. */
432 Jdb_tbuf::search_to_idx(Mword nr)
434 if (nr == (Mword) - 1)
439 if (!_filter_enabled)
444 return unfiltered_idx(e);
447 for (Mword idx_u = 0, idx_f = 0; (e = unfiltered_lookup(idx_u)); idx_u++)
449 if (e->number() == nr)
450 return e->hidden() ? (Mword) - 2 : idx_f;
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 */
467 Jdb_tbuf::event(Mword idx, Mword *number, Unsigned32 *kclock,
468 Unsigned64 *tsc, Unsigned32 *pmc1, Unsigned32 *pmc2)
470 Tb_entry *e = lookup(idx);
475 *number = e->number();
477 *kclock = e->kclock();
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 */
493 Jdb_tbuf::diff_tsc(Mword idx, Signed64 *delta)
495 Tb_entry *e = lookup(idx);
496 Tb_entry *e_prev = lookup(idx + 1);
501 *delta = e->tsc() - e_prev->tsc();
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 */
512 Jdb_tbuf::diff_pmc(Mword idx, Mword nr, Signed32 *delta)
514 Tb_entry *e = lookup(idx);
515 Tb_entry *e_prev = lookup(idx + 1);
522 case 0: *delta = e->pmc1() - e_prev->pmc1(); break;
523 case 1: *delta = e->pmc2() - e_prev->pmc2(); break;
531 Jdb_tbuf::enable_filter()
538 Jdb_tbuf::disable_filter()