- drop x86emu + old biosemu in favor of YABEL - Add YABEL_DIRECTHW to get the old biosemu behavior - add support for vesa console using YABEL - add coreboot table entry with console information - add bootsplash support (reads /bootsplash.jpg from CBFS) Signed-off-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Pattrick Hueper <phueper@hueper.net> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5135 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
		
			
				
	
	
		
			845 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			845 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /******************************************************************************
 | |
|  * Copyright (c) 2004, 2008 IBM Corporation
 | |
|  * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
 | |
|  * All rights reserved.
 | |
|  * This program and the accompanying materials
 | |
|  * are made available under the terms of the BSD License
 | |
|  * which accompanies this distribution, and is available at
 | |
|  * http://www.opensource.org/licenses/bsd-license.php
 | |
|  *
 | |
|  * Contributors:
 | |
|  *     IBM Corporation - initial implementation
 | |
|  *****************************************************************************/
 | |
| 
 | |
| #include <string.h>
 | |
| #include <types.h>
 | |
| #if CONFIG_BOOTSPLASH
 | |
| #include <boot/coreboot_tables.h>
 | |
| #endif
 | |
| 
 | |
| #include <arch/byteorder.h>
 | |
| #define ntohl(x) be32_to_cpu(x)
 | |
| 
 | |
| #include "debug.h"
 | |
| 
 | |
| #include <x86emu/x86emu.h>
 | |
| #include <x86emu/regs.h>
 | |
| #include "../x86emu/prim_ops.h"
 | |
| 
 | |
| #include "biosemu.h"
 | |
| #include "io.h"
 | |
| #include "mem.h"
 | |
| #include "interrupt.h"
 | |
| #include "device.h"
 | |
| 
 | |
| #include <cbfs.h>
 | |
| 
 | |
| #include <delay.h>
 | |
| #include "../../src/lib/jpeg.h"
 | |
| 
 | |
| // pointer to VBEInfoBuffer, set by vbe_prepare
 | |
| u8 *vbe_info_buffer = 0;
 | |
| 
 | |
| // virtual BIOS Memory
 | |
| u8 *biosmem;
 | |
| u32 biosmem_size;
 | |
| 
 | |
| // these structs are for input from and output to OF
 | |
| typedef struct {
 | |
| 	u8 display_type;	// 0=NONE, 1= analog, 2=digital
 | |
| 	u16 screen_width;
 | |
| 	u16 screen_height;
 | |
| 	u16 screen_linebytes;	// bytes per line in framebuffer, may be more than screen_width
 | |
| 	u8 color_depth;	// color depth in bpp
 | |
| 	u32 framebuffer_address;
 | |
| 	u8 edid_block_zero[128];
 | |
| } __attribute__ ((__packed__)) screen_info_t;
 | |
| 
 | |
| typedef struct {
 | |
| 	u8 signature[4];
 | |
| 	u16 size_reserved;
 | |
| 	u8 monitor_number;
 | |
| 	u16 max_screen_width;
 | |
| 	u8 color_depth;
 | |
| } __attribute__ ((__packed__)) screen_info_input_t;
 | |
| 
 | |
| // these structs only store a subset of the VBE defined fields
 | |
| // only those needed.
 | |
| typedef struct {
 | |
| 	char signature[4];
 | |
| 	u16 version;
 | |
| 	u8 *oem_string_ptr;
 | |
| 	u32 capabilities;
 | |
| 	u16 video_mode_list[256];	// lets hope we never have more than 256 video modes...
 | |
| 	u16 total_memory;
 | |
| } vbe_info_t;
 | |
| 
 | |
| typedef struct {
 | |
| 	u16 mode_attributes; // 00
 | |
| 	u8 win_a_attributes; // 02
 | |
| 	u8 win_b_attributes; // 03
 | |
| 	u16 win_granularity; // 04
 | |
| 	u16 win_size;        // 06
 | |
| 	u16 win_a_segment;   // 08
 | |
| 	u16 win_b_segment;   // 0a
 | |
| 	u32 win_func_ptr;    // 0c
 | |
| 	u16 bytes_per_scanline; // 10
 | |
| 	u16 x_resolution;    // 12
 | |
| 	u16 y_resolution;    // 14
 | |
| 	u8 x_charsize;       // 16
 | |
| 	u8 y_charsize;       // 17
 | |
| 	u8 number_of_planes; // 18
 | |
| 	u8 bits_per_pixel;   // 19
 | |
| 	u8 number_of_banks;  // 20
 | |
| 	u8 memory_model;     // 21
 | |
| 	u8 bank_size;        // 22
 | |
| 	u8 number_of_image_pages; // 23
 | |
| 	u8 reserved_page;
 | |
| 	u8 red_mask_size;
 | |
| 	u8 red_mask_pos;
 | |
| 	u8 green_mask_size;
 | |
| 	u8 green_mask_pos;
 | |
| 	u8 blue_mask_size;
 | |
| 	u8 blue_mask_pos;
 | |
| 	u8 reserved_mask_size;
 | |
| 	u8 reserved_mask_pos;
 | |
| 	u8 direct_color_mode_info;
 | |
| 	u32 phys_base_ptr;
 | |
| 	u32 offscreen_mem_offset;
 | |
| 	u16 offscreen_mem_size;
 | |
| 	u8 reserved[206];
 | |
| } __attribute__ ((__packed__)) vesa_mode_info_t;
 | |
