diff options
author | Stefan Reinauer <stepan@coresystems.de> | 2009-08-11 21:28:25 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2009-08-11 21:28:25 +0000 |
commit | 38cd29ebd7282333650cf11ed50c7f2fd4031e80 (patch) | |
tree | 61008ca7d9a8e4ad5e5237e5f7cbc982a8206c55 /util/x86emu/yabel/io.c | |
parent | b339e10f04869a3d8da31e7d52831c32c57302a2 (diff) | |
download | coreboot-38cd29ebd7282333650cf11ed50c7f2fd4031e80.tar.xz |
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/io.c')
-rw-r--r-- | util/x86emu/yabel/io.c | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/util/x86emu/yabel/io.c b/util/x86emu/yabel/io.c new file mode 100644 index 0000000000..16a8b58331 --- /dev/null +++ b/util/x86emu/yabel/io.c @@ -0,0 +1,483 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * Copyright (c) 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 <types.h> +#ifdef CONFIG_COREBOOT_V2 +#include "compat/rtas.h" +#include "compat/time.h" +#else +#include <cpu.h> +#include "rtas.h" +#include <time.h> +#endif +#include "device.h" +#include "debug.h" +#include <x86emu/x86emu.h> + +#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL +#include <device/pci.h> +#include <device/pci_ops.h> +#endif + +// those are defined in net-snk/oflib/pci.c +extern unsigned int read_io(void *, size_t); +extern int write_io(void *, unsigned int, size_t); + +//defined in net-snk/kernel/timer.c +extern u64 get_time(void); + +// these are not used, only needed for linking, must be overridden using X86emu_setupPioFuncs +// with the functions and struct below +void +outb(u8 val, u16 port) +{ + printf("WARNING: outb not implemented!\n"); + HALT_SYS(); +} + +void +outw(u16 val, u16 port) +{ + printf("WARNING: outw not implemented!\n"); + HALT_SYS(); +} + +void +outl(u32 val, u16 port) +{ + printf("WARNING: outl not implemented!\n"); + HALT_SYS(); +} + +u8 +inb(u16 port) +{ + printf("WARNING: inb not implemented!\n"); + HALT_SYS(); + return 0; +} + +u16 +inw(u16 port) +{ + printf("WARNING: inw not implemented!\n"); + HALT_SYS(); + return 0; +} + +u32 +inl(u16 port) +{ + printf("WARNING: inl not implemented!\n"); + HALT_SYS(); + return 0; +} + +u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size); +void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size); +u8 handle_port_61h(void); + +u8 +my_inb(X86EMU_pioAddr addr) +{ + u8 rval = 0xFF; + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__, + addr); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr); + rval = read_io((void *)translated_addr, 1); + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __func__, + addr, rval); + return rval; + } else { + switch (addr) { + case 0x61: + //8254 KB Controller / Timer Port + rval = handle_port_61h(); + //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval); + return rval; + break; + case 0xCFC: + case 0xCFD: + case 0xCFE: + case 0xCFF: + // PCI Config Mechanism 1 Ports + return (u8) pci_cfg_read(addr, 1); + break; + case 0x0a: + CHECK_DBG(DEBUG_INTR) { + X86EMU_trace_on(); + } + M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + //HALT_SYS(); + // no break, intentional fall-through to default!! + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __func__, addr); + rval = *((u8 *) (bios_device.io_buffer + addr)); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n", + __func__, addr, rval); + return rval; + break; + } + } +} + +u16 +my_inw(X86EMU_pioAddr addr) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__, + addr); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr); + u16 rval; + if ((translated_addr & (u64) 0x1) == 0) { + // 16 bit aligned access... + u16 tempval = read_io((void *)translated_addr, 2); + //little endian conversion + rval = in16le((void *) &tempval); + } else { + // unaligned access, read single bytes, little-endian + rval = (read_io((void *)translated_addr, 1) << 8) + | (read_io((void *)(translated_addr + 1), 1)); + } + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__, + addr, rval); + return rval; + } else { + switch (addr) { + case 0xCFC: + case 0xCFE: + //PCI Config Mechanism 1 + return (u16) pci_cfg_read(addr, 2); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __func__, addr); + u16 rval = + in16le((void *) bios_device.io_buffer + addr); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n", + __func__, addr, rval); + return rval; + break; + } + } +} + +u32 +my_inl(X86EMU_pioAddr addr) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__, + addr); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr); + u32 rval; + if ((translated_addr & (u64) 0x3) == 0) { + // 32 bit aligned access... + u32 tempval = read_io((void *) translated_addr, 4); + //little endian conversion + rval = in32le((void *) &tempval); + } else { + // unaligned access, read single bytes, little-endian + rval = (read_io((void *)(translated_addr), 1) << 24) + | (read_io((void *)(translated_addr + 1), 1) << 16) + | (read_io((void *)(translated_addr + 2), 1) << 8) + | (read_io((void *)(translated_addr + 3), 1)); + } + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__, + addr, rval); + return rval; + } else { + switch (addr) { + case 0xCFC: + //PCI Config Mechanism 1 + return pci_cfg_read(addr, 4); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __func__, addr); + u32 rval = + in32le((void *) bios_device.io_buffer + addr); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n", + __func__, addr, rval); + return rval; + break; + } + } +} + +void +my_outb(X86EMU_pioAddr addr, u8 val) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", + __func__, addr, val); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr); + write_io((void *) translated_addr, val, 1); + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__, + addr, val); + } else { + switch (addr) { + case 0xCFC: + case 0xCFD: + case 0xCFE: + case 0xCFF: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 1); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%02x) writing to bios_device.io_buffer\n", + __func__, addr, val); + *((u8 *) (bios_device.io_buffer + addr)) = val; + break; + } + } +} + +void +my_outw(X86EMU_pioAddr addr, u16 val) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", + __func__, addr, val); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr); + if ((translated_addr & (u64) 0x1) == 0) { + // little-endian conversion + u16 tempval = in16le((void *) &val); + // 16 bit aligned access... + write_io((void *) translated_addr, tempval, 2); + } else { + // unaligned access, write single bytes, little-endian + write_io(((void *) (translated_addr + 1)), + (u8) ((val & 0xFF00) >> 8), 1); + write_io(((void *) translated_addr), + (u8) (val & 0x00FF), 1); + } + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__, + addr, val); + } else { + switch (addr) { + case 0xCFC: + case 0xCFE: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 2); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%04x) writing to bios_device.io_buffer\n", + __func__, addr, val); + out16le((void *) bios_device.io_buffer + addr, val); + break; + } + } +} + +void +my_outl(X86EMU_pioAddr addr, u32 val) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", + __func__, addr, val); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr); + if ((translated_addr & (u64) 0x3) == 0) { + // little-endian conversion + u32 tempval = in32le((void *) &val); + // 32 bit aligned access... + write_io((void *) translated_addr, tempval, 4); + } else { + // unaligned access, write single bytes, little-endian + write_io(((void *) translated_addr + 3), + (u8) ((val & 0xFF000000) >> 24), 1); + write_io(((void *) translated_addr + 2), + (u8) ((val & 0x00FF0000) >> 16), 1); + write_io(((void *) translated_addr + 1), + (u8) ((val & 0x0000FF00) >> 8), 1); + write_io(((void *) translated_addr), + (u8) (val & 0x000000FF), 1); + } + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__, + addr, val); + } else { + switch (addr) { + case 0xCFC: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 4); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%08x) writing to bios_device.io_buffer\n", + __func__, addr, val); + out32le((void *) bios_device.io_buffer + addr, val); + break; + } + } +} + +u32 +pci_cfg_read(X86EMU_pioAddr addr, u8 size) +{ + u32 rval = 0xFFFFFFFF; + struct device * dev; + if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) { + // PCI Configuration Mechanism 1 step 1 + // write to 0xCF8, sets bus, device, function and Config Space offset + // later read from 0xCFC-0xCFF returns the value... + u8 bus, devfn, offs; + u32 port_cf8_val = my_inl(0xCF8); + if ((port_cf8_val & 0x80000000) != 0) { + //highest bit enables config space mapping + bus = (port_cf8_val & 0x00FF0000) >> 16; + devfn = (port_cf8_val & 0x0000FF00) >> 8; + offs = (port_cf8_val & 0x000000FF); + offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly + DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n", + __func__, bus, devfn, offs); +#if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1 + dev = dev_find_slot(bus, devfn); + DEBUG_PRINTF_INTR("%s(): dev_find_slot() returned: %s\n", + __func__, dev_path(dev)); + if (dev == 0) { + // fail accesses to non-existent devices... +#else + dev = bios_device.dev; + if ((bus != bios_device.bus) + || (devfn != bios_device.devfn)) { + // fail accesses to any device but ours... +#endif + printf + ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n", + __func__, bus, bios_device.bus, devfn, + bios_device.devfn, offs); + SET_FLAG(F_CF); + HALT_SYS(); + return 0; + } else { +#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL + switch (size) { + case 1: + rval = pci_read_config8(dev, offs); + break; + case 2: + rval = pci_read_config16(dev, offs); + break; + case 4: + rval = pci_read_config32(dev, offs); + break; + } +#else + rval = + (u32) rtas_pci_config_read(bios_device. + puid, size, + bus, devfn, + offs); +#endif + DEBUG_PRINTF_IO + ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n", + __func__, addr, offs, size, rval); + } + } + } + return rval; +} + +void +pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size) +{ + if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) { + // PCI Configuration Mechanism 1 step 1 + // write to 0xCF8, sets bus, device, function and Config Space offset + // later write to 0xCFC-0xCFF sets the value... + u8 bus, devfn, offs; + u32 port_cf8_val = my_inl(0xCF8); + if ((port_cf8_val & 0x80000000) != 0) { + //highest bit enables config space mapping + bus = (port_cf8_val & 0x00FF0000) >> 16; + devfn = (port_cf8_val & 0x0000FF00) >> 8; + offs = (port_cf8_val & 0x000000FF); + offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly + if ((bus != bios_device.bus) + || (devfn != bios_device.devfn)) { + // fail accesses to any device but ours... + printf + ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n", + bus, devfn >> 3, devfn & 7, offs); + HALT_SYS(); + } else { +#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL + switch (size) { + case 1: + pci_write_config8(bios_device.dev, offs, val); + break; + case 2: + pci_write_config16(bios_device.dev, offs, val); + break; + case 4: + pci_write_config32(bios_device.dev, offs, val); + break; + } +#else + rtas_pci_config_write(bios_device.puid, + size, bus, devfn, offs, + val); +#endif + DEBUG_PRINTF_IO + ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n", + __func__, addr, offs, size, val); + } + } + } +} + +u8 +handle_port_61h(void) +{ + static u64 last_time = 0; + u64 curr_time = get_time(); + u64 time_diff; // time since last call + u32 period_ticks; // length of a period in ticks + u32 nr_periods; //number of periods passed since last call + // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??) + time_diff = curr_time - last_time; + // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second) + // TODO: as long as the frequency does not change, we should not calculate this every time + period_ticks = (15 * tb_freq) / 1000000; + nr_periods = time_diff / period_ticks; + // if the number if ticks passed since last call is odd, we toggle bit 4 + if ((nr_periods % 2) != 0) { + *((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10; + } + //finally read the value from the io_buffer + return *((u8 *) (bios_device.io_buffer + 0x61)); +} |