327 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			327 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
/****************************************************************************
 | 
						|
*
 | 
						|
*                        BIOS emulator and interface
 | 
						|
*                      to Realmode X86 Emulator Library
 | 
						|
*
 | 
						|
*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
 | 
						|
*  Jason Jin <Jason.jin@freescale.com>
 | 
						|
*
 | 
						|
*               Copyright (C) 1996-1999 SciTech Software, Inc.
 | 
						|
*
 | 
						|
*  ========================================================================
 | 
						|
*
 | 
						|
*  Permission to use, copy, modify, distribute, and sell this software and
 | 
						|
*  its documentation for any purpose is hereby granted without fee,
 | 
						|
*  provided that the above copyright notice appear in all copies and that
 | 
						|
*  both that copyright notice and this permission notice appear in
 | 
						|
*  supporting documentation, and that the name of the authors not be used
 | 
						|
*  in advertising or publicity pertaining to distribution of the software
 | 
						|
*  without specific, written prior permission.  The authors makes no
 | 
						|
*  representations about the suitability of this software for any purpose.
 | 
						|
*  It is provided "as is" without express or implied warranty.
 | 
						|
*
 | 
						|
*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
						|
*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
						|
*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 | 
						|
*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 | 
						|
*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | 
						|
*  PERFORMANCE OF THIS SOFTWARE.
 | 
						|
*
 | 
						|
*  ========================================================================
 | 
						|
*
 | 
						|
* Language:     ANSI C
 | 
						|
* Environment:  Any
 | 
						|
* Developer:    Kendall Bennett
 | 
						|
*
 | 
						|
* Description:  Module implementing the BIOS specific functions.
 | 
						|
*
 | 
						|
* 		Jason ported this file to u-boot to run the ATI video card
 | 
						|
* 		video BIOS.
 | 
						|
*
 | 
						|
****************************************************************************/
 | 
						|
 | 
						|
#include <common.h>
 | 
						|
 | 
						|
#if defined(CONFIG_BIOSEMU)
 | 
						|
 | 
						|
#include "biosemui.h"
 | 
						|
 | 
						|
/*----------------------------- Implementation ----------------------------*/
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
PARAMETERS:
 | 
						|
intno   - Interrupt number being serviced
 | 
						|
 | 
						|
REMARKS:
 | 
						|
Handler for undefined interrupts.
 | 
						|
****************************************************************************/
 | 
						|