| 
 | |
| typedef struct {
 | |
| 	u16 video_mode;
 | |
| 	union {
 | |
| 		vesa_mode_info_t vesa;
 | |
| 		u8 mode_info_block[256];
 | |
| 	};
 | |
| 	// our crap
 | |
| 	//u16 attributes;
 | |
| 	//u16 linebytes;
 | |
| 	//u16 x_resolution;
 | |
| 	//u16 y_resolution;
 | |
| 	//u8 x_charsize;
 | |
| 	//u8 y_charsize;
 | |
| 	//u8 bits_per_pixel;
 | |
| 	//u8 memory_model;
 | |
| 	//u32 framebuffer_address;
 | |
| } vbe_mode_info_t;
 | |
| 
 | |
| typedef struct {
 | |
| 	u8 port_number;	// i.e. monitor number
 | |
| 	u8 edid_transfer_time;
 | |
| 	u8 ddc_level;
 | |
| 	u8 edid_block_zero[128];
 | |
| } vbe_ddc_info_t;
 | |
| 
 | |
| static inline u8
 | |
| vbe_prepare(void)
 | |
| {
 | |
| 	vbe_info_buffer = biosmem + (VBE_SEGMENT << 4);	// segment:offset off VBE Data Area
 | |
| 	//clear buffer
 | |
| 	memset(vbe_info_buffer, 0, 512);
 | |
| 	//set VbeSignature to "VBE2" to indicate VBE 2.0+ request
 | |
| 	vbe_info_buffer[0] = 'V';
 | |
| 	vbe_info_buffer[0] = 'B';
 | |
| 	vbe_info_buffer[0] = 'E';
 | |
| 	vbe_info_buffer[0] = '2';
 | |
| 	// ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
 | |
| 	M.x86.R_EDI = 0x0;
 | |
| 	M.x86.R_ES = VBE_SEGMENT;
 | |
| 
 | |
| 	return 0;		// successfull init
 | |
| }
 | |
| 
 | |
| // VBE Function 00h
 | |
| u8
 | |
| vbe_info(vbe_info_t * info)
 | |
| {
 | |
| 	vbe_prepare();
 | |
| 	// call VBE function 00h (Info Function)
 | |
| 	M.x86.R_EAX = 0x4f00;
 | |
| 
 | |
| 	// enable trace
 | |
| 	CHECK_DBG(DEBUG_TRACE_X86EMU) {
 | |
| 		X86EMU_trace_on();
 | |
| 	}
 | |
| 	// run VESA Interrupt
 | |
| 	runInt10();
 | |
| 
 | |
| 	if (M.x86.R_AL != 0x4f) {
 | |
| 		DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
 | |
| 				 __func__, M.x86.R_AL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (M.x86.R_AH != 0x0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
 | |
| 		     __func__, M.x86.R_AH);
 | |
| 		return M.x86.R_AH;
 | |
| 	}
 | |
| 	//printf("VBE Info Dump:");
 | |
| 	//dump(vbe_info_buffer, 64);
 | |
| 
 | |
| 	//offset 0: signature
 | |
| 	info->signature[0] = vbe_info_buffer[0];
 | |
| 	info->signature[1] = vbe_info_buffer[1];
 | |
| 	info->signature[2] = vbe_info_buffer[2];
 | |
| 	info->signature[3] = vbe_info_buffer[3];
 | |
| 
 | |
| 	// offset 4: 16bit le containing VbeVersion
 | |
| 	info->version = in16le(vbe_info_buffer + 4);
 | |
| 
 | |
| 	// offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
 | |
| 	info->oem_string_ptr =
 | |
| 	    biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
 | |
| 		       in16le(vbe_info_buffer + 6));
 | |
