1 /****************************************************************************
3 * BIOS emulator and interface
4 * to Realmode X86 Emulator Library
6 * ========================================================================
8 * Copyright (C) 2007 Freescale Semiconductor, Inc.
9 * Jason Jin<Jason.jin@freescale.com>
11 * Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
13 * This file may be distributed and/or modified under the terms of the
14 * GNU General Public License version 2.0 as published by the Free
15 * Software Foundation and appearing in the file LICENSE.GPL included
16 * in the packaging of this file.
18 * Licensees holding a valid Commercial License for this product from
19 * SciTech Software, Inc. may use this file in accordance with the
20 * Commercial License Agreement provided with the Software.
22 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
23 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * See http://www.scitechsoft.com/license/ for information about
27 * the licensing options available and how to purchase a Commercial
30 * Contact license@scitechsoft.com if any conditions of this licensing
31 * are not clear to you, or you have questions about licensing options.
33 * ========================================================================
37 * Developer: Kendall Bennett
39 * Description: This file includes BIOS emulator I/O and memory access
42 * Jason ported this file to u-boot to run the ATI video card
43 * BIOS in u-boot. Removed some emulate functions such as the
44 * timer port access. Made all the VGA port except reading 0x3c3
45 * be emulated. Seems like reading 0x3c3 should return the high
46 * 16 bit of the io port.
48 ****************************************************************************/
55 /*------------------------- Global Variables ------------------------------*/
57 #ifndef CONFIG_X86EMU_RAW_IO
58 static char *BE_biosDate = "08/14/99";
59 static u8 BE_model = 0xFC;
60 static u8 BE_submodel = 0x00;
63 #undef DEBUG_IO_ACCESS
65 #ifdef DEBUG_IO_ACCESS
66 #define debug_io(fmt, ...) printf(fmt, ##__VA_ARGS__)
68 #define debug_io(x, b...)
71 /*----------------------------- Implementation ----------------------------*/
73 /****************************************************************************
75 addr - Emulator memory address to convert
78 Actual memory address to read or write the data
81 This function converts an emulator memory address in a 32-bit range to
82 a real memory address that we wish to access. It handles splitting up the
83 memory address space appropriately to access the emulator BIOS image, video
84 memory and system BIOS etc.
85 ****************************************************************************/
86 static u8 *BE_memaddr(u32 addr)
88 if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
89 return (u8*)(_BE_env.biosmem_base + addr - 0xC0000);
90 } else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) {
91 DB(printf("BE_memaddr: address %#lx may be invalid!\n",
93 return (u8 *)M.mem_base;
94 } else if (addr >= 0xA0000 && addr <= 0xBFFFF) {
95 return (u8*)(_BE_env.busmem_base + addr - 0xA0000);
97 #ifdef CONFIG_X86EMU_RAW_IO
98 else if (addr >= 0xD0000 && addr <= 0xFFFFF) {
99 /* We map the real System BIOS directly on real PC's */
100 DB(printf("BE_memaddr: System BIOS address %#lx\n",
102 return (u8 *)_BE_env.busmem_base + addr - 0xA0000;
105 else if (addr >= 0xFFFF5 && addr < 0xFFFFE) {
106 /* Return a faked BIOS date string for non-x86 machines */
107 debug_io("BE_memaddr - Returning BIOS date\n");
108 return (u8 *)(BE_biosDate + addr - 0xFFFF5);
109 } else if (addr == 0xFFFFE) {
110 /* Return system model identifier for non-x86 machines */
111 debug_io("BE_memaddr - Returning model\n");
113 } else if (addr == 0xFFFFF) {
114 /* Return system submodel identifier for non-x86 machines */
115 debug_io("BE_memaddr - Returning submodel\n");
119 else if (addr > M.mem_size - 1) {
121 return (u8 *)M.mem_base;
124 return (u8 *)(M.mem_base + addr);
127 /****************************************************************************
129 addr - Emulator memory address to read
132 Byte value read from emulator memory.
135 Reads a byte value from the emulator memory. We have three distinct memory
136 regions that are handled differently, which this function handles.
137 ****************************************************************************/
138 u8 X86API BE_rdb(u32 addr)
140 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
143 u8 val = readb_le(BE_memaddr(addr));
148 /****************************************************************************
150 addr - Emulator memory address to read
153 Word value read from emulator memory.
156 Reads a word value from the emulator memory. We have three distinct memory
157 regions that are handled differently, which this function handles.
158 ****************************************************************************/
159 u16 X86API BE_rdw(u32 addr)
161 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
164 u8 *base = BE_memaddr(addr);
165 u16 val = readw_le(base);
170 /****************************************************************************
172 addr - Emulator memory address to read
175 Long value read from emulator memory.
178 Reads a 32-bit value from the emulator memory. We have three distinct memory
179 regions that are handled differently, which this function handles.
180 ****************************************************************************/
181 u32 X86API BE_rdl(u32 addr)
183 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
186 u8 *base = BE_memaddr(addr);
187 u32 val = readl_le(base);
192 /****************************************************************************
194 addr - Emulator memory address to read
198 Writes a byte value to emulator memory. We have three distinct memory
199 regions that are handled differently, which this function handles.
200 ****************************************************************************/
201 void X86API BE_wrb(u32 addr, u8 val)
203 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
204 writeb_le(BE_memaddr(addr), val);
208 /****************************************************************************
210 addr - Emulator memory address to read
214 Writes a word value to emulator memory. We have three distinct memory
215 regions that are handled differently, which this function handles.
216 ****************************************************************************/
217 void X86API BE_wrw(u32 addr, u16 val)
219 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
220 u8 *base = BE_memaddr(addr);
221 writew_le(base, val);
226 /****************************************************************************
228 addr - Emulator memory address to read
232 Writes a 32-bit value to emulator memory. We have three distinct memory
233 regions that are handled differently, which this function handles.
234 ****************************************************************************/
235 void X86API BE_wrl(u32 addr, u32 val)
237 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
238 u8 *base = BE_memaddr(addr);
239 writel_le(base, val);
243 #if !defined(CONFIG_X86EMU_RAW_IO)
245 /* For Non-Intel machines we may need to emulate some I/O port accesses that
246 * the BIOS may try to access, such as the PCI config registers.
249 #define IS_TIMER_PORT(port) (0x40 <= port && port <= 0x43)
250 #define IS_CMOS_PORT(port) (0x70 <= port && port <= 0x71)
251 /*#define IS_VGA_PORT(port) (_BE_env.emulateVGA && 0x3C0 <= port && port <= 0x3DA)*/
252 #define IS_VGA_PORT(port) (0x3C0 <= port && port <= 0x3DA)
253 #define IS_PCI_PORT(port) (0xCF8 <= port && port <= 0xCFF)
254 #define IS_SPKR_PORT(port) (port == 0x61)
256 /****************************************************************************
258 port - Port to read from
259 type - Type of access to perform
262 Performs an emulated read from the Standard VGA I/O ports. If the target
263 hardware does not support mapping the VGA I/O and memory (such as some
264 PowerPC systems), we emulate the VGA so that the BIOS will still be able to
265 set NonVGA display modes such as on ATI hardware.
266 ****************************************************************************/
267 static u8 VGA_inpb (const int port)
271 debug_io("vga_inb.%04X -> ", (u16) port);
274 /* 3C0 has funky characteristics because it can act as either
275 a data register or index register depending on the state
276 of an internal flip flop in the hardware. Hence we have
277 to emulate that functionality in here. */
278 if (_BE_env.flipFlop3C0 == 0) {
279 /* Access 3C0 as index register */
280 val = _BE_env.emu3C0;
282 /* Access 3C0 as data register */
283 if (_BE_env.emu3C0 < ATT_C)
284 val = _BE_env.emu3C1[_BE_env.emu3C0];
286 _BE_env.flipFlop3C0 ^= 1;
289 if (_BE_env.emu3C0 < ATT_C)
290 return _BE_env.emu3C1[_BE_env.emu3C0];
293 return _BE_env.emu3C2;
295 return _BE_env.emu3C4;
297 if (_BE_env.emu3C4 < ATT_C)
298 return _BE_env.emu3C5[_BE_env.emu3C4];
301 return _BE_env.emu3C6;
303 return _BE_env.emu3C7;
305 return _BE_env.emu3C8;
307 if (_BE_env.emu3C7 < PAL_C)
308 return _BE_env.emu3C9[_BE_env.emu3C7++];
311 return _BE_env.emu3CE;
313 if (_BE_env.emu3CE < GRA_C)
314 return _BE_env.emu3CF[_BE_env.emu3CE];
317 if (_BE_env.emu3C2 & 0x1)
318 return _BE_env.emu3D4;
321 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
322 return _BE_env.emu3D5[_BE_env.emu3D4];
325 _BE_env.flipFlop3C0 = 0;
326 val = _BE_env.emu3DA;
327 _BE_env.emu3DA ^= 0x9;
333 /****************************************************************************
335 port - Port to write to
336 type - Type of access to perform
339 Performs an emulated write to one of the 8253 timer registers. For now
340 we only emulate timer 0 which is the only timer that the BIOS code appears
342 ****************************************************************************/
343 static void VGA_outpb (int port, u8 val)
347 /* 3C0 has funky characteristics because it can act as either
348 a data register or index register depending on the state
349 of an internal flip flop in the hardware. Hence we have
350 to emulate that functionality in here. */
351 if (_BE_env.flipFlop3C0 == 0) {
352 /* Access 3C0 as index register */
353 _BE_env.emu3C0 = val;
355 /* Access 3C0 as data register */
356 if (_BE_env.emu3C0 < ATT_C)
357 _BE_env.emu3C1[_BE_env.emu3C0] = val;
359 _BE_env.flipFlop3C0 ^= 1;
362 _BE_env.emu3C2 = val;
365 _BE_env.emu3C4 = val;
368 if (_BE_env.emu3C4 < ATT_C)
369 _BE_env.emu3C5[_BE_env.emu3C4] = val;
372 _BE_env.emu3C6 = val;
375 _BE_env.emu3C7 = (int) val *3;
379 _BE_env.emu3C8 = (int) val *3;
383 if (_BE_env.emu3C8 < PAL_C)
384 _BE_env.emu3C9[_BE_env.emu3C8++] = val;
387 _BE_env.emu3CE = val;
390 if (_BE_env.emu3CE < GRA_C)
391 _BE_env.emu3CF[_BE_env.emu3CE] = val;
394 if (_BE_env.emu3C2 & 0x1)
395 _BE_env.emu3D4 = val;
398 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
399 _BE_env.emu3D5[_BE_env.emu3D4] = val;
404 /****************************************************************************
406 regOffset - Offset into register space for non-DWORD accesses
407 value - Value to write to register for PCI_WRITE_* operations
408 func - Function to perform (PCIAccessRegFlags)
411 Value read from configuration register for PCI_READ_* operations
414 Accesses a PCI configuration space register by decoding the value currently
415 stored in the _BE_env.configAddress variable and passing it through to the
416 portable PCI_accessReg function.
417 ****************************************************************************/
418 static u32 BE_accessReg(int regOffset, u32 value, int func)
421 int function, device, bus;
427 /* Decode the configuration register values for the register we wish to
430 regOffset += (_BE_env.configAddress & 0xFF);
431 function = (_BE_env.configAddress >> 8) & 0x7;
432 device = (_BE_env.configAddress >> 11) & 0x1F;
433 bus = (_BE_env.configAddress >> 16) & 0xFF;
435 /* Ignore accesses to all devices other than the one we're POSTing */
436 if ((function == _BE_env.vgaInfo.function) &&
437 (device == _BE_env.vgaInfo.device) &&
438 (bus == _BE_env.vgaInfo.bus)) {
441 pci_read_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
445 pci_read_config_word(_BE_env.vgaInfo.pcidev, regOffset,
449 pci_read_config_dword(_BE_env.vgaInfo.pcidev, regOffset,
453 pci_write_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
458 pci_write_config_word(_BE_env.vgaInfo.pcidev, regOffset,
462 case REG_WRITE_DWORD:
463 pci_write_config_dword(_BE_env.vgaInfo.pcidev,
471 PCIDeviceInfo pciInfo;
475 pciInfo.slot.p.Function = (_BE_env.configAddress >> 8) & 0x7;
476 pciInfo.slot.p.Device = (_BE_env.configAddress >> 11) & 0x1F;
477 pciInfo.slot.p.Bus = (_BE_env.configAddress >> 16) & 0xFF;
478 pciInfo.slot.p.Enable = 1;
480 /* Ignore accesses to all devices other than the one we're POSTing */
481 if ((pciInfo.slot.p.Function ==
482 _BE_env.vgaInfo.pciInfo->slot.p.Function)
483 && (pciInfo.slot.p.Device == _BE_env.vgaInfo.pciInfo->slot.p.Device)
484 && (pciInfo.slot.p.Bus == _BE_env.vgaInfo.pciInfo->slot.p.Bus))
485 return PCI_accessReg((_BE_env.configAddress & 0xFF) + regOffset,
486 value, func, &pciInfo);
491 /****************************************************************************
493 port - Port to read from
494 type - Type of access to perform
497 Performs an emulated read from one of the PCI configuration space registers.
498 We emulate this using our PCI_accessReg function which will access the PCI
499 configuration space registers in a portable fashion.
500 ****************************************************************************/
501 static u32 PCI_inp(int port, int type)
505 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
507 return BE_accessReg(port - 0xCFC, 0, REG_READ_BYTE);
510 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
512 return BE_accessReg(port - 0xCFC, 0, REG_READ_WORD);
516 return _BE_env.configAddress;
517 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
518 return BE_accessReg(0, 0, REG_READ_DWORD);
524 /****************************************************************************
526 port - Port to write to
527 type - Type of access to perform
530 Performs an emulated write to one of the PCI control registers.
531 ****************************************************************************/
532 static void PCI_outp(int port, u32 val, int type)
536 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
538 BE_accessReg(port - 0xCFC, val, REG_WRITE_BYTE);
541 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
543 BE_accessReg(port - 0xCFC, val, REG_WRITE_WORD);
545 case REG_WRITE_DWORD:
548 _BE_env.configAddress = val & 0x80FFFFFC;
550 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
551 BE_accessReg(0, val, REG_WRITE_DWORD);
558 /****************************************************************************
560 port - Port to write to
563 Value read from the I/O port
566 Performs an emulated 8-bit read from an I/O port. We handle special cases
567 that we need to emulate in here, and fall through to reflecting the write
568 through to the real hardware if we don't need to special case it.
569 ****************************************************************************/
570 u8 X86API BE_inb(X86EMU_pioAddr port)
574 #if !defined(CONFIG_X86EMU_RAW_IO)
575 if (IS_VGA_PORT(port)){
576 /*seems reading port 0x3c3 return the high 16 bit of io port*/
578 val = LOG_inpb(port);
580 val = VGA_inpb(port);
582 else if (IS_TIMER_PORT(port))
583 DB(printf("Can not interept TIMER port now!\n");)
584 else if (IS_SPKR_PORT(port))
585 DB(printf("Can not interept SPEAKER port now!\n");)
586 else if (IS_CMOS_PORT(port))
587 DB(printf("Can not interept CMOS port now!\n");)
588 else if (IS_PCI_PORT(port))
589 val = PCI_inp(port, REG_READ_BYTE);
590 else if (port < 0x100) {
591 DB(printf("WARN: INVALID inb.%04X -> %02X\n", (u16) port, val);)
592 val = LOG_inpb(port);
596 debug_io("inb.%04X -> ", (u16) port);
597 val = LOG_inpb(port);
598 debug_io("%02X\n", val);
604 /****************************************************************************
606 port - Port to write to
609 Value read from the I/O port
612 Performs an emulated 16-bit read from an I/O port. We handle special cases
613 that we need to emulate in here, and fall through to reflecting the write
614 through to the real hardware if we don't need to special case it.
615 ****************************************************************************/
616 u16 X86API BE_inw(X86EMU_pioAddr port)
620 #if !defined(CONFIG_X86EMU_RAW_IO)
621 if (IS_PCI_PORT(port))
622 val = PCI_inp(port, REG_READ_WORD);
623 else if (port < 0x100) {
624 DB(printf("WARN: Maybe INVALID inw.%04X -> %04X\n", (u16) port, val);)
625 val = LOG_inpw(port);
629 debug_io("inw.%04X -> ", (u16) port);
630 val = LOG_inpw(port);
631 debug_io("%04X\n", val);
637 /****************************************************************************
639 port - Port to write to
642 Value read from the I/O port
645 Performs an emulated 32-bit read from an I/O port. We handle special cases
646 that we need to emulate in here, and fall through to reflecting the write
647 through to the real hardware if we don't need to special case it.
648 ****************************************************************************/
649 u32 X86API BE_inl(X86EMU_pioAddr port)
653 #if !defined(CONFIG_X86EMU_RAW_IO)
654 if (IS_PCI_PORT(port))
655 val = PCI_inp(port, REG_READ_DWORD);
656 else if (port < 0x100) {
657 val = LOG_inpd(port);
661 debug_io("inl.%04X -> ", (u16) port);
662 val = LOG_inpd(port);
663 debug_io("%08X\n", val);
669 /****************************************************************************
671 port - Port to write to
672 val - Value to write to port
675 Performs an emulated 8-bit write to an I/O port. We handle special cases
676 that we need to emulate in here, and fall through to reflecting the write
677 through to the real hardware if we don't need to special case it.
678 ****************************************************************************/
679 void X86API BE_outb(X86EMU_pioAddr port, u8 val)
681 #if !defined(CONFIG_X86EMU_RAW_IO)
682 if (IS_VGA_PORT(port))
683 VGA_outpb(port, val);
684 else if (IS_TIMER_PORT(port))
685 DB(printf("Can not interept TIMER port now!\n");)
686 else if (IS_SPKR_PORT(port))
687 DB(printf("Can not interept SPEAKER port now!\n");)
688 else if (IS_CMOS_PORT(port))
689 DB(printf("Can not interept CMOS port now!\n");)
690 else if (IS_PCI_PORT(port))
691 PCI_outp(port, val, REG_WRITE_BYTE);
692 else if (port < 0x100) {
693 DB(printf("WARN:Maybe INVALID outb.%04X <- %02X\n", (u16) port, val);)
694 LOG_outpb(port, val);
698 debug_io("outb.%04X <- %02X", (u16) port, val);
699 LOG_outpb(port, val);
704 /****************************************************************************
706 port - Port to write to
707 val - Value to write to port
710 Performs an emulated 16-bit write to an I/O port. We handle special cases
711 that we need to emulate in here, and fall through to reflecting the write
712 through to the real hardware if we don't need to special case it.
713 ****************************************************************************/
714 void X86API BE_outw(X86EMU_pioAddr port, u16 val)
716 #if !defined(CONFIG_X86EMU_RAW_IO)
717 if (IS_VGA_PORT(port)) {
718 VGA_outpb(port, val);
719 VGA_outpb(port + 1, val >> 8);
720 } else if (IS_PCI_PORT(port)) {
721 PCI_outp(port, val, REG_WRITE_WORD);
722 } else if (port < 0x100) {
723 DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16)port,
725 LOG_outpw(port, val);
729 debug_io("outw.%04X <- %04X", (u16) port, val);
730 LOG_outpw(port, val);
735 /****************************************************************************
737 port - Port to write to
738 val - Value to write to port
741 Performs an emulated 32-bit write to an I/O port. We handle special cases
742 that we need to emulate in here, and fall through to reflecting the write
743 through to the real hardware if we don't need to special case it.
744 ****************************************************************************/
745 void X86API BE_outl(X86EMU_pioAddr port, u32 val)
747 #if !defined(CONFIG_X86EMU_RAW_IO)
748 if (IS_PCI_PORT(port)) {
749 PCI_outp(port, val, REG_WRITE_DWORD);
750 } else if (port < 0x100) {
751 DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);)
752 LOG_outpd(port, val);
756 debug_io("outl.%04X <- %08X", (u16) port, val);
757 LOG_outpd(port, val);