static void X86API undefined_intr(int intno)
 | 
						|
{
 | 
						|
	if (BE_rdw(intno * 4 + 2) == BIOS_SEG) {
 | 
						|
		DB(printf("biosEmu: undefined interrupt %xh called!\n", intno);)
 | 
						|
	} else
 | 
						|
		X86EMU_prepareForInt(intno);
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
PARAMETERS:
 | 
						|
intno   - Interrupt number being serviced
 | 
						|
 | 
						|
REMARKS:
 | 
						|
This function handles the default system BIOS Int 10h (the default is stored
 | 
						|
in the Int 42h vector by the system BIOS at bootup). We only need to handle
 | 
						|
a small number of special functions used by the BIOS during POST time.
 | 
						|
****************************************************************************/
 | 
						|
static void X86API int42(int intno)
 | 
						|
{
 | 
						|
	if (M.x86.R_AH == 0x12 && M.x86.R_BL == 0x32) {
 | 
						|
		if (M.x86.R_AL == 0) {
 | 
						|
			/* Enable CPU accesses to video memory */
 | 
						|
			PM_outpb(0x3c2, PM_inpb(0x3cc) | (u8) 0x02);
 | 
						|
			return;
 | 
						|
		} else if (M.x86.R_AL == 1) {
 | 
						|
			/* Disable CPU accesses to video memory */
 | 
						|
			PM_outpb(0x3c2, PM_inpb(0x3cc) & (u8) ~ 0x02);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
#ifdef  DEBUG
 | 
						|
		else {
 | 
						|
			printf("int42: unknown function AH=0x12, BL=0x32, AL=%#02x\n",
 | 
						|
			     M.x86.R_AL);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
	}
 | 
						|
#ifdef  DEBUG
 | 
						|
	else {
 | 
						|
		printf("int42: unknown function AH=%#02x, AL=%#02x, BL=%#02x\n",
 | 
						|
		     M.x86.R_AH, M.x86.R_AL, M.x86.R_BL);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
PARAMETERS:
 | 
						|
intno   - Interrupt number being serviced
 | 
						|
 | 
						|
REMARKS:
 | 
						|
This function handles the default system BIOS Int 10h. If the POST code
 | 
						|
has not yet re-vectored the Int 10h BIOS interrupt vector, we handle this
 | 
						|
by simply calling the int42 interrupt handler above. Very early in the
 | 
						|
BIOS POST process, the vector gets replaced and we simply let the real
 | 
						|
mode interrupt handler process the interrupt.
 | 
						|
****************************************************************************/
 | 
						|
static void X86API int10(int intno)
 | 
						|
{
 | 
						|
	if (BE_rdw(intno * 4 + 2) == BIOS_SEG)
 | 
						|
		int42(intno);
 | 
						|
	else
 | 
						|
		X86EMU_prepareForInt(intno);
 | 
						|
}
 | 
						|
 | 
						|
/* Result codes returned by the PCI BIOS */
 | 
						|
 | 
						|
#define SUCCESSFUL          0x00
 | 
						|
#define FUNC_NOT_SUPPORT    0x81
 | 
						|
#define BAD_VENDOR_ID       0x83
 | 
						|
#define DEVICE_NOT_FOUND    0x86
 | 
						|
#define BAD_REGISTER_NUMBER 0x87
 | 
						|
#define SET_FAILED          0x88
 | 
						|
#define BUFFER_TOO_SMALL    0x89
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
PARAMETERS:
 | 
						|
intno   - Interrupt number being serviced
 | 
						|
 | 
						|
REMARKS:
 | 
						|
This function handles the default Int 1Ah interrupt handler for the real
 | 
						|
mode code, which provides support for the PCI BIOS functions. Since we only
 | 
						|
want to allow the real mode BIOS code *only* see the PCI config space for
 | 
						|
its own device, we only return information for the specific PCI config
 | 
						|
space that we have passed in to the init function. This solves problems
 | 
						|
when using the BIOS to warm boot a secondary adapter when there is an
 | 
						|
identical adapter before it on the bus (some BIOS'es get confused in this
 | 
						|
case).
 | 
						|
****************************************************************************/
 | 
						|
static void X86API int1A(int unused)
 | 
						|
{
 | 
						|
	u16 pciSlot;
 | 
						|
 | 
						|
#ifdef __KERNEL__
 | 
						|
	u8 interface, subclass, baseclass;
 | 
						|
 | 
						|
	/* Initialise the PCI slot number */
 | 
						|
	pciSlot = ((int)_BE_env.vgaInfo.bus << 8) |
 | 
						|
	    ((int)_BE_env.vgaInfo.device << 3) | (int)_BE_env.vgaInfo.function;
 | 
						|
#else
 | 
						|
/* Fail if no PCI device information has been registered */
 | 
						|
	if (!_BE_env.vgaInfo.pciInfo)
 | 
						|
		return;
 | 
						|
 | 
						|
	pciSlot = (u16) (_BE_env.vgaInfo.pciInfo->slot.i >> 8);
 | 
						|
#endif
 | 
						|
	switch (M.x86.R_AX) {
 | 
						|
	case 0xB101:		/* PCI bios present? */
 | 
						|
		M.x86.R_AL = 0x00;	/* no config space/special cycle generation support */
 | 
						|
		M.x86.R_EDX = 0x20494350;	/* " ICP" */
 | 
						|
		M.x86.R_BX = 0x0210;	/* Version 2.10 */
 | 
						|
		M.x86.R_CL = 0;	/* Max bus number in system */
 | 
						|
		CLEAR_FLAG(F_CF);
 | 
						|
		break;
 | 
						|
	case 0xB102:		/* Find PCI device */
 | 
						|
		M.x86.R_AH = DEVICE_NOT_FOUND;
 | 
						|
#ifdef __KERNEL__
 | 
						|
		if (M.x86.R_DX == _BE_env.vgaInfo.VendorID &&
 | 
						|
		    M.x86.R_CX == _BE_env.vgaInfo.DeviceID && M.x86.R_SI == 0) {
 | 
						|
#else
 | 
						|
		if (M.x86.R_DX == _BE_env.vgaInfo.pciInfo->VendorID &&
 | 
						|
		    M.x86.R_CX == _BE_env.vgaInfo.pciInfo->DeviceID &&
 | 
						|
		    M.x86.R_SI == 0) {
 | 
						|
#endif
 | 
						|
			M.x86.R_AH = SUCCESSFUL;
 | 
						|
			M.x86.R_BX = pciSlot;
 | 
						|
		}
 | 
						|
		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
 | 
						|
		break;
 | 
						|
	case 0xB103:		/* Find PCI class code */
 | 
						|
		M.x86.R_AH = DEVICE_NOT_FOUND;
 | 
						|
#ifdef __KERNEL__
 | 
						|
		pci_read_config_byte(_BE_env.vgaInfo.pcidev, PCI_CLASS_PROG,
 | 
						|
				     &interface);
 | 
						|
		pci_read_config_byte(_BE_env.vgaInfo.pcidev, PCI_CLASS_DEVICE,
 | 
						|
				     &subclass);
 | 
						|
		pci_read_config_byte(_BE_env.vgaInfo.pcidev,
 | 
						|
				     PCI_CLASS_DEVICE + 1, &baseclass);
 | 
						|
		if (M.x86.R_CL == interface && M.x86.R_CH == subclass
 | 
						|
		    && (u8) (M.x86.R_ECX >> 16) == baseclass) {
 | 
						|
#else
 | 
						|
		if (M.x86.R_CL == _BE_env.vgaInfo.pciInfo->Interface &&
 | 
						|
		    M.x86.R_CH == _BE_env.vgaInfo.pciInfo->SubClass &&
 | 
						|
		    (u8) (M.x86.R_ECX >> 16) ==
 | 
						|
		    _BE_env.vgaInfo.pciInfo->BaseClass) {
 | 
						|
#endif
 | 
						|
			M.x86.R_AH = SUCCESSFUL;
 | 
						|
			M.x86.R_BX = pciSlot;
 | 
						|
		}
 | 
						|
		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
 | 
						|
		break;
 | 
						|
	case 0xB108:		/* Read configuration byte */
 | 
						|
		M.x86.R_AH = BAD_REGISTER_NUMBER;
 | 
						|
		if (M.x86.R_BX == pciSlot) {
 | 
						|
			M.x86.R_AH = SUCCESSFUL;
 | 
						|
#ifdef __KERNEL__
 | 
						|
			pci_read_config_byte(_BE_env.vgaInfo.pcidev, M.x86.R_DI,
 | 
						|
					     &M.x86.R_CL);
 | 
						|
#else
 | 
						|
			M.x86.R_CL =
 | 
						|
			    (u8) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_BYTE,
 | 
						|
					       _BE_env.vgaInfo.pciInfo);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
 | 
						|
		break;
 | 
						|
	case 0xB109:		/* Read configuration word */
 | 
						|
		M.x86.R_AH = BAD_REGISTER_NUMBER;
 | 
						|
		if (M.x86.R_BX == pciSlot) {
 | 
						|
			M.x86.R_AH = SUCCESSFUL;
 | 
						|
#ifdef __KERNEL__
 | 
						|
			pci_read_config_word(_BE_env.vgaInfo.pcidev, M.x86.R_DI,
 | 
						|
					     &M.x86.R_CX);
 | 
						|
#else
 | 
						|
			M.x86.R_CX =
 | 
						|
			    (u16) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_WORD,
 | 
						|
						_BE_env.vgaInfo.pciInfo);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
 | 
						|
		break;
 | 
						|
	case 0xB10A:		/* Read configuration dword */
 | 
						|
		M.x86.R_AH = BAD_REGISTER_NUMBER;
 | 
						|
		if (M.x86.R_BX == pciSlot) {
 | 
						|
			M.x86.R_AH = SUCCESSFUL;
 | 
						|
#ifdef __KERNEL__
 | 
						|
			pci_read_config_dword(_BE_env.vgaInfo.pcidev,
 | 
						|
					      M.x86.R_DI, &M.x86.R_ECX);
 | 
						|
#else
 | 
						|
			M.x86.R_ECX =
 | 
						|
			    (u32) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_DWORD,
 | 
						|
						_BE_env.vgaInfo.pciInfo);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
 | 
						|
		break;
 | 
						|
	case 0xB10B:		/* Write configuration byte */
 | 
						|
		M.x86.R_AH = BAD_REGISTER_NUMBER;
 | 
						|
		if (M.x86.R_BX == pciSlot) {
 | 
						|
			M.x86.R_AH = SUCCESSFUL;
 | 
						|
#ifdef __KERNEL__
 | 
						|
			pci_write_config_byte(_BE_env.vgaInfo.pcidev,
 | 
						|
					      M.x86.R_DI, M.x86.R_CL);
 | 
						|
#else
 | 
						|
			PCI_accessReg(M.x86.R_DI, M.x86.R_CL, PCI_WRITE_BYTE,
 | 
						|
				      _BE_env.vgaInfo.pciInfo);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
 | 
						|
		break;
 | 
						|
	case 0xB10C:		/* Write configuration word */
 | 
						|
		M.x86.R_AH = BAD_REGISTER_NUMBER;
 | 
						|
		if (M.x86.R_BX == pciSlot) {
 | 
						|
			M.x86.R_AH = SUCCESSFUL;
 | 
						|
#ifdef __KERNEL__
 | 
						|
			pci_write_config_word(_BE_env.vgaInfo.pcidev,
 | 
						|
					      M.x86.R_DI, M.x86.R_CX);
 | 
						|
#else
 | 
						|
			PCI_accessReg(M.x86.R_DI, M.x86.R_CX, PCI_WRITE_WORD,
 | 
						|
				      _BE_env.vgaInfo.pciInfo);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
 | 
						|
		break;
 | 
						|
	case 0xB10D:		/* Write configuration dword */
 | 
						|
		M.x86.R_AH = BAD_REGISTER_NUMBER;
 | 
						|
		if (M.x86.R_BX == pciSlot) {
 | 
						|
			M.x86.R_AH = SUCCESSFUL;
 | 
						|
#ifdef __KERNEL__
 | 
						|
			pci_write_config_dword(_BE_env.vgaInfo.pcidev,
 | 
						|
					       M.x86.R_DI, M.x86.R_ECX);
 | 
						|
#else
 | 
						|
			PCI_accessReg(M.x86.R_DI, M.x86.R_ECX, PCI_WRITE_DWORD,
 | 
						|
				      _BE_env.vgaInfo.pciInfo);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		printf("biosEmu/bios.int1a: unknown function AX=%#04x\n",
 | 
						|
		       M.x86.R_AX);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
REMARKS:
 | 
						|
This function initialises the BIOS emulation functions for the specific
 | 
						|
PCI display device. We insulate the real mode BIOS from any other devices
 | 
						|
on the bus, so that it will work correctly thinking that it is the only
 | 
						|
device present on the bus (ie: avoiding any adapters present in from of
 | 
						|
the device we are trying to control).
 | 
						|
****************************************************************************/
 | 
						|
#define BE_constLE_32(v)    ((((((v)&0xff00)>>8)|(((v)&0xff)<<8))<<16)|(((((v)&0xff000000)>>8)|(((v)&0x00ff0000)<<8))>>16))
 | 
						|
 | 
						|
void _BE_bios_init(u32 * intrTab)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	X86EMU_intrFuncs bios_intr_tab[256];
 | 
						|
 | 
						|
	for (i = 0; i < 256; ++i) {
 | 
						|
		intrTab[i] = BE_constLE_32(BIOS_SEG << 16);
 | 
						|
		bios_intr_tab[i] = undefined_intr;
 | 
						|
	}
 | 
						|
	bios_intr_tab[0x10] = int10;
 | 
						|
	bios_intr_tab[0x1A] = int1A;
 | 
						|
	bios_intr_tab[0x42] = int42;
 | 
						|
	bios_intr_tab[0x6D] = int10;
 | 
						|
	X86EMU_setupIntrFuncs(bios_intr_tab);
 | 
						|
}
 | 
						|
#endif
 |