| 
 | |
| 	// offset 10: 32bit le capabilities
 | |
| 	info->capabilities = in32le(vbe_info_buffer + 10);
 | |
| 
 | |
| 	// offset 14: 32 bit le containing segment:offset of supported video mode table
 | |
| 	u16 *video_mode_ptr;
 | |
| 	video_mode_ptr =
 | |
| 	    (u16 *) (biosmem +
 | |
| 			  ((in16le(vbe_info_buffer + 16) << 4) +
 | |
| 			   in16le(vbe_info_buffer + 14)));
 | |
| 	u32 i = 0;
 | |
| 	do {
 | |
| 		info->video_mode_list[i] = in16le(video_mode_ptr + i);
 | |
| 		i++;
 | |
| 	}
 | |
| 	while ((i <
 | |
| 		(sizeof(info->video_mode_list) /
 | |
| 		 sizeof(info->video_mode_list[0])))
 | |
| 	       && (info->video_mode_list[i - 1] != 0xFFFF));
 | |
| 
 | |
| 	//offset 18: 16bit le total memory in 64KB blocks
 | |
| 	info->total_memory = in16le(vbe_info_buffer + 18);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| // VBE Function 01h
 | |
| u8
 | |
| vbe_get_mode_info(vbe_mode_info_t * mode_info)
 | |
| {
 | |
| 	vbe_prepare();
 | |
| 	// call VBE function 01h (Return VBE Mode Info Function)
 | |
| 	M.x86.R_EAX = 0x4f01;
 | |
| 	M.x86.R_CX = mode_info->video_mode;
 | |
| 
 | |
| 	// enable trace
 | |
| 	CHECK_DBG(DEBUG_TRACE_X86EMU) {
 | |
| 		X86EMU_trace_on();
 | |
| 	}
 | |
| 	// run VESA Interrupt
 | |
| 	runInt10();
 | |
| 
 | |
| 	if (M.x86.R_AL != 0x4f) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
 | |
| 		     __func__, M.x86.R_AL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (M.x86.R_AH != 0x0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
 | |
| 		     __func__, mode_info->video_mode, M.x86.R_AH);
 | |
| 		return M.x86.R_AH;
 | |
| 	}
 | |
| 
 | |
| 	//pointer to mode_info_block is in ES:DI
 | |
| 	memcpy(mode_info->mode_info_block,
 | |
| 	       biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
 | |
| 	       sizeof(mode_info->mode_info_block));
 | |
| 
 | |
| 	//printf("Mode Info Dump:");
 | |
| 	//dump(mode_info_block, 64);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| // VBE Function 02h
 | |
| u8
 | |
| vbe_set_mode(vbe_mode_info_t * mode_info)
 | |
| {
 | |
| 	vbe_prepare();
 | |
| 	// call VBE function 02h (Set VBE Mode Function)
 | |
| 	M.x86.R_EAX = 0x4f02;
 | |
| 	M.x86.R_BX = mode_info->video_mode;
 | |
| 	M.x86.R_BX |= 0x4000;	// set bit 14 to request linear framebuffer mode
 | |
| 	M.x86.R_BX &= 0x7FFF;	// clear bit 15 to request clearing of framebuffer
 | |
| 
 | |
| 	DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
 | |
| 			 M.x86.R_BX);
 | |
| 
 | |
| 	// enable trace
 | |
| 	CHECK_DBG(DEBUG_TRACE_X86EMU) {
 | |
| 		X86EMU_trace_on();
 | |
| 	}
 | |
| 	// run VESA Interrupt
 | |
| 	runInt10();
 | |
| 
 | |
| 	if (M.x86.R_AL != 0x4f) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
 | |
| 		     __func__, M.x86.R_AL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (M.x86.R_AH != 0x0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
 | |
| 		     __func__, mode_info->video_mode, M.x86.R_AH);
 | |
| 		return M.x86.R_AH;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| //VBE Function 08h
 | |
| u8
 | |
| vbe_set_palette_format(u8 format)
 | |
| {
 | |
| 	vbe_prepare();
 | |
| 	// call VBE function 09h (Set/Get Palette Data Function)
 | |
| 	M.x86.R_EAX = 0x4f08;
 | |
| 	M.x86.R_BL = 0x00;	// set format
 | |
| 	M.x86.R_BH = format;
 | |
| 
 | |
| 	DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
 | |
| 			 format);
 | |
| 
 | |
