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"
40 // pointer to VBEInfoBuffer, set by vbe_prepare
41 u8 *vbe_info_buffer = 0;
43 // virtual BIOS Memory
47 // these structs are for input from and output to OF
49 u8 display_type; // 0=NONE, 1= analog, 2=digital
52 u16 screen_linebytes; // bytes per line in framebuffer, may be more than screen_width
53 u8 color_depth; // color depth in bpp
54 u32 framebuffer_address;
55 u8 edid_block_zero[128];
56 } __attribute__ ((__packed__)) screen_info_t;
64 } __attribute__ ((__packed__)) screen_info_input_t;
66 // these structs only store a subset of the VBE defined fields
73 u16 video_mode_list[256]; // lets hope we never have more than 256 video modes...
78 u16 mode_attributes; // 00
79 u8 win_a_attributes; // 02
80 u8 win_b_attributes; // 03
81 u16 win_granularity; // 04
83 u16 win_a_segment; // 08
84 u16 win_b_segment; // 0a
85 u32 win_func_ptr; // 0c
86 u16 bytes_per_scanline; // 10
87 u16 x_resolution; // 12
88 u16 y_resolution; // 14
91 u8 number_of_planes; // 18
92 u8 bits_per_pixel; // 19
93 u8 number_of_banks; // 20
94 u8 memory_model; // 21
96 u8 number_of_image_pages; // 23
104 u8 reserved_mask_size;
105 u8 reserved_mask_pos;
106 u8 direct_color_mode_info;
108 u32 offscreen_mem_offset;
109 u16 offscreen_mem_size;
111 } __attribute__ ((__packed__)) vesa_mode_info_t;
116 vesa_mode_info_t vesa;
117 u8 mode_info_block[256];
128 //u32 framebuffer_address;
132 u8 port_number; // i.e. monitor number
133 u8 edid_transfer_time;
135 u8 edid_block_zero[128];
141 vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
143 memset(vbe_info_buffer, 0, 512);
144 //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
145 vbe_info_buffer[0] = 'V';
146 vbe_info_buffer[0] = 'B';
147 vbe_info_buffer[0] = 'E';
148 vbe_info_buffer[0] = '2';
149 // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
151 M.x86.R_ES = VBE_SEGMENT;
153 return 0; // successfull init
158 vbe_info(vbe_info_t * info)
161 // call VBE function 00h (Info Function)
162 M.x86.R_EAX = 0x4f00;
165 CHECK_DBG(DEBUG_TRACE_X86EMU) {
168 // run VESA Interrupt
171 if (M.x86.R_AL != 0x4f) {
172 DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
173 __func__, M.x86.R_AL);
177 if (M.x86.R_AH != 0x0) {
179 ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
180 __func__, M.x86.R_AH);
183 //printf("VBE Info Dump:");
184 //dump(vbe_info_buffer, 64);
186 //offset 0: signature
187 info->signature[0] = vbe_info_buffer[0];
188 info->signature[1] = vbe_info_buffer[1];
189 info->signature[2] = vbe_info_buffer[2];
190 info->signature[3] = vbe_info_buffer[3];
192 // offset 4: 16bit le containing VbeVersion
193 info->version = in16le(vbe_info_buffer + 4);
195 // offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
196 info->oem_string_ptr =
197 biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
198 in16le(vbe_info_buffer + 6));
200 // offset 10: 32bit le capabilities
201 info->capabilities = in32le(vbe_info_buffer + 10);
203 // offset 14: 32 bit le containing segment:offset of supported video mode table
207 ((in16le(vbe_info_buffer + 16) << 4) +
208 in16le(vbe_info_buffer + 14)));
211 info->video_mode_list[i] = in16le(video_mode_ptr + i);
215 (sizeof(info->video_mode_list) /
216 sizeof(info->video_mode_list[0])))
217 && (info->video_mode_list[i - 1] != 0xFFFF));
219 //offset 18: 16bit le total memory in 64KB blocks
220 info->total_memory = in16le(vbe_info_buffer + 18);
227 vbe_get_mode_info(vbe_mode_info_t * mode_info)
230 // call VBE function 01h (Return VBE Mode Info Function)
231 M.x86.R_EAX = 0x4f01;
232 M.x86.R_CX = mode_info->video_mode;
235 CHECK_DBG(DEBUG_TRACE_X86EMU) {
238 // run VESA Interrupt
241 if (M.x86.R_AL != 0x4f) {
243 ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
244 __func__, M.x86.R_AL);
248 if (M.x86.R_AH != 0x0) {
250 ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
251 __func__, mode_info->video_mode, M.x86.R_AH);
255 //pointer to mode_info_block is in ES:DI
256 memcpy(mode_info->mode_info_block,
257 biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
258 sizeof(mode_info->mode_info_block));
260 //printf("Mode Info Dump:");
261 //dump(mode_info_block, 64);
268 vbe_set_mode(vbe_mode_info_t * mode_info)
271 // call VBE function 02h (Set VBE Mode Function)
272 M.x86.R_EAX = 0x4f02;
273 M.x86.R_BX = mode_info->video_mode;
274 M.x86.R_BX |= 0x4000; // set bit 14 to request linear framebuffer mode
275 M.x86.R_BX &= 0x7FFF; // clear bit 15 to request clearing of framebuffer
277 DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
281 CHECK_DBG(DEBUG_TRACE_X86EMU) {
284 // run VESA Interrupt
287 if (M.x86.R_AL != 0x4f) {
289 ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
290 __func__, M.x86.R_AL);
294 if (M.x86.R_AH != 0x0) {
296 ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
297 __func__, mode_info->video_mode, M.x86.R_AH);
305 vbe_set_palette_format(u8 format)
308 // call VBE function 09h (Set/Get Palette Data Function)
309 M.x86.R_EAX = 0x4f08;
310 M.x86.R_BL = 0x00; // set format
313 DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
317 CHECK_DBG(DEBUG_TRACE_X86EMU) {
320 // run VESA Interrupt
323 if (M.x86.R_AL != 0x4f) {
325 ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
326 __func__, M.x86.R_AL);
330 if (M.x86.R_AH != 0x0) {
332 ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
333 __func__, M.x86.R_AH);
341 vbe_set_color(u16 color_number, u32 color_value)
344 // call VBE function 09h (Set/Get Palette Data Function)
345 M.x86.R_EAX = 0x4f09;
346 M.x86.R_BL = 0x00; // set color
347 M.x86.R_CX = 0x01; // set only one entry
348 M.x86.R_DX = color_number;
349 // ES:DI is address where color_value is stored, we store it at 2000:0000
353 // store color value at ES:DI
354 out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
356 DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
357 color_number, color_value);
360 CHECK_DBG(DEBUG_TRACE_X86EMU) {
363 // run VESA Interrupt
366 if (M.x86.R_AL != 0x4f) {
368 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
369 __func__, M.x86.R_AL);
373 if (M.x86.R_AH != 0x0) {
375 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
376 __func__, M.x86.R_AH);
383 vbe_get_color(u16 color_number, u32 * color_value)
386 // call VBE function 09h (Set/Get Palette Data Function)
387 M.x86.R_EAX = 0x4f09;
388 M.x86.R_BL = 0x00; // get color
389 M.x86.R_CX = 0x01; // get only one entry
390 M.x86.R_DX = color_number;
391 // ES:DI is address where color_value is stored, we store it at 2000:0000
396 CHECK_DBG(DEBUG_TRACE_X86EMU) {
399 // run VESA Interrupt
402 if (M.x86.R_AL != 0x4f) {
404 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
405 __func__, M.x86.R_AL);
409 if (M.x86.R_AH != 0x0) {
411 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
412 __func__, M.x86.R_AH);
415 // read color value from ES:DI
416 *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
418 DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
419 color_number, *color_value);
426 vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
429 // call VBE function 15h (DDC Info Function)
430 M.x86.R_EAX = 0x4f15;
431 M.x86.R_BL = 0x00; // get DDC Info
432 M.x86.R_CX = ddc_info->port_number;
437 CHECK_DBG(DEBUG_TRACE_X86EMU) {
440 // run VESA Interrupt
443 if (M.x86.R_AL != 0x4f) {
445 ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
446 __func__, M.x86.R_AL);
450 if (M.x86.R_AH != 0x0) {
452 ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
453 __func__, ddc_info->port_number, M.x86.R_AH);
456 // BH = approx. time in seconds to transfer one EDID block
457 ddc_info->edid_transfer_time = M.x86.R_BH;
459 ddc_info->ddc_level = M.x86.R_BL;
462 // call VBE function 15h (DDC Info Function)
463 M.x86.R_EAX = 0x4f15;
464 M.x86.R_BL = 0x01; // read EDID
465 M.x86.R_CX = ddc_info->port_number;
466 M.x86.R_DX = 0x0; // block number
467 // ES:DI is address where EDID is stored, we store it at 2000:0000
472 CHECK_DBG(DEBUG_TRACE_X86EMU) {
475 // run VESA Interrupt
478 if (M.x86.R_AL != 0x4f) {
480 ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
481 __func__, M.x86.R_AL);
485 if (M.x86.R_AH != 0x0) {
487 ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
488 __func__, ddc_info->port_number, M.x86.R_AH);
492 memcpy(ddc_info->edid_block_zero,
493 biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
494 sizeof(ddc_info->edid_block_zero));
505 // XXX FIXME these need to be filled with sane values
507 // get a copy of input struct...
508 screen_info_input_t input;
509 // output is pointer to the address passed as argv[4]
510 screen_info_t local_output;
511 screen_info_t *output = &local_output;
513 memset(&input, 0, sizeof(screen_info_input_t));
515 memset(&output, 0, sizeof(screen_info_t));
518 rval = vbe_info(&info);
522 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
523 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
524 DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
525 DEBUG_PRINTF_VBE("Capabilities:\n");
526 DEBUG_PRINTF_VBE("\tDAC: %s\n",
527 (info.capabilities & 0x1) ==
528 0 ? "fixed 6bit" : "switchable 6/8bit");
529 DEBUG_PRINTF_VBE("\tVGA: %s\n",
530 (info.capabilities & 0x2) ==
531 0 ? "compatible" : "not compatible");
532 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
533 (info.capabilities & 0x4) ==
534 0 ? "normal" : "use blank bit in Function 09h");
536 // argv[4] may be a pointer with enough space to return screen_info_t
537 // as input, it must contain a screen_info_input_t with the following content:
538 // byte[0:3] = "DDC\0" (zero-terminated signature header)
539 // byte[4:5] = reserved space for the return struct... just in case we ever change
540 // the struct and dont have reserved enough memory (and let's hope the struct
541 // never gets larger than 64KB)
542 // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
543 // byte[7:8] = max. screen width (OF may want to limit this)
544 // byte[9] = required color depth in bpp
545 if (strncmp((char *) input.signature, "DDC", 4) != 0) {
547 ("%s: Invalid input signature! expected: %s, is: %s\n",
548 __func__, "DDC", input.signature);
551 if (input.size_reserved != sizeof(screen_info_t)) {
553 ("%s: Size of return struct is wrong, required: %d, available: %d\n",
554 __func__, (int) sizeof(screen_info_t),
555 input.size_reserved);
559 vbe_ddc_info_t ddc_info;
560 ddc_info.port_number = input.monitor_number;
561 vbe_get_ddc_info(&ddc_info);
564 DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
565 ddc_info.edid_transfer_time);
566 DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
567 DEBUG_PRINTF_VBE("DDC: EDID: \n");
568 CHECK_DBG(DEBUG_VBE) {
569 dump(ddc_info.edid_block_zero,
570 sizeof(ddc_info.edid_block_zero));
573 if (*((u64 *) ddc_info.edid_block_zero) !=
574 (u64) 0x00FFFFFFFFFFFF00) {
575 // invalid EDID signature... probably no monitor
577 output->display_type = 0x0;
579 } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
581 output->display_type = 2;
584 output->display_type = 1;
586 DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
587 memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
588 sizeof(ddc_info.edid_block_zero));
590 vbe_mode_info_t mode_info;
591 vbe_mode_info_t best_mode_info;
592 // initialize best_mode to 0
593 memset(&best_mode_info, 0, sizeof(best_mode_info));
594 while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
595 //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
596 vbe_get_mode_info(&mode_info);
598 // FIXME all these values are little endian!
600 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
601 mode_info.video_mode,
602 (mode_info.attributes & 0x1) ==
603 0 ? "not supported" : "supported");
604 DEBUG_PRINTF_VBE("\tTTY: %s\n",
605 (mode_info.attributes & 0x4) ==
607 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
608 (mode_info.attributes & 0x8) ==
609 0 ? "monochrome" : "color",
610 (mode_info.attributes & 0x10) ==
611 0 ? "text" : "graphics");
612 DEBUG_PRINTF_VBE("\tVGA: %s\n",
613 (mode_info.attributes & 0x20) ==
614 0 ? "compatible" : "not compatible");
615 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
616 (mode_info.attributes & 0x40) ==
618 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
619 (mode_info.attributes & 0x80) ==
621 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
622 mode_info.x_resolution,
623 mode_info.y_resolution);
624 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
625 mode_info.x_charsize, mode_info.y_charsize);
626 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
627 mode_info.bits_per_pixel);
628 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
629 mode_info.memory_model);
630 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
631 mode_info.framebuffer_address);
633 if ((mode_info.vesa.bits_per_pixel == input.color_depth)
634 && (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width)
635 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0) // framebuffer mode
636 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0) // graphics
637 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0) // color
638 && (le16_to_cpu(mode_info.vesa.x_resolution) > le16_to_cpu(best_mode_info.vesa.x_resolution))) // better than previous best_mode
640 // yiiiihaah... we found a new best mode
641 memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
646 if (best_mode_info.video_mode != 0) {
648 ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
649 best_mode_info.video_mode,
650 best_mode_info.x_resolution,
651 best_mode_info.y_resolution,
652 best_mode_info.bits_per_pixel,
653 best_mode_info.framebuffer_address);
655 //printf("Mode Info Dump:");
656 //dump(best_mode_info.mode_info_block, 64);
658 // set the video mode
659 vbe_set_mode(&best_mode_info);
661 if ((info.capabilities & 0x1) != 0) {
662 // switch to 8 bit palette format
663 vbe_set_palette_format(8);
666 // - first 216 colors are mixed colors for each component in 6 steps
668 // - then 10 shades of the three primary colors
669 // - then 10 shades of grey
673 // - finally black is color 0 and white color FF (because SLOF expects it
675 // this resembles the palette that the kernel/X Server seems to expect...
677 u8 mixed_color_values[6] =
678 { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
679 u8 primary_color_values[10] =
680 { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
683 u8 mc_size = sizeof(mixed_color_values);
684 u8 prim_size = sizeof(primary_color_values);
691 for (r = 0; r < mc_size; r++) {
692 for (g = 0; g < mc_size; g++) {
693 for (b = 0; b < mc_size; b++) {
695 (r * mc_size * mc_size) +
698 curr_color |= ((u32) mixed_color_values[r]) << 16; //red value
699 curr_color |= ((u32) mixed_color_values[g]) << 8; //green value
700 curr_color |= (u32) mixed_color_values[b]; //blue value
701 vbe_set_color(curr_color_index,
707 // 10 shades of each primary color
709 for (r = 0; r < prim_size; r++) {
710 curr_color_index = mc_size * mc_size * mc_size + r;
711 curr_color = ((u32) primary_color_values[r]) << 16;
712 vbe_set_color(curr_color_index, curr_color);
715 for (g = 0; g < prim_size; g++) {
717 mc_size * mc_size * mc_size + prim_size + g;
718 curr_color = ((u32) primary_color_values[g]) << 8;
719 vbe_set_color(curr_color_index, curr_color);
722 for (b = 0; b < prim_size; b++) {
724 mc_size * mc_size * mc_size + prim_size * 2 + b;
725 curr_color = (u32) primary_color_values[b];
726 vbe_set_color(curr_color_index, curr_color);
729 for (i = 0; i < prim_size; i++) {
731 mc_size * mc_size * mc_size + prim_size * 3 + i;
733 curr_color |= ((u32) primary_color_values[i]) << 16; //red
734 curr_color |= ((u32) primary_color_values[i]) << 8; //green
735 curr_color |= ((u32) primary_color_values[i]); //blue
736 vbe_set_color(curr_color_index, curr_color);
739 // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
740 vbe_set_color(0x00, 0x00000000);
741 vbe_set_color(0xFF, 0x00FFFFFF);
743 output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution);
744 output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution);
745 output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline);
746 output->color_depth = best_mode_info.vesa.bits_per_pixel;
747 output->framebuffer_address =
748 le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
750 printf("%s: No suitable video mode found!\n", __func__);
751 //unset display_type...
752 output->display_type = 0;
757 #if CONFIG_BOOTSPLASH
758 vbe_mode_info_t mode_info;
760 void vbe_set_graphics(void)
766 rval = vbe_info(&info);
770 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
771 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
772 DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
773 DEBUG_PRINTF_VBE("Capabilities:\n");
774 DEBUG_PRINTF_VBE("\tDAC: %s\n",
775 (info.capabilities & 0x1) ==
776 0 ? "fixed 6bit" : "switchable 6/8bit");
777 DEBUG_PRINTF_VBE("\tVGA: %s\n",
778 (info.capabilities & 0x2) ==
779 0 ? "compatible" : "not compatible");
780 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
781 (info.capabilities & 0x4) ==
782 0 ? "normal" : "use blank bit in Function 09h");
784 mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE;
785 vbe_get_mode_info(&mode_info);
786 unsigned char *framebuffer =
787 (unsigned char *) le32_to_cpu(mode_info.vesa.phys_base_ptr);
788 DEBUG_PRINTF_VBE("FRAMEBUFFER: 0x%08x\n", framebuffer);
789 vbe_set_mode(&mode_info);
791 struct jpeg_decdata *decdata;
792 decdata = malloc(sizeof(*decdata));
794 /* Switching Intel IGD to 1MB video memory will break this. Who
796 int imagesize = 1024*768*2;
798 unsigned char *jpeg = cbfs_find_file("bootsplash.jpg", CBFS_TYPE_BOOTSPLASH);
800 DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n");
803 DEBUG_PRINTF_VBE("Splash at %08x ...\n", jpeg);
807 DEBUG_PRINTF_VBE("Decompressing boot splash screen...\n");
808 ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata);
809 DEBUG_PRINTF_VBE("returns %x\n", ret);
812 void fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
814 framebuffer->physical_address = le32_to_cpu(mode_info.vesa.phys_base_ptr);
816 framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution);
817 framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution);
818 framebuffer->bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline);
819 framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel;
821 framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos;
822 framebuffer->red_mask_size = mode_info.vesa.red_mask_size;
824 framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos;
825 framebuffer->green_mask_size = mode_info.vesa.green_mask_size;
827 framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos;
828 framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size;
830 framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos;
831 framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size;
834 void vbe_textmode_console(void)
836 /* Wait, just a little bit more, pleeeease ;-) */
839 M.x86.R_EAX = 0x0003;