diff options
Diffstat (limited to 'util/x86emu/x86_interrupts.c')
-rw-r--r-- | util/x86emu/x86_interrupts.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/util/x86emu/x86_interrupts.c b/util/x86emu/x86_interrupts.c new file mode 100644 index 0000000000..c20c01725c --- /dev/null +++ b/util/x86emu/x86_interrupts.c @@ -0,0 +1,244 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2001 Ronald G. Minnich + * Copyright (C) 2005 Nick.Barker9@btinternet.com + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <string.h> +#ifdef CONFIG_COREBOOT_V2 +#include <console/console.h> +#include <arch/io.h> +#define printk(x...) do_printk(x) +#else +#include <console.h> +#include <io.h> +#endif + +struct eregs { + uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi; + uint32_t vector; + uint32_t error_code; + uint32_t eip; + uint32_t cs; + uint32_t eflags; +}; + +enum { + CHECK = 0xb001, + FINDDEV = 0xb102, + READCONFBYTE = 0xb108, + READCONFWORD = 0xb109, + READCONFDWORD = 0xb10a, + WRITECONFBYTE = 0xb10b, + WRITECONFWORD = 0xb10c, + WRITECONFDWORD = 0xb10d +}; + +// errors go in AH. Just set these up so that word assigns +// will work. KISS. +enum { + PCIBIOS_NODEV = 0x8600, + PCIBIOS_BADREG = 0x8700 +}; + +int int12_handler(struct eregs *regs) +{ + regs->eax = 64 * 1024; + return 0; +} + +int int1a_handler(struct eregs *regs) +{ + unsigned short func = (unsigned short) regs->eax; + int retval = 0; + unsigned short devid, vendorid, devfn; + /* Use short to get rid of gabage in upper half of 32-bit register */ + short devindex; + unsigned char bus; + struct device *dev; + + switch(func) { + case CHECK: + regs->edx = 0x4350; + regs->ecx = 0x2049; + retval = 0; + break; + case FINDDEV: + { + devid = regs->ecx; + vendorid = regs->edx; + devindex = regs->esi; + dev = 0; +#ifdef CONFIG_COREBOOT_V2 + while ((dev = dev_find_device(vendorid, devid, dev))) { +#else + while ((dev = dev_find_pci_device(vendorid, devid, dev))) { +#endif + if (devindex <= 0) + break; + devindex--; + } + if (dev) { + unsigned short busdevfn; + regs->eax = 0; + // busnum is an unsigned char; + // devfn is an int, so we mask it off. + busdevfn = (dev->bus->secondary << 8) + | (dev->path.pci.devfn & 0xff); + printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn); + regs->ebx = busdevfn; + retval = 0; + } else { + regs->eax = PCIBIOS_NODEV; + retval = -1; + } + } + break; + case READCONFDWORD: + case READCONFWORD: + case READCONFBYTE: + case WRITECONFDWORD: + case WRITECONFWORD: + case WRITECONFBYTE: + { + unsigned long dword; + unsigned short word; + unsigned char byte; + unsigned char reg; + + devfn = regs->ebx & 0xff; + bus = regs->ebx >> 8; + reg = regs->edi; + dev = dev_find_slot(bus, devfn); + if (! dev) { + printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn); + // idiots. the pcibios guys assumed you'd never pass a bad bus/devfn! + regs->eax = PCIBIOS_BADREG; + retval = -1; + } + switch(func) { + case READCONFBYTE: + byte = pci_read_config8(dev, reg); + regs->ecx = byte; + break; + case READCONFWORD: + word = pci_read_config16(dev, reg); + regs->ecx = word; + break; + case READCONFDWORD: + dword = pci_read_config32(dev, reg); + regs->ecx = dword; + break; + case WRITECONFBYTE: + byte = regs->ecx; + pci_write_config8(dev, reg, byte); + break; + case WRITECONFWORD: + word = regs->ecx; + pci_write_config16(dev, reg, word); + break; + case WRITECONFDWORD: + dword = regs->ecx; + pci_write_config32(dev, reg, dword); + break; + } + + if (retval) + retval = PCIBIOS_BADREG; + printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", + func, bus, devfn, reg, regs->ecx); + regs->eax = 0; + retval = 0; + } + break; + default: + printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); + break; + } + + return retval; +} + +int int15_handler(struct eregs *regs) +{ + int res = -1; + + /* This int15 handler is VIA Tech. specific. Other chipsets need other + * handlers. The right way to do this is to move this handler code into + * the mainboard or northbridge code. + */ + switch (regs->eax & 0xffff) { + case 0x5f19: + break; + case 0x5f18: + regs->eax = 0x5f; + // MCLK = 133, 32M frame buffer, 256 M main memory + regs->ebx = 0x545; + regs->ecx = 0x060; + res = 0; + break; + case 0x5f00: + regs->eax = 0x8600; + break; + case 0x5f01: + regs->eax = 0x5f; + regs->ecx = (regs->ecx & 0xffffff00 ) | 2; // panel type = 2 = 1024 * 768 + res = 0; + break; + case 0x5f02: + regs->eax = 0x5f; + regs->ebx = (regs->ebx & 0xffff0000) | 2; + regs->ecx = (regs->ecx & 0xffff0000) | 0x401; // PAL + crt only + regs->edx = (regs->edx & 0xffff0000) | 0; // TV Layout - default + res = 0; + break; + case 0x5f0f: + regs->eax = 0x860f; + break; + /* And now Intel IGD code */ +#define BOOT_DISPLAY_CRT (1 << 0) +#define BOOT_DISPLAY_TV (1 << 1) +#define BOOT_DISPLAY_EFP (1 << 2) +#define BOOT_DISPLAY_LCD (1 << 3) +#define BOOT_DISPLAY_CRT2 (1 << 4) +#define BOOT_DISPLAY_TV2 (1 << 5) +#define BOOT_DISPLAY_EFP2 (1 << 6) +#define BOOT_DISPLAY_LCD2 (1 << 7) + + case 0x5f35: + regs->eax = 0x5f; + regs->ecx = BOOT_DISPLAY_LCD|BOOT_DISPLAY_CRT; + res = 0; + break; + case 0x5f40: + regs->eax = 0x5f; + regs->ecx = 3; // This is mainboard specific + printk(BIOS_DEBUG, "DISPLAY=%x\n", regs->ecx); + res = 0; + break; + default: + printk(BIOS_DEBUG, "Unknown INT15 function %04x!\n", + regs->eax & 0xffff); + } + + return res; +} + |