| 	// enable trace
 | |
| 	CHECK_DBG(DEBUG_TRACE_X86EMU) {
 | |
| 		X86EMU_trace_on();
 | |
| 	}
 | |
| 	// run VESA Interrupt
 | |
| 	runInt10();
 | |
| 
 | |
| 	if (M.x86.R_AL != 0x4f) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
 | |
| 		     __func__, M.x86.R_AL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (M.x86.R_AH != 0x0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
 | |
| 		     __func__, M.x86.R_AH);
 | |
| 		return M.x86.R_AH;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| // VBE Function 09h
 | |
| u8
 | |
| vbe_set_color(u16 color_number, u32 color_value)
 | |
| {
 | |
| 	vbe_prepare();
 | |
| 	// call VBE function 09h (Set/Get Palette Data Function)
 | |
| 	M.x86.R_EAX = 0x4f09;
 | |
| 	M.x86.R_BL = 0x00;	// set color
 | |
| 	M.x86.R_CX = 0x01;	// set only one entry
 | |
| 	M.x86.R_DX = color_number;
 | |
| 	// ES:DI is address where color_value is stored, we store it at 2000:0000
 | |
| 	M.x86.R_ES = 0x2000;
 | |
| 	M.x86.R_DI = 0x0;
 | |
| 
 | |
| 	// store color value at ES:DI
 | |
| 	out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
 | |
| 
 | |
| 	DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
 | |
| 			 color_number, color_value);
 | |
| 
 | |
| 	// enable trace
 | |
| 	CHECK_DBG(DEBUG_TRACE_X86EMU) {
 | |
| 		X86EMU_trace_on();
 | |
| 	}
 | |
| 	// run VESA Interrupt
 | |
| 	runInt10();
 | |
| 
 | |
| 	if (M.x86.R_AL != 0x4f) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
 | |
| 		     __func__, M.x86.R_AL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (M.x86.R_AH != 0x0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
 | |
| 		     __func__, M.x86.R_AH);
 | |
| 		return M.x86.R_AH;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| u8
 | |
| vbe_get_color(u16 color_number, u32 * color_value)
 | |
| {
 | |
| 	vbe_prepare();
 | |
| 	// call VBE function 09h (Set/Get Palette Data Function)
 | |
| 	M.x86.R_EAX = 0x4f09;
 | |
| 	M.x86.R_BL = 0x00;	// get color
 | |
| 	M.x86.R_CX = 0x01;	// get only one entry
 | |
| 	M.x86.R_DX = color_number;
 | |
| 	// ES:DI is address where color_value is stored, we store it at 2000:0000
 | |
| 	M.x86.R_ES = 0x2000;
 | |
| 	M.x86.R_DI = 0x0;
 | |
| 
 | |
| 	// enable trace
 | |
| 	CHECK_DBG(DEBUG_TRACE_X86EMU) {
 | |
| 		X86EMU_trace_on();
 | |
| 	}
 | |
| 	// run VESA Interrupt
 | |
| 	runInt10();
 | |
| 
 | |
| 	if (M.x86.R_AL != 0x4f) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
 | |
| 		     __func__, M.x86.R_AL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (M.x86.R_AH != 0x0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
 | |
| 		     __func__, M.x86.R_AH);
 | |
| 		return M.x86.R_AH;
 | |
| 	}
 | |
| 	// read color value from ES:DI
 | |
| 	*color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
 | |
| 
 | |
| 	DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
 | |
| 			 color_number, *color_value);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| // VBE Function 15h
 | |
| u8
 | |
| vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
 | |
| {
 | |
| 	vbe_prepare();
 | |
| 	// call VBE function 15h (DDC Info Function)
 | |
| 	M.x86.R_EAX = 0x4f15;
 | |
| 	M.x86.R_BL = 0x00;	// get DDC Info
 | |
| 	M.x86.R_CX = ddc_info->port_number;
 | |
| 	M.x86.R_ES = 0x0;
 | |
| 	M.x86.R_DI = 0x0;
 | |
| 
 | |
| 	// enable trace
 | |
| 	CHECK_DBG(DEBUG_TRACE_X86EMU) {
 | |
| 		X86EMU_trace_on();
 | |
| 	}
 | |
| 	// run VESA Interrupt
 | |
| 	runInt10();
 | |
| 
 | |
| 	if (M.x86.R_AL != 0x4f) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
 | |
| 		     __func__, M.x86.R_AL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (M.x86.R_AH != 0x0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
 | |
| 		     __func__, ddc_info->port_number, M.x86.R_AH);
 | |
| 		return M.x86.R_AH;
 | |
| 	}
 | |
