1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
5 * This program and the accompanying materials
6 * are made available under the terms of the BSD License
7 * which accompanies this distribution, and is available at
8 * http://www.opensource.org/licenses/bsd-license.php
11 * IBM Corporation - initial implementation
12 *****************************************************************************/
17 #include <boot/coreboot_tables.h>
20 #include <arch/byteorder.h>
21 #define ntohl(x) be32_to_cpu(x)
25 #include <x86emu/x86emu.h>
26 #include <x86emu/regs.h>
27 #include "../x86emu/prim_ops.h"
32 #include "interrupt.h"
38 #include "../../src/lib/jpeg.h"
42 // pointer to VBEInfoBuffer, set by vbe_prepare
43 u8 *vbe_info_buffer = 0;
45 // virtual BIOS Memory
52 vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
54 memset(vbe_info_buffer, 0, 512);
55 //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
56 vbe_info_buffer[0] = 'V';
57 vbe_info_buffer[0] = 'B';
58 vbe_info_buffer[0] = 'E';
59 vbe_info_buffer[0] = '2';
60 // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
62 M.x86.R_ES = VBE_SEGMENT;
64 return 0; // successfull init
70 vbe_info(vbe_info_t * info)
73 // call VBE function 00h (Info Function)
77 CHECK_DBG(DEBUG_TRACE_X86EMU) {
83 if (M.x86.R_AL != 0x4f) {
84 DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
85 __func__, M.x86.R_AL);
89 if (M.x86.R_AH != 0x0) {
91 ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
92 __func__, M.x86.R_AH);
95 //printf("VBE Info Dump:");
96 //dump(vbe_info_buffer, 64);
99 info->signature[0] = vbe_info_buffer[0];
100 info->signature[1] = vbe_info_buffer[1];
101 info->signature[2] = vbe_info_buffer[2];
102 info->signature[3] = vbe_info_buffer[3];
104 // offset 4: 16bit le containing VbeVersion
105 info->version = in16le(vbe_info_buffer + 4);
107 // offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
108 info->oem_string_ptr =
109 biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
110 in16le(vbe_info_buffer + 6));
112 // offset 10: 32bit le capabilities
113 info->capabilities = in32le(vbe_info_buffer + 10);
115 // offset 14: 32 bit le containing segment:offset of supported video mode table
119 ((in16le(vbe_info_buffer + 16) << 4) +
120 in16le(vbe_info_buffer + 14)));
123 info->video_mode_list[i] = in16le(video_mode_ptr + i);
127 (sizeof(info->video_mode_list) /
128 sizeof(info->video_mode_list[0])))
129 && (info->video_mode_list[i - 1] != 0xFFFF));
131 //offset 18: 16bit le total memory in 64KB blocks
132 info->total_memory = in16le(vbe_info_buffer + 18);
139 vbe_get_mode_info(vbe_mode_info_t * mode_info)
142 // call VBE function 01h (Return VBE Mode Info Function)
143 M.x86.R_EAX = 0x4f01;
144 M.x86.R_CX = mode_info->video_mode;
147 CHECK_DBG(DEBUG_TRACE_X86EMU) {
150 // run VESA Interrupt
153 if (M.x86.R_AL != 0x4f) {
155 ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
156 __func__, M.x86.R_AL);
160 if (M.x86.R_AH != 0x0) {
162 ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
163 __func__, mode_info->video_mode, M.x86.R_AH);
167 //pointer to mode_info_block is in ES:DI
168 memcpy(mode_info->mode_info_block,
169 biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
170 sizeof(mode_info->mode_info_block));
172 //printf("Mode Info Dump:");
173 //dump(mode_info_block, 64);
180 vbe_set_mode(vbe_mode_info_t * mode_info)
183 // call VBE function 02h (Set VBE Mode Function)
184 M.x86.R_EAX = 0x4f02;
185 M.x86.R_BX = mode_info->video_mode;
186 M.x86.R_BX |= 0x4000; // set bit 14 to request linear framebuffer mode
187 M.x86.R_BX &= 0x7FFF; // clear bit 15 to request clearing of framebuffer
189 DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
193 CHECK_DBG(DEBUG_TRACE_X86EMU) {
196 // run VESA Interrupt
199 if (M.x86.R_AL != 0x4f) {
201 ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
202 __func__, M.x86.R_AL);
206 if (M.x86.R_AH != 0x0) {
208 ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
209 __func__, mode_info->video_mode, M.x86.R_AH);
218 vbe_set_palette_format(u8 format)
221 // call VBE function 09h (Set/Get Palette Data Function)
222 M.x86.R_EAX = 0x4f08;
223 M.x86.R_BL = 0x00; // set format
226 DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
230 CHECK_DBG(DEBUG_TRACE_X86EMU) {
233 // run VESA Interrupt
236 if (M.x86.R_AL != 0x4f) {
238 ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
239 __func__, M.x86.R_AL);
243 if (M.x86.R_AH != 0x0) {
245 ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
246 __func__, M.x86.R_AH);
254 vbe_set_color(u16 color_number, u32 color_value)
257 // call VBE function 09h (Set/Get Palette Data Function)
258 M.x86.R_EAX = 0x4f09;
259 M.x86.R_BL = 0x00; // set color
260 M.x86.R_CX = 0x01; // set only one entry
261 M.x86.R_DX = color_number;
262 // ES:DI is address where color_value is stored, we store it at 2000:0000
266 // store color value at ES:DI
267 out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
269 DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
270 color_number, color_value);
273 CHECK_DBG(DEBUG_TRACE_X86EMU) {
276 // run VESA Interrupt
279 if (M.x86.R_AL != 0x4f) {
281 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
282 __func__, M.x86.R_AL);
286 if (M.x86.R_AH != 0x0) {
288 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
289 __func__, M.x86.R_AH);
296 vbe_get_color(u16 color_number, u32 * color_value)
299 // call VBE function 09h (Set/Get Palette Data Function)
300 M.x86.R_EAX = 0x4f09;
301 M.x86.R_BL = 0x00; // get color
302 M.x86.R_CX = 0x01; // get only one entry
303 M.x86.R_DX = color_number;
304 // ES:DI is address where color_value is stored, we store it at 2000:0000
309 CHECK_DBG(DEBUG_TRACE_X86EMU) {
312 // run VESA Interrupt
315 if (M.x86.R_AL != 0x4f) {
317 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
318 __func__, M.x86.R_AL);
322 if (M.x86.R_AH != 0x0) {
324 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
325 __func__, M.x86.R_AH);
328 // read color value from ES:DI
329 *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
331 DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
332 color_number, *color_value);
339 vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
342 // call VBE function 15h (DDC Info Function)
343 M.x86.R_EAX = 0x4f15;
344 M.x86.R_BL = 0x00; // get DDC Info
345 M.x86.R_CX = ddc_info->port_number;
350 CHECK_DBG(DEBUG_TRACE_X86EMU) {
353 // run VESA Interrupt
356 if (M.x86.R_AL != 0x4f) {
358 ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
359 __func__, M.x86.R_AL);
363 if (M.x86.R_AH != 0x0) {
365 ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
366 __func__, ddc_info->port_number, M.x86.R_AH);
369 // BH = approx. time in seconds to transfer one EDID block
370 ddc_info->edid_transfer_time = M.x86.R_BH;
372 ddc_info->ddc_level = M.x86.R_BL;
375 // call VBE function 15h (DDC Info Function)
376 M.x86.R_EAX = 0x4f15;
377 M.x86.R_BL = 0x01; // read EDID
378 M.x86.R_CX = ddc_info->port_number;
379 M.x86.R_DX = 0x0; // block number
380 // ES:DI is address where EDID is stored, we store it at 2000:0000
385 CHECK_DBG(DEBUG_TRACE_X86EMU) {
388 // run VESA Interrupt
391 if (M.x86.R_AL != 0x4f) {
393 ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
394 __func__, M.x86.R_AL);
398 if (M.x86.R_AH != 0x0) {
400 ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
401 __func__, ddc_info->port_number, M.x86.R_AH);
405 memcpy(ddc_info->edid_block_zero,
406 biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
407 sizeof(ddc_info->edid_block_zero));
418 // XXX FIXME these need to be filled with sane values
420 // get a copy of input struct...
421 screen_info_input_t input;
422 // output is pointer to the address passed as argv[4]
423 screen_info_t local_output;
424 screen_info_t *output = &local_output;
426 memset(&input, 0, sizeof(screen_info_input_t));
428 memset(&output, 0, sizeof(screen_info_t));
431 rval = vbe_info(&info);
435 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
436 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
437 DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
438 DEBUG_PRINTF_VBE("Capabilities:\n");
439 DEBUG_PRINTF_VBE("\tDAC: %s\n",
440 (info.capabilities & 0x1) ==
441 0 ? "fixed 6bit" : "switchable 6/8bit");
442 DEBUG_PRINTF_VBE("\tVGA: %s\n",
443 (info.capabilities & 0x2) ==
444 0 ? "compatible" : "not compatible");
445 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
446 (info.capabilities & 0x4) ==
447 0 ? "normal" : "use blank bit in Function 09h");
449 // argv[4] may be a pointer with enough space to return screen_info_t
450 // as input, it must contain a screen_info_input_t with the following content:
451 // byte[0:3] = "DDC\0" (zero-terminated signature header)
452 // byte[4:5] = reserved space for the return struct... just in case we ever change
453 // the struct and dont have reserved enough memory (and let's hope the struct
454 // never gets larger than 64KB)
455 // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
456 // byte[7:8] = max. screen width (OF may want to limit this)
457 // byte[9] = required color depth in bpp
458 if (strncmp((char *) input.signature, "DDC", 4) != 0) {
460 ("%s: Invalid input signature! expected: %s, is: %s\n",
461 __func__, "DDC", input.signature);
464 if (input.size_reserved != sizeof(screen_info_t)) {
466 ("%s: Size of return struct is wrong, required: %d, available: %d\n",
467 __func__, (int) sizeof(screen_info_t),
468 input.size_reserved);
472 vbe_ddc_info_t ddc_info;
473 ddc_info.port_number = input.monitor_number;
474 vbe_get_ddc_info(&ddc_info);
477 DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
478 ddc_info.edid_transfer_time);
479 DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
480 DEBUG_PRINTF_VBE("DDC: EDID: \n");
481 CHECK_DBG(DEBUG_VBE) {
482 dump(ddc_info.edid_block_zero,
483 sizeof(ddc_info.edid_block_zero));
486 /* This could fail because of alignment issues, so use a longer form.
487 *((u64 *) ddc_info.edid_block_zero) != (u64) 0x00FFFFFFFFFFFF00ULL
489 if (ddc_info.edid_block_zero[0] != 0x00 ||
490 ddc_info.edid_block_zero[1] != 0xFF ||
491 ddc_info.edid_block_zero[2] != 0xFF ||
492 ddc_info.edid_block_zero[3] != 0xFF ||
493 ddc_info.edid_block_zero[4] != 0xFF ||
494 ddc_info.edid_block_zero[5] != 0xFF ||
495 ddc_info.edid_block_zero[6] != 0xFF ||
496 ddc_info.edid_block_zero[7] != 0x00 ) {
497 // invalid EDID signature... probably no monitor
499 output->display_type = 0x0;
501 } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
503 output->display_type = 2;
506 output->display_type = 1;
508 DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
509 memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
510 sizeof(ddc_info.edid_block_zero));
512 vbe_mode_info_t mode_info;
513 vbe_mode_info_t best_mode_info;
514 // initialize best_mode to 0
515 memset(&best_mode_info, 0, sizeof(best_mode_info));
516 while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
517 //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
518 vbe_get_mode_info(&mode_info);
520 // FIXME all these values are little endian!
522 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
523 mode_info.video_mode,
524 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x1) ==
525 0 ? "not supported" : "supported");
526 DEBUG_PRINTF_VBE("\tTTY: %s\n",
527 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x4) ==
529 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
530 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) ==
531 0 ? "monochrome" : "color",
532 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) ==
533 0 ? "text" : "graphics");
534 DEBUG_PRINTF_VBE("\tVGA: %s\n",
535 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x20) ==
536 0 ? "compatible" : "not compatible");
537 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
538 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x40) ==
540 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
541 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) ==
543 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
544 le16_to_cpu(mode_info.vesa.x_resolution),
545 le16_to_cpu(mode_info.vesa.y_resolution));
546 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
547 mode_info.vesa.x_charsize, mode_info.vesa.y_charsize);
548 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
549 mode_info.vesa.bits_per_pixel);
550 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
551 mode_info.vesa.memory_model);
552 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
553 le32_to_cpu(mode_info.vesa.phys_base_ptr));
555 if ((mode_info.vesa.bits_per_pixel == input.color_depth)
556 && (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width)
557 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0) // framebuffer mode
558 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0) // graphics
559 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0) // color
560 && (le16_to_cpu(mode_info.vesa.x_resolution) > le16_to_cpu(best_mode_info.vesa.x_resolution))) // better than previous best_mode
562 // yiiiihaah... we found a new best mode
563 memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
568 if (best_mode_info.video_mode != 0) {
570 ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
571 best_mode_info.video_mode,
572 best_mode_info.vesa.x_resolution,
573 best_mode_info.vesa.y_resolution,
574 best_mode_info.vesa.bits_per_pixel,
575 le32_to_cpu(best_mode_info.vesa.phys_base_ptr));
577 //printf("Mode Info Dump:");
578 //dump(best_mode_info.mode_info_block, 64);
580 // set the video mode
581 vbe_set_mode(&best_mode_info);
583 if ((info.capabilities & 0x1) != 0) {
584 // switch to 8 bit palette format
585 vbe_set_palette_format(8);
588 // - first 216 colors are mixed colors for each component in 6 steps
590 // - then 10 shades of the three primary colors
591 // - then 10 shades of grey
595 // - finally black is color 0 and white color FF (because SLOF expects it
597 // this resembles the palette that the kernel/X Server seems to expect...
599 u8 mixed_color_values[6] =
600 { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
601 u8 primary_color_values[10] =
602 { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
605 u8 mc_size = sizeof(mixed_color_values);
606 u8 prim_size = sizeof(primary_color_values);
613 for (r = 0; r < mc_size; r++) {
614 for (g = 0; g < mc_size; g++) {
615 for (b = 0; b < mc_size; b++) {
617 (r * mc_size * mc_size) +
620 curr_color |= ((u32) mixed_color_values[r]) << 16; //red value
621 curr_color |= ((u32) mixed_color_values[g]) << 8; //green value
622 curr_color |= (u32) mixed_color_values[b]; //blue value
623 vbe_set_color(curr_color_index,
629 // 10 shades of each primary color
631 for (r = 0; r < prim_size; r++) {
632 curr_color_index = mc_size * mc_size * mc_size + r;
633 curr_color = ((u32) primary_color_values[r]) << 16;
634 vbe_set_color(curr_color_index, curr_color);
637 for (g = 0; g < prim_size; g++) {
639 mc_size * mc_size * mc_size + prim_size + g;
640 curr_color = ((u32) primary_color_values[g]) << 8;
641 vbe_set_color(curr_color_index, curr_color);
644 for (b = 0; b < prim_size; b++) {
646 mc_size * mc_size * mc_size + prim_size * 2 + b;
647 curr_color = (u32) primary_color_values[b];
648 vbe_set_color(curr_color_index, curr_color);
651 for (i = 0; i < prim_size; i++) {
653 mc_size * mc_size * mc_size + prim_size * 3 + i;
655 curr_color |= ((u32) primary_color_values[i]) << 16; //red
656 curr_color |= ((u32) primary_color_values[i]) << 8; //green
657 curr_color |= ((u32) primary_color_values[i]); //blue
658 vbe_set_color(curr_color_index, curr_color);
661 // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
662 vbe_set_color(0x00, 0x00000000);
663 vbe_set_color(0xFF, 0x00FFFFFF);
665 output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution);
666 output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution);
667 output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline);
668 output->color_depth = best_mode_info.vesa.bits_per_pixel;
669 output->framebuffer_address =
670 le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
672 printf("%s: No suitable video mode found!\n", __func__);
673 //unset display_type...
674 output->display_type = 0;
680 vbe_mode_info_t mode_info;
682 void vbe_set_graphics(void)
687 rval = vbe_info(&info);
691 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
692 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
693 DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
694 DEBUG_PRINTF_VBE("Capabilities:\n");
695 DEBUG_PRINTF_VBE("\tDAC: %s\n",
696 (info.capabilities & 0x1) ==
697 0 ? "fixed 6bit" : "switchable 6/8bit");
698 DEBUG_PRINTF_VBE("\tVGA: %s\n",
699 (info.capabilities & 0x2) ==
700 0 ? "compatible" : "not compatible");
701 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
702 (info.capabilities & 0x4) ==
703 0 ? "normal" : "use blank bit in Function 09h");
705 mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE;
706 vbe_get_mode_info(&mode_info);
707 unsigned char *framebuffer =
708 (unsigned char *) le32_to_cpu(mode_info.vesa.phys_base_ptr);
709 DEBUG_PRINTF_VBE("FRAMEBUFFER: 0x%p\n", framebuffer);
710 vbe_set_mode(&mode_info);
712 struct jpeg_decdata *decdata;
713 decdata = malloc(sizeof(*decdata));
715 /* Switching Intel IGD to 1MB video memory will break this. Who
717 // int imagesize = 1024*768*2;
719 unsigned char *jpeg = cbfs_find_file("bootsplash.jpg", CBFS_TYPE_BOOTSPLASH);
721 DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n");
724 DEBUG_PRINTF_VBE("Splash at %p ...\n", jpeg);
728 DEBUG_PRINTF_VBE("Decompressing boot splash screen...\n");
729 ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata);
730 DEBUG_PRINTF_VBE("returns %x\n", ret);
733 void fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
735 framebuffer->physical_address = le32_to_cpu(mode_info.vesa.phys_base_ptr);
737 framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution);
738 framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution);
739 framebuffer->bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline);
740 framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel;
742 framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos;
743 framebuffer->red_mask_size = mode_info.vesa.red_mask_size;
745 framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos;
746 framebuffer->green_mask_size = mode_info.vesa.green_mask_size;
748 framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos;
749 framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size;
751 framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos;
752 framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size;
755 void vbe_textmode_console(void)
757 /* Wait, just a little bit more, pleeeease ;-) */
760 M.x86.R_EAX = 0x0003;