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