| 	// BH = approx. time in seconds to transfer one EDID block
 | |
| 	ddc_info->edid_transfer_time = M.x86.R_BH;
 | |
| 	// BL = DDC Level
 | |
| 	ddc_info->ddc_level = M.x86.R_BL;
 | |
| 
 | |
| 	vbe_prepare();
 | |
| 	// call VBE function 15h (DDC Info Function)
 | |
| 	M.x86.R_EAX = 0x4f15;
 | |
| 	M.x86.R_BL = 0x01;	// read EDID
 | |
| 	M.x86.R_CX = ddc_info->port_number;
 | |
| 	M.x86.R_DX = 0x0;	// block number
 | |
| 	// ES:DI is address where EDID is stored, we store it at 2000:0000
 | |
| 	M.x86.R_ES = 0x2000;
 | |
| 	M.x86.R_DI = 0x0;
 | |
| 
 | |
| 	// enable trace
 | |
| 	CHECK_DBG(DEBUG_TRACE_X86EMU) {
 | |
| 		X86EMU_trace_on();
 | |
| 	}
 | |
| 	// run VESA Interrupt
 | |
| 	runInt10();
 | |
| 
 | |
| 	if (M.x86.R_AL != 0x4f) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
 | |
| 		     __func__, M.x86.R_AL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (M.x86.R_AH != 0x0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
 | |
| 		     __func__, ddc_info->port_number, M.x86.R_AH);
 | |
| 		return M.x86.R_AH;
 | |
| 	}
 | |
| 
 | |
| 	memcpy(ddc_info->edid_block_zero,
 | |
| 	       biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
 | |
| 	       sizeof(ddc_info->edid_block_zero));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| u32
 | |
| vbe_get_info(void)
 | |
| {
 | |
| 	u8 rval;
 | |
| 	int i;
 | |
| 
 | |
| 	// XXX FIXME these need to be filled with sane values
 | |
| 
 | |
| 	// get a copy of input struct...
 | |
| 	screen_info_input_t input;
 | |
| 	// output is pointer to the address passed as argv[4]
 | |
| 	screen_info_t local_output;
 | |
| 	screen_info_t *output = &local_output;
 | |
| 	// zero input
 | |
| 	memset(&input, 0, sizeof(screen_info_input_t));
 | |
| 	// zero output
 | |
| 	memset(&output, 0, sizeof(screen_info_t));
 | |
| 
 | |
| 	vbe_info_t info;
 | |
| 	rval = vbe_info(&info);
 | |
| 	if (rval != 0)
 | |
| 		return rval;
 | |
| 
 | |
| 	DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
 | |
| 	DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
 | |
| 	DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
 | |
| 	DEBUG_PRINTF_VBE("Capabilities:\n");
 | |
| 	DEBUG_PRINTF_VBE("\tDAC: %s\n",
 | |
| 			 (info.capabilities & 0x1) ==
 | |
| 			 0 ? "fixed 6bit" : "switchable 6/8bit");
 | |
| 	DEBUG_PRINTF_VBE("\tVGA: %s\n",
 | |
| 			 (info.capabilities & 0x2) ==
 | |
| 			 0 ? "compatible" : "not compatible");
 | |
| 	DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
 | |
| 			 (info.capabilities & 0x4) ==
 | |
| 			 0 ? "normal" : "use blank bit in Function 09h");
 | |
| 
 | |
| 	// argv[4] may be a pointer with enough space to return screen_info_t
 | |
| 	// as input, it must contain a screen_info_input_t with the following content:
 | |
| 	// byte[0:3] = "DDC\0" (zero-terminated signature header)
 | |
| 	// byte[4:5] = reserved space for the return struct... just in case we ever change
 | |
| 	//             the struct and dont have reserved enough memory (and let's hope the struct
 | |
| 	//             never gets larger than 64KB)
 | |
| 	// byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
 | |
| 	// byte[7:8] = max. screen width (OF may want to limit this)
 | |
| 	// byte[9] = required color depth in bpp
 | |
