]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/tb_entry.cpp
603fd61e3d297ba8a5d15ab6fb7fba8548f52d2e
[l4.git] / kernel / fiasco / src / kern / tb_entry.cpp
1 INTERFACE:
2
3 #include "initcalls.h"
4 #include "l4_error.h"
5
6 enum {
7   Tbuf_unused             = 0,
8   Tbuf_pf,
9   Tbuf_ipc,
10   Tbuf_ipc_res,
11   Tbuf_ipc_trace,
12   Tbuf_ke,
13   Tbuf_ke_reg,
14   Tbuf_exregs,
15   Tbuf_breakpoint,
16   Tbuf_pf_res,
17   Tbuf_preemption,
18   Tbuf_ke_bin,
19   Tbuf_dynentries,
20
21   Tbuf_max                = 0x80,
22   Tbuf_hidden             = 0x80,
23 };
24
25 #include "l4_types.h"
26
27 class Tb_entry;
28 class Context;
29 class Space;
30 class Sched_context;
31 class Syscall_frame;
32 class Trap_state;
33 class Tb_entry_formatter;
34
35 struct Tb_log_table_entry
36 {
37   char const *name;
38   unsigned char *patch;
39   Tb_entry_formatter *fmt;
40 };
41
42 extern Tb_log_table_entry _log_table[];
43 extern Tb_log_table_entry _log_table_end;
44
45
46
47 class Tb_entry
48 {
49 protected:
50   Mword         _number;        ///< event number
51   Address       _ip;            ///< instruction pointer
52   Context const *_ctx;          ///< Context
53   Unsigned64    _tsc;           ///< time stamp counter
54   Unsigned32    _pmc1;          ///< performance counter value 1
55   Unsigned32    _pmc2;          ///< performance counter value 2
56   Unsigned32    _kclock;        ///< lower 32 bits of kernel clock
57   Unsigned8     _type;          ///< type of entry
58   Unsigned8     _cpu;           ///< CPU
59
60   static Mword (*rdcnt1)();
61   static Mword (*rdcnt2)();
62
63 public:
64   class Group_order
65   {
66   public:
67     Group_order() : _o(0) {} // not grouped
68     Group_order(unsigned v) : _o(2 + v) {}
69     static Group_order none() { return Group_order(); }
70     static Group_order last() { return Group_order(255, true); }
71     static Group_order first() { return Group_order(0); }
72     static Group_order direct() { return Group_order(1, true); }
73
74     bool not_grouped() const { return _o == 0; }
75     bool is_direct() const { return _o == 1; }
76     bool is_first() const { return _o == 2; }
77     bool is_last() const { return _o == 255; }
78     bool grouped() const { return _o >= 2; }
79     unsigned char depth() const { return _o - 2; }
80
81   private:
82     Group_order(unsigned char v, bool) : _o(v) {}
83     unsigned char _o;
84   };
85
86   Group_order has_partner() const { return Group_order::none(); }
87   Group_order is_partner(Tb_entry const *) const { return Group_order::none(); }
88   Mword partner() const { return 0; }
89
90 } __attribute__((__packed__, __aligned__(8)));
91
92
93 class Tb_entry_union : public Tb_entry
94 {
95 private:
96   char _padding[Tb_entry_size - sizeof(Tb_entry)];
97 };
98
99 static_assert(sizeof(Tb_entry_union) == Tb_entry::Tb_entry_size,
100               "Tb_entry_union has the wrong size");
101
102 struct Tb_entry_empty : public Tb_entry
103 {
104   unsigned print(int, char *) const { return 0; }
105 };
106
107 class Tb_entry_formatter
108 {
109 public:
110   typedef Tb_entry::Group_order Group_order;
111
112   virtual unsigned print(Tb_entry const *e, int max, char *buf) const = 0;
113   virtual Group_order has_partner(Tb_entry const *e) const = 0;
114   virtual Group_order is_pair(Tb_entry const *e, Tb_entry const *n) const = 0;
115   virtual Mword partner(Tb_entry const *e) const = 0;
116
117   static Tb_entry_formatter const *get_fmt(Tb_entry const *e)
118   {
119     if (e->type() >= Tbuf_dynentries)
120       return _log_table[e->type() - Tbuf_dynentries].fmt;
121
122     return _fixed[e->type()];
123   }
124
125 private:
126   static Tb_entry_formatter const *_fixed[];
127 };
128
129
130 template< typename T >
131 class Tb_entry_formatter_t : public Tb_entry_formatter
132 {
133 public:
134   typedef T const *Const_ptr;
135   typedef T *Ptr;
136
137   unsigned print(Tb_entry const *e, int max, char *buf) const
138   { return static_cast<Const_ptr>(e)->print(max, buf); }
139
140   Group_order has_partner(Tb_entry const *e) const
141   { return static_cast<Const_ptr>(e)->has_partner(); }
142
143   Group_order is_pair(Tb_entry const *e, Tb_entry const *n) const
144   {
145     //assert (get_fmt(e) == &singleton);
146
147     if (&singleton == get_fmt(n))
148       return static_cast<Const_ptr>(e)->is_partner(static_cast<Const_ptr>(n));
149     return Tb_entry::Group_order::none();
150   }
151
152   Mword partner(Tb_entry const *e) const
153   { return static_cast<Const_ptr>(e)->partner(); }
154
155   static Tb_entry_formatter_t const singleton;
156 };
157
158 template<typename T>
159 Tb_entry_formatter_t<T> const Tb_entry_formatter_t<T>::singleton;
160
161
162 /** logged ipc. */
163 class Tb_entry_ipc : public Tb_entry
164 {
165 private:
166   L4_msg_tag    _tag;           ///< message tag
167   Mword _dword[2];      ///< first two message words
168   L4_obj_ref    _dst;           ///< destination id
169   Mword       _dbg_id;
170   Mword       _label;
171   L4_timeout_pair _timeout;     ///< timeout
172 public:
173   Tb_entry_ipc() : _timeout(0) {}
174   unsigned print(int max, char *buf) const;
175 };
176
177 /** logged ipc result. */
178 class Tb_entry_ipc_res : public Tb_entry
179 {
180 private:
181   L4_msg_tag    _tag;           ///< message tag
182   Mword _dword[2];      ///< first two dwords
183   L4_error      _result;        ///< result
184   Mword _from;          ///< receive descriptor
185   Mword _pair_event;    ///< referred event
186   Unsigned8     _have_snd;      ///< ipc had send part
187   Unsigned8     _is_np;         ///< next period bit set
188 public:
189   unsigned print(int max, char *buf) const;
190 };
191
192 /** logged ipc for user level tracing with Vampir. */
193 class Tb_entry_ipc_trace : public Tb_entry
194 {
195 private:
196   Unsigned64    _snd_tsc;       ///< entry tsc
197   L4_msg_tag    _result;        ///< result
198   L4_obj_ref    _snd_dst;       ///< send destination
199   Mword _rcv_dst;       ///< rcv partner
200   Unsigned8     _snd_desc;
201   Unsigned8     _rcv_desc;
202 public:
203   unsigned print(int max, char *buf) const;
204 };
205
206 #if 0
207 /** logged short-cut ipc failed. */
208 class Tb_entry_ipc_sfl : public Tb_entry_base
209 {
210 private:
211   Global_id     _from;  ///< short ipc rcv descriptor
212   L4_timeout_pair       _timeout;       ///< ipc timeout
213   Global_id     _dst;           ///< partner
214   Unsigned8     _is_irq, _snd_lst, _dst_ok, _dst_lck, _preempt;
215 };
216 #endif
217
218 /** logged pagefault. */
219 class Tb_entry_pf : public Tb_entry
220 {
221 private:
222   Address       _pfa;           ///< pagefault address
223   Mword _error;         ///< pagefault error code
224   Space *_space;
225 public:
226   unsigned print(int max, char *buf) const;
227 };
228
229 /** pagefault result. */
230 class Tb_entry_pf_res : public Tb_entry
231 {
232 private:
233   Address       _pfa;
234   L4_error      _err;
235   L4_error      _ret;
236 public:
237   unsigned print(int max, char *buf) const;
238 };
239
240
241 /** logged kernel event. */
242 template<typename BASE, unsigned TAG>
243 class Tb_entry_ke_t : public BASE
244 {
245 protected:
246   union Msg
247   {
248     char msg[BASE::Tb_entry_size - sizeof(BASE)];
249     struct Ptr
250     {
251       char tag[2];
252       char const *ptr;
253     } mptr;
254   } _msg;
255 } __attribute__((__packed__));
256
257 typedef Tb_entry_ke_t<Tb_entry, Tbuf_ke> Tb_entry_ke;
258
259 class Tb_entry_ke_reg_b : public Tb_entry
260 {
261 public:
262   Mword v[3];
263 } __attribute__((__packed__));
264
265 class Tb_entry_ke_reg : public Tb_entry_ke_t<Tb_entry_ke_reg_b, Tbuf_ke_reg>
266 {
267 };
268
269 /** logged breakpoint. */
270 class Tb_entry_bp : public Tb_entry
271 {
272 private:
273   Address       _address;       ///< breakpoint address
274   int           _len;           ///< breakpoint length
275   Mword _value;         ///< value at address
276   int           _mode;          ///< breakpoint mode
277 public:
278   unsigned print(int max, char *buf) const;
279 };
280
281 /** logged context switch. */
282 class Tb_entry_ctx_sw : public Tb_entry
283 {
284 public:
285   using Tb_entry::_ip;
286
287   Context const *dst;           ///< switcher target
288   Context const *dst_orig;
289   Address kernel_ip;
290   Mword lock_cnt;
291   Space const *from_space;
292   Sched_context const *from_sched;
293   Mword from_prio;
294   unsigned print(int max, char *buf) const;
295 } __attribute__((packed));
296
297 /** logged scheduling event. */
298 class Tb_entry_sched : public Tb_entry
299 {
300 public:
301   unsigned short mode;
302   Context const *owner;
303   unsigned short id;
304   unsigned short prio;
305   signed long left;
306   unsigned long quantum;
307
308   unsigned print(int max, char *buf) const;
309 } __attribute__((packed));
310
311 /** logged binary kernel event. */
312 class Tb_entry_ke_bin : public Tb_entry
313 {
314 public:
315   char _msg[Tb_entry_size - sizeof(Tb_entry)];
316   enum { SIZE = 30 };
317 };
318
319
320
321 IMPLEMENTATION:
322
323 #include <cstring>
324 #include <cstdarg>
325
326 #include "entry_frame.h"
327 #include "globals.h"
328 #include "kip.h"
329 #include "static_init.h"
330 #include "trap_state.h"
331
332
333 PROTECTED static Mword Tb_entry::dummy_read_pmc() { return 0; }
334
335 Mword (*Tb_entry::rdcnt1)() = dummy_read_pmc;
336 Mword (*Tb_entry::rdcnt2)() = dummy_read_pmc;
337 Tb_entry_formatter const *Tb_entry_formatter::_fixed[Tbuf_dynentries];
338
339
340 PUBLIC static
341 void
342 Tb_entry_formatter::set_fixed(unsigned type, Tb_entry_formatter const *f)
343 {
344   if (type >= Tbuf_dynentries)
345     return;
346
347   _fixed[type] = f;
348 }
349
350
351 PUBLIC static
352 void
353 Tb_entry::set_rdcnt(int num, Mword (*f)())
354 {
355   if (!f)
356     f = dummy_read_pmc;
357
358   switch (num)
359     {
360     case 0: rdcnt1 = f; break;
361     case 1: rdcnt2 = f; break;
362     }
363 }
364
365 PUBLIC inline
366 void
367 Tb_entry::clear()
368 { _type = Tbuf_unused; }
369
370 PUBLIC inline NEEDS["kip.h", "globals.h"]
371 void
372 Tb_entry::set_global(char type, Context const *ctx, Address ip)
373 {
374   _type   = type;
375   _ctx    = ctx;
376   _ip     = ip;
377   _kclock = (Unsigned32)Kip::k()->clock;
378   _cpu    = current_cpu();
379 }
380
381 PUBLIC inline
382 void
383 Tb_entry::hide()
384 { _type |= Tbuf_hidden; }
385
386 PUBLIC inline
387 void
388 Tb_entry::unhide()
389 { _type &= ~Tbuf_hidden; }
390
391 PUBLIC inline
392 Address
393 Tb_entry::ip() const
394 { return _ip; }
395
396 PUBLIC inline
397 Context const *
398 Tb_entry::ctx() const
399 { return _ctx; }
400
401 PUBLIC inline
402 Unsigned8
403 Tb_entry::type() const
404 { return _type & (Tbuf_max-1); }
405
406 PUBLIC inline
407 int
408 Tb_entry::hidden() const
409 { return _type & Tbuf_hidden; }
410
411 PUBLIC inline
412 Mword
413 Tb_entry::number() const
414 { return _number; }
415
416 PUBLIC inline
417 void
418 Tb_entry::number(Mword number)
419 { _number = number; }
420
421 PUBLIC inline
422 void
423 Tb_entry::rdpmc1()
424 { _pmc1 = rdcnt1(); }
425
426 PUBLIC inline
427 void
428 Tb_entry::rdpmc2()
429 { _pmc2 = rdcnt2(); }
430
431 PUBLIC inline
432 Unsigned32
433 Tb_entry::kclock() const
434 { return _kclock; }
435
436 PUBLIC inline
437 Unsigned8
438 Tb_entry::cpu() const
439 { return _cpu; }
440
441 PUBLIC inline
442 Unsigned64
443 Tb_entry::tsc() const
444 { return _tsc; }
445
446 PUBLIC inline
447 Unsigned32
448 Tb_entry::pmc1() const
449 { return _pmc1; }
450
451 PUBLIC inline
452 Unsigned32
453 Tb_entry::pmc2() const
454 { return _pmc2; }
455
456
457 PUBLIC inline NEEDS ["entry_frame.h"]
458 void
459 Tb_entry_ipc::set(Context const *ctx, Mword ip, Syscall_frame *ipc_regs, Utcb *utcb,
460                   Mword dbg_id, Unsigned64 left)
461 {
462   set_global(Tbuf_ipc, ctx, ip);
463   _dst       = ipc_regs->ref();
464   _label     = ipc_regs->from_spec();
465
466
467   _dbg_id = dbg_id;
468
469   _timeout   = ipc_regs->timeout();
470   _tag       = ipc_regs->tag();
471   if (ipc_regs->next_period())
472     {
473       _dword[0]  = (Unsigned32)(left & 0xffffffff);
474       _dword[1]  = (Unsigned32)(left >> 32);
475     }
476   else
477     {
478       // hint for gcc
479       register Mword tmp0 = utcb->values[0];
480       register Mword tmp1 = utcb->values[1];
481       _dword[0]  = tmp0;
482       _dword[1]  = tmp1;
483     }
484 }
485
486 PUBLIC inline
487 Mword
488 Tb_entry_ipc::ipc_type() const
489 { return _dst.op(); }
490
491 PUBLIC inline
492 Mword
493 Tb_entry_ipc::dbg_id() const
494 { return _dbg_id; }
495
496 PUBLIC inline
497 L4_obj_ref
498 Tb_entry_ipc::dst() const
499 { return _dst; }
500
501 PUBLIC inline
502 L4_timeout_pair
503 Tb_entry_ipc::timeout() const
504 { return _timeout; }
505
506 PUBLIC inline
507 L4_msg_tag
508 Tb_entry_ipc::tag() const
509 { return _tag; }
510
511 PUBLIC inline
512 Mword
513 Tb_entry_ipc::label() const
514 { return _label; }
515
516 PUBLIC inline
517 Mword
518 Tb_entry_ipc::dword(unsigned index) const
519 { return _dword[index]; }
520
521
522 PUBLIC inline NEEDS ["entry_frame.h"]
523 void
524 Tb_entry_ipc_res::set(Context const *ctx, Mword ip, Syscall_frame *ipc_regs,
525                       Utcb *utcb,
526                       Mword result, Mword pair_event, Unsigned8 have_snd,
527                       Unsigned8 is_np)
528 {
529   set_global(Tbuf_ipc_res, ctx, ip);
530   // hint for gcc
531   register Mword tmp0 = utcb->values[0];
532   register Mword tmp1 = utcb->values[1];
533   _dword[0]   = tmp0;
534   _dword[1]   = tmp1;
535   _tag        = ipc_regs->tag();
536   _pair_event = pair_event;
537   _result     = L4_error::from_raw(result);
538   _from       = ipc_regs->from_spec();
539   _have_snd   = have_snd;
540   _is_np      = is_np;
541 }
542
543 PUBLIC inline
544 int
545 Tb_entry_ipc_res::have_snd() const
546 { return _have_snd; }
547
548 PUBLIC inline
549 int
550 Tb_entry_ipc_res::is_np() const
551 { return _is_np; }
552
553 PUBLIC inline
554 Mword
555 Tb_entry_ipc_res::from() const
556 { return _from; }
557
558 PUBLIC inline
559 L4_error
560 Tb_entry_ipc_res::result() const
561 { return _result; }
562
563 PUBLIC inline
564 L4_msg_tag
565 Tb_entry_ipc_res::tag() const
566 { return _tag; }
567
568 PUBLIC inline
569 Mword
570 Tb_entry_ipc_res::dword(unsigned index) const
571 { return _dword[index]; }
572
573 PUBLIC inline
574 Mword
575 Tb_entry_ipc_res::pair_event() const
576 { return _pair_event; }
577
578
579 PUBLIC inline
580 void
581 Tb_entry_ipc_trace::set(Context const *ctx, Mword ip, Unsigned64 snd_tsc,
582                         L4_obj_ref const &snd_dst, Mword rcv_dst,
583                         L4_msg_tag result, Unsigned8 snd_desc,
584                         Unsigned8 rcv_desc)
585 {
586   set_global(Tbuf_ipc_trace, ctx, ip);
587   _snd_tsc  = snd_tsc;
588   _snd_dst  = snd_dst;
589   _rcv_dst  = rcv_dst;
590   _result   = result;
591   _snd_desc = snd_desc;
592   _rcv_desc = rcv_desc;
593 }
594
595 PUBLIC inline
596 void
597 Tb_entry_pf::set(Context const *ctx, Address ip, Address pfa,
598                  Mword error, Space *spc)
599 {
600   set_global(Tbuf_pf, ctx, ip);
601   _pfa   = pfa;
602   _error = error;
603   _space = spc;
604 }
605
606 PUBLIC inline
607 Mword
608 Tb_entry_pf::error() const
609 { return _error; }
610
611 PUBLIC inline
612 Address
613 Tb_entry_pf::pfa() const
614 { return _pfa; }
615
616 PUBLIC inline
617 Space*
618 Tb_entry_pf::space() const
619 { return _space; }
620
621
622 PUBLIC inline
623 void
624 Tb_entry_pf_res::set(Context const *ctx, Address ip, Address pfa, 
625                      L4_error err, L4_error ret)
626 {
627   set_global(Tbuf_pf_res, ctx, ip);
628   _pfa = pfa;
629   _err = err;
630   _ret = ret;
631 }
632
633 PUBLIC inline
634 Address
635 Tb_entry_pf_res::pfa() const
636 { return _pfa; }
637
638 PUBLIC inline
639 L4_error
640 Tb_entry_pf_res::err() const
641 { return _err; }
642
643 PUBLIC inline
644 L4_error
645 Tb_entry_pf_res::ret() const
646 { return _ret; }
647
648
649 PUBLIC inline
650 void
651 Tb_entry_bp::set(Context const *ctx, Address ip,
652                  int mode, int len, Mword value, Address address)
653 {
654   set_global(Tbuf_breakpoint, ctx, ip);
655   _mode    = mode;
656   _len     = len;
657   _value   = value;
658   _address = address;
659 }
660
661
662
663 PUBLIC inline
664 int
665 Tb_entry_bp::mode() const
666 { return _mode; }
667
668 PUBLIC inline
669 int
670 Tb_entry_bp::len() const
671 { return _len; }
672
673 PUBLIC inline
674 Mword
675 Tb_entry_bp::value() const
676 { return _value; }
677
678 PUBLIC inline
679 Address
680 Tb_entry_bp::addr() const
681 { return _address; }
682
683
684
685 PUBLIC template<typename BASE, unsigned TAG> inline
686 void
687 Tb_entry_ke_t<BASE, TAG>::set(Context const *ctx, Address ip)
688 { this->set_global(TAG, ctx, ip); }
689
690 PUBLIC template<typename BASE, unsigned TAG> inline
691 void
692 Tb_entry_ke_t<BASE, TAG>::set_const(Context const *ctx, Address ip, char const *msg)
693 {
694   this->set_global(TAG, ctx, ip);
695   _msg.mptr.tag[0] = 0;
696   _msg.mptr.tag[1] = 1;
697   _msg.mptr.ptr = msg;
698 }
699
700 PUBLIC template<typename BASE, unsigned TAG> inline
701 void
702 Tb_entry_ke_t<BASE, TAG>::set_buf(unsigned i, char c)
703 {
704   if (i < sizeof(_msg.msg)-1)
705     _msg.msg[i] = c >= ' ' ? c : '.';
706 }
707
708 PUBLIC template<typename BASE, unsigned TAG> inline
709 void
710 Tb_entry_ke_t<BASE, TAG>::term_buf(unsigned i)
711 {
712   _msg.msg[i < sizeof(_msg.msg)-1 ? i : sizeof(_msg.msg)-1] = '\0';
713 }
714
715 PUBLIC template<typename BASE, unsigned TAG> inline
716 char const *
717 Tb_entry_ke_t<BASE, TAG>::msg() const
718 {
719   return _msg.mptr.tag[0] == 0 && _msg.mptr.tag[1] == 1 ? _msg.mptr.ptr : _msg.msg;
720 }
721
722 PUBLIC inline
723 void
724 Tb_entry_ke_bin::set(Context const *ctx, Address ip)
725 { set_global(Tbuf_ke_bin, ctx, ip); }
726
727 PUBLIC inline
728 void
729 Tb_entry_ke_bin::set_buf(unsigned i, char c)
730 {
731   if (i < sizeof(_msg)-1)
732     _msg[i] = c;
733 }
734
735 PUBLIC inline
736 void
737 Tb_entry_ke_reg::set_const(Context const *ctx, Mword eip,
738                            const char *msg,
739                            Mword v1, Mword v2, Mword v3)
740 {
741   Tb_entry_ke_t<Tb_entry_ke_reg_b, Tbuf_ke_reg>::set_const(ctx, eip, msg);
742   v[0] = v1;
743   v[1] = v2;
744   v[2] = v3;
745 }
746