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 ****************************************************************************/
53 /*------------------------- Global Variables ------------------------------*/
56 static char *BE_biosDate = "08/14/99";
57 static u8 BE_model = 0xFC;
58 static u8 BE_submodel = 0x00;
61 /*----------------------------- Implementation ----------------------------*/
63 /****************************************************************************
65 addr - Emulator memory address to convert
68 Actual memory address to read or write the data
71 This function converts an emulator memory address in a 32-bit range to
72 a real memory address that we wish to access. It handles splitting up the
73 memory address space appropriately to access the emulator BIOS image, video
74 memory and system BIOS etc.
75 ****************************************************************************/
76 static u8 *BE_memaddr(u32 addr)
78 if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
79 return (u8*)(_BE_env.biosmem_base + addr - 0xC0000);
80 } else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) {
81 DB(printf("BE_memaddr: address %#lx may be invalid!\n", addr);)
83 } else if (addr >= 0xA0000 && addr <= 0xBFFFF) {
84 return (u8*)(_BE_env.busmem_base + addr - 0xA0000);
87 else if (addr >= 0xD0000 && addr <= 0xFFFFF) {
88 /* We map the real System BIOS directly on real PC's */
89 DB(printf("BE_memaddr: System BIOS address %#lx\n", addr);)
90 return _BE_env.busmem_base + addr - 0xA0000;
93 else if (addr >= 0xFFFF5 && addr < 0xFFFFE) {
94 /* Return a faked BIOS date string for non-x86 machines */
95 DB(printf("BE_memaddr - Returning BIOS date\n");)
96 return (u8 *)(BE_biosDate + addr - 0xFFFF5);
97 } else if (addr == 0xFFFFE) {
98 /* Return system model identifier for non-x86 machines */
99 DB(printf("BE_memaddr - Returning model\n");)
101 } else if (addr == 0xFFFFF) {
102 /* Return system submodel identifier for non-x86 machines */
103 DB(printf("BE_memaddr - Returning submodel\n");)
107 else if (addr > M.mem_size - 1) {
112 return M.mem_base + addr;
115 /****************************************************************************
117 addr - Emulator memory address to read
120 Byte value read from emulator memory.
123 Reads a byte value from the emulator memory. We have three distinct memory
124 regions that are handled differently, which this function handles.
125 ****************************************************************************/
126 u8 X86API BE_rdb(u32 addr)
128 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
131 u8 val = readb_le(BE_memaddr(addr));
136 /****************************************************************************
138 addr - Emulator memory address to read
141 Word value read from emulator memory.
144 Reads a word value from the emulator memory. We have three distinct memory
145 regions that are handled differently, which this function handles.
146 ****************************************************************************/
147 u16 X86API BE_rdw(u32 addr)
149 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
152 u8 *base = BE_memaddr(addr);
153 u16 val = readw_le(base);
158 /****************************************************************************
160 addr - Emulator memory address to read
163 Long value read from emulator memory.
166 Reads a 32-bit value from the emulator memory. We have three distinct memory
167 regions that are handled differently, which this function handles.
168 ****************************************************************************/
169 u32 X86API BE_rdl(u32 addr)
171 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
174 u8 *base = BE_memaddr(addr);
175 u32 val = readl_le(base);
180 /****************************************************************************
182 addr - Emulator memory address to read
186 Writes a byte value to emulator memory. We have three distinct memory
187 regions that are handled differently, which this function handles.
188 ****************************************************************************/
189 void X86API BE_wrb(u32 addr, u8 val)
191 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
192 writeb_le(BE_memaddr(addr), val);
196 /****************************************************************************
198 addr - Emulator memory address to read
202 Writes a word value to emulator memory. We have three distinct memory
203 regions that are handled differently, which this function handles.
204 ****************************************************************************/
205 void X86API BE_wrw(u32 addr, u16 val)
207 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
208 u8 *base = BE_memaddr(addr);
209 writew_le(base, val);
214 /****************************************************************************
216 addr - Emulator memory address to read
220 Writes a 32-bit value to emulator memory. We have three distinct memory
221 regions that are handled differently, which this function handles.
222 ****************************************************************************/
223 void X86API BE_wrl(u32 addr, u32 val)
225 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
226 u8 *base = BE_memaddr(addr);
227 writel_le(base, val);
231 #if defined(DEBUG) || !defined(__i386__)
233 /* For Non-Intel machines we may need to emulate some I/O port accesses that
234 * the BIOS may try to access, such as the PCI config registers.
237 #define IS_TIMER_PORT(port) (0x40 <= port && port <= 0x43)
238 #define IS_CMOS_PORT(port) (0x70 <= port && port <= 0x71)
239 /*#define IS_VGA_PORT(port) (_BE_env.emulateVGA && 0x3C0 <= port && port <= 0x3DA)*/
240 #define IS_VGA_PORT(port) (0x3C0 <= port && port <= 0x3DA)
241 #define IS_PCI_PORT(port) (0xCF8 <= port && port <= 0xCFF)
242 #define IS_SPKR_PORT(port) (port == 0x61)
244 /****************************************************************************
246 port - Port to read from
247 type - Type of access to perform
250 Performs an emulated read from the Standard VGA I/O ports. If the target
251 hardware does not support mapping the VGA I/O and memory (such as some
252 PowerPC systems), we emulate the VGA so that the BIOS will still be able to
253 set NonVGA display modes such as on ATI hardware.
254 ****************************************************************************/
255 static u8 VGA_inpb (const int port)
261 /* 3C0 has funky characteristics because it can act as either
262 a data register or index register depending on the state
263 of an internal flip flop in the hardware. Hence we have
264 to emulate that functionality in here. */
265 if (_BE_env.flipFlop3C0 == 0) {
266 /* Access 3C0 as index register */
267 val = _BE_env.emu3C0;
269 /* Access 3C0 as data register */
270 if (_BE_env.emu3C0 < ATT_C)
271 val = _BE_env.emu3C1[_BE_env.emu3C0];
273 _BE_env.flipFlop3C0 ^= 1;
276 if (_BE_env.emu3C0 < ATT_C)
277 return _BE_env.emu3C1[_BE_env.emu3C0];
280 return _BE_env.emu3C2;
282 return _BE_env.emu3C4;
284 if (_BE_env.emu3C4 < ATT_C)
285 return _BE_env.emu3C5[_BE_env.emu3C4];
288 return _BE_env.emu3C6;
290 return _BE_env.emu3C7;
292 return _BE_env.emu3C8;
294 if (_BE_env.emu3C7 < PAL_C)
295 return _BE_env.emu3C9[_BE_env.emu3C7++];
298 return _BE_env.emu3CE;
300 if (_BE_env.emu3CE < GRA_C)
301 return _BE_env.emu3CF[_BE_env.emu3CE];
304 if (_BE_env.emu3C2 & 0x1)
305 return _BE_env.emu3D4;
308 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
309 return _BE_env.emu3D5[_BE_env.emu3D4];
312 _BE_env.flipFlop3C0 = 0;
313 val = _BE_env.emu3DA;
314 _BE_env.emu3DA ^= 0x9;
320 /****************************************************************************
322 port - Port to write to
323 type - Type of access to perform
326 Performs an emulated write to one of the 8253 timer registers. For now
327 we only emulate timer 0 which is the only timer that the BIOS code appears
329 ****************************************************************************/
330 static void VGA_outpb (int port, u8 val)
334 /* 3C0 has funky characteristics because it can act as either
335 a data register or index register depending on the state
336 of an internal flip flop in the hardware. Hence we have
337 to emulate that functionality in here. */
338 if (_BE_env.flipFlop3C0 == 0) {
339 /* Access 3C0 as index register */
340 _BE_env.emu3C0 = val;
342 /* Access 3C0 as data register */
343 if (_BE_env.emu3C0 < ATT_C)
344 _BE_env.emu3C1[_BE_env.emu3C0] = val;
346 _BE_env.flipFlop3C0 ^= 1;
349 _BE_env.emu3C2 = val;
352 _BE_env.emu3C4 = val;
355 if (_BE_env.emu3C4 < ATT_C)
356 _BE_env.emu3C5[_BE_env.emu3C4] = val;
359 _BE_env.emu3C6 = val;
362 _BE_env.emu3C7 = (int) val *3;
366 _BE_env.emu3C8 = (int) val *3;
370 if (_BE_env.emu3C8 < PAL_C)
371 _BE_env.emu3C9[_BE_env.emu3C8++] = val;
374 _BE_env.emu3CE = val;
377 if (_BE_env.emu3CE < GRA_C)
378 _BE_env.emu3CF[_BE_env.emu3CE] = val;
381 if (_BE_env.emu3C2 & 0x1)
382 _BE_env.emu3D4 = val;
385 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
386 _BE_env.emu3D5[_BE_env.emu3D4] = val;
391 /****************************************************************************
393 regOffset - Offset into register space for non-DWORD accesses
394 value - Value to write to register for PCI_WRITE_* operations
395 func - Function to perform (PCIAccessRegFlags)
398 Value read from configuration register for PCI_READ_* operations
401 Accesses a PCI configuration space register by decoding the value currently
402 stored in the _BE_env.configAddress variable and passing it through to the
403 portable PCI_accessReg function.
404 ****************************************************************************/
405 static u32 BE_accessReg(int regOffset, u32 value, int func)
408 int function, device, bus;
414 /* Decode the configuration register values for the register we wish to
417 regOffset += (_BE_env.configAddress & 0xFF);
418 function = (_BE_env.configAddress >> 8) & 0x7;
419 device = (_BE_env.configAddress >> 11) & 0x1F;
420 bus = (_BE_env.configAddress >> 16) & 0xFF;
422 /* Ignore accesses to all devices other than the one we're POSTing */
423 if ((function == _BE_env.vgaInfo.function) &&
424 (device == _BE_env.vgaInfo.device) &&
425 (bus == _BE_env.vgaInfo.bus)) {
428 pci_read_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
432 pci_read_config_word(_BE_env.vgaInfo.pcidev, regOffset,
436 pci_read_config_dword(_BE_env.vgaInfo.pcidev, regOffset,
440 pci_write_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
445 pci_write_config_word(_BE_env.vgaInfo.pcidev, regOffset,
449 case REG_WRITE_DWORD:
450 pci_write_config_dword(_BE_env.vgaInfo.pcidev,
458 PCIDeviceInfo pciInfo;
462 pciInfo.slot.p.Function = (_BE_env.configAddress >> 8) & 0x7;
463 pciInfo.slot.p.Device = (_BE_env.configAddress >> 11) & 0x1F;
464 pciInfo.slot.p.Bus = (_BE_env.configAddress >> 16) & 0xFF;
465 pciInfo.slot.p.Enable = 1;
467 /* Ignore accesses to all devices other than the one we're POSTing */
468 if ((pciInfo.slot.p.Function ==
469 _BE_env.vgaInfo.pciInfo->slot.p.Function)
470 && (pciInfo.slot.p.Device == _BE_env.vgaInfo.pciInfo->slot.p.Device)
471 && (pciInfo.slot.p.Bus == _BE_env.vgaInfo.pciInfo->slot.p.Bus))
472 return PCI_accessReg((_BE_env.configAddress & 0xFF) + regOffset,
473 value, func, &pciInfo);
478 /****************************************************************************
480 port - Port to read from
481 type - Type of access to perform
484 Performs an emulated read from one of the PCI configuration space registers.
485 We emulate this using our PCI_accessReg function which will access the PCI
486 configuration space registers in a portable fashion.
487 ****************************************************************************/
488 static u32 PCI_inp(int port, int type)
492 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
494 return BE_accessReg(port - 0xCFC, 0, REG_READ_BYTE);
497 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
499 return BE_accessReg(port - 0xCFC, 0, REG_READ_WORD);
503 return _BE_env.configAddress;
504 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
505 return BE_accessReg(0, 0, REG_READ_DWORD);
511 /****************************************************************************
513 port - Port to write to
514 type - Type of access to perform
517 Performs an emulated write to one of the PCI control registers.
518 ****************************************************************************/
519 static void PCI_outp(int port, u32 val, int type)
523 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
525 BE_accessReg(port - 0xCFC, val, REG_WRITE_BYTE);
528 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
530 BE_accessReg(port - 0xCFC, val, REG_WRITE_WORD);
532 case REG_WRITE_DWORD:
535 _BE_env.configAddress = val & 0x80FFFFFC;
537 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
538 BE_accessReg(0, val, REG_WRITE_DWORD);
545 /****************************************************************************
547 port - Port to write to
550 Value read from the I/O port
553 Performs an emulated 8-bit read from an I/O port. We handle special cases
554 that we need to emulate in here, and fall through to reflecting the write
555 through to the real hardware if we don't need to special case it.
556 ****************************************************************************/
557 u8 X86API BE_inb(X86EMU_pioAddr port)
561 #if defined(DEBUG) || !defined(__i386__)
562 if (IS_VGA_PORT(port)){
563 /*seems reading port 0x3c3 return the high 16 bit of io port*/
565 val = LOG_inpb(port);
567 val = VGA_inpb(port);
569 else if (IS_TIMER_PORT(port))
570 DB(printf("Can not interept TIMER port now!\n");)
571 else if (IS_SPKR_PORT(port))
572 DB(printf("Can not interept SPEAKER port now!\n");)
573 else if (IS_CMOS_PORT(port))
574 DB(printf("Can not interept CMOS port now!\n");)
575 else if (IS_PCI_PORT(port))
576 val = PCI_inp(port, REG_READ_BYTE);
577 else if (port < 0x100) {
578 DB(printf("WARN: INVALID inb.%04X -> %02X\n", (u16) port, val);)
579 val = LOG_inpb(port);
582 val = LOG_inpb(port);
586 /****************************************************************************
588 port - Port to write to
591 Value read from the I/O port
594 Performs an emulated 16-bit read from an I/O port. We handle special cases
595 that we need to emulate in here, and fall through to reflecting the write
596 through to the real hardware if we don't need to special case it.
597 ****************************************************************************/
598 u16 X86API BE_inw(X86EMU_pioAddr port)
602 #if defined(DEBUG) || !defined(__i386__)
603 if (IS_PCI_PORT(port))
604 val = PCI_inp(port, REG_READ_WORD);
605 else if (port < 0x100) {
606 DB(printf("WARN: Maybe INVALID inw.%04X -> %04X\n", (u16) port, val);)
607 val = LOG_inpw(port);
610 val = LOG_inpw(port);
614 /****************************************************************************
616 port - Port to write to
619 Value read from the I/O port
622 Performs an emulated 32-bit read from an I/O port. We handle special cases
623 that we need to emulate in here, and fall through to reflecting the write
624 through to the real hardware if we don't need to special case it.
625 ****************************************************************************/
626 u32 X86API BE_inl(X86EMU_pioAddr port)
630 #if defined(DEBUG) || !defined(__i386__)
631 if (IS_PCI_PORT(port))
632 val = PCI_inp(port, REG_READ_DWORD);
633 else if (port < 0x100) {
634 val = LOG_inpd(port);
637 val = LOG_inpd(port);
641 /****************************************************************************
643 port - Port to write to
644 val - Value to write to port
647 Performs an emulated 8-bit write to an I/O port. We handle special cases
648 that we need to emulate in here, and fall through to reflecting the write
649 through to the real hardware if we don't need to special case it.
650 ****************************************************************************/
651 void X86API BE_outb(X86EMU_pioAddr port, u8 val)
653 #if defined(DEBUG) || !defined(__i386__)
654 if (IS_VGA_PORT(port))
655 VGA_outpb(port, val);
656 else if (IS_TIMER_PORT(port))
657 DB(printf("Can not interept TIMER port now!\n");)
658 else if (IS_SPKR_PORT(port))
659 DB(printf("Can not interept SPEAKER port now!\n");)
660 else if (IS_CMOS_PORT(port))
661 DB(printf("Can not interept CMOS port now!\n");)
662 else if (IS_PCI_PORT(port))
663 PCI_outp(port, val, REG_WRITE_BYTE);
664 else if (port < 0x100) {
665 DB(printf("WARN:Maybe INVALID outb.%04X <- %02X\n", (u16) port, val);)
666 LOG_outpb(port, val);
669 LOG_outpb(port, val);
672 /****************************************************************************
674 port - Port to write to
675 val - Value to write to port
678 Performs an emulated 16-bit write to an I/O port. We handle special cases
679 that we need to emulate in here, and fall through to reflecting the write
680 through to the real hardware if we don't need to special case it.
681 ****************************************************************************/
682 void X86API BE_outw(X86EMU_pioAddr port, u16 val)
684 #if defined(DEBUG) || !defined(__i386__)
685 if (IS_VGA_PORT(port)) {
686 VGA_outpb(port, val);
687 VGA_outpb(port + 1, val >> 8);
688 } else if (IS_PCI_PORT(port))
689 PCI_outp(port, val, REG_WRITE_WORD);
690 else if (port < 0x100) {
691 DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port,
693 LOG_outpw(port, val);
696 LOG_outpw(port, val);
699 /****************************************************************************
701 port - Port to write to
702 val - Value to write to port
705 Performs an emulated 32-bit write to an I/O port. We handle special cases
706 that we need to emulate in here, and fall through to reflecting the write
707 through to the real hardware if we don't need to special case it.
708 ****************************************************************************/
709 void X86API BE_outl(X86EMU_pioAddr port, u32 val)
711 #if defined(DEBUG) || !defined(__i386__)
712 if (IS_PCI_PORT(port))
713 PCI_outp(port, val, REG_WRITE_DWORD);
714 else if (port < 0x100) {
715 DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);)
716 LOG_outpd(port, val);
719 LOG_outpd(port, val);