| 	if (strncmp((char *) input.signature, "DDC", 4) != 0) {
 | |
| 		printf
 | |
| 		    ("%s: Invalid input signature! expected: %s, is: %s\n",
 | |
| 		     __func__, "DDC", input.signature);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	if (input.size_reserved != sizeof(screen_info_t)) {
 | |
| 		printf
 | |
| 		    ("%s: Size of return struct is wrong, required: %d, available: %d\n",
 | |
| 		     __func__, (int) sizeof(screen_info_t),
 | |
| 		     input.size_reserved);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	vbe_ddc_info_t ddc_info;
 | |
| 	ddc_info.port_number = input.monitor_number;
 | |
| 	vbe_get_ddc_info(&ddc_info);
 | |
| 
 | |
| #if 0
 | |
| 	DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
 | |
| 			 ddc_info.edid_transfer_time);
 | |
| 	DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
 | |
| 	DEBUG_PRINTF_VBE("DDC: EDID: \n");
 | |
| 	CHECK_DBG(DEBUG_VBE) {
 | |
| 		dump(ddc_info.edid_block_zero,
 | |
| 		     sizeof(ddc_info.edid_block_zero));
 | |
| 	}
 | |
| #endif
 | |
| 	if (*((u64 *) ddc_info.edid_block_zero) !=
 | |
| 	    (u64) 0x00FFFFFFFFFFFF00) {
 | |
| 		// invalid EDID signature... probably no monitor
 | |
| 
 | |
| 		output->display_type = 0x0;
 | |
| 		return 0;
 | |
| 	} else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
 | |
| 		// digital display
 | |
| 		output->display_type = 2;
 | |
| 	} else {
 | |
| 		// analog
 | |
| 		output->display_type = 1;
 | |
| 	}
 | |
| 	DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
 | |
| 	memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
 | |
| 	       sizeof(ddc_info.edid_block_zero));
 | |
| 	i = 0;
 | |
| 	vbe_mode_info_t mode_info;
 | |
| 	vbe_mode_info_t best_mode_info;
 | |
| 	// initialize best_mode to 0
 | |
| 	memset(&best_mode_info, 0, sizeof(best_mode_info));
 | |
| 	while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
 | |
| 		//DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
 | |
| 		vbe_get_mode_info(&mode_info);
 | |
| 
 | |
| 		// FIXME all these values are little endian!
 | |
| 
 | |
| 		DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
 | |
| 				 mode_info.video_mode,
 | |
| 				 (mode_info.attributes & 0x1) ==
 | |
| 				 0 ? "not supported" : "supported");
 | |
| 		DEBUG_PRINTF_VBE("\tTTY: %s\n",
 | |
| 				 (mode_info.attributes & 0x4) ==
 | |
| 				 0 ? "no" : "yes");
 | |
| 		DEBUG_PRINTF_VBE("\tMode: %s %s\n",
 | |
| 				 (mode_info.attributes & 0x8) ==
 | |
| 				 0 ? "monochrome" : "color",
 | |
| 				 (mode_info.attributes & 0x10) ==
 | |
| 				 0 ? "text" : "graphics");
 | |
| 		DEBUG_PRINTF_VBE("\tVGA: %s\n",
 | |
| 				 (mode_info.attributes & 0x20) ==
 | |
| 				 0 ? "compatible" : "not compatible");
 | |
| 		DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
 | |
| 				 (mode_info.attributes & 0x40) ==
 | |
| 				 0 ? "yes" : "no");
 | |
| 		DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
 | |
| 				 (mode_info.attributes & 0x80) ==
 | |
| 				 0 ? "no" : "yes");
 | |
| 		DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
 | |
| 				 mode_info.x_resolution,
 | |
| 				 mode_info.y_resolution);
 | |
| 		DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
 | |
| 				 mode_info.x_charsize, mode_info.y_charsize);
 | |
| 		DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
 | |
| 				 mode_info.bits_per_pixel);
 | |
| 		DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
 | |
| 				 mode_info.memory_model);
 | |
| 		DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
 | |
| 				 mode_info.framebuffer_address);
 | |
| 
 | |
| 		if ((mode_info.vesa.bits_per_pixel == input.color_depth)
 | |
| 		    && (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width)
 | |
| 		    && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0)	// framebuffer mode
 | |
| 		    && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0)	// graphics
 | |
| 		    && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0)	// color
 | |
| 		    && (le16_to_cpu(mode_info.vesa.x_resolution) > le16_to_cpu(best_mode_info.vesa.x_resolution)))	// better than previous best_mode
 | |
| 		{
 | |
| 			// yiiiihaah... we found a new best mode
 | |
| 			memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
 | |
| 		}
 | |
| 		i++;
 | |
| 	}
 | |
| 
 | |
