summaryrefslogtreecommitdiff
path: root/util/x86emu/yabel/device.c
diff options
context:
space:
mode:
authorStefan Reinauer <stepan@coresystems.de>2009-08-11 21:28:25 +0000
committerStefan Reinauer <stepan@openbios.org>2009-08-11 21:28:25 +0000
commit38cd29ebd7282333650cf11ed50c7f2fd4031e80 (patch)
tree61008ca7d9a8e4ad5e5237e5f7cbc982a8206c55 /util/x86emu/yabel/device.c
parentb339e10f04869a3d8da31e7d52831c32c57302a2 (diff)
Don't pull in x86emu from a foreign directory anymore. This
produced numerous problems in the past, including the fact that x86emu doesn't work in v3 anymore even though it lives in the v3 repository. Since this is a cross-repository move, keeping the history in the v2 tree would make life hard for everone. So check the v3 repository for x86emu history since the merger. The his commit is based on an svn export of r1175 of the coreboot-v3 repository. Signed-off-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Patrick Georgi <patrick.georgi@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4532 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/x86emu/yabel/device.c')
-rw-r--r--util/x86emu/yabel/device.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/util/x86emu/yabel/device.c b/util/x86emu/yabel/device.c
new file mode 100644
index 0000000000..d5c114ccb6
--- /dev/null
+++ b/util/x86emu/yabel/device.c
@@ -0,0 +1,461 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "device.h"
+#ifdef CONFIG_COREBOOT_V2
+#include "compat/rtas.h"
+#else
+#include "rtas.h"
+#endif
+#include <string.h>
+#include "debug.h"
+
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ops.h>
+#include <device/resource.h>
+
+/* the device we are working with... */
+biosemu_device_t bios_device;
+//max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges
+translate_address_t translate_address_array[11];
+u8 taa_last_entry;
+
+typedef struct {
+ u8 info;
+ u8 bus;
+ u8 devfn;
+ u8 cfg_space_offset;
+ u64 address;
+ u64 size;
+} __attribute__ ((__packed__)) assigned_address_t;
+
+#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
+/* coreboot version */
+
+void
+biosemu_dev_get_addr_info(void)
+{
+ int taa_index = 0;
+ int i = 0;
+ struct resource *r;
+ u8 bus = bios_device.dev->bus->link;
+ u16 devfn = bios_device.dev->path.pci.devfn;
+
+ bios_device.bus = bus;
+ bios_device.devfn = devfn;
+
+ DEBUG_PRINTF("bus: %x, devfn: %x\n", bus, devfn);
+ for (i = 0; i < bios_device.dev->resources; i++) {
+ r = &bios_device.dev->resource[i];
+ translate_address_array[taa_index].info = r->flags;
+ translate_address_array[taa_index].bus = bus;
+ translate_address_array[taa_index].devfn = devfn;
+ translate_address_array[taa_index].cfg_space_offset =
+ r->index;
+ translate_address_array[taa_index].address = r->base;
+ translate_address_array[taa_index].size = r->size;
+ /* dont translate addresses... all addresses are 1:1 */
+ translate_address_array[taa_index].address_offset = 0;
+ taa_index++;
+ }
+ /* Expansion ROM */
+ translate_address_array[taa_index].info = IORESOURCE_MEM | IORESOURCE_READONLY;
+ translate_address_array[taa_index].bus = bus;
+ translate_address_array[taa_index].devfn = devfn;
+ translate_address_array[taa_index].cfg_space_offset = 0x30;
+ translate_address_array[taa_index].address = bios_device.dev->rom_address;
+ translate_address_array[taa_index].size = 0; /* TODO: do we need the size? */
+ /* dont translate addresses... all addresses are 1:1 */
+ translate_address_array[taa_index].address_offset = 0;
+ taa_index++;
+ /* legacy ranges if its a VGA card... */
+ if ((bios_device.dev->class & 0xFF0000) == 0x030000) {
+ DEBUG_PRINTF("%s: VGA device found, adding legacy resources... \n", __func__);
+ /* I/O 0x3B0-0x3BB */
+ translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_IO;
+ translate_address_array[taa_index].bus = bus;
+ translate_address_array[taa_index].devfn = devfn;
+ translate_address_array[taa_index].cfg_space_offset = 0;
+ translate_address_array[taa_index].address = 0x3b0;
+ translate_address_array[taa_index].size = 0xc;
+ /* dont translate addresses... all addresses are 1:1 */
+ translate_address_array[taa_index].address_offset = 0;
+ taa_index++;
+ /* I/O 0x3C0-0x3DF */
+ translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_IO;
+ translate_address_array[taa_index].bus = bus;
+ translate_address_array[taa_index].devfn = devfn;
+ translate_address_array[taa_index].cfg_space_offset = 0;
+ translate_address_array[taa_index].address = 0x3c0;
+ translate_address_array[taa_index].size = 0x20;
+ /* dont translate addresses... all addresses are 1:1 */
+ translate_address_array[taa_index].address_offset = 0;
+ taa_index++;
+ /* Mem 0xA0000-0xBFFFF */
+ translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_MEM;
+ translate_address_array[taa_index].bus = bus;
+ translate_address_array[taa_index].devfn = devfn;
+ translate_address_array[taa_index].cfg_space_offset = 0;
+ translate_address_array[taa_index].address = 0xa0000;
+ translate_address_array[taa_index].size = 0x20000;
+ /* dont translate addresses... all addresses are 1:1 */
+ translate_address_array[taa_index].address_offset = 0;
+ taa_index++;
+ }
+ // store last entry index of translate_address_array
+ taa_last_entry = taa_index - 1;
+#ifdef CONFIG_DEBUG
+ //dump translate_address_array
+ printf("translate_address_array: \n");
+ translate_address_t ta;
+ for (i = 0; i <= taa_last_entry; i++) {
+ ta = translate_address_array[i];
+ printf
+ ("%d: info: %08lx bus: %02x devfn: %02x cfg_space_offset: %02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
+ i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
+ ta.address, ta.address_offset, ta.size);
+ }
+#endif
+}
+#else
+// use translate_address_dev and get_puid from net-snk's net_support.c
+void translate_address_dev(u64 *, phandle_t);
+u64 get_puid(phandle_t node);
+
+
+// scan all adresses assigned to the device ("assigned-addresses" and "reg")
+// store in translate_address_array for faster translation using dev_translate_address
+void
+biosemu_dev_get_addr_info(void)
+{
+ // get bus/dev/fn from assigned-addresses
+ int32_t len;
+ //max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges
+ assigned_address_t buf[11];
+ len =
+ of_getprop(bios_device.phandle, "assigned-addresses", buf,
+ sizeof(buf));
+ bios_device.bus = buf[0].bus;
+ bios_device.devfn = buf[0].devfn;
+ DEBUG_PRINTF("bus: %x, devfn: %x\n", bios_device.bus,
+ bios_device.devfn);
+ //store address translations for all assigned-addresses and regs in
+ //translate_address_array for faster translation later on...
+ int i = 0;
+ // index to insert data into translate_address_array
+ int taa_index = 0;
+ u64 address_offset;
+ for (i = 0; i < (len / sizeof(assigned_address_t)); i++, taa_index++) {
+ //copy all info stored in assigned-addresses
+ translate_address_array[taa_index].info = buf[i].info;
+ translate_address_array[taa_index].bus = buf[i].bus;
+ translate_address_array[taa_index].devfn = buf[i].devfn;
+ translate_address_array[taa_index].cfg_space_offset =
+ buf[i].cfg_space_offset;
+ translate_address_array[taa_index].address = buf[i].address;
+ translate_address_array[taa_index].size = buf[i].size;
+ // translate first address and store it as address_offset
+ address_offset = buf[i].address;
+ translate_address_dev(&address_offset, bios_device.phandle);
+ translate_address_array[taa_index].address_offset =
+ address_offset - buf[i].address;
+ }
+ //get "reg" property
+ len = of_getprop(bios_device.phandle, "reg", buf, sizeof(buf));
+ for (i = 0; i < (len / sizeof(assigned_address_t)); i++) {
+ if ((buf[i].size == 0) || (buf[i].cfg_space_offset != 0)) {
+ // we dont care for ranges with size 0 and
+ // BARs and Expansion ROM must be in assigned-addresses... so in reg
+ // we only look for those without config space offset set...
+ // i.e. the legacy ranges
+ continue;
+ }
+ //copy all info stored in assigned-addresses
+ translate_address_array[taa_index].info = buf[i].info;
+ translate_address_array[taa_index].bus = buf[i].bus;
+ translate_address_array[taa_index].devfn = buf[i].devfn;
+ translate_address_array[taa_index].cfg_space_offset =
+ buf[i].cfg_space_offset;
+ translate_address_array[taa_index].address = buf[i].address;
+ translate_address_array[taa_index].size = buf[i].size;
+ // translate first address and store it as address_offset
+ address_offset = buf[i].address;
+ translate_address_dev(&address_offset, bios_device.phandle);
+ translate_address_array[taa_index].address_offset =
+ address_offset - buf[i].address;
+ taa_index++;
+ }
+ // store last entry index of translate_address_array
+ taa_last_entry = taa_index - 1;
+#ifdef CONFIG_DEBUG
+ //dump translate_address_array
+ printf("translate_address_array: \n");
+ translate_address_t ta;
+ for (i = 0; i <= taa_last_entry; i++) {
+ ta = translate_address_array[i];
+ printf
+ ("%d: %02x%02x%02x%02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
+ i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
+ ta.address, ta.address_offset, ta.size);
+ }
+#endif
+}
+#endif
+
+// to simulate accesses to legacy VGA Memory (0xA0000-0xBFFFF)
+// we look for the first prefetchable memory BAR, if no prefetchable BAR found,
+// we use the first memory BAR
+// dev_translate_addr will translate accesses to the legacy VGA Memory into the found vmem BAR
+void
+biosemu_dev_find_vmem_addr(void)
+{
+ int i = 0;
+ translate_address_t ta;
+ s8 tai_np = -1, tai_p = -1; // translate_address_array index for non-prefetchable and prefetchable memory
+ //search backwards to find first entry
+ for (i = taa_last_entry; i >= 0; i--) {
+ ta = translate_address_array[i];
+ if ((ta.cfg_space_offset >= 0x10)
+ && (ta.cfg_space_offset <= 0x24)) {
+ //only BARs
+ if ((ta.info & 0x03) >= 0x02) {
+ //32/64bit memory
+ tai_np = i;
+ if ((ta.info & 0x40) != 0) {
+ // prefetchable
+ tai_p = i;
+ }
+ }
+ }
+ }
+ if (tai_p != -1) {
+ ta = translate_address_array[tai_p];
+ bios_device.vmem_addr = ta.address;
+ bios_device.vmem_size = ta.size;
+ DEBUG_PRINTF
+ ("%s: Found prefetchable Virtual Legacy Memory BAR: %llx, size: %llx\n",
+ __func__, bios_device.vmem_addr,
+ bios_device.vmem_size);
+ } else if (tai_np != -1) {
+ ta = translate_address_array[tai_np];
+ bios_device.vmem_addr = ta.address;
+ bios_device.vmem_size = ta.size;
+ DEBUG_PRINTF
+ ("%s: Found non-prefetchable Virtual Legacy Memory BAR: %llx, size: %llx",
+ __func__, bios_device.vmem_addr,
+ bios_device.vmem_size);
+ }
+ // disable vmem
+ //bios_device.vmem_size = 0;
+}
+
+#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
+void
+biosemu_dev_get_puid(void)
+{
+ // get puid
+ bios_device.puid = get_puid(bios_device.phandle);
+ DEBUG_PRINTF("puid: 0x%llx\n", bios_device.puid);
+}
+#endif
+
+void
+biosemu_dev_get_device_vendor_id(void)
+{
+
+ u32 pci_config_0;
+#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
+ pci_config_0 = pci_read_config32(bios_device.dev, 0x0);
+#else
+ pci_config_0 =
+ rtas_pci_config_read(bios_device.puid, 4, bios_device.bus,
+ bios_device.devfn, 0x0);
+#endif
+ bios_device.pci_device_id =
+ (u16) ((pci_config_0 & 0xFFFF0000) >> 16);
+ bios_device.pci_vendor_id = (u16) (pci_config_0 & 0x0000FFFF);
+ DEBUG_PRINTF("PCI Device ID: %04x, PCI Vendor ID: %x\n",
+ bios_device.pci_device_id, bios_device.pci_vendor_id);
+}
+
+/* Check whether the device has a valid Expansion ROM and search the PCI Data
+ * Structure and any Expansion ROM Header (using dev_scan_exp_header()) for
+ * needed information. If the rom_addr parameter is != 0, it is the address of
+ * the Expansion ROM image and will be used, if it is == 0, the Expansion ROM
+ * BAR address will be used.
+ */
+u8
+biosemu_dev_check_exprom(unsigned long rom_base_addr)
+{
+ int i = 0;
+ translate_address_t ta;
+ u16 pci_ds_offset;
+ pci_data_struct_t pci_ds;
+ if (rom_base_addr == 0) {
+ // check for ExpROM Address (Offset 30) in taa
+ for (i = 0; i <= taa_last_entry; i++) {
+ ta = translate_address_array[i];
+ if (ta.cfg_space_offset == 0x30) {
+ //translated address
+ rom_base_addr = ta.address + ta.address_offset;
+ break;
+ }
+ }
+ }
+ /* In the ROM there could be multiple Expansion ROM Images... start
+ * searching them for an x86 image.
+ */
+ do {
+ if (rom_base_addr == 0) {
+ printf("Error: no Expansion ROM address found!\n");
+ return -1;
+ }
+ set_ci();
+ u16 rom_signature = in16le((void *) rom_base_addr);
+ clr_ci();
+ if (rom_signature != 0xaa55) {
+ printf
+ ("Error: invalid Expansion ROM signature: %02x!\n",
+ *((u16 *) rom_base_addr));
+ return -1;
+ }
+ set_ci();
+ // at offset 0x18 is the (16bit little-endian) pointer to the PCI Data Structure
+ pci_ds_offset = in16le((void *) (rom_base_addr + 0x18));
+ //copy the PCI Data Structure
+ memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset),
+ sizeof(pci_ds));
+ clr_ci();
+#ifdef CONFIG_DEBUG
+ DEBUG_PRINTF("PCI Data Structure @%lx:\n",
+ rom_base_addr + pci_ds_offset);
+ dump((void *) &pci_ds, sizeof(pci_ds));
+#endif
+ if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) {
+ printf("Invalid PCI Data Structure found!\n");
+ break;
+ }
+ //little-endian conversion
+ pci_ds.vendor_id = in16le(&pci_ds.vendor_id);
+ pci_ds.device_id = in16le(&pci_ds.device_id);
+ pci_ds.img_length = in16le(&pci_ds.img_length);
+ pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length);
+ if (pci_ds.vendor_id != bios_device.pci_vendor_id) {
+ printf
+ ("Image has invalid Vendor ID: %04x, expected: %04x\n",
+ pci_ds.vendor_id, bios_device.pci_vendor_id);
+ break;
+ }
+ if (pci_ds.device_id != bios_device.pci_device_id) {
+ printf
+ ("Image has invalid Device ID: %04x, expected: %04x\n",
+ pci_ds.device_id, bios_device.pci_device_id);
+ break;
+ }
+ DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512);
+ DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type);
+ if (pci_ds.code_type == 0) {
+ //x86 image
+ //store image address and image length in bios_device struct
+ bios_device.img_addr = rom_base_addr;
+ bios_device.img_size = pci_ds.img_length * 512;
+ // we found the image, exit the loop
+ break;
+ } else {
+ // no x86 image, check next image (if any)
+ rom_base_addr += pci_ds.img_length * 512;
+ }
+ if ((pci_ds.indicator & 0x80) == 0x80) {
+ //last image found, exit the loop
+ DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n");
+ break;
+ }
+ }
+ while (bios_device.img_addr == 0);
+ // in case we did not find a valid x86 Expansion ROM Image
+ if (bios_device.img_addr == 0) {
+ printf("Error: no valid x86 Expansion ROM Image found!\n");
+ return -1;
+ }
+ return 0;
+}
+
+u8
+biosemu_dev_init(struct device * device)
+{
+ u8 rval = 0;
+ //init bios_device struct
+#ifdef CONFIG_COREBOOT_V2
+ DEBUG_PRINTF("%s\n", __func__);
+#else
+ DEBUG_PRINTF("%s(%s)\n", __func__, device->dtsname);
+#endif
+ memset(&bios_device, 0, sizeof(bios_device));
+
+#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
+ bios_device.ihandle = of_open(device_name);
+ if (bios_device.ihandle == 0) {
+ DEBUG_PRINTF("%s is no valid device!\n", device_name);
+ return -1;
+ }
+ bios_device.phandle = of_finddevice(device_name);
+#else
+ bios_device.dev = device;
+#endif
+ biosemu_dev_get_addr_info();
+#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
+ biosemu_dev_find_vmem_addr();
+ biosemu_dev_get_puid();
+#endif
+ biosemu_dev_get_device_vendor_id();
+ return rval;
+}
+
+// translate address function using translate_address_array assembled
+// by dev_get_addr_info... MUCH faster than calling translate_address_dev
+// and accessing client interface for every translation...
+// returns: 0 if addr not found in translate_address_array, 1 if found.
+u8
+biosemu_dev_translate_address(unsigned long * addr)
+{
+ int i = 0;
+ translate_address_t ta;
+#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
+ /* we dont need this hack for coreboot... we can access legacy areas */
+ //check if it is an access to legacy VGA Mem... if it is, map the address
+ //to the vmem BAR and then translate it...
+ // (translation info provided by Ben Herrenschmidt)
+ // NOTE: the translation seems to only work for NVIDIA cards... but it is needed
+ // to make some NVIDIA cards work at all...
+ if ((bios_device.vmem_size > 0)
+ && ((*addr >= 0xA0000) && (*addr < 0xB8000))) {
+ *addr = (*addr - 0xA0000) * 4 + 2 + bios_device.vmem_addr;
+ }
+ if ((bios_device.vmem_size > 0)
+ && ((*addr >= 0xB8000) && (*addr < 0xC0000))) {
+ u8 shift = *addr & 1;
+ *addr &= 0xfffffffe;
+ *addr = (*addr - 0xB8000) * 4 + shift + bios_device.vmem_addr;
+ }
+#endif
+ for (i = 0; i <= taa_last_entry; i++) {
+ ta = translate_address_array[i];
+ if ((*addr >= ta.address) && (*addr <= (ta.address + ta.size))) {
+ *addr += ta.address_offset;
+ return 1;
+ }
+ }
+ return 0;
+}