1 /****************************************************************************
3 * BIOS emulator and interface
4 * to Realmode X86 Emulator Library
6 * ========================================================================
8 * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
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 ****************************************************************************/
50 #if defined(CONFIG_BIOSEMU)
54 /*------------------------- Global Variables ------------------------------*/
57 static char *BE_biosDate = "08/14/99";
58 static u8 BE_model = 0xFC;
59 static u8 BE_submodel = 0x00;
62 /*----------------------------- Implementation ----------------------------*/
64 /****************************************************************************
66 addr - Emulator memory address to convert
69 Actual memory address to read or write the data
72 This function converts an emulator memory address in a 32-bit range to
73 a real memory address that we wish to access. It handles splitting up the
74 memory address space appropriately to access the emulator BIOS image, video
75 memory and system BIOS etc.
76 ****************************************************************************/
77 static u8 *BE_memaddr(u32 addr)
79 if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
80 return (u8*)(_BE_env.biosmem_base + addr - 0xC0000);
81 } else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) {
82 DB(printf("BE_memaddr: address %#lx may be invalid!\n", addr);)
84 } else if (addr >= 0xA0000 && addr <= 0xBFFFF) {
85 return (u8*)(_BE_env.busmem_base + addr - 0xA0000);
88 else if (addr >= 0xD0000 && addr <= 0xFFFFF) {
89 /* We map the real System BIOS directly on real PC's */
90 DB(printf("BE_memaddr: System BIOS address %#lx\n", addr);)
91 return _BE_env.busmem_base + addr - 0xA0000;
94 else if (addr >= 0xFFFF5 && addr < 0xFFFFE) {
95 /* Return a faked BIOS date string for non-x86 machines */
96 DB(printf("BE_memaddr - Returning BIOS date\n");)
97 return BE_biosDate + addr - 0xFFFF5;
98 } else if (addr == 0xFFFFE) {
99 /* Return system model identifier for non-x86 machines */
100 DB(printf("BE_memaddr - Returning model\n");)
102 } else if (addr == 0xFFFFF) {
103 /* Return system submodel identifier for non-x86 machines */
104 DB(printf("BE_memaddr - Returning submodel\n");)
108 else if (addr > M.mem_size - 1) {
113 return M.mem_base + addr;
116 /****************************************************************************
118 addr - Emulator memory address to read
121 Byte value read from emulator memory.
124 Reads a byte value from the emulator memory. We have three distinct memory
125 regions that are handled differently, which this function handles.
126 ****************************************************************************/
127 u8 X86API BE_rdb(u32 addr)
129 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
132 u8 val = readb_le(BE_memaddr(addr));
137 /****************************************************************************
139 addr - Emulator memory address to read
142 Word value read from emulator memory.
145 Reads a word value from the emulator memory. We have three distinct memory
146 regions that are handled differently, which this function handles.
147 ****************************************************************************/
148 u16 X86API BE_rdw(u32 addr)
150 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
153 u8 *base = BE_memaddr(addr);
154 u16 val = readw_le(base);
159 /****************************************************************************
161 addr - Emulator memory address to read
164 Long value read from emulator memory.
167 Reads a 32-bit value from the emulator memory. We have three distinct memory
168 regions that are handled differently, which this function handles.
169 ****************************************************************************/
170 u32 X86API BE_rdl(u32 addr)
172 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
175 u8 *base = BE_memaddr(addr);
176 u32 val = readl_le(base);
181 /****************************************************************************
183 addr - Emulator memory address to read
187 Writes a byte value to emulator memory. We have three distinct memory
188 regions that are handled differently, which this function handles.
189 ****************************************************************************/
190 void X86API BE_wrb(u32 addr, u8 val)
192 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
193 writeb_le(BE_memaddr(addr), val);
197 /****************************************************************************
199 addr - Emulator memory address to read
203 Writes a word value to emulator memory. We have three distinct memory
204 regions that are handled differently, which this function handles.
205 ****************************************************************************/
206 void X86API BE_wrw(u32 addr, u16 val)
208 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
209 u8 *base = BE_memaddr(addr);
210 writew_le(base, val);
215 /****************************************************************************
217 addr - Emulator memory address to read
221 Writes a 32-bit value to emulator memory. We have three distinct memory
222 regions that are handled differently, which this function handles.
223 ****************************************************************************/
224 void X86API BE_wrl(u32 addr, u32 val)
226 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
227 u8 *base = BE_memaddr(addr);
228 writel_le(base, val);
232 #if defined(DEBUG) || !defined(__i386__)
234 /* For Non-Intel machines we may need to emulate some I/O port accesses that
235 * the BIOS may try to access, such as the PCI config registers.
238 #define IS_TIMER_PORT(port) (0x40 <= port && port <= 0x43)
239 #define IS_CMOS_PORT(port) (0x70 <= port && port <= 0x71)
240 /*#define IS_VGA_PORT(port) (_BE_env.emulateVGA && 0x3C0 <= port && port <= 0x3DA)*/
241 #define IS_VGA_PORT(port) (0x3C0 <= port && port <= 0x3DA)
242 #define IS_PCI_PORT(port) (0xCF8 <= port && port <= 0xCFF)
243 #define IS_SPKR_PORT(port) (port == 0x61)
245 /****************************************************************************
247 port - Port to read from
248 type - Type of access to perform
251 Performs an emulated read from the Standard VGA I/O ports. If the target
252 hardware does not support mapping the VGA I/O and memory (such as some
253 PowerPC systems), we emulate the VGA so that the BIOS will still be able to
254 set NonVGA display modes such as on ATI hardware.
255 ****************************************************************************/
256 static u8 VGA_inpb (const int port)
262 /* 3C0 has funky characteristics because it can act as either
263 a data register or index register depending on the state
264 of an internal flip flop in the hardware. Hence we have
265 to emulate that functionality in here. */
266 if (_BE_env.flipFlop3C0 == 0) {
267 /* Access 3C0 as index register */
268 val = _BE_env.emu3C0;
270 /* Access 3C0 as data register */
271 if (_BE_env.emu3C0 < ATT_C)
272 val = _BE_env.emu3C1[_BE_env.emu3C0];
274 _BE_env.flipFlop3C0 ^= 1;
277 if (_BE_env.emu3C0 < ATT_C)
278 return _BE_env.emu3C1[_BE_env.emu3C0];
281 return _BE_env.emu3C2;
283 return _BE_env.emu3C4;
285 if (_BE_env.emu3C4 < ATT_C)
286 return _BE_env.emu3C5[_BE_env.emu3C4];
289 return _BE_env.emu3C6;
291 return _BE_env.emu3C7;
293 return _BE_env.emu3C8;
295 if (_BE_env.emu3C7 < PAL_C)
296 return _BE_env.emu3C9[_BE_env.emu3C7++];
299 return _BE_env.emu3CE;
301 if (_BE_env.emu3CE < GRA_C)
302 return _BE_env.emu3CF[_BE_env.emu3CE];
305 if (_BE_env.emu3C2 & 0x1)
306 return _BE_env.emu3D4;
309 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
310 return _BE_env.emu3D5[_BE_env.emu3D4];
313 _BE_env.flipFlop3C0 = 0;
314 val = _BE_env.emu3DA;
315 _BE_env.emu3DA ^= 0x9;
321 /****************************************************************************
323 port - Port to write to
324 type - Type of access to perform
327 Performs an emulated write to one of the 8253 timer registers. For now
328 we only emulate timer 0 which is the only timer that the BIOS code appears
330 ****************************************************************************/
331 static void VGA_outpb (int port, u8 val)
335 /* 3C0 has funky characteristics because it can act as either
336 a data register or index register depending on the state
337 of an internal flip flop in the hardware. Hence we have
338 to emulate that functionality in here. */
339 if (_BE_env.flipFlop3C0 == 0) {
340 /* Access 3C0 as index register */
341 _BE_env.emu3C0 = val;
343 /* Access 3C0 as data register */
344 if (_BE_env.emu3C0 < ATT_C)
345 _BE_env.emu3C1[_BE_env.emu3C0] = val;
347 _BE_env.flipFlop3C0 ^= 1;
350 _BE_env.emu3C2 = val;
353 _BE_env.emu3C4 = val;
356 if (_BE_env.emu3C4 < ATT_C)
357 _BE_env.emu3C5[_BE_env.emu3C4] = val;
360 _BE_env.emu3C6 = val;
363 _BE_env.emu3C7 = (int) val *3;
367 _BE_env.emu3C8 = (int) val *3;
371 if (_BE_env.emu3C8 < PAL_C)
372 _BE_env.emu3C9[_BE_env.emu3C8++] = val;
375 _BE_env.emu3CE = val;
378 if (_BE_env.emu3CE < GRA_C)
379 _BE_env.emu3CF[_BE_env.emu3CE] = val;
382 if (_BE_env.emu3C2 & 0x1)
383 _BE_env.emu3D4 = val;
386 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
387 _BE_env.emu3D5[_BE_env.emu3D4] = val;
392 /****************************************************************************
394 regOffset - Offset into register space for non-DWORD accesses
395 value - Value to write to register for PCI_WRITE_* operations
396 func - Function to perform (PCIAccessRegFlags)
399 Value read from configuration register for PCI_READ_* operations
402 Accesses a PCI configuration space register by decoding the value currently
403 stored in the _BE_env.configAddress variable and passing it through to the
404 portable PCI_accessReg function.
405 ****************************************************************************/
406 static u32 BE_accessReg(int regOffset, u32 value, int func)
409 int function, device, bus;
415 /* Decode the configuration register values for the register we wish to
418 regOffset += (_BE_env.configAddress & 0xFF);
419 function = (_BE_env.configAddress >> 8) & 0x7;
420 device = (_BE_env.configAddress >> 11) & 0x1F;
421 bus = (_BE_env.configAddress >> 16) & 0xFF;
423 /* Ignore accesses to all devices other than the one we're POSTing */
424 if ((function == _BE_env.vgaInfo.function) &&
425 (device == _BE_env.vgaInfo.device) &&
426 (bus == _BE_env.vgaInfo.bus)) {
429 pci_read_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
433 pci_read_config_word(_BE_env.vgaInfo.pcidev, regOffset,
437 pci_read_config_dword(_BE_env.vgaInfo.pcidev, regOffset,
441 pci_write_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
446 pci_write_config_word(_BE_env.vgaInfo.pcidev, regOffset,
450 case REG_WRITE_DWORD:
451 pci_write_config_dword(_BE_env.vgaInfo.pcidev,
459 PCIDeviceInfo pciInfo;
463 pciInfo.slot.p.Function = (_BE_env.configAddress >> 8) & 0x7;
464 pciInfo.slot.p.Device = (_BE_env.configAddress >> 11) & 0x1F;
465 pciInfo.slot.p.Bus = (_BE_env.configAddress >> 16) & 0xFF;
466 pciInfo.slot.p.Enable = 1;
468 /* Ignore accesses to all devices other than the one we're POSTing */
469 if ((pciInfo.slot.p.Function ==
470 _BE_env.vgaInfo.pciInfo->slot.p.Function)
471 && (pciInfo.slot.p.Device == _BE_env.vgaInfo.pciInfo->slot.p.Device)
472 && (pciInfo.slot.p.Bus == _BE_env.vgaInfo.pciInfo->slot.p.Bus))
473 return PCI_accessReg((_BE_env.configAddress & 0xFF) + regOffset,
474 value, func, &pciInfo);
479 /****************************************************************************
481 port - Port to read from
482 type - Type of access to perform
485 Performs an emulated read from one of the PCI configuration space registers.
486 We emulate this using our PCI_accessReg function which will access the PCI
487 configuration space registers in a portable fashion.
488 ****************************************************************************/
489 static u32 PCI_inp(int port, int type)
493 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
495 return BE_accessReg(port - 0xCFC, 0, REG_READ_BYTE);
498 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
500 return BE_accessReg(port - 0xCFC, 0, REG_READ_WORD);
504 return _BE_env.configAddress;
505 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
506 return BE_accessReg(0, 0, REG_READ_DWORD);
512 /****************************************************************************
514 port - Port to write to
515 type - Type of access to perform
518 Performs an emulated write to one of the PCI control registers.
519 ****************************************************************************/
520 static void PCI_outp(int port, u32 val, int type)
524 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
526 BE_accessReg(port - 0xCFC, val, REG_WRITE_BYTE);
529 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
531 BE_accessReg(port - 0xCFC, val, REG_WRITE_WORD);
533 case REG_WRITE_DWORD:
536 _BE_env.configAddress = val & 0x80FFFFFC;
538 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
539 BE_accessReg(0, val, REG_WRITE_DWORD);
546 /****************************************************************************
548 port - Port to write to
551 Value read from the I/O port
554 Performs an emulated 8-bit read from an I/O port. We handle special cases
555 that we need to emulate in here, and fall through to reflecting the write
556 through to the real hardware if we don't need to special case it.
557 ****************************************************************************/
558 u8 X86API BE_inb(X86EMU_pioAddr port)
562 #if defined(DEBUG) || !defined(__i386__)
563 if (IS_VGA_PORT(port)){
564 /*seems reading port 0x3c3 return the high 16 bit of io port*/
566 val = LOG_inpb(port);
568 val = VGA_inpb(port);
570 else if (IS_TIMER_PORT(port))
571 DB(printf("Can not interept TIMER port now!\n");)
572 else if (IS_SPKR_PORT(port))
573 DB(printf("Can not interept SPEAKER port now!\n");)
574 else if (IS_CMOS_PORT(port))
575 DB(printf("Can not interept CMOS port now!\n");)
576 else if (IS_PCI_PORT(port))
577 val = PCI_inp(port, REG_READ_BYTE);
578 else if (port < 0x100) {
579 DB(printf("WARN: INVALID inb.%04X -> %02X\n", (u16) port, val);)
580 val = LOG_inpb(port);
583 val = LOG_inpb(port);
587 /****************************************************************************
589 port - Port to write to
592 Value read from the I/O port
595 Performs an emulated 16-bit read from an I/O port. We handle special cases
596 that we need to emulate in here, and fall through to reflecting the write
597 through to the real hardware if we don't need to special case it.
598 ****************************************************************************/
599 u16 X86API BE_inw(X86EMU_pioAddr port)
603 #if defined(DEBUG) || !defined(__i386__)
604 if (IS_PCI_PORT(port))
605 val = PCI_inp(port, REG_READ_WORD);
606 else if (port < 0x100) {
607 DB(printf("WARN: Maybe INVALID inw.%04X -> %04X\n", (u16) port, val);)
608 val = LOG_inpw(port);
611 val = LOG_inpw(port);
615 /****************************************************************************
617 port - Port to write to
620 Value read from the I/O port
623 Performs an emulated 32-bit read from an I/O port. We handle special cases
624 that we need to emulate in here, and fall through to reflecting the write
625 through to the real hardware if we don't need to special case it.
626 ****************************************************************************/
627 u32 X86API BE_inl(X86EMU_pioAddr port)
631 #if defined(DEBUG) || !defined(__i386__)
632 if (IS_PCI_PORT(port))
633 val = PCI_inp(port, REG_READ_DWORD);
634 else if (port < 0x100) {
635 val = LOG_inpd(port);
638 val = LOG_inpd(port);
642 /****************************************************************************
644 port - Port to write to
645 val - Value to write to port
648 Performs an emulated 8-bit write to an I/O port. We handle special cases
649 that we need to emulate in here, and fall through to reflecting the write
650 through to the real hardware if we don't need to special case it.
651 ****************************************************************************/
652 void X86API BE_outb(X86EMU_pioAddr port, u8 val)
654 #if defined(DEBUG) || !defined(__i386__)
655 if (IS_VGA_PORT(port))
656 VGA_outpb(port, val);
657 else if (IS_TIMER_PORT(port))
658 DB(printf("Can not interept TIMER port now!\n");)
659 else if (IS_SPKR_PORT(port))
660 DB(printf("Can not interept SPEAKER port now!\n");)
661 else if (IS_CMOS_PORT(port))
662 DB(printf("Can not interept CMOS port now!\n");)
663 else if (IS_PCI_PORT(port))
664 PCI_outp(port, val, REG_WRITE_BYTE);
665 else if (port < 0x100) {
666 DB(printf("WARN:Maybe INVALID outb.%04X <- %02X\n", (u16) port, val);)
667 LOG_outpb(port, val);
670 LOG_outpb(port, val);
673 /****************************************************************************
675 port - Port to write to
676 val - Value to write to port
679 Performs an emulated 16-bit write to an I/O port. We handle special cases
680 that we need to emulate in here, and fall through to reflecting the write
681 through to the real hardware if we don't need to special case it.
682 ****************************************************************************/
683 void X86API BE_outw(X86EMU_pioAddr port, u16 val)
685 #if defined(DEBUG) || !defined(__i386__)
686 if (IS_VGA_PORT(port)) {
687 VGA_outpb(port, val);
688 VGA_outpb(port + 1, val >> 8);
689 } else if (IS_PCI_PORT(port))
690 PCI_outp(port, val, REG_WRITE_WORD);
691 else if (port < 0x100) {
692 DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port,
694 LOG_outpw(port, val);
697 LOG_outpw(port, val);
700 /****************************************************************************
702 port - Port to write to
703 val - Value to write to port
706 Performs an emulated 32-bit write to an I/O port. We handle special cases
707 that we need to emulate in here, and fall through to reflecting the write
708 through to the real hardware if we don't need to special case it.
709 ****************************************************************************/
710 void X86API BE_outl(X86EMU_pioAddr port, u32 val)
712 #if defined(DEBUG) || !defined(__i386__)
713 if (IS_PCI_PORT(port))
714 PCI_outp(port, val, REG_WRITE_DWORD);
715 else if (port < 0x100) {
716 DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);)
717 LOG_outpd(port, val);
720 LOG_outpd(port, val);