| 	if (best_mode_info.video_mode != 0) {
 | |
| 		DEBUG_PRINTF_VBE
 | |
| 		    ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
 | |
| 		     best_mode_info.video_mode,
 | |
| 		     best_mode_info.x_resolution,
 | |
| 		     best_mode_info.y_resolution,
 | |
| 		     best_mode_info.bits_per_pixel,
 | |
| 		     best_mode_info.framebuffer_address);
 | |
| 
 | |
| 		//printf("Mode Info Dump:");
 | |
| 		//dump(best_mode_info.mode_info_block, 64);
 | |
| 
 | |
| 		// set the video mode
 | |
| 		vbe_set_mode(&best_mode_info);
 | |
| 
 | |
| 		if ((info.capabilities & 0x1) != 0) {
 | |
| 			// switch to 8 bit palette format
 | |
| 			vbe_set_palette_format(8);
 | |
| 		}
 | |
| 		// setup a palette:
 | |
| 		// - first 216 colors are mixed colors for each component in 6 steps
 | |
| 		//   (6*6*6=216)
 | |
| 		// - then 10 shades of the three primary colors
 | |
| 		// - then 10 shades of grey
 | |
| 		// -------
 | |
| 		// = 256 colors
 | |
| 		//
 | |
| 		// - finally black is color 0 and white color FF (because SLOF expects it
 | |
| 		//   this way...)
 | |
| 		// this resembles the palette that the kernel/X Server seems to expect...
 | |
| 
 | |
| 		u8 mixed_color_values[6] =
 | |
