Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / drivers / bios_emulator / bios.c
diff --git a/qemu/roms/u-boot/drivers/bios_emulator/bios.c b/qemu/roms/u-boot/drivers/bios_emulator/bios.c
new file mode 100644 (file)
index 0000000..bcc192f
--- /dev/null
@@ -0,0 +1,324 @@
+/****************************************************************************
+*
+*                        BIOS emulator and interface
+*                      to Realmode X86 Emulator Library
+*
+*  Copyright (C) 2007 Freescale Semiconductor, Inc.
+*  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.
+*
+****************************************************************************/
+
+#define __io
+#include <asm/io.h>
+#include <common.h>
+#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);
+}