]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ux/pic-ux.cpp
update
[l4.git] / kernel / fiasco / src / kern / ux / pic-ux.cpp
1 /*
2  * Fiasco-UX
3  * Architecture specific interrupt code
4  */
5
6 INTERFACE:
7
8 #include "config.h"
9 #include <sys/poll.h>
10
11 EXTENSION class Pic
12 {
13 public:
14   static int irq_pending();
15   static void eat(unsigned);
16   static void set_owner(int);
17   static unsigned int map_irq_to_gate(unsigned);
18   static bool setup_irq_prov(unsigned irq, const char * const path,
19                              void (*bootstrap_func)());
20   static void irq_prov_shutdown();
21   static unsigned int get_pid_for_irq_prov(unsigned);
22   static bool get_ipi_gate(unsigned irq, unsigned long &gate);
23
24   enum
25   {
26     Irq_timer    = 0,
27     Irq_con      = 1,
28     Irq_net      = 2,
29     Num_dev_irqs = 4,
30     Irq_ipi_base = 4,
31     Num_irqs     = 4 + Config::Max_num_cpus,
32   };
33
34 private:
35   static unsigned int highest_irq;
36   static unsigned int pids[Pic::Num_irqs];
37   static struct pollfd pfd[Pic::Num_irqs];
38 };
39
40 // ------------------------------------------------------------------------
41 INTERFACE[ux && mp]:
42
43 EXTENSION class Pic
44 {
45 public:
46   static void send_ipi(Cpu_number _cpu, unsigned char data);
47   static bool setup_ipi(Cpu_number _cpu, int _tid);
48
49 private:
50   typedef Per_cpu_array<unsigned> Fd_array;
51   static Fd_array ipi_fds;
52 };
53
54 // ------------------------------------------------------------------------
55 IMPLEMENTATION[ux]:
56
57 #include <cassert>                      // for assert
58 #include <csignal>                      // for SIGIO
59 #include <cstdio>                       // for stdin
60 #include <cstdlib>                      // for EXIT_FAILURE
61 #include <fcntl.h>                      // for fcntl
62 #include <pty.h>                        // for termios
63 #include <unistd.h>                     // for fork
64 #include <sys/types.h>                  // for fork
65
66 #include "boot_info.h"                  // for boot_info::fd()
67 #include "emulation.h"
68 #include "initcalls.h"
69
70 unsigned int Pic::highest_irq;
71 unsigned int Pic::pids[Num_irqs];
72 struct pollfd Pic::pfd[Num_irqs];
73
74 PUBLIC static inline
75 unsigned
76 Pic::nr_irqs()
77 { return Num_dev_irqs; }
78
79 IMPLEMENT FIASCO_INIT
80 void
81 Pic::init()
82 {
83   atexit (&irq_prov_shutdown);
84 }
85
86 PRIVATE static
87 bool
88 Pic::prepare_irq(int sockets[2])
89 {
90   struct termios tt;
91
92   if (openpty(&sockets[0], &sockets[1], NULL, NULL, NULL))
93     {
94       perror("openpty");
95       return false;
96     }
97
98   if (tcgetattr(sockets[0], &tt) < 0)
99     {
100       perror("tcgetattr");
101       return false;
102     }
103
104   cfmakeraw(&tt);
105
106   if (tcsetattr(sockets[0], TCSADRAIN, &tt) < 0)
107     {
108       perror("tcsetattr");
109       return false;
110     }
111
112   fflush(NULL);
113
114   return true;
115 }
116
117 IMPLEMENT
118 bool
119 Pic::setup_irq_prov(unsigned irq, const char * const path,
120                     void (*bootstrap_func)())
121 {
122   int sockets[2];
123
124   if (access(path, X_OK | F_OK))
125     {
126       perror(path);
127       return false;
128     }
129
130   if (prepare_irq(sockets) == false)
131     return false;
132
133   switch (pids[irq] = fork())
134     {
135       case -1:
136         return false;
137
138       case 0:
139         break;
140
141       default:
142         close(sockets[1]);
143         fcntl(sockets[0], F_SETFD, FD_CLOEXEC);
144         pfd[irq].fd = sockets[0];
145         return true;
146     }
147
148   // Unblock all signals except SIGINT, we enter jdb with it and don't want
149   // the irq providers to die
150   sigset_t mask;
151   sigemptyset(&mask);
152   sigaddset(&mask, SIGINT);
153   sigprocmask(SIG_SETMASK, &mask, NULL);
154
155   fclose(stdin);
156   fclose(stdout);
157   fclose(stderr);
158
159   dup2(sockets[1], 0);
160   close(sockets[0]);
161   close(sockets[1]);
162   bootstrap_func();
163
164   _exit(EXIT_FAILURE);
165 }
166
167 IMPLEMENT
168 void
169 Pic::irq_prov_shutdown()
170 {
171   for (unsigned int i = 0; i < Num_irqs; i++)
172     if (pids[i])
173       kill(pids[i], SIGTERM);
174 }
175
176 IMPLEMENT inline NEEDS [<cassert>, <csignal>, <fcntl.h>, "boot_info.h"]
177 void
178 Pic::enable_locked(unsigned irq, unsigned /*prio*/)
179 {
180   int flags;
181
182   // If fd is zero, someone tried to activate an IRQ without provider
183   assert (pfd[irq].fd);
184
185   if ((flags = fcntl(pfd[irq].fd, F_GETFL)) < 0                         ||
186        fcntl(pfd[irq].fd, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0    ||
187        fcntl(pfd[irq].fd, F_SETSIG, SIGIO) < 0                          ||
188        fcntl(pfd[irq].fd, F_SETOWN, Boot_info::pid()) < 0)
189     return;
190
191   pfd[irq].events = POLLIN;
192
193   if (irq >= highest_irq)
194     highest_irq = irq + 1;
195 }
196
197 IMPLEMENT inline
198 void
199 Pic::disable_locked(unsigned)
200 {}
201
202 IMPLEMENT inline
203 void
204 Pic::acknowledge_locked(unsigned)
205 {}
206
207 IMPLEMENT inline
208 void
209 Pic::block_locked(unsigned)
210 {}
211
212 IMPLEMENT
213 int
214 Pic::irq_pending()
215 {
216   unsigned int i;
217
218   for (i = 0; i < highest_irq; i++)
219     pfd[i].revents = 0;
220
221   if (poll(pfd, highest_irq, 0) > 0)
222     for (i = 0; i < highest_irq; i++)
223       if (pfd[i].revents & POLLIN)
224         {
225           if (!Emulation::idt_vector_present(0x20 + i))
226             eat(i);
227           else
228             return i;
229         }
230
231   return -1;
232 }
233
234 IMPLEMENT inline NEEDS [<cassert>, <unistd.h>]
235 void
236 Pic::eat(unsigned irq)
237 {
238   char buffer[8];
239
240   assert (pfd[irq].events & POLLIN);
241
242   while (read(pfd[irq].fd, buffer, sizeof (buffer)) > 0)
243     ;
244 }
245
246 /*
247  * Possible problem if an IRQ gets enabled and the system is already
248  * long running and the owner is set wrong?
249  */
250 IMPLEMENT inline
251 void
252 Pic::set_owner(int pid)
253 {
254   for (unsigned int i = 0; i < highest_irq; i++)
255     if (pfd[i].events & POLLIN)
256       fcntl(pfd[i].fd, F_SETOWN, pid);
257 }
258
259 IMPLEMENT inline
260 unsigned int
261 Pic::map_irq_to_gate(unsigned irq)
262 {
263   return 0x20 + irq;
264 }
265
266 IMPLEMENT
267 unsigned int
268 Pic::get_pid_for_irq_prov(unsigned irq)
269 {
270   return pids[irq];
271 }
272
273 // ---------------------------------------------------------------------
274 IMPLEMENTATION[ux && !mp]:
275
276 IMPLEMENT static
277 bool
278 Pic::get_ipi_gate(unsigned, unsigned long &)
279 { return false; }
280
281
282 // ---------------------------------------------------------------------
283 IMPLEMENTATION[ux && mp]:
284
285 #include "ipi.h"
286
287 Pic::Fd_array Pic::ipi_fds;
288
289 IMPLEMENT
290 void
291 Pic::set_cpu(unsigned irq_num, Cpu_number cpu)
292 {
293   printf("Pic::set_cpu(%d, %d)\n", irq_num, cpu);
294 }
295
296 IMPLEMENT static
297 bool
298 Pic::setup_ipi(Cpu_number _cpu, int _tid)
299 {
300   int sockets[2], flags;
301
302   if (prepare_irq(sockets) == false)
303     return false;
304
305   unsigned i = Irq_ipi_base + _cpu;
306
307   pfd[i].fd = sockets[0];
308   ipi_fds[_cpu] = sockets[1];
309
310   if ((flags = fcntl(pfd[i].fd, F_GETFL)) < 0                     ||
311       fcntl(pfd[i].fd, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0 ||
312       fcntl(pfd[i].fd, F_SETSIG, SIGIO) < 0                       ||
313       fcntl(pfd[i].fd, F_SETOWN, _tid) < 0)
314     return false;
315
316   pfd[i].events = POLLIN;
317
318   if (i >= highest_irq)
319     highest_irq = i + 1;
320
321   return true;
322 }
323
324 IMPLEMENT
325 void
326 Pic::send_ipi(Cpu_number _cpu, unsigned char data)
327 {
328   if (ipi_fds[_cpu])
329     if (write(ipi_fds[_cpu], &data, sizeof(data)) != sizeof(data))
330       printf("Write error\n");
331 }
332
333 IMPLEMENT static
334 bool
335 Pic::get_ipi_gate(unsigned irq, unsigned long &gate)
336 {
337   if (irq < Irq_ipi_base)
338     return false;
339
340   // XXX check if irq is the irq for our current context/cpu
341   unsigned char b;
342   if (read(pfd[irq].fd, &b, sizeof(b)) < 1)
343     {
344       printf("read failure\n");
345       return false;
346     }
347
348   printf("IPI message: %c\n", b);
349   gate = Ipi::gate(b);
350
351   return true;
352 }