coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
vbe.c
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
4  *
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer
16  * in the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Contributors:
32  * IBM Corporation - initial implementation
33  *****************************************************************************/
34 
35 #include <boot/coreboot_tables.h>
36 #include <framebuffer_info.h>
37 #include <string.h>
38 #include <types.h>
39 
40 #include <endian.h>
41 
42 #include "debug.h"
43 
44 #include <x86emu/x86emu.h>
45 #include <x86emu/regs.h>
46 #include "../x86emu/prim_ops.h"
47 
48 #include "biosemu.h"
49 #include "io.h"
50 #include "mem.h"
51 #include "interrupt.h"
52 #include "device.h"
53 
54 #include <delay.h>
55 
56 #include <vbe.h>
57 
58 // these structs only store a subset of the VBE defined fields
59 // only those needed.
60 typedef struct {
61  char signature[4];
65  u16 video_mode_list[256]; // lets hope we never have more than
66  // 256 video modes...
68 } vbe_info_t;
69 
70 // pointer to VBEInfoBuffer, set by vbe_prepare
72 
73 // virtual BIOS Memory
76 
77 #if CONFIG(FRAMEBUFFER_SET_VESA_MODE)
78 static inline u8
79 vbe_prepare(void)
80 {
81  vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
82  //clear buffer
83  memset(vbe_info_buffer, 0, 512);
84  //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
85  vbe_info_buffer[0] = 'V';
86  vbe_info_buffer[1] = 'B';
87  vbe_info_buffer[2] = 'E';
88  vbe_info_buffer[3] = '2';
89  // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
90  M.x86.R_EDI = 0x0;
91  M.x86.R_ES = VBE_SEGMENT;
92 
93  return 0; // successful init
94 }
95 
96 // VBE Function 00h
97 static u8
98 vbe_info(vbe_info_t * info)
99 {
100  vbe_prepare();
101  // call VBE function 00h (Info Function)
102  M.x86.R_EAX = 0x4f00;
103 
104  // enable trace
106  X86EMU_trace_on();
107  }
108  // run VESA Interrupt
109  runInt10();
110 
111  if (M.x86.R_AL != 0x4f) {
112  DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
113  __func__, M.x86.R_AL);
114  return -1;
115  }
116 
117  if (M.x86.R_AH != 0x0) {
119  ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
120  __func__, M.x86.R_AH);
121  return M.x86.R_AH;
122  }
123  //printf("VBE Info Dump:");
124  //dump(vbe_info_buffer, 64);
125 
126  //offset 0: signature
127  info->signature[0] = vbe_info_buffer[0];
128  info->signature[1] = vbe_info_buffer[1];
129  info->signature[2] = vbe_info_buffer[2];
130  info->signature[3] = vbe_info_buffer[3];
131 
132  // offset 4: 16bit le containing VbeVersion
133  info->version = in16le(vbe_info_buffer + 4);
134 
135  // offset 6: 32bit le containing segment:offset of OEM String in virtual Mem.
136  info->oem_string_ptr =
137  biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
138  in16le(vbe_info_buffer + 6));
139 
140  // offset 10: 32bit le capabilities
141  info->capabilities = in32le(vbe_info_buffer + 10);
142 
143  // offset 14: 32 bit le containing segment:offset of supported video mode table
144  u16 *video_mode_ptr;
145  video_mode_ptr =
146  (u16 *) (biosmem +
147  ((in16le(vbe_info_buffer + 16) << 4) +
148  in16le(vbe_info_buffer + 14)));
149  u32 i = 0;
150  do {
151  info->video_mode_list[i] = in16le(video_mode_ptr + i);
152  i++;
153  }
154  while ((i <
155  (sizeof(info->video_mode_list) /
156  sizeof(info->video_mode_list[0])))
157  && (info->video_mode_list[i - 1] != 0xFFFF));
158 
159  //offset 18: 16bit le total memory in 64KB blocks
160  info->total_memory = in16le(vbe_info_buffer + 18);
161 
162  return 0;
163 }
164 
165 static int mode_info_valid;
166 
167 // VBE Function 01h
168 static u8
169 vbe_get_mode_info(vbe_mode_info_t * mode_info)
170 {
171  vbe_prepare();
172  // call VBE function 01h (Return VBE Mode Info Function)
173  M.x86.R_EAX = 0x4f01;
174  M.x86.R_CX = mode_info->video_mode;
175 
176  // enable trace
178  X86EMU_trace_on();
179  }
180  // run VESA Interrupt
181  runInt10();
182 
183  if (M.x86.R_AL != 0x4f) {
185  ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
186  __func__, M.x86.R_AL);
187  return -1;
188  }
189 
190  if (M.x86.R_AH != 0x0) {
192  ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
193  __func__, mode_info->video_mode, M.x86.R_AH);
194  return M.x86.R_AH;
195  }
196 
197  //pointer to mode_info_block is in ES:DI
198  memcpy(mode_info->mode_info_block,
199  biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
200  sizeof(mode_info->mode_info_block));
201  mode_info_valid = 1;
202 
203  //printf("Mode Info Dump:");
204  //dump(mode_info_block, 64);
205 
206  return 0;
207 }
208 
209 // VBE Function 02h
210 static u8
211 vbe_set_mode(vbe_mode_info_t * mode_info)
212 {
213  vbe_prepare();
214  // call VBE function 02h (Set VBE Mode Function)
215  M.x86.R_EAX = 0x4f02;
216  M.x86.R_BX = mode_info->video_mode;
217  M.x86.R_BX |= 0x4000; // set bit 14 to request linear framebuffer mode
218  M.x86.R_BX &= 0x7FFF; // clear bit 15 to request clearing of framebuffer
219 
220  DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
221  M.x86.R_BX);
222 
223  // enable trace
225  X86EMU_trace_on();
226  }
227  // run VESA Interrupt
228  runInt10();
229 
230  if (M.x86.R_AL != 0x4f) {
232  ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
233  __func__, M.x86.R_AL);
234  return -1;
235  }
236 
237  if (M.x86.R_AH != 0x0) {
239  ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
240  __func__, mode_info->video_mode, M.x86.R_AH);
241  return M.x86.R_AH;
242  }
243  return 0;
244 }
245 
246 #if 0
247 //VBE Function 08h
248 static u8
249 vbe_set_palette_format(u8 format)
250 {
251  vbe_prepare();
252  // call VBE function 09h (Set/Get Palette Data Function)
253  M.x86.R_EAX = 0x4f08;
254  M.x86.R_BL = 0x00; // set format
255  M.x86.R_BH = format;
256 
257  DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
258  format);
259 
260  // enable trace
262  X86EMU_trace_on();
263  }
264  // run VESA Interrupt
265  runInt10();
266 
267  if (M.x86.R_AL != 0x4f) {
269  ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
270  __func__, M.x86.R_AL);
271  return -1;
272  }
273 
274  if (M.x86.R_AH != 0x0) {
276  ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
277  __func__, M.x86.R_AH);
278  return M.x86.R_AH;
279  }
280  return 0;
281 }
282 
283 // VBE Function 09h
284 static u8
285 vbe_set_color(u16 color_number, u32 color_value)
286 {
287  vbe_prepare();
288  // call VBE function 09h (Set/Get Palette Data Function)
289  M.x86.R_EAX = 0x4f09;
290  M.x86.R_BL = 0x00; // set color
291  M.x86.R_CX = 0x01; // set only one entry
292  M.x86.R_DX = color_number;
293  // ES:DI is address where color_value is stored, we store it at 2000:0000
294  M.x86.R_ES = 0x2000;
295  M.x86.R_DI = 0x0;
296 
297  // store color value at ES:DI
298  out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
299 
300  DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
301  color_number, color_value);
302 
303  // enable trace
305  X86EMU_trace_on();
306  }
307  // run VESA Interrupt
308  runInt10();
309 
310  if (M.x86.R_AL != 0x4f) {
312  ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
313  __func__, M.x86.R_AL);
314  return -1;
315  }
316 
317  if (M.x86.R_AH != 0x0) {
319  ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
320  __func__, M.x86.R_AH);
321  return M.x86.R_AH;
322  }
323  return 0;
324 }
325 
326 static u8
327 vbe_get_color(u16 color_number, u32 *color_value)
328 {
329  vbe_prepare();
330  // call VBE function 09h (Set/Get Palette Data Function)
331  M.x86.R_EAX = 0x4f09;
332  M.x86.R_BL = 0x00; // get color
333  M.x86.R_CX = 0x01; // get only one entry
334  M.x86.R_DX = color_number;
335  // ES:DI is address where color_value is stored, we store it at 2000:0000
336  M.x86.R_ES = 0x2000;
337  M.x86.R_DI = 0x0;
338 
339  // enable trace
341  X86EMU_trace_on();
342  }
343  // run VESA Interrupt
344  runInt10();
345 
346  if (M.x86.R_AL != 0x4f) {
348  ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
349  __func__, M.x86.R_AL);
350  return -1;
351  }
352 
353  if (M.x86.R_AH != 0x0) {
355  ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
356  __func__, M.x86.R_AH);
357  return M.x86.R_AH;
358  }
359  // read color value from ES:DI
360  *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
361 
362  DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
363  color_number, *color_value);
364 
365  return 0;
366 }
367 
368 // VBE Function 15h
369 static u8
370 vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
371 {
372  vbe_prepare();
373  // call VBE function 15h (DDC Info Function)
374  M.x86.R_EAX = 0x4f15;
375  M.x86.R_BL = 0x00; // get DDC Info
376  M.x86.R_CX = ddc_info->port_number;
377  M.x86.R_ES = 0x0;
378  M.x86.R_DI = 0x0;
379 
380  // enable trace
382  X86EMU_trace_on();
383  }
384  // run VESA Interrupt
385  runInt10();
386 
387  if (M.x86.R_AL != 0x4f) {
389  ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
390  __func__, M.x86.R_AL);
391  return -1;
392  }
393 
394  if (M.x86.R_AH != 0x0) {
396  ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
397  __func__, ddc_info->port_number, M.x86.R_AH);
398  return M.x86.R_AH;
399  }
400  // BH = approx. time in seconds to transfer one EDID block
401  ddc_info->edid_transfer_time = M.x86.R_BH;
402  // BL = DDC Level
403  ddc_info->ddc_level = M.x86.R_BL;
404 
405  vbe_prepare();
406  // call VBE function 15h (DDC Info Function)
407  M.x86.R_EAX = 0x4f15;
408  M.x86.R_BL = 0x01; // read EDID
409  M.x86.R_CX = ddc_info->port_number;
410  M.x86.R_DX = 0x0; // block number
411  // ES:DI is address where EDID is stored, we store it at 2000:0000
412  M.x86.R_ES = 0x2000;
413  M.x86.R_DI = 0x0;
414 
415  // enable trace
417  X86EMU_trace_on();
418  }
419  // run VESA Interrupt
420  runInt10();
421 
422  if (M.x86.R_AL != 0x4f) {
424  ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
425  __func__, M.x86.R_AL);
426  return -1;
427  }
428 
429  if (M.x86.R_AH != 0x0) {
431  ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
432  __func__, ddc_info->port_number, M.x86.R_AH);
433  return M.x86.R_AH;
434  }
435 
436  memcpy(ddc_info->edid_block_zero,
437  biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
438  sizeof(ddc_info->edid_block_zero));
439 
440  return 0;
441 }
442 
443 static u32
444 vbe_get_info(void)
445 {
446  u8 rval;
447  int i;
448 
449  // XXX FIXME these need to be filled with sane values
450 
451  // get a copy of input struct...
452  screen_info_input_t input;
453  // output is pointer to the address passed as argv[4]
454  screen_info_t local_output;
455  screen_info_t *output = &local_output;
456  // zero input
457  memset(&input, 0, sizeof(screen_info_input_t));
458  // zero output
459  memset(&output, 0, sizeof(screen_info_t));
460 
462  rval = vbe_info(&info);
463  if (rval != 0)
464  return rval;
465 
466  DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
467  DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
468  DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
469  DEBUG_PRINTF_VBE("Capabilities:\n");
470  DEBUG_PRINTF_VBE("\tDAC: %s\n",
471  (info.capabilities & 0x1) ==
472  0 ? "fixed 6bit" : "switchable 6/8bit");
473  DEBUG_PRINTF_VBE("\tVGA: %s\n",
474  (info.capabilities & 0x2) ==
475  0 ? "compatible" : "not compatible");
476  DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
477  (info.capabilities & 0x4) ==
478  0 ? "normal" : "use blank bit in Function 09h");
479 
480  // argv[4] may be a pointer with enough space to return screen_info_t
481  // as input, it must contain a screen_info_input_t with the following content:
482  // byte[0:3] = "DDC\0" (zero-terminated signature header)
483  // byte[4:5] = reserved space for the return struct... just in case we ever change
484  // the struct and don't have reserved enough memory (and let's hope the struct
485  // never gets larger than 64KB)
486  // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
487  // byte[7:8] = max. screen width (OF may want to limit this)
488  // byte[9] = required color depth in bpp
489  if (strncmp((char *) input.signature, "DDC", 4) != 0) {
490  printf
491  ("%s: Invalid input signature! expected: %s, is: %s\n",
492  __func__, "DDC", input.signature);
493  return -1;
494  }
495  if (input.size_reserved != sizeof(screen_info_t)) {
496  printf
497  ("%s: Size of return struct is wrong, required: %d, available: %d\n",
498  __func__, (int) sizeof(screen_info_t),
499  input.size_reserved);
500  return -1;
501  }
502 
503  vbe_ddc_info_t ddc_info;
504  ddc_info.port_number = input.monitor_number;
505  vbe_get_ddc_info(&ddc_info);
506 
507 #if 0
508  DEBUG_PRINTF_VBE("DDC: edid_transfer_time: %d\n",
509  ddc_info.edid_transfer_time);
510  DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
511  DEBUG_PRINTF_VBE("DDC: EDID:\n");
513  dump(ddc_info.edid_block_zero,
514  sizeof(ddc_info.edid_block_zero));
515  }
516 #endif
517 /* This could fail because of alignment issues, so use a longer form.
518  *((u64 *) ddc_info.edid_block_zero) != (u64) 0x00FFFFFFFFFFFF00ULL
519 */
520  if (ddc_info.edid_block_zero[0] != 0x00 ||
521  ddc_info.edid_block_zero[1] != 0xFF ||
522  ddc_info.edid_block_zero[2] != 0xFF ||
523  ddc_info.edid_block_zero[3] != 0xFF ||
524  ddc_info.edid_block_zero[4] != 0xFF ||
525  ddc_info.edid_block_zero[5] != 0xFF ||
526  ddc_info.edid_block_zero[6] != 0xFF ||
527  ddc_info.edid_block_zero[7] != 0x00 ) {
528  // invalid EDID signature... probably no monitor
529 
530  output->display_type = 0x0;
531  return 0;
532  } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
533  // digital display
534  output->display_type = 2;
535  } else {
536  // analog
537  output->display_type = 1;
538  }
539  DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
540  memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
541  sizeof(ddc_info.edid_block_zero));
542  i = 0;
543  vbe_mode_info_t mode_info;
544  vbe_mode_info_t best_mode_info;
545  // initialize best_mode to 0
546  memset(&best_mode_info, 0, sizeof(best_mode_info));
547  while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
548  //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
549  vbe_get_mode_info(&mode_info);
550 
551  // FIXME all these values are little endian!
552 
553  DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
554  mode_info.video_mode,
555  (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x1) ==
556  0 ? "not supported" : "supported");
557  DEBUG_PRINTF_VBE("\tTTY: %s\n",
558  (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x4) ==
559  0 ? "no" : "yes");
560  DEBUG_PRINTF_VBE("\tMode: %s %s\n",
561  (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) ==
562  0 ? "monochrome" : "color",
563  (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) ==
564  0 ? "text" : "graphics");
565  DEBUG_PRINTF_VBE("\tVGA: %s\n",
566  (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x20) ==
567  0 ? "compatible" : "not compatible");
568  DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
569  (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x40) ==
570  0 ? "yes" : "no");
571  DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
572  (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) ==
573  0 ? "no" : "yes");
574  DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
575  le16_to_cpu(mode_info.vesa.x_resolution),
576  le16_to_cpu(mode_info.vesa.y_resolution));
577  DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
578  mode_info.vesa.x_charsize, mode_info.vesa.y_charsize);
579  DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
580  mode_info.vesa.bits_per_pixel);
581  DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
582  mode_info.vesa.memory_model);
583  DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
584  le32_to_cpu(mode_info.vesa.phys_base_ptr));
585 
586  if ((mode_info.vesa.bits_per_pixel == input.color_depth)
587  && (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width)
588  && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0) // framebuffer mode
589  && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0) // graphics
590  && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0) // color
591  && (le16_to_cpu(mode_info.vesa.x_resolution) > le16_to_cpu(best_mode_info.vesa.x_resolution))) // better than previous best_mode
592  {
593  // yiiiihaah... we found a new best mode
594  memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
595  }
596  i++;
597  }
598 
599  if (best_mode_info.video_mode != 0) {
601  ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
602  best_mode_info.video_mode,
603  best_mode_info.vesa.x_resolution,
604  best_mode_info.vesa.y_resolution,
605  best_mode_info.vesa.bits_per_pixel,
606  le32_to_cpu(best_mode_info.vesa.phys_base_ptr));
607 
608  //printf("Mode Info Dump:");
609  //dump(best_mode_info.mode_info_block, 64);
610 
611  // set the video mode
612  vbe_set_mode(&best_mode_info);
613 
614  if ((info.capabilities & 0x1) != 0) {
615  // switch to 8 bit palette format
616  vbe_set_palette_format(8);
617  }
618  // setup a palette:
619  // - first 216 colors are mixed colors for each component in 6 steps
620  // (6*6*6=216)
621  // - then 10 shades of the three primary colors
622  // - then 10 shades of grey
623  // -------
624  // = 256 colors
625  //
626  // - finally black is color 0 and white color FF (because SLOF expects it
627  // this way...)
628  // this resembles the palette that the kernel/X Server seems to expect...
629 
630  u8 mixed_color_values[6] =
631  { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
632  u8 primary_color_values[10] =
633  { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
634  0x27
635  };
636  u8 mc_size = sizeof(mixed_color_values);
637  u8 prim_size = sizeof(primary_color_values);
638 
639  u8 curr_color_index;
640  u32 curr_color;
641 
642  u8 r, g, b;
643  // 216 mixed colors
644  for (r = 0; r < mc_size; r++) {
645  for (g = 0; g < mc_size; g++) {
646  for (b = 0; b < mc_size; b++) {
647  curr_color_index =
648  (r * mc_size * mc_size) +
649  (g * mc_size) + b;
650  curr_color = 0;
651  curr_color |= ((u32) mixed_color_values[r]) << 16; //red value
652  curr_color |= ((u32) mixed_color_values[g]) << 8; //green value
653  curr_color |= (u32) mixed_color_values[b]; //blue value
654  vbe_set_color(curr_color_index,
655  curr_color);
656  }
657  }
658  }
659 
660  // 10 shades of each primary color
661  // red
662  for (r = 0; r < prim_size; r++) {
663  curr_color_index = mc_size * mc_size * mc_size + r;
664  curr_color = ((u32) primary_color_values[r]) << 16;
665  vbe_set_color(curr_color_index, curr_color);
666  }
667  //green
668  for (g = 0; g < prim_size; g++) {
669  curr_color_index =
670  mc_size * mc_size * mc_size + prim_size + g;
671  curr_color = ((u32) primary_color_values[g]) << 8;
672  vbe_set_color(curr_color_index, curr_color);
673  }
674  //blue
675  for (b = 0; b < prim_size; b++) {
676  curr_color_index =
677  mc_size * mc_size * mc_size + prim_size * 2 + b;
678  curr_color = (u32) primary_color_values[b];
679  vbe_set_color(curr_color_index, curr_color);
680  }
681  // 10 shades of grey
682  for (i = 0; i < prim_size; i++) {
683  curr_color_index =
684  mc_size * mc_size * mc_size + prim_size * 3 + i;
685  curr_color = 0;
686  curr_color |= ((u32) primary_color_values[i]) << 16; //red
687  curr_color |= ((u32) primary_color_values[i]) << 8; //green
688  curr_color |= ((u32) primary_color_values[i]); //blue
689  vbe_set_color(curr_color_index, curr_color);
690  }
691 
692  // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
693  vbe_set_color(0x00, 0x00000000);
694  vbe_set_color(0xFF, 0x00FFFFFF);
695 
696  output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution);
697  output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution);
698  output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline);
699  output->color_depth = best_mode_info.vesa.bits_per_pixel;
700  output->framebuffer_address =
701  le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
702  } else {
703  printf("%s: No suitable video mode found!\n", __func__);
704  //unset display_type...
705  output->display_type = 0;
706  }
707  return 0;
708 }
709 #endif
710 
711 static vbe_mode_info_t mode_info;
712 
713 const vbe_mode_info_t *vbe_mode_info(void)
714 {
715  if (!mode_info_valid || !mode_info.vesa.phys_base_ptr)
716  return NULL;
717  return &mode_info;
718 }
719 
720 void vbe_set_graphics(void)
721 {
722  u8 rval;
723 
725  rval = vbe_info(&info);
726  if (rval != 0)
727  return;
728 
729  DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
730  DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
731  DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
732  DEBUG_PRINTF_VBE("Capabilities:\n");
733  DEBUG_PRINTF_VBE("\tDAC: %s\n",
734  (info.capabilities & 0x1) ==
735  0 ? "fixed 6bit" : "switchable 6/8bit");
736  DEBUG_PRINTF_VBE("\tVGA: %s\n",
737  (info.capabilities & 0x2) ==
738  0 ? "compatible" : "not compatible");
739  DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
740  (info.capabilities & 0x4) ==
741  0 ? "normal" : "use blank bit in Function 09h");
742 
743  mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE;
744  vbe_get_mode_info(&mode_info);
745  vbe_set_mode(&mode_info);
746 
747  const struct lb_framebuffer fb = {
748  .physical_address = mode_info.vesa.phys_base_ptr,
749  .x_resolution = le16_to_cpu(mode_info.vesa.x_resolution),
750  .y_resolution = le16_to_cpu(mode_info.vesa.y_resolution),
751  .bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline),
752  .bits_per_pixel = mode_info.vesa.bits_per_pixel,
753  .red_mask_pos = mode_info.vesa.red_mask_pos,
754  .red_mask_size = mode_info.vesa.red_mask_size,
755  .green_mask_pos = mode_info.vesa.green_mask_pos,
756  .green_mask_size = mode_info.vesa.green_mask_size,
757  .blue_mask_pos = mode_info.vesa.blue_mask_pos,
758  .blue_mask_size = mode_info.vesa.blue_mask_size,
759  .reserved_mask_pos = mode_info.vesa.reserved_mask_pos,
760  .reserved_mask_size = mode_info.vesa.reserved_mask_size,
761  .orientation = LB_FB_ORIENTATION_NORMAL,
762  };
763 
765 }
766 
767 void vbe_textmode_console(void)
768 {
769  /* Wait, just a little bit more, pleeeease ;-) */
770  delay(2);
771 
772  M.x86.R_EAX = 0x0003;
773  runInt10();
774 }
775 
776 #endif
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
void * memset(void *dstpp, int c, size_t len)
Definition: memset.c:12
#define VBE_SEGMENT
Definition: biosemu.h:45
@ LB_FB_ORIENTATION_NORMAL
void delay(unsigned int secs)
Definition: delay.c:8
#define printf(x...)
Definition: debug.h:47
#define DEBUG_VBE
Definition: debug.h:85
#define DEBUG_TRACE_X86EMU
Definition: debug.h:90
#define CHECK_DBG(_flag)
Definition: debug.h:118
#define DEBUG_PRINTF_VBE(_x...)
Definition: debug.h:126
static u16 in16le(void *addr)
Definition: device.h:183
static u32 in32le(void *addr)
Definition: device.h:161
static void out32le(void *addr, u32 val)
Definition: device.h:151
static struct smmstore_params_info info
Definition: ramstage.c:12
struct fb_info * fb_add_framebuffer_info_ex(const struct lb_framebuffer *fb)
Definition: edid_fill_fb.c:36
void runInt10(void)
Definition: interrupt.c:623
#define M
Definition: regs.h:327
int dump
Definition: display.c:23
#define NULL
Definition: stddef.h:19
uint32_t u32
Definition: stdint.h:51
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
int strncmp(const char *s1, const char *s2, int maxlen)
Definition: string.c:114
lb_uint64_t physical_address
u8 edid_block_zero[128]
Definition: vbe.h:96
u8 port_number
Definition: vbe.h:93
u8 edid_transfer_time
Definition: vbe.h:94
u8 ddc_level
Definition: vbe.h:95
Definition: vbe.c:60
u8 * oem_string_ptr
Definition: vbe.c:63
u32 capabilities
Definition: vbe.c:64
u16 version
Definition: vbe.c:62
u16 total_memory
Definition: vbe.c:67
u16 video_mode
Definition: vbe.h:75
u8 mode_info_block[256]
Definition: vbe.h:78
vesa_mode_info_t vesa
Definition: vbe.h:77
u8 * biosmem
Definition: vbe.c:74
u8 * vbe_info_buffer
Definition: vbe.c:71
u32 biosmem_size
Definition: vbe.c:75
void vbe_textmode_console(void)
const vbe_mode_info_t * vbe_mode_info(void)
Returns the mode_info struct from the vbe context, if initialized.
void vbe_set_graphics(void)
int X86EMU_trace_on(void)