| 		    { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
 | |
| 		u8 primary_color_values[10] =
 | |
| 		    { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
 | |
| 			0x27
 | |
| 		};
 | |
| 		u8 mc_size = sizeof(mixed_color_values);
 | |
| 		u8 prim_size = sizeof(primary_color_values);
 | |
| 
 | |
| 		u8 curr_color_index;
 | |
| 		u32 curr_color;
 | |
| 
 | |
| 		u8 r, g, b;
 | |
| 		// 216 mixed colors
 | |
| 		for (r = 0; r < mc_size; r++) {
 | |
| 			for (g = 0; g < mc_size; g++) {
 | |
| 				for (b = 0; b < mc_size; b++) {
 | |
| 					curr_color_index =
 | |
| 					    (r * mc_size * mc_size) +
 | |
| 					    (g * mc_size) + b;
 | |
| 					curr_color = 0;
 | |
| 					curr_color |= ((u32) mixed_color_values[r]) << 16;	//red value
 | |
| 					curr_color |= ((u32) mixed_color_values[g]) << 8;	//green value
 | |
| 					curr_color |= (u32) mixed_color_values[b];	//blue value
 | |
| 					vbe_set_color(curr_color_index,
 | |
| 						      curr_color);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// 10 shades of each primary color
 | |
| 		// red
 | |
| 		for (r = 0; r < prim_size; r++) {
 | |
| 			curr_color_index = mc_size * mc_size * mc_size + r;
 | |
| 			curr_color = ((u32) primary_color_values[r]) << 16;
 | |
| 			vbe_set_color(curr_color_index, curr_color);
 | |
| 		}
 | |
| 		//green
 | |
| 		for (g = 0; g < prim_size; g++) {
 | |
| 			curr_color_index =
 | |
| 			    mc_size * mc_size * mc_size + prim_size + g;
 | |
| 			curr_color = ((u32) primary_color_values[g]) << 8;
 | |
| 			vbe_set_color(curr_color_index, curr_color);
 | |
| 		}
 | |
| 		//blue
 | |
| 		for (b = 0; b < prim_size; b++) {
 | |
| 			curr_color_index =
 | |
| 			    mc_size * mc_size * mc_size + prim_size * 2 + b;
 | |
| 			curr_color = (u32) primary_color_values[b];
 | |
| 			vbe_set_color(curr_color_index, curr_color);
 | |
| 		}
 | |
| 		// 10 shades of grey
 | |
| 		for (i = 0; i < prim_size; i++) {
 | |
| 			curr_color_index =
 | |
| 			    mc_size * mc_size * mc_size + prim_size * 3 + i;
 | |
| 			curr_color = 0;
 | |
| 			curr_color |= ((u32) primary_color_values[i]) << 16;	//red
 | |
| 			curr_color |= ((u32) primary_color_values[i]) << 8;	//green
 | |
| 			curr_color |= ((u32) primary_color_values[i]);	//blue
 | |
| 			vbe_set_color(curr_color_index, curr_color);
 | |
| 		}
 | |
| 
 | |
| 		// SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
 | |
| 		vbe_set_color(0x00, 0x00000000);
 | |
| 		vbe_set_color(0xFF, 0x00FFFFFF);
 | |
| 
 | |
| 		output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution);
 | |
| 		output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution);
 | |
| 		output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline);
 | |
| 		output->color_depth = best_mode_info.vesa.bits_per_pixel;
 | |
| 		output->framebuffer_address =
 | |
| 		    le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
 | |
| 	} else {
 | |
| 		printf("%s: No suitable video mode found!\n", __func__);
 | |
| 		//unset display_type...
 | |
| 		output->display_type = 0;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #if CONFIG_BOOTSPLASH
 | |
| vbe_mode_info_t mode_info;
 | |
| 
 | |
| void vbe_set_graphics(void)
 | |
| {
 | |
| 	u8 rval;
 | |
| 	int i;
 | |
| 
 | |
| 	vbe_info_t info;
 | |
| 	rval = vbe_info(&info);
 | |
| 	if (rval != 0)
 | |
| 		return;
 | |
| 
 | |
| 	DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
 | |
| 	DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
 | |
| 	DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
 | |
| 	DEBUG_PRINTF_VBE("Capabilities:\n");
 | |
| 	DEBUG_PRINTF_VBE("\tDAC: %s\n",
 | |
| 			 (info.capabilities & 0x1) ==
 | |
| 			 0 ? "fixed 6bit" : "switchable 6/8bit");
 | |
| 	DEBUG_PRINTF_VBE("\tVGA: %s\n",
 | |
| 			 (info.capabilities & 0x2) ==
 | |
| 			 0 ? "compatible" : "not compatible");
 | |
| 	DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
 | |
| 			 (info.capabilities & 0x4) ==
 | |
| 			 0 ? "normal" : "use blank bit in Function 09h");
 | |
| 
 | |
| 	mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE;
 | |
| 	vbe_get_mode_info(&mode_info);
 | |
| 	unsigned char *framebuffer = 
 | |
| 		(unsigned char *) le32_to_cpu(mode_info.vesa.phys_base_ptr);
 | |
| 	DEBUG_PRINTF_VBE("FRAMEBUFFER: 0x%08x\n", framebuffer);
 | |
| 	vbe_set_mode(&mode_info);
 | |
| 
 | |
| 	struct jpeg_decdata *decdata;
 | |
| 	decdata = malloc(sizeof(*decdata));
 | |
| 
 | |
| 	/* Switching Intel IGD to 1MB video memory will break this. Who
 | |
| 	 * cares. */
 | |
| 	int imagesize = 1024*768*2;
 | |
| 	
 | |
| 	struct cbfs_file *file = cbfs_find("bootsplash.jpg");
 | |
| 	if (!file) { 
 | |
| 		DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n");
 | |
| 		return;
 | |
| 	}
 | |
| 	unsigned char *jpeg = ((unsigned char *)file) + ntohl(file->offset);
 | |
| 	DEBUG_PRINTF_VBE("Splash at %08x ...\n", jpeg);
 | |
| 	dump(jpeg, 64);
 | |
| 
 | |
| 	int ret = 0;
 | |
| 	DEBUG_PRINTF_VBE("Decompressing boot splash screen...\n");
 | |
| 	ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata);
 | |
| 	DEBUG_PRINTF_VBE("returns %x\n", ret);
 | |
| }
 | |
| 
 | |
| void fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
 | |
| {
 | |
| 	framebuffer->physical_address = le32_to_cpu(mode_info.vesa.phys_base_ptr);
 | |
| 
 | |
| 	framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution);
 | |
| 	framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution);
 | |
| 	framebuffer->bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline);
 | |
| 	framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel;
 | |
| 
 | |
| 	framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos;
 | |
| 	framebuffer->red_mask_size = mode_info.vesa.red_mask_size;
 | |
| 
 | |
| 	framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos;
 | |
| 	framebuffer->green_mask_size = mode_info.vesa.green_mask_size;
 | |
| 
 | |
| 	framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos;
 | |
| 	framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size;
 | |
| 
 | |
| 	framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos;
 | |
| 	framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size;
 | |
| }
 | |
| 
 | |
| void vbe_textmode_console(void)
 | |
| {
 | |
| 	/* Wait, just a little bit more, pleeeease ;-) */
 | |
| 	delay(2);
 | |
| 
 | |
| 	M.x86.R_EAX = 0x0003;
 | |
| 	runInt10();
 | |
| }
 | |
| 
 | |
| #endif
 |