Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / biosemu / vbe.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include <stdint.h>
18 #include <cpu.h>
19
20 #include "debug.h"
21
22 #include <x86emu/x86emu.h>
23 #include <x86emu/regs.h>
24 #include <x86emu/prim_ops.h>    // for push_word
25
26 #include "biosemu.h"
27 #include "io.h"
28 #include "mem.h"
29 #include "interrupt.h"
30 #include "device.h"
31 #include "vbe.h"
32
33 static X86EMU_memFuncs my_mem_funcs = {
34         my_rdb, my_rdw, my_rdl,
35         my_wrb, my_wrw, my_wrl
36 };
37
38 static X86EMU_pioFuncs my_pio_funcs = {
39         my_inb, my_inw, my_inl,
40         my_outb, my_outw, my_outl
41 };
42
43 // pointer to VBEInfoBuffer, set by vbe_prepare
44 uint8_t *vbe_info_buffer = 0;
45 // virtual BIOS Memory
46 uint8_t *biosmem;
47 uint32_t biosmem_size;
48
49 // these structs are for input from and output to OF
50 typedef struct {
51         uint8_t display_type;   // 0=NONE, 1= analog, 2=digital
52         uint16_t screen_width;
53         uint16_t screen_height;
54         uint16_t screen_linebytes;      // bytes per line in framebuffer, may be more than screen_width
55         uint8_t color_depth;    // color depth in bpp
56         uint32_t framebuffer_address;
57         uint8_t edid_block_zero[128];
58 } __attribute__ ((__packed__)) screen_info_t;
59
60 typedef struct {
61         uint8_t signature[4];
62         uint16_t size_reserved;
63         uint8_t monitor_number;
64         uint16_t max_screen_width;
65         uint8_t color_depth;
66 } __attribute__ ((__packed__)) screen_info_input_t;
67
68 // these structs only store a subset of the VBE defined fields
69 // only those needed.
70 typedef struct {
71         char signature[4];
72         uint16_t version;
73         uint8_t *oem_string_ptr;
74         uint32_t capabilities;
75         uint16_t video_mode_list[256];  // lets hope we never have more than 256 video modes...
76         uint16_t total_memory;
77 } vbe_info_t;
78
79 typedef struct {
80         uint16_t video_mode;
81         uint8_t mode_info_block[256];
82         uint16_t attributes;
83         uint16_t linebytes;
84         uint16_t x_resolution;
85         uint16_t y_resolution;
86         uint8_t x_charsize;
87         uint8_t y_charsize;
88         uint8_t bits_per_pixel;
89         uint8_t memory_model;
90         uint32_t framebuffer_address;
91 } vbe_mode_info_t;
92
93 typedef struct {
94         uint8_t port_number;    // i.e. monitor number
95         uint8_t edid_transfer_time;
96         uint8_t ddc_level;
97         uint8_t edid_block_zero[128];
98 } vbe_ddc_info_t;
99
100 static inline uint8_t
101 vbe_prepare(void)
102 {
103         vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
104         //clear buffer
105         memset(vbe_info_buffer, 0, 512);
106         //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
107         vbe_info_buffer[0] = 'V';
108         vbe_info_buffer[0] = 'B';
109         vbe_info_buffer[0] = 'E';
110         vbe_info_buffer[0] = '2';
111         // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
112         M.x86.R_EDI = 0x0;
113         M.x86.R_ES = VBE_SEGMENT;
114
115         return 0;               // successful init
116 }
117
118 // VBE Function 00h
119 static uint8_t
120 vbe_info(vbe_info_t * info)
121 {
122         vbe_prepare();
123         // call VBE function 00h (Info Function)
124         M.x86.R_EAX = 0x4f00;
125
126         // enable trace
127         CHECK_DBG(DEBUG_TRACE_X86EMU) {
128                 X86EMU_trace_on();
129         }
130         // run VESA Interrupt
131         runInt10();
132
133         if (M.x86.R_AL != 0x4f) {
134                 DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
135                                  __FUNCTION__, M.x86.R_AL);
136                 return -1;
137         }
138
139         if (M.x86.R_AH != 0x0) {
140                 DEBUG_PRINTF_VBE
141                     ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
142                      __FUNCTION__, M.x86.R_AH);
143                 return M.x86.R_AH;
144         }
145         //printf("VBE Info Dump:");
146         //dump(vbe_info_buffer, 64);
147
148         //offset 0: signature
149         info->signature[0] = vbe_info_buffer[0];
150         info->signature[1] = vbe_info_buffer[1];
151         info->signature[2] = vbe_info_buffer[2];
152         info->signature[3] = vbe_info_buffer[3];
153
154         // offset 4: 16bit le containing VbeVersion
155         info->version = in16le(vbe_info_buffer + 4);
156
157         // offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
158         info->oem_string_ptr =
159             biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
160                        in16le(vbe_info_buffer + 6));
161
162         // offset 10: 32bit le capabilities
163         info->capabilities = in32le(vbe_info_buffer + 10);
164
165         // offset 14: 32 bit le containing segment:offset of supported video mode table
166         uint16_t *video_mode_ptr;
167         video_mode_ptr =
168             (uint16_t *) (biosmem +
169                           ((in16le(vbe_info_buffer + 16) << 4) +
170                            in16le(vbe_info_buffer + 14)));
171         uint32_t i = 0;
172         do {
173                 info->video_mode_list[i] = in16le(video_mode_ptr + i);
174                 i++;
175         }
176         while ((i <
177                 (sizeof(info->video_mode_list) /
178                  sizeof(info->video_mode_list[0])))
179                && (info->video_mode_list[i - 1] != 0xFFFF));
180
181         //offset 18: 16bit le total memory in 64KB blocks
182         info->total_memory = in16le(vbe_info_buffer + 18);
183
184         return 0;
185 }
186
187 // VBE Function 01h
188 static uint8_t
189 vbe_get_mode_info(vbe_mode_info_t * mode_info)
190 {
191         vbe_prepare();
192         // call VBE function 01h (Return VBE Mode Info Function)
193         M.x86.R_EAX = 0x4f01;
194         M.x86.R_CX = mode_info->video_mode;
195
196         // enable trace
197         CHECK_DBG(DEBUG_TRACE_X86EMU) {
198                 X86EMU_trace_on();
199         }
200         // run VESA Interrupt
201         runInt10();
202
203         if (M.x86.R_AL != 0x4f) {
204                 DEBUG_PRINTF_VBE
205                     ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
206                      __FUNCTION__, M.x86.R_AL);
207                 return -1;
208         }
209
210         if (M.x86.R_AH != 0x0) {
211                 DEBUG_PRINTF_VBE
212                     ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
213                      __FUNCTION__, mode_info->video_mode, M.x86.R_AH);
214                 return M.x86.R_AH;
215         }
216         //pointer to mode_info_block is in ES:DI
217         memcpy(mode_info->mode_info_block,
218                biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
219                sizeof(mode_info->mode_info_block));
220
221         //printf("Mode Info Dump:");
222         //dump(mode_info_block, 64);
223
224         // offset 0: 16bit le mode attributes
225         mode_info->attributes = in16le(mode_info->mode_info_block);
226
227         // offset 16: 16bit le bytes per scan line
228         mode_info->linebytes = in16le(mode_info->mode_info_block + 16);
229
230         // offset 18: 16bit le x resolution
231         mode_info->x_resolution = in16le(mode_info->mode_info_block + 18);
232
233         // offset 20: 16bit le y resolution
234         mode_info->y_resolution = in16le(mode_info->mode_info_block + 20);
235
236         // offset 22: 8bit le x charsize
237         mode_info->x_charsize = *(mode_info->mode_info_block + 22);
238
239         // offset 23: 8bit le y charsize
240         mode_info->y_charsize = *(mode_info->mode_info_block + 23);
241
242         // offset 25: 8bit le bits per pixel
243         mode_info->bits_per_pixel = *(mode_info->mode_info_block + 25);
244
245         // offset 27: 8bit le memory model
246         mode_info->memory_model = *(mode_info->mode_info_block + 27);
247
248         // offset 40: 32bit le containg offset of frame buffer memory ptr
249         mode_info->framebuffer_address =
250             in32le(mode_info->mode_info_block + 40);
251
252         return 0;
253 }
254
255 // VBE Function 02h
256 static uint8_t
257 vbe_set_mode(vbe_mode_info_t * mode_info)
258 {
259         vbe_prepare();
260         // call VBE function 02h (Set VBE Mode Function)
261         M.x86.R_EAX = 0x4f02;
262         M.x86.R_BX = mode_info->video_mode;
263         M.x86.R_BX |= 0x4000;   // set bit 14 to request linear framebuffer mode
264         M.x86.R_BX &= 0x7FFF;   // clear bit 15 to request clearing of framebuffer
265
266         DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __FUNCTION__,
267                          M.x86.R_BX);
268
269         // enable trace
270         CHECK_DBG(DEBUG_TRACE_X86EMU) {
271                 X86EMU_trace_on();
272         }
273         // run VESA Interrupt
274         runInt10();
275
276         if (M.x86.R_AL != 0x4f) {
277                 DEBUG_PRINTF_VBE
278                     ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
279                      __FUNCTION__, M.x86.R_AL);
280                 return -1;
281         }
282
283         if (M.x86.R_AH != 0x0) {
284                 DEBUG_PRINTF_VBE
285                     ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
286                      __FUNCTION__, mode_info->video_mode, M.x86.R_AH);
287                 return M.x86.R_AH;
288         }
289         return 0;
290 }
291
292 //VBE Function 08h
293 static uint8_t
294 vbe_set_palette_format(uint8_t format)
295 {
296         vbe_prepare();
297         // call VBE function 09h (Set/Get Palette Data Function)
298         M.x86.R_EAX = 0x4f08;
299         M.x86.R_BL = 0x00;      // set format
300         M.x86.R_BH = format;
301
302         DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __FUNCTION__,
303                          format);
304
305         // enable trace
306         CHECK_DBG(DEBUG_TRACE_X86EMU) {
307                 X86EMU_trace_on();
308         }
309         // run VESA Interrupt
310         runInt10();
311
312         if (M.x86.R_AL != 0x4f) {
313                 DEBUG_PRINTF_VBE
314                     ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
315                      __FUNCTION__, M.x86.R_AL);
316                 return -1;
317         }
318
319         if (M.x86.R_AH != 0x0) {
320                 DEBUG_PRINTF_VBE
321                     ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
322                      __FUNCTION__, M.x86.R_AH);
323                 return M.x86.R_AH;
324         }
325         return 0;
326 }
327
328 // VBE Function 09h
329 static uint8_t
330 vbe_set_color(uint16_t color_number, uint32_t color_value)
331 {
332         vbe_prepare();
333         // call VBE function 09h (Set/Get Palette Data Function)
334         M.x86.R_EAX = 0x4f09;
335         M.x86.R_BL = 0x00;      // set color
336         M.x86.R_CX = 0x01;      // set only one entry
337         M.x86.R_DX = color_number;
338         // ES:DI is address where color_value is stored, we store it at 2000:0000
339         M.x86.R_ES = 0x2000;
340         M.x86.R_DI = 0x0;
341
342         // store color value at ES:DI
343         out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
344
345         DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __FUNCTION__,
346                          color_number, color_value);
347
348         // enable trace
349         CHECK_DBG(DEBUG_TRACE_X86EMU) {
350                 X86EMU_trace_on();
351         }
352         // run VESA Interrupt
353         runInt10();
354
355         if (M.x86.R_AL != 0x4f) {
356                 DEBUG_PRINTF_VBE
357                     ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
358                      __FUNCTION__, M.x86.R_AL);
359                 return -1;
360         }
361
362         if (M.x86.R_AH != 0x0) {
363                 DEBUG_PRINTF_VBE
364                     ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
365                      __FUNCTION__, M.x86.R_AH);
366                 return M.x86.R_AH;
367         }
368         return 0;
369 }
370
371 #if 0
372 static uint8_t
373 vbe_get_color(uint16_t color_number, uint32_t * color_value)
374 {
375         vbe_prepare();
376         // call VBE function 09h (Set/Get Palette Data Function)
377         M.x86.R_EAX = 0x4f09;
378         M.x86.R_BL = 0x00;      // get color
379         M.x86.R_CX = 0x01;      // get only one entry
380         M.x86.R_DX = color_number;
381         // ES:DI is address where color_value is stored, we store it at 2000:0000
382         M.x86.R_ES = 0x2000;
383         M.x86.R_DI = 0x0;
384
385         // enable trace
386         CHECK_DBG(DEBUG_TRACE_X86EMU) {
387                 X86EMU_trace_on();
388         }
389         // run VESA Interrupt
390         runInt10();
391
392         if (M.x86.R_AL != 0x4f) {
393                 DEBUG_PRINTF_VBE
394                     ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
395                      __FUNCTION__, M.x86.R_AL);
396                 return -1;
397         }
398
399         if (M.x86.R_AH != 0x0) {
400                 DEBUG_PRINTF_VBE
401                     ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
402                      __FUNCTION__, M.x86.R_AH);
403                 return M.x86.R_AH;
404         }
405         // read color value from ES:DI
406         *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
407
408         DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __FUNCTION__,
409                          color_number, *color_value);
410
411         return 0;
412 }
413 #endif
414
415 // VBE Function 15h
416 static uint8_t
417 vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
418 {
419         vbe_prepare();
420         // call VBE function 15h (DDC Info Function)
421         M.x86.R_EAX = 0x4f15;
422         M.x86.R_BL = 0x00;      // get DDC Info
423         M.x86.R_CX = ddc_info->port_number;
424         M.x86.R_ES = 0x0;
425         M.x86.R_DI = 0x0;
426
427         // enable trace
428         CHECK_DBG(DEBUG_TRACE_X86EMU) {
429                 X86EMU_trace_on();
430         }
431         // run VESA Interrupt
432         runInt10();
433
434         if (M.x86.R_AL != 0x4f) {
435                 DEBUG_PRINTF_VBE
436                     ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
437                      __FUNCTION__, M.x86.R_AL);
438                 return -1;
439         }
440
441         if (M.x86.R_AH != 0x0) {
442                 DEBUG_PRINTF_VBE
443                     ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
444                      __FUNCTION__, ddc_info->port_number, M.x86.R_AH);
445                 return M.x86.R_AH;
446         }
447         // BH = approx. time in seconds to transfer one EDID block
448         ddc_info->edid_transfer_time = M.x86.R_BH;
449         // BL = DDC Level
450         ddc_info->ddc_level = M.x86.R_BL;
451
452         vbe_prepare();
453         // call VBE function 15h (DDC Info Function)
454         M.x86.R_EAX = 0x4f15;
455         M.x86.R_BL = 0x01;      // read EDID
456         M.x86.R_CX = ddc_info->port_number;
457         M.x86.R_DX = 0x0;       // block number
458         // ES:DI is address where EDID is stored, we store it at 2000:0000
459         M.x86.R_ES = 0x2000;
460         M.x86.R_DI = 0x0;
461
462         // enable trace
463         CHECK_DBG(DEBUG_TRACE_X86EMU) {
464                 X86EMU_trace_on();
465         }
466         // run VESA Interrupt
467         runInt10();
468
469         if (M.x86.R_AL != 0x4f) {
470                 DEBUG_PRINTF_VBE
471                     ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
472                      __FUNCTION__, M.x86.R_AL);
473                 return -1;
474         }
475
476         if (M.x86.R_AH != 0x0) {
477                 DEBUG_PRINTF_VBE
478                     ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
479                      __FUNCTION__, ddc_info->port_number, M.x86.R_AH);
480                 return M.x86.R_AH;
481         }
482
483         memcpy(ddc_info->edid_block_zero,
484                biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
485                sizeof(ddc_info->edid_block_zero));
486
487         return 0;
488 }
489
490 uint32_t
491 vbe_get_info(uint8_t argc, char ** argv)
492 {
493         uint8_t rval;
494         static const uint8_t valid_edid_sig[] = {
495                 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
496         };
497         uint32_t i;
498
499         if (argc < 4) {
500                 printf
501                     ("Usage %s <vmem_base> <device_path> <address of screen_info_t>\n",
502                      argv[0]);
503                 int i = 0;
504                 for (i = 0; i < argc; i++) {
505                         printf("argv[%d]: %s\n", i, argv[i]);
506                 }
507                 return -1;
508         }
509         // get a copy of input struct...
510         screen_info_input_t input =
511             *((screen_info_input_t *) strtoul((char *) argv[4], 0, 16));
512         // output is pointer to the address passed as argv[4]
513         screen_info_t *output =
514             (screen_info_t *) strtoul((char *) argv[4], 0, 16);
515         // zero output
516         memset(output, 0, sizeof(screen_info_t));
517
518         // argv[1] is address of virtual BIOS mem...
519         // argv[2] is the size
520         biosmem = (uint8_t *) strtoul(argv[1], 0, 16);
521         biosmem_size = strtoul(argv[2], 0, 16);;
522         if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) {
523                 printf("Error: Not enough virtual memory: %x, required: %x!\n",
524                        biosmem_size, MIN_REQUIRED_VMEM_SIZE);
525                 return -1;
526         }
527         // argv[3] is the device to open and use...
528         if (dev_init((char *) argv[3]) != 0) {
529                 printf("Error initializing device!\n");
530                 return -1;
531         }
532         //setup interrupt handler
533         X86EMU_intrFuncs intrFuncs[256];
534         for (i = 0; i < 256; i++)
535                 intrFuncs[i] = handleInterrupt;
536         X86EMU_setupIntrFuncs(intrFuncs);
537         X86EMU_setupPioFuncs(&my_pio_funcs);
538         X86EMU_setupMemFuncs(&my_mem_funcs);
539
540         // set mem_base
541         M.mem_base = (long) biosmem;
542         M.mem_size = biosmem_size;
543         DEBUG_PRINTF_VBE("membase set: %08x, size: %08x\n", (int) M.mem_base,
544                          (int) M.mem_size);
545
546         vbe_info_t info;
547         rval = vbe_info(&info);
548         if (rval != 0)
549                 return rval;
550
551         DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
552         DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
553         DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
554         DEBUG_PRINTF_VBE("Capabilities:\n");
555         DEBUG_PRINTF_VBE("\tDAC: %s\n",
556                          (info.capabilities & 0x1) ==
557                          0 ? "fixed 6bit" : "switchable 6/8bit");
558         DEBUG_PRINTF_VBE("\tVGA: %s\n",
559                          (info.capabilities & 0x2) ==
560                          0 ? "compatible" : "not compatible");
561         DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
562                          (info.capabilities & 0x4) ==
563                          0 ? "normal" : "use blank bit in Function 09h");
564
565         // argv[4] may be a pointer with enough space to return screen_info_t
566         // as input, it must contain a screen_info_input_t with the following content:
567         // byte[0:3] = "DDC\0" (zero-terminated signature header)
568         // byte[4:5] = reserved space for the return struct... just in case we ever change
569         //             the struct and dont have reserved enough memory (and let's hope the struct
570         //             never gets larger than 64KB)
571         // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
572         // byte[7:8] = max. screen width (OF may want to limit this)
573         // byte[9] = required color depth in bpp
574         if (strncmp((char *) input.signature, "DDC", 4) != 0) {
575                 printf
576                     ("%s: Invalid input signature! expected: %s, is: %s\n",
577                      __FUNCTION__, "DDC", input.signature);
578                 return -1;
579         }
580         if (input.size_reserved != sizeof(screen_info_t)) {
581                 printf
582                     ("%s: Size of return struct is wrong, required: %d, available: %d\n",
583                      __FUNCTION__, (int) sizeof(screen_info_t),
584                      input.size_reserved);
585                 return -1;
586         }
587
588         vbe_ddc_info_t ddc_info;
589         ddc_info.port_number = input.monitor_number;
590         vbe_get_ddc_info(&ddc_info);
591
592 #if 0
593         DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
594                          ddc_info.edid_transfer_time);
595         DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
596         DEBUG_PRINTF_VBE("DDC: EDID: \n");
597         CHECK_DBG(DEBUG_VBE) {
598                 dump(ddc_info.edid_block_zero,
599                      sizeof(ddc_info.edid_block_zero));
600         }
601 #endif
602         if (memcmp(ddc_info.edid_block_zero, valid_edid_sig, 8) != 0) {
603                 // invalid EDID signature... probably no monitor
604                 output->display_type = 0x0;
605                 return 0;
606         } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
607                 // digital display
608                 output->display_type = 2;
609         } else {
610                 // analog
611                 output->display_type = 1;
612         }
613         DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
614         memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
615                sizeof(ddc_info.edid_block_zero));
616         i = 0;
617         vbe_mode_info_t mode_info;
618         vbe_mode_info_t best_mode_info;
619         // initialize best_mode to 0
620         memset(&best_mode_info, 0, sizeof(best_mode_info));
621         while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
622                 //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
623                 vbe_get_mode_info(&mode_info);
624 #if 0
625                 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
626                                  mode_info.video_mode,
627                                  (mode_info.attributes & 0x1) ==
628                                  0 ? "not supported" : "supported");
629                 DEBUG_PRINTF_VBE("\tTTY: %s\n",
630                                  (mode_info.attributes & 0x4) ==
631                                  0 ? "no" : "yes");
632                 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
633                                  (mode_info.attributes & 0x8) ==
634                                  0 ? "monochrome" : "color",
635                                  (mode_info.attributes & 0x10) ==
636                                  0 ? "text" : "graphics");
637                 DEBUG_PRINTF_VBE("\tVGA: %s\n",
638                                  (mode_info.attributes & 0x20) ==
639                                  0 ? "compatible" : "not compatible");
640                 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
641                                  (mode_info.attributes & 0x40) ==
642                                  0 ? "yes" : "no");
643                 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
644                                  (mode_info.attributes & 0x80) ==
645                                  0 ? "no" : "yes");
646                 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
647                                  mode_info.x_resolution,
648                                  mode_info.y_resolution);
649                 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
650                                  mode_info.x_charsize, mode_info.y_charsize);
651                 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
652                                  mode_info.bits_per_pixel);
653                 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
654                                  mode_info.memory_model);
655                 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
656                                  mode_info.framebuffer_address);
657 #endif
658                 if ((mode_info.bits_per_pixel == input.color_depth)
659                     && (mode_info.x_resolution <= input.max_screen_width)
660                     && ((mode_info.attributes & 0x80) != 0)     // framebuffer mode
661                     && ((mode_info.attributes & 0x10) != 0)     // graphics
662                     && ((mode_info.attributes & 0x8) != 0)      // color
663                     && (mode_info.x_resolution > best_mode_info.x_resolution))  // better than previous best_mode
664                 {
665                         // yiiiihaah... we found a new best mode
666                         memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
667                 }
668                 i++;
669         }
670
671         if (best_mode_info.video_mode != 0) {
672                 DEBUG_PRINTF_VBE
673                     ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
674                      best_mode_info.video_mode,
675                      best_mode_info.x_resolution,
676                      best_mode_info.y_resolution,
677                      best_mode_info.bits_per_pixel,
678                      best_mode_info.framebuffer_address);
679
680                 //printf("Mode Info Dump:");
681                 //dump(best_mode_info.mode_info_block, 64);
682
683                 // set the video mode
684                 vbe_set_mode(&best_mode_info);
685
686                 if ((info.capabilities & 0x1) != 0) {
687                         // switch to 8 bit palette format
688                         vbe_set_palette_format(8);
689                 }
690                 // setup a palette:
691                 // - first 216 colors are mixed colors for each component in 6 steps
692                 //   (6*6*6=216)
693                 // - then 10 shades of the three primary colors
694                 // - then 10 shades of grey
695                 // -------
696                 // = 256 colors
697                 //
698                 // - finally black is color 0 and white color FF (because SLOF expects it
699                 //   this way...)
700                 // this resembles the palette that the kernel/X Server seems to expect...
701
702                 uint8_t mixed_color_values[6] =
703                     { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
704                 uint8_t primary_color_values[10] =
705                     { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
706                         0x27
707                 };
708                 uint8_t mc_size = sizeof(mixed_color_values);
709                 uint8_t prim_size = sizeof(primary_color_values);
710
711                 uint8_t curr_color_index;
712                 uint32_t curr_color;
713
714                 uint8_t r, g, b;
715                 // 216 mixed colors
716                 for (r = 0; r < mc_size; r++) {
717                         for (g = 0; g < mc_size; g++) {
718                                 for (b = 0; b < mc_size; b++) {
719                                         curr_color_index =
720                                             (r * mc_size * mc_size) +
721                                             (g * mc_size) + b;
722                                         curr_color = 0;
723                                         curr_color |= ((uint32_t) mixed_color_values[r]) << 16; //red value
724                                         curr_color |= ((uint32_t) mixed_color_values[g]) << 8;  //green value
725                                         curr_color |= (uint32_t) mixed_color_values[b]; //blue value
726                                         vbe_set_color(curr_color_index,
727                                                       curr_color);
728                                 }
729                         }
730                 }
731
732                 // 10 shades of each primary color
733                 // red
734                 for (r = 0; r < prim_size; r++) {
735                         curr_color_index = mc_size * mc_size * mc_size + r;
736                         curr_color = ((uint32_t) primary_color_values[r]) << 16;
737                         vbe_set_color(curr_color_index, curr_color);
738                 }
739                 //green
740                 for (g = 0; g < prim_size; g++) {
741                         curr_color_index =
742                             mc_size * mc_size * mc_size + prim_size + g;
743                         curr_color = ((uint32_t) primary_color_values[g]) << 8;
744                         vbe_set_color(curr_color_index, curr_color);
745                 }
746                 //blue
747                 for (b = 0; b < prim_size; b++) {
748                         curr_color_index =
749                             mc_size * mc_size * mc_size + prim_size * 2 + b;
750                         curr_color = (uint32_t) primary_color_values[b];
751                         vbe_set_color(curr_color_index, curr_color);
752                 }
753                 // 10 shades of grey
754                 for (i = 0; i < prim_size; i++) {
755                         curr_color_index =
756                             mc_size * mc_size * mc_size + prim_size * 3 + i;
757                         curr_color = 0;
758                         curr_color |= ((uint32_t) primary_color_values[i]) << 16;       //red
759                         curr_color |= ((uint32_t) primary_color_values[i]) << 8;        //green
760                         curr_color |= ((uint32_t) primary_color_values[i]);     //blue
761                         vbe_set_color(curr_color_index, curr_color);
762                 }
763
764                 // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
765                 vbe_set_color(0x00, 0x00000000);
766                 vbe_set_color(0xFF, 0x00FFFFFF);
767
768                 output->screen_width = best_mode_info.x_resolution;
769                 output->screen_height = best_mode_info.y_resolution;
770                 output->screen_linebytes = best_mode_info.linebytes;
771                 output->color_depth = best_mode_info.bits_per_pixel;
772                 output->framebuffer_address =
773                     best_mode_info.framebuffer_address;
774         } else {
775                 printf("%s: No suitable video mode found!\n", __FUNCTION__);
776                 //unset display_type...
777                 output->display_type = 0;
778         }
779         return 0;
780 }