]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/icu_helper.cpp
update
[l4.git] / kernel / fiasco / src / kern / icu_helper.cpp
1 INTERFACE:
2
3 #include "irq.h"
4 #include "kobject_helper.h"
5 #include "l4_buf_iter.h"
6
7 class Icu_h_base
8 {
9 public:
10   enum Op
11   {
12     Op_bind       = 0,
13     Op_unbind     = 1,
14     Op_info       = 2,
15     Op_msi_info   = 3,
16     Op_eoi        = Irq::Op_eoi_2, // 4
17     Op_unmask     = Op_eoi,
18     Op_mask       = 5,
19     Op_set_mode   = 6,
20   };
21
22   enum Feature
23   {
24     Msi_bit = 0x80000000
25   };
26 };
27
28
29 template< typename REAL_ICU >
30 class Icu_h : public Kobject_h<REAL_ICU>, public Icu_h_base
31 {
32 protected:
33   REAL_ICU const *this_icu() const
34   { return nonull_static_cast<REAL_ICU const *>(this); }
35
36   REAL_ICU *this_icu()
37   { return nonull_static_cast<REAL_ICU *>(this); }
38 };
39
40
41 IMPLEMENTATION:
42
43
44 PROTECTED
45 Irq *
46 Icu_h_base::deref_irq(L4_msg_tag *tag, Utcb const *utcb)
47 {
48   L4_snd_item_iter snd_items(utcb, tag->words());
49   Irq *irq;
50
51   if (!tag->items() || !snd_items.next())
52     {
53       *tag = Kobject_iface::commit_result(-L4_err::EInval);
54       return 0;
55     }
56
57   L4_fpage bind_irq(snd_items.get()->d);
58   if (EXPECT_FALSE(!bind_irq.is_objpage()))
59     {
60       *tag = Kobject_iface::commit_error(utcb, L4_error::Overflow);
61       return 0;
62     }
63
64   register Context *const c_thread = ::current();
65   register Space *const c_space = c_thread->space();
66   unsigned char irq_rights = 0;
67   irq = Kobject::dcast<Irq*>(c_space->lookup_local(bind_irq.obj_index(), &irq_rights));
68
69   if (!irq)
70     {
71       *tag = Kobject_iface::commit_result(-L4_err::EInval);
72       return 0;
73     }
74
75   if (EXPECT_FALSE(!(irq_rights & L4_fpage::X)))
76     {
77       *tag = Kobject_iface::commit_result(-L4_err::EPerm);
78       return 0;
79     }
80
81   return irq;
82 }
83
84
85 PUBLIC inline
86 template<typename REAL_ICU>
87 void
88 Icu_h<REAL_ICU>::icu_mask_irq(bool mask, unsigned irqnum)
89 {
90   Irq_base *i = this_icu()->icu_get_irq(irqnum);
91
92   if (EXPECT_FALSE(!i))
93     return;
94
95   if (mask)
96     i->mask();
97   else
98     i->unmask();
99 }
100
101 PUBLIC inline
102 template<typename REAL_ICU>
103 L4_msg_tag
104 Icu_h<REAL_ICU>::icu_unbind_irq(unsigned irqnum)
105 {
106   Irq_base *irq = this_icu()->icu_get_irq(irqnum);
107
108   if (irq)
109     irq->unbind();
110
111   return Kobject_iface::commit_result(0);
112 }
113
114 PUBLIC inline
115 template<typename REAL_ICU>
116 L4_msg_tag
117 Icu_h<REAL_ICU>::icu_get_msi_info(Mword msi, Utcb *out)
118 {
119   (void) msi;
120   (void) out;
121   return Kobject_iface::commit_result(-L4_err::EInval);
122 }
123
124 PUBLIC template< typename REAL_ICU >
125 inline
126 L4_msg_tag
127 Icu_h<REAL_ICU>::icu_invoke(L4_obj_ref, Mword /*rights*/,
128                             Syscall_frame *f,
129                             Utcb const *utcb, Utcb *out)
130 {
131   L4_msg_tag tag = f->tag();
132
133   switch (utcb->values[0])
134     {
135     case Op_bind:
136       if (tag.words() < 2)
137         return Kobject_iface::commit_result(-L4_err::EInval);
138
139       if (Irq *irq = deref_irq(&tag, utcb))
140         return this_icu()->icu_bind_irq(irq, utcb->values[1]);
141       else
142         return tag;
143
144     case Op_unbind:
145       if (tag.words() < 2)
146         return Kobject_iface::commit_result(-L4_err::EInval);
147
148       if (deref_irq(&tag, utcb))
149         return this_icu()->icu_unbind_irq(utcb->values[1]);
150       else
151         return tag;
152
153     case Op_info:
154       this_icu()->icu_get_info(&out->values[0], &out->values[1], &out->values[2]);
155       return Kobject_iface::commit_result(0, 3);
156
157     case Op_msi_info:
158       if (tag.words() < 2)
159         return Kobject_iface::commit_result(-L4_err::EInval);
160       return this_icu()->icu_get_msi_info(utcb->values[1], out);
161
162     case Op_unmask:
163     case Op_mask:
164       if (tag.words() < 2)
165         return Kobject_h<REAL_ICU>::no_reply();
166
167       this_icu()->icu_mask_irq(utcb->values[0] == Op_mask, utcb->values[1]);
168       return Kobject_h<REAL_ICU>::no_reply();
169
170     case Op_set_mode:
171       if (tag.words() >= 3)
172         {
173           Irq_base *irq = this_icu()->icu_get_irq(utcb->values[1]);
174
175           if (irq)
176             {
177               irq->set_mode(utcb->values[2]);
178               return Kobject_iface::commit_result(0);
179             }
180         }
181
182       return Kobject_iface::commit_result(-L4_err::EInval);
183
184     default:
185       return Kobject_iface::commit_result(-L4_err::ENosys);
186     }
187 }
188
189 PUBLIC
190 template< typename REAL_ICU >
191 L4_msg_tag
192 Icu_h<REAL_ICU>::kinvoke(L4_obj_ref ref, Mword rights,
193                          Syscall_frame *f,
194                          Utcb const *in, Utcb *out)
195 {
196   L4_msg_tag tag = f->tag();
197
198   if (EXPECT_FALSE(tag.proto() != L4_msg_tag::Label_irq))
199     return Kobject_iface::commit_result(-L4_err::EBadproto);
200
201   return icu_invoke(ref, rights, f, in, out);
202 }
203