]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4con/server/src/main.c
Inital import
[l4.git] / l4 / pkg / l4con / server / src / main.c
1 /**
2  * \file        con/server/src/main.c
3  * \brief       'main' of the con server
4  *
5  * \date        2001
6  * \author      Christian Helmuth <ch12@os.inf.tu-dresden.de>
7  *              Frank Mehnert <fm3@os.inf.tu-dresden.de> */
8 /*
9  * (c) 2001-2009 Technische Universität Dresden
10  * This file is part of TUD:OS and distributed under the terms of the
11  * GNU General Public License 2.
12  * Please see the COPYING-GPL-2 file for details.
13  */
14
15 /* L4 includes */
16 #include <l4/l4con/l4con.h>
17 #include <l4/l4con/l4con_ev.h>
18 #include <l4/input/libinput.h>
19 #include <l4/sys/kdebug.h>
20 #include <l4/util/parse_cmd.h>
21 #include <l4/util/macros.h>
22 #include <l4/sys/err.h>
23 #include <l4/re/c/mem_alloc.h>
24 #include <l4/re/c/namespace.h>
25 #include <l4/sys/thread.h>
26 #if defined(ARCH_x86) || defined(ARCH_amd64)
27 #include <l4/util/rdtsc.h>
28 #endif
29
30 /* LibC includes */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <setjmp.h>
35 #include <pthread-l4.h>
36
37 /* local includes */
38 #include "config.h"
39 #include "ev.h"
40 #include "events.h"
41 #include "gmode.h"
42 #include "l4con.h"
43 #include "main.h"
44 #include "vc.h"
45 #include "srv.h"
46
47 int noaccel;                            /* 1=disable pslim HW acceleration */
48 int nolog;                              /* 1=disable logging to logserver */
49 int pan;                                /* 1=pan display to 4MB boundary */
50 int use_fastmemcpy = 1;                 /* 1=fast memcpy using SSE2 */
51 int cpu_load;
52 int cpu_load_history;
53 int vbemode;
54
55 struct l4con_vc *vc[MAX_NR_L4CONS];     /* virtual consoles */
56 int fg_vc = -1;                         /* current foreground vc */
57 int want_vc = 0;                        /* the vc we want to switch to */
58                                         /* if we set want_vc = -1, con_loop
59                                          * must look for an open vc in list;
60                                          * don't switch to USED VCs, only to
61                                          * that in OUT/INOUT mode */
62 int update_id;                          /* 1=redraw vc id */
63 pthread_mutex_t want_vc_lock = PTHREAD_MUTEX_INITIALIZER;/* mutex for want_vc */
64 l4_cap_idx_t ev_partner_l4id = L4_INVALID_CAP;/* current event handler */
65 l4_cap_idx_t vc_partner_l4id = L4_INVALID_CAP;/* current active client */
66 l4_uint8_t vc_mode = CON_CLOSED;                /* mode of current console */
67 l4re_util_video_goos_fb_t goosfb;
68
69
70 static void do_switch(int i_new, int i_old);
71
72 static void
73 fast_memcpy(l4_uint8_t *dst, l4_uint8_t *src, l4_size_t size)
74 {
75 #if defined(ARCH_x86) || defined(ARCH_amd64)
76   l4_umword_t dummy;
77
78   asm volatile ("cld ; rep movsl"
79                 :"=S"(dummy), "=D"(dummy), "=c"(dummy)
80                 :"S"(src), "D"(dst),"c"(size/sizeof(l4_umword_t)));
81 #else
82   memcpy(dst, src, size);
83 #endif
84 }
85
86 /* fast memcpy using movntq (moving using non-temporal hint)
87  * cache line size is 32 bytes */
88 static void
89 fast_memcpy_mmx2_32(l4_uint8_t *dst, l4_uint8_t *src, l4_size_t size)
90 {
91 #if defined(ARCH_x86) || defined(ARCH_amd64)
92   l4_mword_t dummy;
93
94   /* don't execute emms in side the timer loop because at this point the
95    * fpu state is lazy allocated so we may have a kernel entry here */
96   asm ("emms");
97
98   asm volatile ("lea    (%%esi,%%edx,8),%%esi     \n\t"
99                 "lea    (%%edi,%%edx,8),%%edi     \n\t"
100                 "neg    %%edx                     \n\t"
101                 ".align 8                         \n\t"
102                 "0:                               \n\t"
103                 "mov    $64,%%ecx                 \n\t"
104                 ".align 16                        \n\t"
105                 "# block prefetch 4096 bytes      \n\t"
106                 "1:                               \n\t"
107                 "movl   (%%esi,%%edx,8),%%eax     \n\t"
108                 "movl   32(%%esi,%%edx,8),%%eax   \n\t"
109                 "add    $8,%%edx                  \n\t"
110                 "dec    %%ecx                     \n\t"
111                 "jnz    1b                        \n\t"
112                 "sub    $(32*16),%%edx            \n\t"
113                 "mov    $128,%%ecx                \n\t"
114                 ".align 16                        \n\t"
115                 "2: # copy 4096 bytes             \n\t"
116                 "movq   (%%esi,%%edx,8),%%mm0     \n\t"
117                 "movq   8(%%esi,%%edx,8),%%mm1    \n\t"
118                 "movq   16(%%esi,%%edx,8),%%mm2   \n\t"
119                 "movq   24(%%esi,%%edx,8),%%mm3   \n\t"
120                 "movntq %%mm0,(%%edi,%%edx,8)     \n\t"
121                 "movntq %%mm1,8(%%edi,%%edx,8)    \n\t"
122                 "movntq %%mm2,16(%%edi,%%edx,8)   \n\t"
123                 "movntq %%mm3,24(%%edi,%%edx,8)   \n\t"
124                 "add    $4,%%edx                  \n\t"
125                 "dec    %%ecx                     \n\t"
126                 "jnz    2b                        \n\t"
127                 "or     %%edx,%%edx               \n\t"
128                 "jnz    0b                        \n\t"
129                 "sfence                           \n\t"
130                 "emms                             \n\t"
131                 : "=d" (dummy)
132                 : "S" (src), "D" (dst), "d" (size/8)
133                 : "eax", "ebx", "ecx", "memory");
134 #else
135   memcpy(dst, src, size);
136 #endif
137 }
138
139 /** Find first available (non-opened) vc in list. */
140 static int
141 get_free_vc(void)
142 {
143   int i;
144
145   for (i=0; i < MAX_NR_L4CONS; i++)
146     {
147       if (vc[i]->mode == CON_CLOSED)
148         return i;
149     }
150
151   printf("Ooops, all vcs occupied\n");
152   return -CON_EFREE;
153 }
154
155 /** send con_event redraw.
156  * @pre have want_vc_lock */
157 static void
158 redraw_vc(int vcnum)
159 {
160    struct l4input ev_struct;
161
162    if (vcnum >= MAX_NR_L4CONS)
163      return;
164
165    ev_struct.time = l4re_kip()->clock;
166    ev_struct.type = EV_CON;
167    ev_struct.code = EV_CON_REDRAW;
168    ev_struct.value = 0;
169
170    send_event_client(vc[vcnum], &ev_struct);
171 }
172
173
174 /** send con_event background. */
175 static void
176 background_vc(int vcnum)
177 {
178    struct l4input ev_struct;
179
180    if (vcnum >= MAX_NR_L4CONS || vcnum < 0)
181      return;
182
183    ev_struct.time = l4re_kip()->clock;
184    ev_struct.type = EV_CON;
185    ev_struct.code = EV_CON_BACKGROUND;
186    ev_struct.value = 0;
187
188    send_event_client(vc[vcnum], &ev_struct);
189
190    vc[vcnum]->fb_mapped = 0;
191 }
192
193 /** Announce that we want to switch to another console.
194  *  This function should not block for a longer time. */
195 void
196 request_vc(int nr)
197 {
198   pthread_mutex_lock(&want_vc_lock);
199   want_vc = nr;
200   pthread_mutex_unlock(&want_vc_lock);
201 }
202
203 /** Announce that we want to switch to another console.
204  *  This function should not block for a longer time. */
205 void
206 request_vc_delta(int delta)
207 {
208   int new_vc;
209
210   if (delta == 0)
211     return;
212   pthread_mutex_lock(&want_vc_lock);
213   new_vc = fg_vc + delta;
214   for (;;)
215     {
216       if (new_vc <= 0)
217         new_vc = MAX_NR_L4CONS-1;
218       else if (new_vc >= MAX_NR_L4CONS)
219         new_vc = 1;
220       if (new_vc == fg_vc || (vc[new_vc]->mode & CON_OUT))
221         break;
222       new_vc += delta < 0 ? -1 : +1;
223     }
224   want_vc = new_vc;
225   pthread_mutex_unlock(&want_vc_lock);
226 }
227
228 /** Switch to other console (want_vc != fg_vc).
229  * @pre have want_vc_lock */
230 static void
231 switch_vc(void)
232 {
233   int i;
234
235   if ((want_vc > 0) && (want_vc & 0x1000))
236     {
237       /* special case: close current console */
238       printf("Still missing: %s %d\n", __func__, __LINE__);
239 #ifdef FIXME
240       CORBA_Environment env = dice_default_environment;
241       pthread_mutex_unlock(&want_vc_lock);
242       con_vc_close_call(&(vc[want_vc & ~0x1000]->vc_l4id), &env);
243       pthread_mutex_lock(&want_vc_lock);
244 #endif
245       want_vc = -1;
246     }
247
248   if (want_vc < 0)
249     {
250       struct l4con_vc *new;
251
252       if ((new = vc[fg_vc]))
253         {
254           for (; (new = new->prev); )
255             {
256               if ((new->mode & CON_OUT) && !(new->mode & CON_MASTER))
257                 {
258                   i = new->vc_number;
259                   goto found;
260                 }
261             }
262         }
263
264       for (i=0; i<MAX_NR_L4CONS; i++)
265         {
266           if ((vc[i]->mode & CON_OUT) && !(vc[i]->mode & CON_MASTER))
267             {
268 found:
269               printf("switch to vc %02d\n", i);
270
271               /* need fb_lock for that */
272               do_switch(i, 0);
273               redraw_vc(i);
274               want_vc = fg_vc = i;
275               break;
276             }
277         }
278       if (i == MAX_NR_L4CONS)
279         {
280           printf("All vc's closed\n");
281           /* switch to vc 0 (master) */
282           do_switch(0, -1);
283           want_vc = fg_vc = 0;
284         }
285     }
286   else
287     {
288       /* request for explicit switch (event or open) */
289       if (want_vc >= MAX_NR_L4CONS)
290         {
291           /* return to sane state */
292           want_vc         = fg_vc;
293           ev_partner_l4id = vc[fg_vc]->ev_partner_l4id;
294           vc_partner_l4id = vc[fg_vc]->vc_partner_l4id;
295           vc_mode         = vc[fg_vc]->mode;
296           return;
297         }
298
299       /* check if want_vc is open */
300       if (vc[want_vc]->mode & CON_OUT)
301         {
302           do_switch(want_vc, fg_vc);
303           redraw_vc(want_vc);
304
305           /* set a sane state */
306           fg_vc = want_vc;
307         }
308       else
309         {
310           /* set a sane state */
311           want_vc = fg_vc;
312         }
313     }
314 }
315
316 static void
317 do_switch(int i_new, int i_old)
318 {
319   struct l4con_vc *old = (i_old >= 0) ? vc[i_old] : 0;
320   struct l4con_vc *new = (i_new >= 0) ? vc[i_new] : 0;
321
322   /* save old vc */
323   if (old != 0)
324     {
325       pthread_mutex_lock(&old->fb_lock);
326       if (old->save_restore && old->vfb)
327         {
328           /* save screen */
329           if (use_fastmemcpy && (new->vfb_size % 4096 == 0))
330             fast_memcpy_mmx2_32(old->vfb, vis_vmem, old->vfb_size);
331           else
332             fast_memcpy        (old->vfb, vis_vmem, old->vfb_size);
333         }
334       old->fb       = old->vfb_in_server ? old->vfb : 0;
335       old->pan_xofs = old->vfb_in_server ? 0        : pan_offs_x;
336       old->pan_yofs = old->vfb_in_server ? 0        : pan_offs_y;
337       old->do_copy  = bg_do_copy;
338       old->do_fill  = bg_do_fill;
339       old->do_sync  = bg_do_sync;
340       old->do_drty  = 0;
341       old->next     = new;
342       pthread_mutex_unlock(&old->fb_lock);
343     }
344
345   /* setup new vc */
346   if (new != 0)
347     {
348       pthread_mutex_lock(&new->fb_lock);
349       new->fb       = gr_vmem;
350       new->pan_xofs = pan_offs_x;
351       new->pan_yofs = pan_offs_y;
352       new->do_copy  = fg_do_copy;
353       new->do_fill  = fg_do_fill;
354       new->do_sync  = fg_do_sync;
355       new->do_drty  = fg_do_drty;
356       new->prev     = old;
357
358       if (i_new == 0 || !new->save_restore || !new->vfb)
359         {
360           /* We clear the screen here for security reasons: If save_restore
361            * is false the client is responsible for updating the screen when
362            * it receives the EV_CON_REDRAW event. A malicous client could
363            * "forget" to respond but now has the input focus. */
364           vc_clear(new);
365         }
366
367       if (new->save_restore && new->vfb)
368         {
369           /* restore screen */
370           if (use_fastmemcpy && (new->vfb_size % 4096 == 0))
371             fast_memcpy_mmx2_32(vis_vmem, new->vfb, new->vfb_size);
372           else
373             fast_memcpy        (vis_vmem, new->vfb, new->vfb_size);
374         }
375
376       /* force redraw of changed screen content (needed by VMware) */
377       if (new->do_drty)
378         new->do_drty(0, 0, fb_info.width, fb_info.height);
379
380       pthread_mutex_unlock(&new->fb_lock);
381
382       update_id = 1;
383     }
384
385   /* tell old console that we flash its video memory */
386   if (i_old)
387     background_vc(i_old);
388
389   if (old && old->fb_mapped)
390   {
391     /* Flush video memory of old console.
392      * XXX This does not work on current Fiasco implementation because the
393      * mapping database does not record mappings of pages beyond end of
394      * physical RAM. */
395     l4_addr_t map_addr;
396
397     for (map_addr=(l4_addr_t)gr_vmem;
398          map_addr+L4_SUPERPAGESIZE < (l4_addr_t)gr_vmem_maxmap;
399          map_addr+=L4_SUPERPAGESIZE)
400       {
401 #ifdef FIXME
402         l4_fpage_unmap(l4_fpage(map_addr, L4_LOG2_SUPERPAGESIZE, 0, 0),
403                        L4_FP_FLUSH_PAGE | L4_FP_OTHER_SPACES);
404 #endif
405       }
406   }
407   ev_partner_l4id = vc[i_new]->ev_partner_l4id;
408   vc_partner_l4id = vc[i_new]->vc_partner_l4id;
409   vc_mode         = vc[i_new]->mode;
410 }
411
412 /******************************************************************************
413  * con_if - IDL server functions                                              *
414  ******************************************************************************/
415
416 /** \brief Query for new (not opened) virtual console
417  *
418  * in:  request       ... Flick request structure
419  *      sbuf_size     ... max IPC string buffer
420  * out: vcid          ... threadid of vc_thread
421  *      _ev           ... Flick exception (unused)
422  * ret: 0             ... success
423  *      -???          ... if no VC unused */
424 #ifdef FIXME
425 long
426 con_if_openqry_component (CORBA_Object _dice_corba_obj,
427                           unsigned long sbuf1_size,
428                           unsigned long sbuf2_size,
429                           unsigned long sbuf3_size,
430                           unsigned char priority,
431                           l4_threadid_t *vcid,
432                           short vfbmode,
433                           CORBA_Server_Environment *_dice_corba_env)
434 {
435   l4thread_t vc_tid;
436   l4_threadid_t vc_l4id, dummy;
437   l4dm_dataspace_t ds;
438   l4_offs_t ds_offs;
439   l4_addr_t ds_map_addr;
440   l4_size_t ds_map_size;
441   int vc_num;
442   char name[32];
443
444   /* check sbuf_size */
445   if (!sbuf1_size
446       || (sbuf2_size != 0 && sbuf3_size == 0)
447       || (sbuf2_size == 0 && sbuf3_size != 0)
448       || (sbuf1_size + sbuf2_size + sbuf3_size) > CONFIG_MAX_SBUF_SIZE)
449     {
450       printf("Wrong string buffer size\n");
451       return -CON_EXPARAM;
452     }
453
454   /* find first available (non-opened) vc in list */
455   if ((vc_num = get_free_vc()) == -CON_EFREE)
456     return vc_num;
457
458   /* allocate memory for sbuf */
459   sprintf(name, "ipcbuf1 for "l4util_idfmt"", l4util_idstr(*_dice_corba_obj));
460   if (!(vc[vc_num]->sbuf1 =
461         l4dm_mem_allocate_named(sbuf1_size, L4RM_MAP, name)))
462     {
463       printf("Ooops, not enough memory for 1st string buffer\n");
464       return -CON_ENOMEM;
465     }
466
467   vc[vc_num]->sbuf2 = 0;
468   if (sbuf2_size > 0)
469     {
470       sprintf(name, "ipcbuf2 for "l4util_idfmt"",
471           l4util_idstr(*_dice_corba_obj));
472       if (sbuf2_size)
473         {
474           if (!(vc[vc_num]->sbuf2 =
475                 l4dm_mem_allocate_named(sbuf2_size, L4RM_MAP, name)))
476             {
477               printf("Ooops, not enough memory for 2nd string buffer\n");
478               l4dm_mem_release(vc[vc_num]->sbuf1);
479               return -CON_ENOMEM;
480             }
481         }
482     }
483
484   vc[vc_num]->sbuf3 = 0;
485   if (sbuf3_size > 0)
486     {
487       sprintf(name, "ipcbuf3 for "l4util_idfmt"",
488               l4util_idstr(*_dice_corba_obj));
489       if (sbuf3_size)
490         {
491           if (!(vc[vc_num]->sbuf3 =
492                 l4dm_mem_allocate_named(sbuf3_size, L4RM_MAP, name)))
493             {
494               printf("Ooops, not enough memory for 3rd string buffer\n");
495               l4dm_mem_release(vc[vc_num]->sbuf1);
496               l4dm_mem_release(vc[vc_num]->sbuf2);
497               return -CON_ENOMEM;
498             }
499         }
500     }
501
502   vc[vc_num]->fb              = 0;
503   vc[vc_num]->vfb             = 0;
504   vc[vc_num]->vfb_in_server   = vfbmode;
505   vc[vc_num]->mode            = CON_OPENING;
506   vc[vc_num]->vc_partner_l4id = *_dice_corba_obj;
507   vc[vc_num]->sbuf1_size      = sbuf1_size;
508   vc[vc_num]->sbuf2_size      = sbuf2_size;
509   vc[vc_num]->sbuf3_size      = sbuf3_size;
510   vc[vc_num]->fb_mapped       = 0;
511
512   if (vfbmode)
513     vc[vc_num]->save_restore  = 1;
514
515   sprintf(name, ".vc-%.2d", vc_num);
516   vc_tid = l4thread_create_long(L4THREAD_INVALID_ID,
517                                 (l4thread_fn_t) vc_loop, name,
518                                 L4THREAD_INVALID_SP, L4THREAD_DEFAULT_SIZE,
519                                 priority, (void *) vc[vc_num],
520                                 L4THREAD_CREATE_SYNC);
521
522   vc_l4id = l4thread_l4_id(vc_tid);
523
524   vc[vc_num]->vc_l4id         = vc_l4id;
525   vc[vc_num]->ev_partner_l4id = L4_INVALID_CAP;
526
527   // transfer ownership of ipc buffers to client thread
528   if (L4RM_REGION_DATASPACE == l4rm_lookup(vc[vc_num]->sbuf1, &ds_map_addr,
529                                            &ds_map_size, &ds, &ds_offs, &dummy))
530     l4dm_transfer(&ds, vc_l4id);
531   if (L4RM_REGION_DATASPACE == l4rm_lookup(vc[vc_num]->sbuf2, &ds_map_addr,
532                                            &ds_map_size, &ds, &ds_offs, &dummy))
533     l4dm_transfer(&ds, vc_l4id);
534   if (L4RM_REGION_DATASPACE == l4rm_lookup(vc[vc_num]->sbuf3, &ds_map_addr,
535                                            &ds_map_size, &ds, &ds_offs, &dummy))
536     l4dm_transfer(&ds, vc_l4id);
537
538   /* reply vc_thread id */
539   *vcid  = vc_l4id;
540
541   return 0;
542 }
543 #endif
544
545 /*static*/ int
546 vc_open(struct l4con_vc *vc, l4_uint8_t mode, l4_cap_idx_t ev_handler);
547
548 long
549 con_if_open_component(short vfbmode)
550 {
551   //l4thread_t vc_tid;
552   //l4_threadid_t vc_l4id, dummy;
553   //l4dm_dataspace_t ds;
554   //l4_addr_t ds_offs;
555   //l4_addr_t ds_map_addr;
556   //l4_size_t ds_map_size;
557   long r;
558   int vc_num;
559   //char name[32];
560
561   /* find first available (non-opened) vc in list */
562   if ((vc_num = get_free_vc()) == -CON_EFREE)
563     return vc_num;
564
565   vc[vc_num]->fb              = 0;
566   vc[vc_num]->vfb             = 0;
567   vc[vc_num]->vfb_in_server   = vfbmode;
568   vc[vc_num]->mode            = CON_OPENING;
569   //vc[vc_num]->vc_partner_l4id = *_dice_corba_obj;
570   //vc[vc_num]->sbuf1_size      = sbuf1_size;
571   //vc[vc_num]->sbuf2_size      = sbuf2_size;
572   //vc[vc_num]->sbuf3_size      = sbuf3_size;
573   vc[vc_num]->fb_mapped       = 0;
574
575   if (vfbmode)
576     vc[vc_num]->save_restore  = 1;
577
578 #if 0
579   sprintf(name, ".vc-%.2d", vc_num);
580   vc_tid = l4thread_create_long(L4THREAD_INVALID_ID,
581                                 (l4thread_fn_t) vc_loop, name,
582                                 L4THREAD_INVALID_SP, L4THREAD_DEFAULT_SIZE,
583                                 priority, (void *) vc[vc_num],
584                                 L4THREAD_CREATE_SYNC);
585
586   vc_l4id = l4thread_l4_id(vc_tid);
587
588   vc[vc_num]->vc_l4id         = vc_l4id;
589 #endif
590 //  vc[vc_num]->ev_partner_l4id = L4_INVALID_CAP;
591
592   //return vc_open(vc, mode & CON_INOUT, *ev_handler);
593
594   if ((r = vc_open(vc[vc_num], CON_INOUT, L4_INVALID_CAP)))
595     return r;
596
597   create_event(vc[vc_num]);
598
599   fill_out_info(vc[vc_num]);
600
601   return vc_num;
602 }
603
604 #ifdef FIXME
605 long
606 con_if_screenshot_component (CORBA_Object _dice_corba_obj,
607                              short vc_nr,
608                              l4dm_dataspace_t *ds,
609                              l4_uint32_t *xres,
610                              l4_uint32_t *yres,
611                              l4_uint32_t *bpp,
612                              CORBA_Server_Environment *_dice_corba_env)
613 {
614   void *addr;
615   struct l4con_vc *vc_shoot;
616
617   if (vc_nr >= MAX_NR_L4CONS)
618     return -L4_EINVAL;
619
620   if (vc_nr == 0)
621     vc_nr = fg_vc;
622
623   vc_shoot = vc[vc_nr];
624
625   if (!(vc_shoot->mode & CON_INOUT))
626     return -L4_EINVAL;
627
628   if (!vc_shoot->vfb_in_server && vc_nr != fg_vc)
629     return -L4_EINVAL;
630
631   pthread_mutex_lock(&vc_shoot->fb_lock);
632
633   if (!(addr = l4dm_mem_ds_allocate_named(vc_shoot->vfb_size, 0, "screenshot",
634                                           (l4dm_dataspace_t*)ds)))
635     {
636       printf("Allocating dataspace failed\n");
637       return -CON_ENOMEM;
638     }
639
640   /* XXX consider situations where
641    * bytes_per_line != bytes_per_pixel * xres !!! */
642   memcpy(addr, vc_shoot->vfb_in_server ? vc_shoot->vfb : vc_shoot->fb,
643          vc_shoot->vfb_size);
644
645   pthread_mutex_unlock(&vc_shoot->fb_lock);
646
647   *xres = fb_info.width;
648   *yres = fb_info.height;
649   *bpp  = fb_info.bits_per_pixel;
650
651   l4rm_detach(addr);
652
653   /* transfer ds to caller so that it can be freed again */
654   l4dm_transfer((l4dm_dataspace_t*)ds, *_dice_corba_obj);
655
656   return 0;
657 }
658 #endif
659
660 /** \brief Close all virtual consoles of a client
661  *
662  * in:  request       ... Flick request structure
663  *      client        ... id of client to close all vcs off
664  * out: _ev           ... Flick exception (unused)
665  * ret: 0             ... success
666  *      -???          ... if some error occured on closing a vc */
667 #ifdef FIXME
668 long
669 con_if_close_all_component (CORBA_Object _dice_corba_obj,
670                             const l4_threadid_t *client,
671                             CORBA_Server_Environment *_dice_corba_env)
672 {
673   int i;
674
675   for (i=0; i<MAX_NR_L4CONS; i++)
676     {
677       if (vc[i]->mode != CON_CLOSED && vc[i]->mode != CON_CLOSING)
678         {
679           /* don't use l4_task_equal here since we only know the task number */
680           if (vc[i]->vc_partner_l4id.id.task == client->id.task)
681             {
682               /* found console bound to client -- close it */
683               CORBA_Environment env = dice_default_environment;
684               int ret = con_vc_close_call(&(vc[i]->vc_l4id), &env);
685               if (ret || DICE_HAS_EXCEPTION(&env))
686                 printf("Error %d (env=%02x) closing app "l4util_idfmt
687                        " service thread "l4util_idfmt,
688                     ret, DICE_IPC_ERROR(&env), l4util_idstr(*client),
689                     l4util_idstr(vc[i]->vc_l4id));
690             }
691         }
692     }
693
694   return 0;
695 }
696 #endif
697
698 void
699 periodic_work(void)
700 {
701   static l4_kernel_clock_t last_active_fast;
702   static l4_kernel_clock_t last_active_slow;
703   l4_kernel_clock_t clock = l4re_kip()->clock;
704
705   if (clock - last_active_fast >= 25000)
706     {
707       // switch to another console?
708       pthread_mutex_lock(&want_vc_lock);
709       if (want_vc != fg_vc)
710         switch_vc();
711       pthread_mutex_unlock(&want_vc_lock);
712
713       // update status bar
714       if (update_id && fg_vc >= 0)
715         {
716           pthread_mutex_lock(&vc[fg_vc]->fb_lock);
717           vc_show_id(vc[fg_vc]);
718           pthread_mutex_unlock(&vc[fg_vc]->fb_lock);
719           update_id = 0;
720           // force updating load indicator
721           last_active_slow = clock - 1000000;
722         }
723
724       // update DROPS logo
725       if (vc[fg_vc]->logo_x != 100000)
726         {
727           pthread_mutex_lock(&vc[fg_vc]->fb_lock);
728           vc_show_drops_cscs_logo();
729           pthread_mutex_unlock(&vc[fg_vc]->fb_lock);
730         }
731
732       last_active_fast = clock;
733     }
734
735   if (clock - last_active_slow >= 1000000)
736     {
737       pthread_mutex_lock(&vc[fg_vc]->fb_lock);
738
739       // update memory information
740       vc_show_dmphys_poolsize(vc[fg_vc]);
741
742       if (cpu_load)
743         // update load indicator
744         vc_show_cpu_load(vc[fg_vc]);
745
746       pthread_mutex_unlock(&vc[fg_vc]->fb_lock);
747       last_active_slow = clock;
748     }
749 }
750
751
752 #ifdef ARCH_x86
753 #if 0
754 static int sse_faulted;
755
756 static int
757 rm_fault_sse(l4_msgtag_t tag, l4_utcb_t *utcb, l4_cap_idx_t src)
758 {
759   extern char after_sse_insn[];
760   sse_faulted = 1;
761   utcb->exc.eip = (l4_umword_t)after_sse_insn;
762   return L4RM_REPLY_EMPTY;
763 }
764 #endif
765 #endif // ARCH_x86
766
767 static void
768 check_fast_memcpy(void)
769 {
770 #if defined(ARCH_x86) || defined(ARCH_amd64)
771   if (use_fastmemcpy)
772     {
773       /* assume AMD64 has SSE */
774 # ifdef ARCH_x86
775       l4_uint64_t src, dst;
776 #warning Restore exception handler hook!!!
777       //l4rm_set_unkown_fault_callback(rm_fault_sse);
778       asm volatile("emms; movq (%0),%%mm0; movntq %%mm0,(%1); sfence; emms"
779                    : : "r"(&src), "r"(&dst) , "m"(src) : "memory");
780       asm volatile(".global after_sse_insn; after_sse_insn:" ::: "memory");
781       //l4rm_set_unkown_fault_callback(NULL);
782       if (1) //!sse_faulted)
783         {
784 # endif
785           printf("Using fast memcpy.\n");
786 # ifdef ARCH_x86
787         }
788       else
789         {
790           printf("Fast memcpy not supported by this CPU.\n");
791           use_fastmemcpy = 0;
792         }
793 # endif
794       return;
795     }
796 #else
797   use_fastmemcpy = 0;
798 #endif
799   printf("Not using fast memcpy\n");
800 }
801
802 #if defined(ARCH_x86) || defined(ARCH_amd64)
803 #if 0
804 static int rdpmc_faulted;
805
806 static int
807 rm_fault_rdpmc(l4_msgtag_t tag, l4_utcb_t *utcb, l4_cap_idx_t src)
808 {
809   extern char after_rdpmc_insn[];
810   if (*(l4_uint16_t *)utcb->exc.eip != 0x330f) // sanity check
811     {
812       printf("Not faulted at rdpmc function (pc = %lx)", utcb->exc.eip);
813       return L4RM_REPLY_NO_REPLY;
814     }
815   utcb->exc.eip = (l4_umword_t)after_rdpmc_insn;
816   rdpmc_faulted = 1;
817   return L4RM_REPLY_EMPTY;
818 }
819 #endif
820
821 static void
822 check_cpuload(void)
823 {
824   if (cpu_load)
825     {
826 #warning restore exception handler hook (PMC)!!!
827      // l4rm_set_unkown_fault_callback(rm_fault_rdpmc);
828       asm volatile("" ::: "memory");
829       l4_rdpmc_32(0);
830       asm volatile(".global after_rdpmc_insn; after_rdpmc_insn:" ::: "memory");
831       //l4rm_set_unkown_fault_callback(NULL);
832       if (1) //!rdpmc_faulted)
833         {
834           printf("Enabling CPU load indicator\n"
835                  "\033[32mALTGR+PAUSE switches CPU load indicator!\033[m\n");
836         }
837       else
838         {
839           printf("Disabling CPU load indicator since rdpmc not available\n");
840           cpu_load = 0;
841         }
842     }
843 }
844 #else
845 static void
846 check_cpuload(void)
847 {
848   cpu_load = 0;
849 }
850 #endif
851
852 #if 0
853 extern int console_puts(const char *s);
854 static void
855 my_LOG_outstring(const char *s)
856 {
857   console_puts(s);
858 }
859 #endif
860
861 /* Make sure that the jiffies symbol is taken from libio.a not libinput.a. */
862 asm (".globl jiffies");
863
864 /** \brief Main function
865  */
866 int
867 main(int argc, const char *argv[])
868 {
869   int error;
870   int use_events = 0;
871
872 #ifdef ARCH_arm
873   noaccel = 1;
874 #endif
875
876   if ((error = parse_cmdline(&argc, &argv,
877                     'a', "noaccel", "disable hardware acceleration",
878                     PARSE_CMD_SWITCH, 1, &noaccel,
879 #ifndef ARCH_arm
880                     'c', "cpuload", "show CPU load using rdtsc and rdpmc(0)",
881                     PARSE_CMD_SWITCH, 1, &cpu_load,
882 #endif
883                     'e', "events", "use event server to free resources",
884                     PARSE_CMD_SWITCH, 1, &use_events,
885                     'l', "nolog", "don't connect to logserver",
886                     PARSE_CMD_SWITCH, 1, &nolog,
887                     'm', "nomouse", "don't transmit mouse events to clients",
888                     PARSE_CMD_SWITCH, 1, &nomouse,
889                     'b', "genabsevents", "generate absolute mouse events out of relatives",
890                     PARSE_CMD_SWITCH, 1, &gen_abs_events,
891                     'n', "nofastmemcpy", "force to not use fast memcpy",
892                     PARSE_CMD_SWITCH, 0, &use_fastmemcpy,
893                     'p', "pan", "use panning to restrict client window",
894                     PARSE_CMD_SWITCH, 1, &pan,
895                     ' ', "noshift", "no shift key for console switching",
896                     PARSE_CMD_SWITCH, 1, &noshift,
897                     'v', "vbemode", "set VESA mode",
898                     PARSE_CMD_INT, 0, &vbemode,
899                     0)))
900     {
901       switch (error)
902         {
903         case -1: printf("Bad parameter for parse_cmdline()\n"); break;
904         case -2: printf("Out of memory in parse_cmdline()\n"); break;
905         case -4: return 1;
906         default: printf("Error %d in parse_cmdline()\n", error); break;
907         }
908     }
909
910   cpu_load_history = 1;
911
912   /* do not use logserver (in case the log goes to a console) */
913 #ifdef FIXME
914   if (nolog)
915     LOG_outstring = my_LOG_outstring;
916 #endif
917
918   /* check if CPU supports fast memcpy */
919   check_fast_memcpy();
920   check_cpuload();
921
922   vc_init();
923
924   /* switch to master console: initial screen output (DROPS logo) */
925   do_switch(0, -1);
926   vc_show_id(vc[0]);
927   fg_vc = want_vc = 0;
928   update_id = 0;
929
930   ev_init();
931
932   /* start thread listening for exit events */
933   //if (use_events)
934   //  init_events();
935
936   printf("Running. Video mode is %ldx%ld@%d.\n",
937          fb_info.width, fb_info.height,
938          l4re_video_bits_per_pixel(&fb_info.pixel_info));
939
940   /* idl service loop */
941   return server_loop();
942 }