]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/dirq_pic_pin-ia32-ux.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / dirq_pic_pin-ia32-ux.cpp
1 INTERFACE[ia32,amd64,ux]:
2
3 #include "irq_chip.h"
4 #include "irq_pin.h"
5
6
7 EXTENSION class Dirq_pic_pin
8 {
9 public:
10   class Chip : public Irq_chip
11   {
12   public:
13     static unsigned vector(unsigned irq)
14     {
15       return (irq < 0x10) ? irq + 0x20 : irq + 0x30;
16     }
17
18     bool reserve(unsigned irq);
19     void reset(unsigned irq);
20     Irq_base *irq(unsigned irq);
21     bool is_free(unsigned irq);
22     bool alloc(Irq_base *irq, unsigned irqnum);
23     bool free(Irq_base *irq, unsigned irqnum);
24     void setup(Irq_base *irq, unsigned irqnum);
25
26     unsigned nr_irqs() const { return 16; }
27
28     bool valloc(Irq_base *irq, unsigned vector);
29     static bool vfree(Irq_base *irq, unsigned vector, void *handler);
30     virtual void disable_irq(unsigned vector);
31
32   protected:
33     Irq_base *virq(unsigned v);
34   };
35 };
36
37
38 IMPLEMENTATION [ia32,ux]:
39 enum { Register_arg0 = 0 }; // eax
40
41 IMPLEMENTATION [amd64]:
42 enum { Register_arg0 = 7 }; // rdi
43
44 IMPLEMENTATION[ia32,amd64,ux]:
45
46 #include <cassert>
47
48 #include "cpu_lock.h"
49 #include "globalconfig.h"
50 #include "globals.h"
51 #include "irq_chip.h"
52 #include "logdefs.h"
53 #include "thread.h"
54
55 #include "idt.h"
56
57 class Entry_code
58 {
59 private:
60   struct
61   {
62     char push;
63     char mov;
64     Signed32 irq_adr;
65     char jmp;
66     Unsigned32 jmp_adr;
67     char pad;
68   } __attribute__((packed)) _d;
69
70 public:
71   void irq(Irq_base *irq)
72   {
73     _d.irq_adr = (Address)irq;
74   }
75
76   Irq *irq() const
77   { return nonull_static_cast<Irq*>((Irq_base*)((Smword)(_d.irq_adr))); }
78
79   bool is_free() const
80   { return !_d.push; }
81
82   void free()
83   {
84     _d.push = 0;
85   }
86
87 };
88
89 static Entry_code _entry_code[256-0x20];
90
91 PUBLIC
92 void
93 Entry_code::setup()
94 {
95   extern char __generic_irq_entry[];
96   // push %eax/%rdi
97   _d.push = 0x50 + Register_arg0;
98
99   // mov imm32, %eax/%rdi
100   _d.mov = 0xb8 + Register_arg0;
101   irq(0);
102
103   // jmp __generic_irq_entry
104   _d.jmp = 0xe9;
105   _d.jmp_adr = (Address)__generic_irq_entry - (Address)&_d - 11;
106 }
107
108 /** The corresponding hardware interrupt occurred -- handle it. 
109     This method checks whether the attached receiver is ready to receive 
110     an IRQ message, and if so, restarts it so that it can pick up the IRQ
111     message using ipc_receiver_ready().
112  */
113 #if 0
114 asm (
115     ".global __irq_entry_template     \n"
116     ".global __irq_entry_template_end \n"
117     ".align 4                         \n"
118     "__irq_entry_template:            \n"
119     "  pushq %rdi \n"
120     "  mov $0, %edi \n"
121 //    "  push %eax                      \n"
122 //    "  mov $0, %eax                   \n"
123     "  jmp __generic_irq_entry        \n"
124     "__irq_entry_template_end:        \n"
125     );
126 #endif
127
128 IMPLEMENT
129 bool
130 Dirq_pic_pin::Chip::is_free(unsigned irqn)
131 {
132   if (irqn >= Config::Max_num_dirqs)
133     return false;
134
135   unsigned v = vector(irqn);
136   return _entry_code[v -0x20].is_free();
137 }
138
139 IMPLEMENT
140 Irq_base *
141 Dirq_pic_pin::Chip::virq(unsigned v)
142 {
143   return _entry_code[v -0x20].irq();
144 }
145
146 IMPLEMENT
147 Irq_base *
148 Dirq_pic_pin::Chip::irq(unsigned irqn)
149 {
150   if (irqn >= Config::Max_num_dirqs)
151     return 0;
152
153   unsigned v = vector(irqn);
154
155   return virq(v);
156 }
157
158
159 IMPLEMENT
160 void
161 Dirq_pic_pin::Chip::disable_irq(unsigned vector)
162 {
163   extern char entry_int_pic_ignore[];
164   Idt::set_entry(vector, Address(&entry_int_pic_ignore), false);
165 }
166
167 IMPLEMENT
168 bool
169 Dirq_pic_pin::Chip::alloc(Irq_base *irq, unsigned irqn)
170 {
171   if (irqn >= Config::Max_num_dirqs)
172     return false;
173
174   unsigned v = vector(irqn);
175   if (valloc(irq, v))
176     {
177       setup(irq, irqn);
178       return true;
179     }
180
181   return false;
182 }
183
184 IMPLEMENT
185 bool
186 Dirq_pic_pin::Chip::valloc(Irq_base *irq, unsigned v)
187 {
188   if (v >= APIC_IRQ_BASE - 0x10)
189     return false;
190
191   if (!_entry_code[v -0x20].is_free())
192     return false;
193
194   _entry_code[v -0x20].setup();
195   _entry_code[v -0x20].irq(irq);
196
197
198   // force code to memory before setting IDT entry
199   asm volatile ( "" : : : "memory" );
200
201   Idt::set_entry(v, (Address)&_entry_code[v -0x20], false);
202   return true;
203 }
204
205 IMPLEMENT
206 bool
207 Dirq_pic_pin::Chip::free(Irq_base *irq, unsigned irqn)
208 {
209   if (irqn >= Config::Max_num_dirqs)
210     return false;
211
212   unsigned v = vector(irqn);
213   return vfree(irq, v, 0);
214 }
215
216 IMPLEMENT
217 bool
218 Dirq_pic_pin::Chip::vfree(Irq_base *irq, unsigned v, void *handler)
219 {
220   if (v >= APIC_IRQ_BASE - 0x10)
221     return false;
222
223   if (_entry_code[v -0x20].is_free())
224     return false;
225
226   if (_entry_code[v-0x20].irq() != irq)
227     return false;
228
229   _entry_code[v-0x20].free();
230
231   Idt::set_entry(v, (Address)handler, false);
232   return true;
233 }
234
235 IMPLEMENT
236 void
237 Dirq_pic_pin::Chip::reset(unsigned irqn)
238 {
239   unsigned v = vector(irqn);
240   Idt::set_entry(v, (Address)&_entry_code[v -0x20], false);
241 }
242
243 IMPLEMENT
244 void
245 Dirq_pic_pin::Chip::setup(Irq_base *irq, unsigned irqnum)
246 {
247   irq->pin()->replace<Dirq_pic_pin>(irqnum);
248 }
249
250 IMPLEMENT
251 bool
252 Dirq_pic_pin::Chip::reserve(unsigned irqn)
253 {
254   if (irqn >= Config::Max_num_dirqs)
255     return false;
256
257   unsigned v = vector(irqn);
258   if (!_entry_code[v -0x20].is_free())
259     return false;
260
261   _entry_code[v -0x20].setup();
262   return true;
263 }
264
265 PUBLIC inline
266 unsigned
267 Dirq_pic_pin::vector() const
268 { return irq() < 0x10 ? irq() + 0x20 : irq() + 0x30; }
269
270 extern "C" void entry_int_pic_ignore(void);
271
272
273 PROTECTED
274 void
275 Dirq_pic_pin::disable_vector()
276 {
277   unsigned vector = this->vector();
278   _entry_code[vector -0x20].free();
279 }
280 PUBLIC
281 void
282 Dirq_pic_pin::disable()
283 {
284   unsigned vector = this->vector();
285   Idt::set_entry(vector, Address(&entry_int_pic_ignore), false);
286   _entry_code[vector -0x20].free();
287 }
288
289
290 IMPLEMENT FIASCO_INIT
291 void
292 Dirq_pic_pin::init()
293 {
294   static Chip _ia;
295   Irq_chip::hw_chip = &_ia;
296 }
297