diff options
author | Stefan Reinauer <reinauer@chromium.org> | 2012-11-30 12:34:04 -0800 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2012-11-30 23:59:58 +0100 |
commit | 8d7115560d469f901d7d8ccb242d0b437e7394aa (patch) | |
tree | 0f1b4bd63c48a233c49d5a9ca15f08a1675d1ff4 /src/device/oprom/yabel/mem.c | |
parent | 4b6be985aae8bff84ae442e7be7669e93694fa1e (diff) |
Rename devices -> device
to match src/include/device
Change-Id: I5d0e5b4361c34881a3b81347aac48738cb5b9af0
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/1960
Tested-by: build bot (Jenkins)
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Diffstat (limited to 'src/device/oprom/yabel/mem.c')
-rw-r--r-- | src/device/oprom/yabel/mem.c | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/src/device/oprom/yabel/mem.c b/src/device/oprom/yabel/mem.c new file mode 100644 index 0000000000..4b4a552813 --- /dev/null +++ b/src/device/oprom/yabel/mem.c @@ -0,0 +1,501 @@ +/****************************************************************************** + * 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> +#include "debug.h" +#include "device.h" +#include "x86emu/x86emu.h" +#include "biosemu.h" +#include "mem.h" +#include "compat/time.h" + +#if !CONFIG_YABEL_DIRECTHW || !CONFIG_YABEL_DIRECTHW + +#if CONFIG_PCI_OPTION_ROM_RUN_YABEL +#include <device/resource.h> +#endif + +// define a check for access to certain (virtual) memory regions (interrupt handlers, BIOS Data Area, ...) +#if CONFIG_X86EMU_DEBUG +static u8 in_check = 0; // to avoid recursion... + +static inline void DEBUG_CHECK_VMEM_READ(u32 _addr, u32 _rval) +{ + u16 ebda_segment; + u32 ebda_size; + if (!((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0))) + return; + in_check = 1; + /* determine ebda_segment and size + * since we are using my_rdx calls, make sure, this is after setting in_check! */ + /* offset 03 in BDA is EBDA segment */ + ebda_segment = my_rdw(0x40e); + /* first value in ebda is size in KB */ + ebda_size = my_rdb(ebda_segment << 4) * 1024; + /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ + if (_addr < 0x400) { + DEBUG_PRINTF_CS_IP("%s: read from Interrupt Vector %x --> %x\n", + __func__, _addr / 4, _rval); + } + /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ + else if ((_addr >= 0x400) && (_addr < 0x500)) { + DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Area: addr: %x --> %x\n", + __func__, _addr, _rval); + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* access to first 64k of memory... */ + else if (_addr < 0x10000) { + DEBUG_PRINTF_CS_IP("%s: read from segment 0000h: addr: %x --> %x\n", + __func__, _addr, _rval); + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* read from PMM_CONV_SEGMENT */ + else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { + DEBUG_PRINTF_CS_IP("%s: read from PMM Segment %04xh: addr: %x --> %x\n", + __func__, PMM_CONV_SEGMENT, _addr, _rval); + /* HALT_SYS(); */ + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* read from PNP_DATA_SEGMENT */ + else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { + DEBUG_PRINTF_CS_IP("%s: read from PnP Data Segment %04xh: addr: %x --> %x\n", + __func__, PNP_DATA_SEGMENT, _addr, _rval); + /* HALT_SYS(); */ + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* read from EBDA Segment */ + else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { + DEBUG_PRINTF_CS_IP("%s: read from Extended BIOS Data Area %04xh, size: %04x: addr: %x --> %x\n", + __func__, ebda_segment, ebda_size, _addr, _rval); + } + /* read from BIOS_DATA_SEGMENT */ + else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { + DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Segment %04xh: addr: %x --> %x\n", + __func__, BIOS_DATA_SEGMENT, _addr, _rval); + /* for PMM debugging */ + /*if (_addr == BIOS_DATA_SEGMENT << 4) { + X86EMU_trace_on(); + M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + }*/ + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + in_check = 0; +} + +static inline void DEBUG_CHECK_VMEM_WRITE(u32 _addr, u32 _val) +{ + u16 ebda_segment; + u32 ebda_size; + if (!((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0))) + return; + in_check = 1; + /* determine ebda_segment and size + * since we are using my_rdx calls, make sure that this is after + * setting in_check! */ + /* offset 03 in BDA is EBDA segment */ + ebda_segment = my_rdw(0x40e); + /* first value in ebda is size in KB */ + ebda_size = my_rdb(ebda_segment << 4) * 1024; + /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ + if (_addr < 0x400) { + DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n", + __func__, _addr / 4, _val); + } + /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ + else if ((_addr >= 0x400) && (_addr < 0x500)) { + DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Area: addr: %x <-- %x\n", + __func__, _addr, _val); + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* access to first 64k of memory...*/ + else if (_addr < 0x10000) { + DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n", + __func__, _addr, _val); + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* write to PMM_CONV_SEGMENT... */ + else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { + DEBUG_PRINTF_CS_IP("%s: write to PMM Segment %04xh: addr: %x <-- %x\n", + __func__, PMM_CONV_SEGMENT, _addr, _val); + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* write to PNP_DATA_SEGMENT... */ + else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { + DEBUG_PRINTF_CS_IP("%s: write to PnP Data Segment %04xh: addr: %x <-- %x\n", + __func__, PNP_DATA_SEGMENT, _addr, _val); + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* write to EBDA Segment... */ + else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { + DEBUG_PRINTF_CS_IP("%s: write to Extended BIOS Data Area %04xh, size: %04x: addr: %x <-- %x\n", + __func__, ebda_segment, ebda_size, _addr, _val); + } + /* write to BIOS_DATA_SEGMENT... */ + else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { + DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Segment %04xh: addr: %x <-- %x\n", + __func__, BIOS_DATA_SEGMENT, _addr, _val); + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + /* write to current CS segment... */ + else if ((_addr < ((M.x86.R_CS << 4) | 0xffff)) && (_addr > (M.x86.R_CS << 4))) { + DEBUG_PRINTF_CS_IP("%s: write to CS segment %04xh: addr: %x <-- %x\n", + __func__, M.x86.R_CS, _addr, _val); + /* dump registers */ + /* x86emu_dump_xregs(); */ + } + in_check = 0; +} +#else +static inline void DEBUG_CHECK_VMEM_READ(u32 _addr, u32 _rval) {}; +static inline void DEBUG_CHECK_VMEM_WRITE(u32 _addr, u32 _val) {}; +#endif + +//update time in BIOS Data Area +//DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz +//byte at 0x70 is timer overflow (set if midnight passed since last call to interrupt 1a function 00 +//cur_val is the current value, of offset 6c... +static void +update_time(u32 cur_val) +{ + //for convenience, we let the start of timebase be at midnight, we currently dont support + //real daytime anyway... + u64 ticks_per_day = tb_freq * 60 * 24; + // at 18Hz a period is ~55ms, converted to ticks (tb_freq is ticks/second) + u32 period_ticks = (55 * tb_freq) / 1000; + u64 curr_time = get_time(); + u64 ticks_since_midnight = curr_time % ticks_per_day; + u32 periods_since_midnight = ticks_since_midnight / period_ticks; + // if periods since midnight is smaller than last value, set overflow + // at BDA Offset 0x70 + if (periods_since_midnight < cur_val) { + my_wrb(0x470, 1); + } + // store periods since midnight at BDA offset 0x6c + my_wrl(0x46c, periods_since_midnight); +} + +// read byte from memory +u8 +my_rdb(u32 addr) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr); + u8 rval; + if (translated != 0) { + //translation successfull, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n", + __func__, addr); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr); + set_ci(); + rval = *((u8 *) translated_addr); + clr_ci(); + DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __func__, addr, + rval); + return rval; + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __func__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* read from virtual memory */ + rval = *((u8 *) (M.mem_base + addr)); + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; + } + return -1; +} + +//read word from memory +u16 +my_rdw(u32 addr) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr); + u16 rval; + if (translated != 0) { + //translation successfull, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n", + __func__, addr); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr); + // check for legacy memory, because of the remapping to BARs, the reads must + // be byte reads... + if ((addr >= 0xa0000) && (addr < 0xc0000)) { + //read bytes a using my_rdb, because of the remapping to BARs + //words may not be contiguous in memory, so we need to translate + //every address... + rval = ((u8) my_rdb(addr)) | + (((u8) my_rdb(addr + 1)) << 8); + } else { + if ((translated_addr & (u64) 0x1) == 0) { + // 16 bit aligned access... + set_ci(); + rval = in16le((void *) translated_addr); + clr_ci(); + } else { + // unaligned access, read single bytes + set_ci(); + rval = (*((u8 *) translated_addr)) | + (*((u8 *) translated_addr + 1) << 8); + clr_ci(); + } + } + DEBUG_PRINTF_MEM("%s(%08x) VGA --> %04x\n", __func__, addr, + rval); + return rval; + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __func__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* read from virtual memory */ + rval = in16le((void *) (M.mem_base + addr)); + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; + } + return -1; +} + +//read long from memory +u32 +my_rdl(u32 addr) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr); + u32 rval; + if (translated != 0) { + //translation successfull, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n", + __func__, addr); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr); + // check for legacy memory, because of the remapping to BARs, the reads must + // be byte reads... + if ((addr >= 0xa0000) && (addr < 0xc0000)) { + //read bytes a using my_rdb, because of the remapping to BARs + //dwords may not be contiguous in memory, so we need to translate + //every address... + rval = ((u8) my_rdb(addr)) | + (((u8) my_rdb(addr + 1)) << 8) | + (((u8) my_rdb(addr + 2)) << 16) | + (((u8) my_rdb(addr + 3)) << 24); + } else { + if ((translated_addr & (u64) 0x3) == 0) { + // 32 bit aligned access... + set_ci(); + rval = in32le((void *) translated_addr); + clr_ci(); + } else { + // unaligned access, read single bytes + set_ci(); + rval = (*((u8 *) translated_addr)) | + (*((u8 *) translated_addr + 1) << 8) | + (*((u8 *) translated_addr + 2) << 16) | + (*((u8 *) translated_addr + 3) << 24); + clr_ci(); + } + } + DEBUG_PRINTF_MEM("%s(%08x) VGA --> %08x\n", __func__, addr, + rval); + //HALT_SYS(); + return rval; + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __func__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* read from virtual memory */ + rval = in32le((void *) (M.mem_base + addr)); + switch (addr) { + case 0x46c: + //BDA Time Data, update it, before reading + update_time(rval); + rval = in32le((void *) (M.mem_base + addr)); + break; + } + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; + } + return -1; +} + +//write byte to memory +void +my_wrb(u32 addr, u8 val) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr); + if (translated != 0) { + //translation successfull, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n", + __func__, addr, val); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr); + set_ci(); + *((u8 *) translated_addr) = val; + clr_ci(); + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __func__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); + *((u8 *) (M.mem_base + addr)) = val; + } +} + +void +my_wrw(u32 addr, u16 val) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr); + if (translated != 0) { + //translation successfull, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n", + __func__, addr, val); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr); + // check for legacy memory, because of the remapping to BARs, the reads must + // be byte reads... + if ((addr >= 0xa0000) && (addr < 0xc0000)) { + //read bytes a using my_rdb, because of the remapping to BARs + //words may not be contiguous in memory, so we need to translate + //every address... + my_wrb(addr, (u8) (val & 0x00FF)); + my_wrb(addr + 1, (u8) ((val & 0xFF00) >> 8)); + } else { + if ((translated_addr & (u64) 0x1) == 0) { + // 16 bit aligned access... + set_ci(); + out16le((void *) translated_addr, val); + clr_ci(); + } else { + // unaligned access, write single bytes + set_ci(); + *((u8 *) translated_addr) = + (u8) (val & 0x00FF); + *((u8 *) translated_addr + 1) = + (u8) ((val & 0xFF00) >> 8); + clr_ci(); + } + } + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __func__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); + out16le((void *) (M.mem_base + addr), val); + } +} +void +my_wrl(u32 addr, u32 val) +{ + unsigned long translated_addr = addr; + u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr); + if (translated != 0) { + //translation successfull, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n", + __func__, addr, val); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr); + // check for legacy memory, because of the remapping to BARs, the reads must + // be byte reads... + if ((addr >= 0xa0000) && (addr < 0xc0000)) { + //read bytes a using my_rdb, because of the remapping to BARs + //words may not be contiguous in memory, so we need to translate + //every address... + my_wrb(addr, (u8) (val & 0x000000FF)); + my_wrb(addr + 1, (u8) ((val & 0x0000FF00) >> 8)); + my_wrb(addr + 2, (u8) ((val & 0x00FF0000) >> 16)); + my_wrb(addr + 3, (u8) ((val & 0xFF000000) >> 24)); + } else { + if ((translated_addr & (u64) 0x3) == 0) { + // 32 bit aligned access... + set_ci(); + out32le((void *) translated_addr, val); + clr_ci(); + } else { + // unaligned access, write single bytes + set_ci(); + *((u8 *) translated_addr) = + (u8) (val & 0x000000FF); + *((u8 *) translated_addr + 1) = + (u8) ((val & 0x0000FF00) >> 8); + *((u8 *) translated_addr + 2) = + (u8) ((val & 0x00FF0000) >> 16); + *((u8 *) translated_addr + 3) = + (u8) ((val & 0xFF000000) >> 24); + clr_ci(); + } + } + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __func__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); + out32le((void *) (M.mem_base + addr), val); + } +} +#else +u8 +my_rdb(u32 addr) +{ + return rdb(addr); +} + +u16 +my_rdw(u32 addr) +{ + return rdw(addr); +} + +u32 +my_rdl(u32 addr) +{ + return rdl(addr); +} + +void +my_wrb(u32 addr, u8 val) +{ + wrb(addr, val); +} + +void +my_wrw(u32 addr, u16 val) +{ + wrw(addr, val); +} + +void +my_wrl(u32 addr, u32 val) +{ + wrl(addr, val); +} +#endif |