u-boot/arch/x86/lib/bios_interrupts.c
Simon Glass 0ca2426bea x86: Add support for running option ROMs natively
On x86 machines we can use an emulator to run option ROMS as with other
architectures. But with some additional effort (mostly due to the 16-bit
nature of option ROMs) we can run them natively. Add support for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
2014-11-25 06:38:57 -07:00

217 lines
5.2 KiB
C

/*
* From Coreboot
*
* Copyright (C) 2001 Ronald G. Minnich
* Copyright (C) 2005 Nick.Barker9@btinternet.com
* Copyright (C) 2007-2009 coresystems GmbH
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <asm/pci.h>
#include "bios_emul.h"
/* errors go in AH. Just set these up so that word assigns will work */
enum {
PCIBIOS_SUCCESSFUL = 0x0000,
PCIBIOS_UNSUPPORTED = 0x8100,
PCIBIOS_BADVENDOR = 0x8300,
PCIBIOS_NODEV = 0x8600,
PCIBIOS_BADREG = 0x8700
};
int int10_handler(void)
{
static u8 cursor_row, cursor_col;
int res = 0;
switch ((M.x86.R_EAX & 0xff00) >> 8) {
case 0x01: /* Set cursor shape */
res = 1;
break;
case 0x02: /* Set cursor position */
if (cursor_row != ((M.x86.R_EDX >> 8) & 0xff) ||
cursor_col >= (M.x86.R_EDX & 0xff)) {
debug("\n");
}
cursor_row = (M.x86.R_EDX >> 8) & 0xff;
cursor_col = M.x86.R_EDX & 0xff;
res = 1;
break;
case 0x03: /* Get cursor position */
M.x86.R_EAX &= 0x00ff;
M.x86.R_ECX = 0x0607;
M.x86.R_EDX = (cursor_row << 8) | cursor_col;
res = 1;
break;
case 0x06: /* Scroll up */
debug("\n");
res = 1;
break;
case 0x08: /* Get Character and Mode at Cursor Position */
M.x86.R_EAX = 0x0f00 | 'A'; /* White on black 'A' */
res = 1;
break;
case 0x09: /* Write Character and attribute */
case 0x0e: /* Write Character */
debug("%c", M.x86.R_EAX & 0xff);
res = 1;
break;
case 0x0f: /* Get video mode */
M.x86.R_EAX = 0x5002; /*80 x 25 */
M.x86.R_EBX &= 0x00ff;
res = 1;
break;
default:
printf("Unknown INT10 function %04x\n", M.x86.R_EAX & 0xffff);
break;
}
return res;
}
int int12_handler(void)
{
M.x86.R_EAX = 64 * 1024;
return 1;
}
int int16_handler(void)
{
int res = 0;
switch ((M.x86.R_EAX & 0xff00) >> 8) {
case 0x00: /* Check for Keystroke */
M.x86.R_EAX = 0x6120; /* Space Bar, Space */
res = 1;
break;
case 0x01: /* Check for Keystroke */
M.x86.R_EFLG |= 1 << 6; /* Zero Flag set (no key available) */
res = 1;
break;
default:
printf("Unknown INT16 function %04x\n", M.x86.R_EAX & 0xffff);
break;
}
return res;
}
#define PCI_CONFIG_SPACE_TYPE1 (1 << 0)
#define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4)
int int1a_handler(void)
{
unsigned short func = (unsigned short)M.x86.R_EAX;
int retval = 1;
unsigned short devid, vendorid, devfn;
/* Use short to get rid of gabage in upper half of 32-bit register */
short devindex;
unsigned char bus;
pci_dev_t dev;
u32 dword;
u16 word;
u8 byte, reg;
switch (func) {
case 0xb101: /* PCIBIOS Check */
M.x86.R_EDX = 0x20494350; /* ' ICP' */
M.x86.R_EAX &= 0xffff0000; /* Clear AH / AL */
M.x86.R_EAX |= PCI_CONFIG_SPACE_TYPE1 |
PCI_SPECIAL_CYCLE_TYPE1;
/*
* last bus in the system. Hard code to 255 for now.
* dev_enumerate() does not seem to tell us (publically)
*/
M.x86.R_ECX = 0xff;
M.x86.R_EDI = 0x00000000; /* protected mode entry */
retval = 1;
break;
case 0xb102: /* Find Device */
devid = M.x86.R_ECX;
vendorid = M.x86.R_EDX;
devindex = M.x86.R_ESI;
dev = pci_find_device(vendorid, devid, devindex);
if (dev != -1) {
unsigned short busdevfn;
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
M.x86.R_EAX |= PCIBIOS_SUCCESSFUL;
/*
* busnum is an unsigned char;
* devfn is an int, so we mask it off.
*/
busdevfn = (PCI_BUS(dev) << 8) | PCI_DEV(dev) << 3 |
PCI_FUNC(dev);
debug("0x%x: return 0x%x\n", func, busdevfn);
M.x86.R_EBX = busdevfn;
retval = 1;
} else {
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
M.x86.R_EAX |= PCIBIOS_NODEV;
retval = 0;
}
break;
case 0xb10a: /* Read Config Dword */
case 0xb109: /* Read Config Word */
case 0xb108: /* Read Config Byte */
case 0xb10d: /* Write Config Dword */
case 0xb10c: /* Write Config Word */
case 0xb10b: /* Write Config Byte */
devfn = M.x86.R_EBX & 0xff;
bus = M.x86.R_EBX >> 8;
reg = M.x86.R_EDI;
dev = PCI_BDF(bus, devfn >> 3, devfn & 7);
if (!dev) {
debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func,
bus, devfn);
/* Or are we supposed to return PCIBIOS_NODEV? */
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
M.x86.R_EAX |= PCIBIOS_BADREG;
retval = 0;
return retval;
}
switch (func) {
case 0xb108: /* Read Config Byte */
byte = pci_read_config8(dev, reg);
M.x86.R_ECX = byte;
break;
case 0xb109: /* Read Config Word */
word = pci_read_config16(dev, reg);
M.x86.R_ECX = word;
break;
case 0xb10a: /* Read Config Dword */
dword = pci_read_config32(dev, reg);
M.x86.R_ECX = dword;
break;
case 0xb10b: /* Write Config Byte */
byte = M.x86.R_ECX;
pci_write_config8(dev, reg, byte);
break;
case 0xb10c: /* Write Config Word */
word = M.x86.R_ECX;
pci_write_config16(dev, reg, word);
break;
case 0xb10d: /* Write Config Dword */
dword = M.x86.R_ECX;
pci_write_config32(dev, reg, dword);
break;
}
#ifdef CONFIG_REALMODE_DEBUG
debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", func,
bus, devfn, reg, M.x86.R_ECX);
#endif
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
M.x86.R_EAX |= PCIBIOS_SUCCESSFUL;
retval = 1;
break;
default:
printf("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
M.x86.R_EAX |= PCIBIOS_UNSUPPORTED;
retval = 0;
break;
}
return retval;
}