From a0dc29629c0091449a4065a93812e8522e7d0540 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Sun, 16 Mar 2008 14:29:32 -0400 Subject: [PATCH] Basic support for PCI BIOS. This patch adds real-mode pci bios callbacks. It also adds support for a hardcoded $PIR table. The pci config functions are moved from rombios32.c to pci.c. Note that protected mode pci-bios calls were not added. --- Makefile | 4 +- src/clock.c | 7 -- src/config.h | 1 + src/pci.c | 38 ++++++ src/pci.h | 13 ++ src/pcibios.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++ src/rombios32.c | 44 +------ src/util.h | 3 + 8 files changed, 381 insertions(+), 51 deletions(-) create mode 100644 src/pci.c create mode 100644 src/pci.h create mode 100644 src/pcibios.c diff --git a/Makefile b/Makefile index 1ffe500..cb1cdd0 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,8 @@ OUT=out/ # Source files SRC16=floppy.c disk.c system.c clock.c serial.c kbd.c mouse.c output.c \ - boot.c ata.c cdrom.c apm.c util.c -SRC32=post.c output.c rombios32.c util.c ata.c kbd.c + boot.c ata.c cdrom.c apm.c util.c pcibios.c pci.c +SRC32=post.c output.c rombios32.c util.c ata.c kbd.c pci.c TABLESRC=font.c cbt.c floppy_dbt.c cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ diff --git a/src/clock.c b/src/clock.c index b9d75a3..4d8643f 100644 --- a/src/clock.c +++ b/src/clock.c @@ -215,13 +215,6 @@ handle_1a07(struct bregs *regs) set_success(regs); } -static void -handle_1ab1(struct bregs *regs) -{ - // XXX - pcibios stuff - set_fail(regs); -} - // Unsupported static void handle_1aXX(struct bregs *regs) diff --git a/src/config.h b/src/config.h index 199627e..d61830b 100644 --- a/src/config.h +++ b/src/config.h @@ -7,6 +7,7 @@ #define CONFIG_ATA 1 #define CONFIG_KBD_CALL_INT15_4F 1 #define CONFIG_CDROM_BOOT 1 +#define CONFIG_PCIBIOS 1 #define CONFIG_MAX_ATA_INTERFACES 4 #define CONFIG_MAX_ATA_DEVICES (CONFIG_MAX_ATA_INTERFACES*2) diff --git a/src/pci.c b/src/pci.c new file mode 100644 index 0000000..2dd617b --- /dev/null +++ b/src/pci.c @@ -0,0 +1,38 @@ +#include "pci.h" // PCIDevice +#include "ioport.h" // outl + +void pci_config_writel(PCIDevice *d, u32 addr, u32 val) +{ + outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); + outl(val, 0xcfc); +} + +void pci_config_writew(PCIDevice *d, u32 addr, u16 val) +{ + outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); + outw(val, 0xcfc + (addr & 2)); +} + +void pci_config_writeb(PCIDevice *d, u32 addr, u8 val) +{ + outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); + outb(val, 0xcfc + (addr & 3)); +} + +u32 pci_config_readl(PCIDevice *d, u32 addr) +{ + outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); + return inl(0xcfc); +} + +u16 pci_config_readw(PCIDevice *d, u32 addr) +{ + outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); + return inw(0xcfc + (addr & 2)); +} + +u8 pci_config_readb(PCIDevice *d, u32 addr) +{ + outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); + return inb(0xcfc + (addr & 3)); +} diff --git a/src/pci.h b/src/pci.h new file mode 100644 index 0000000..6afc9a9 --- /dev/null +++ b/src/pci.h @@ -0,0 +1,13 @@ +#include "types.h" // u32 + +typedef struct PCIDevice { + int bus; + int devfn; +} PCIDevice; + +void pci_config_writel(PCIDevice *d, u32 addr, u32 val); +void pci_config_writew(PCIDevice *d, u32 addr, u16 val); +void pci_config_writeb(PCIDevice *d, u32 addr, u8 val); +u32 pci_config_readl(PCIDevice *d, u32 addr); +u16 pci_config_readw(PCIDevice *d, u32 addr); +u8 pci_config_readb(PCIDevice *d, u32 addr); diff --git a/src/pcibios.c b/src/pcibios.c new file mode 100644 index 0000000..29a0ec5 --- /dev/null +++ b/src/pcibios.c @@ -0,0 +1,322 @@ +// Low level ATA disk access +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "types.h" // u32 +#include "util.h" // handle_1ab1 +#include "pci.h" // pci_config_readl + + +/**************************************************************** + * PIR table + ****************************************************************/ + +struct pir { + u32 signature; + u16 version; + u16 size; + u8 router_bus; + u8 router_devfunc; + u16 exclusive_irqs; + u32 compatible_devid; + u32 miniport_data; + u8 reserved[11]; + u8 checksum; +} PACKED; + +struct link_info { + u8 link; + u16 bitmap; +} PACKED; + +struct pir_slot { + u8 bus; + u8 dev; + struct link_info links[4]; + u8 slot_nr; + u8 reserved; +} PACKED; + +struct pir_table { + struct pir pir; + struct pir_slot slots[6]; +} PACKED PIR_TABLE VISIBLE16 __attribute__((aligned(16))) = { +#if CONFIG_PCIBIOS + .pir = { + .signature = 0x52495024, // "$PIR" + .version = 0x0100, + .size = sizeof(struct pir_table), + .router_devfunc = 0x08, + .compatible_devid = 0x70008086, + .checksum = 0x07, // XXX - should auto calculate + }, + .slots = { + { + // first slot entry PCI-to-ISA (embedded) + .dev = 1<<3, + .links = { + {.link = 0x60, .bitmap = 0xdef8}, // INTA# + {.link = 0x61, .bitmap = 0xdef8}, // INTB# + {.link = 0x62, .bitmap = 0xdef8}, // INTC# + {.link = 0x63, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 0, // embedded + }, { + // second slot entry: 1st PCI slot + .dev = 2<<3, + .links = { + {.link = 0x61, .bitmap = 0xdef8}, // INTA# + {.link = 0x62, .bitmap = 0xdef8}, // INTB# + {.link = 0x63, .bitmap = 0xdef8}, // INTC# + {.link = 0x60, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 1, + }, { + // third slot entry: 2nd PCI slot + .dev = 3<<3, + .links = { + {.link = 0x62, .bitmap = 0xdef8}, // INTA# + {.link = 0x63, .bitmap = 0xdef8}, // INTB# + {.link = 0x60, .bitmap = 0xdef8}, // INTC# + {.link = 0x61, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 2, + }, { + // 4th slot entry: 3rd PCI slot + .dev = 4<<3, + .links = { + {.link = 0x63, .bitmap = 0xdef8}, // INTA# + {.link = 0x60, .bitmap = 0xdef8}, // INTB# + {.link = 0x61, .bitmap = 0xdef8}, // INTC# + {.link = 0x62, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 3, + }, { + // 5th slot entry: 4rd PCI slot + .dev = 5<<3, + .links = { + {.link = 0x60, .bitmap = 0xdef8}, // INTA# + {.link = 0x61, .bitmap = 0xdef8}, // INTB# + {.link = 0x62, .bitmap = 0xdef8}, // INTC# + {.link = 0x63, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 4, + }, { + // 6th slot entry: 5rd PCI slot + .dev = 6<<3, + .links = { + {.link = 0x61, .bitmap = 0xdef8}, // INTA# + {.link = 0x62, .bitmap = 0xdef8}, // INTB# + {.link = 0x63, .bitmap = 0xdef8}, // INTC# + {.link = 0x60, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 5, + }, + } +#endif // CONFIG_PCIBIOS +}; + + +/**************************************************************** + * Helper functions + ****************************************************************/ + +#define RET_FUNC_NOT_SUPPORTED 0x81 +#define RET_BAD_VENDOR_ID 0x83 +#define RET_DEVICE_NOT_FOUND 0x86 +#define RET_BUFFER_TOO_SMALL 0x89 + +// installation check +static void +handle_1ab101(struct bregs *regs) +{ + regs->ax = 0x0001; + regs->bx = 0x0210; + regs->cx = 0; + regs->edx = 0x20494350; // "PCI " + // XXX - bochs bios code sets edi to point to 32bit code - but no + // reference to this in spec. + set_cf(regs, 0); +} + +// find pci device +static void +handle_1ab102(struct bregs *regs) +{ + u32 dev = (regs->cx << 16) | regs->dx; + u16 index = regs->si; + int i; + for (i=0; i<0x100; i++) { + PCIDevice d = {0, i}; + u32 v = pci_config_readl(&d, 0); + if (v != dev) + continue; + if (index) { + index--; + continue; + } + // Found it. + regs->bx = i; + set_code_success(regs); + return; + } + set_code_fail(regs, RET_DEVICE_NOT_FOUND); +} + +// find class code +static void +handle_1ab103(struct bregs *regs) +{ + u32 code = regs->ecx << 8; + u16 index = regs->si; + int i; + for (i=0; i<0x100; i++) { + PCIDevice d = {0, i}; + u32 v = pci_config_readl(&d, 0x08); + if (v != code) + continue; + if (index) { + index--; + continue; + } + // Found it. + regs->bx = i; + set_code_success(regs); + return; + } + set_code_fail(regs, RET_DEVICE_NOT_FOUND); +} + +// read configuration byte +static void +handle_1ab108(struct bregs *regs) +{ + PCIDevice d = {regs->bh, regs->bl}; + regs->cl = pci_config_readb(&d, regs->di); + set_code_success(regs); +} + +// read configuration word +static void +handle_1ab109(struct bregs *regs) +{ + PCIDevice d = {regs->bh, regs->bl}; + regs->cx = pci_config_readw(&d, regs->di); + set_code_success(regs); +} + +// read configuration dword +static void +handle_1ab10a(struct bregs *regs) +{ + PCIDevice d = {regs->bh, regs->bl}; + regs->ecx = pci_config_readl(&d, regs->di); + set_code_success(regs); +} + +// write configuration byte +static void +handle_1ab10b(struct bregs *regs) +{ + PCIDevice d = {regs->bh, regs->bl}; + pci_config_writeb(&d, regs->di, regs->cl); + set_code_success(regs); +} + +// write configuration word +static void +handle_1ab10c(struct bregs *regs) +{ + PCIDevice d = {regs->bh, regs->bl}; + pci_config_writew(&d, regs->di, regs->cx); + set_code_success(regs); +} + +// write configuration dword +static void +handle_1ab10d(struct bregs *regs) +{ + PCIDevice d = {regs->bh, regs->bl}; + pci_config_writel(&d, regs->di, regs->ecx); + set_code_success(regs); +} + +// get irq routing options +static void +handle_1ab10e(struct bregs *regs) +{ + // Validate and update size. + u16 size = GET_FARVAR(regs->es, *(u16*)(regs->di+0)); + u32 pirsize = sizeof(PIR_TABLE.slots); + SET_FARVAR(regs->es, *(u16*)(regs->di+0), pirsize); + if (size < pirsize) { + set_code_fail(regs, RET_BUFFER_TOO_SMALL); + return; + } + + // Get dest buffer. + u8 *d = (u8*)(GET_FARVAR(regs->es, *(u16*)(regs->di+2)) + 0); + u16 destseg = GET_FARVAR(regs->es, *(u16*)(regs->di+4)); + + // Memcpy pir table slots to dest buffer. + u8 *p = (u8*)PIR_TABLE.slots; + u8 *end = p + pirsize; + for (; pbx = GET_VAR(CS, PIR_TABLE.pir.exclusive_irqs); + set_code_success(regs); +} + +static void +handle_1ab1XX(struct bregs *regs) +{ + set_code_fail(regs, RET_FUNC_NOT_SUPPORTED); +} + +#define PCI_FIXED_HOST_BRIDGE 0x12378086 // i440FX PCI bridge + +void +handle_1ab1(struct bregs *regs) +{ + //debug_stub(regs); + + if (! CONFIG_PCIBIOS) { + set_fail(regs); + return; + } + + outl(0x80000000, 0x0cf8); + u32 v = inl(0x0cfc); + if ( +#ifdef PCI_FIXED_HOST_BRIDGE + v != PCI_FIXED_HOST_BRIDGE +#else + v == 0xffffffff +#endif + ) { + // Device not present + set_code_fail(regs, 0xff); + return; + } + + switch (regs->al) { + case 0x01: handle_1ab101(regs); break; + case 0x02: handle_1ab102(regs); break; + case 0x03: handle_1ab103(regs); break; + case 0x08: handle_1ab108(regs); break; + case 0x09: handle_1ab109(regs); break; + case 0x0a: handle_1ab10a(regs); break; + case 0x0b: handle_1ab10b(regs); break; + case 0x0c: handle_1ab10c(regs); break; + case 0x0d: handle_1ab10d(regs); break; + case 0x0e: handle_1ab10e(regs); break; + default: handle_1ab1XX(regs); break; + } +} diff --git a/src/rombios32.c b/src/rombios32.c index a3f42fd..5ce8853 100644 --- a/src/rombios32.c +++ b/src/rombios32.c @@ -21,7 +21,8 @@ #include "util.h" // BX_INFO #include "cmos.h" // inb_cmos -#include "types.h" +#include "pci.h" // PCIDevice +#include "types.h" // u32 #define BX_APPNAME "Bochs" @@ -215,11 +216,6 @@ void smp_probe(void) #define PCI_MIN_GNT 0x3e /* 8 bits */ #define PCI_MAX_LAT 0x3f /* 8 bits */ -typedef struct PCIDevice { - int bus; - int devfn; -} PCIDevice; - static u32 pci_bios_io_addr; static u32 pci_bios_mem_addr; static u32 pci_bios_bigmem_addr; @@ -227,42 +223,6 @@ static u32 pci_bios_bigmem_addr; static u8 pci_irqs[4] = { 11, 9, 11, 9 }; static PCIDevice i440_pcidev; -static void pci_config_writel(PCIDevice *d, u32 addr, u32 val) -{ - outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); - outl(val, 0xcfc); -} - -static void pci_config_writew(PCIDevice *d, u32 addr, u32 val) -{ - outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); - outw(val, 0xcfc + (addr & 2)); -} - -static void pci_config_writeb(PCIDevice *d, u32 addr, u32 val) -{ - outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); - outb(val, 0xcfc + (addr & 3)); -} - -static u32 pci_config_readl(PCIDevice *d, u32 addr) -{ - outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); - return inl(0xcfc); -} - -static u32 pci_config_readw(PCIDevice *d, u32 addr) -{ - outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); - return inw(0xcfc + (addr & 2)); -} - -static u32 pci_config_readb(PCIDevice *d, u32 addr) -{ - outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8); - return inb(0xcfc + (addr & 3)); -} - static void pci_set_io_region_addr(PCIDevice *d, int region_num, u32 addr) { u16 cmd; diff --git a/src/util.h b/src/util.h index 4df595a..d553b3a 100644 --- a/src/util.h +++ b/src/util.h @@ -169,6 +169,9 @@ void handle_1583(struct bregs *regs); // apm.c void VISIBLE16 handle_1553(struct bregs *regs); +// pcibios.c +void handle_1ab1(struct bregs *regs); + // util.c void usleep(u32 count); -- 2.25.1