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 ------------------------------*/
58 static char *BE_biosDate = "08/14/99";
59 static u8 BE_model = 0xFC;
60 static u8 BE_submodel = 0x00;
63 /*----------------------------- Implementation ----------------------------*/
65 /****************************************************************************
67 addr - Emulator memory address to convert
70 Actual memory address to read or write the data
73 This function converts an emulator memory address in a 32-bit range to
74 a real memory address that we wish to access. It handles splitting up the
75 memory address space appropriately to access the emulator BIOS image, video
76 memory and system BIOS etc.
77 ****************************************************************************/
78 static u8 *BE_memaddr(u32 addr)
80 if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
81 return (u8*)(_BE_env.biosmem_base + addr - 0xC0000);
82 } else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) {
83 DB(printf("BE_memaddr: address %#lx may be invalid!\n", addr);)
85 } else if (addr >= 0xA0000 && addr <= 0xBFFFF) {
86 return (u8*)(_BE_env.busmem_base + addr - 0xA0000);
89 else if (addr >= 0xD0000 && addr <= 0xFFFFF) {
90 /* We map the real System BIOS directly on real PC's */
91 DB(printf("BE_memaddr: System BIOS address %#lx\n", addr);)
92 return _BE_env.busmem_base + addr - 0xA0000;
95 else if (addr >= 0xFFFF5 && addr < 0xFFFFE) {
96 /* Return a faked BIOS date string for non-x86 machines */
97 DB(printf("BE_memaddr - Returning BIOS date\n");)
98 return (u8 *)(BE_biosDate + addr - 0xFFFF5);
99 } else if (addr == 0xFFFFE) {
100 /* Return system model identifier for non-x86 machines */
101 DB(printf("BE_memaddr - Returning model\n");)
103 } else if (addr == 0xFFFFF) {
104 /* Return system submodel identifier for non-x86 machines */
105 DB(printf("BE_memaddr - Returning submodel\n");)
109 else if (addr > M.mem_size - 1) {
114 return M.mem_base + addr;
117 /****************************************************************************
119 addr - Emulator memory address to read
122 Byte value read from emulator memory.
125 Reads a byte value from the emulator memory. We have three distinct memory
126 regions that are handled differently, which this function handles.
127 ****************************************************************************/
128 u8 X86API BE_rdb(u32 addr)
130 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
133 u8 val = readb_le(BE_memaddr(addr));
138 /****************************************************************************
140 addr - Emulator memory address to read
143 Word value read from emulator memory.
146 Reads a word value from the emulator memory. We have three distinct memory
147 regions that are handled differently, which this function handles.
148 ****************************************************************************/
149 u16 X86API BE_rdw(u32 addr)
151 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
154 u8 *base = BE_memaddr(addr);
155 u16 val = readw_le(base);
160 /****************************************************************************
162 addr - Emulator memory address to read
165 Long value read from emulator memory.
168 Reads a 32-bit value from the emulator memory. We have three distinct memory
169 regions that are handled differently, which this function handles.
170 ****************************************************************************/
171 u32 X86API BE_rdl(u32 addr)
173 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
176 u8 *base = BE_memaddr(addr);
177 u32 val = readl_le(base);
182 /****************************************************************************
184 addr - Emulator memory address to read
188 Writes a byte value to emulator memory. We have three distinct memory
189 regions that are handled differently, which this function handles.
190 ****************************************************************************/
191 void X86API BE_wrb(u32 addr, u8 val)
193 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
194 writeb_le(BE_memaddr(addr), val);
198 /****************************************************************************
200 addr - Emulator memory address to read
204 Writes a word value to emulator memory. We have three distinct memory
205 regions that are handled differently, which this function handles.
206 ****************************************************************************/
207 void X86API BE_wrw(u32 addr, u16 val)
209 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
210 u8 *base = BE_memaddr(addr);
211 writew_le(base, val);
216 /****************************************************************************
218 addr - Emulator memory address to read
222 Writes a 32-bit value to emulator memory. We have three distinct memory
223 regions that are handled differently, which this function handles.
224 ****************************************************************************/
225 void X86API BE_wrl(u32 addr, u32 val)
227 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
228 u8 *base = BE_memaddr(addr);
229 writel_le(base, val);
233 #if defined(DEBUG) || !defined(__i386__)
235 /* For Non-Intel machines we may need to emulate some I/O port accesses that
236 * the BIOS may try to access, such as the PCI config registers.
239 #define IS_TIMER_PORT(port) (0x40 <= port && port <= 0x43)
240 #define IS_CMOS_PORT(port) (0x70 <= port && port <= 0x71)
241 /*#define IS_VGA_PORT(port) (_BE_env.emulateVGA && 0x3C0 <= port && port <= 0x3DA)*/
242 #define IS_VGA_PORT(port) (0x3C0 <= port && port <= 0x3DA)
243 #define IS_PCI_PORT(port) (0xCF8 <= port && port <= 0xCFF)
244 #define IS_SPKR_PORT(port) (port == 0x61)
246 /****************************************************************************
248 port - Port to read from
249 type - Type of access to perform
252 Performs an emulated read from the Standard VGA I/O ports. If the target
253 hardware does not support mapping the VGA I/O and memory (such as some
254 PowerPC systems), we emulate the VGA so that the BIOS will still be able to
255 set NonVGA display modes such as on ATI hardware.
256 ****************************************************************************/
257 static u8 VGA_inpb (const int port)
263 /* 3C0 has funky characteristics because it can act as either
264 a data register or index register depending on the state
265 of an internal flip flop in the hardware. Hence we have
266 to emulate that functionality in here. */
267 if (_BE_env.flipFlop3C0 == 0) {
268 /* Access 3C0 as index register */
269 val = _BE_env.emu3C0;
271 /* Access 3C0 as data register */
272 if (_BE_env.emu3C0 < ATT_C)
273 val = _BE_env.emu3C1[_BE_env.emu3C0];
275 _BE_env.flipFlop3C0 ^= 1;
278 if (_BE_env.emu3C0 < ATT_C)
279 return _BE_env.emu3C1[_BE_env.emu3C0];
282 return _BE_env.emu3C2;
284 return _BE_env.emu3C4;
286 if (_BE_env.emu3C4 < ATT_C)
287 return _BE_env.emu3C5[_BE_env.emu3C4];
290 return _BE_env.emu3C6;
292 return _BE_env.emu3C7;
294 return _BE_env.emu3C8;
296 if (_BE_env.emu3C7 < PAL_C)
297 return _BE_env.emu3C9[_BE_env.emu3C7++];
300 return _BE_env.emu3CE;
302 if (_BE_env.emu3CE < GRA_C)
303 return _BE_env.emu3CF[_BE_env.emu3CE];
306 if (_BE_env.emu3C2 & 0x1)
307 return _BE_env.emu3D4;
310 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
311 return _BE_env.emu3D5[_BE_env.emu3D4];
314 _BE_env.flipFlop3C0 = 0;
315 val = _BE_env.emu3DA;
316 _BE_env.emu3DA ^= 0x9;
322 /****************************************************************************
324 port - Port to write to
325 type - Type of access to perform
328 Performs an emulated write to one of the 8253 timer registers. For now
329 we only emulate timer 0 which is the only timer that the BIOS code appears
331 ****************************************************************************/
332 static void VGA_outpb (int port, u8 val)
336 /* 3C0 has funky characteristics because it can act as either
337 a data register or index register depending on the state
338 of an internal flip flop in the hardware. Hence we have
339 to emulate that functionality in here. */
340 if (_BE_env.flipFlop3C0 == 0) {
341 /* Access 3C0 as index register */
342 _BE_env.emu3C0 = val;
344 /* Access 3C0 as data register */
345 if (_BE_env.emu3C0 < ATT_C)
346 _BE_env.emu3C1[_BE_env.emu3C0] = val;
348 _BE_env.flipFlop3C0 ^= 1;
351 _BE_env.emu3C2 = val;
354 _BE_env.emu3C4 = val;
357 if (_BE_env.emu3C4 < ATT_C)
358 _BE_env.emu3C5[_BE_env.emu3C4] = val;
361 _BE_env.emu3C6 = val;
364 _BE_env.emu3C7 = (int) val *3;
368 _BE_env.emu3C8 = (int) val *3;
372 if (_BE_env.emu3C8 < PAL_C)
373 _BE_env.emu3C9[_BE_env.emu3C8++] = val;
376 _BE_env.emu3CE = val;
379 if (_BE_env.emu3CE < GRA_C)
380 _BE_env.emu3CF[_BE_env.emu3CE] = val;
383 if (_BE_env.emu3C2 & 0x1)
384 _BE_env.emu3D4 = val;
387 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
388 _BE_env.emu3D5[_BE_env.emu3D4] = val;
393 /****************************************************************************
395 regOffset - Offset into register space for non-DWORD accesses
396 value - Value to write to register for PCI_WRITE_* operations
397 func - Function to perform (PCIAccessRegFlags)
400 Value read from configuration register for PCI_READ_* operations
403 Accesses a PCI configuration space register by decoding the value currently
404 stored in the _BE_env.configAddress variable and passing it through to the
405 portable PCI_accessReg function.
406 ****************************************************************************/
407 static u32 BE_accessReg(int regOffset, u32 value, int func)
410 int function, device, bus;
416 /* Decode the configuration register values for the register we wish to
419 regOffset += (_BE_env.configAddress & 0xFF);
420 function = (_BE_env.configAddress >> 8) & 0x7;
421 device = (_BE_env.configAddress >> 11) & 0x1F;
422 bus = (_BE_env.configAddress >> 16) & 0xFF;
424 /* Ignore accesses to all devices other than the one we're POSTing */
425 if ((function == _BE_env.vgaInfo.function) &&
426 (device == _BE_env.vgaInfo.device) &&
427 (bus == _BE_env.vgaInfo.bus)) {
430 pci_read_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
434 pci_read_config_word(_BE_env.vgaInfo.pcidev, regOffset,
438 pci_read_config_dword(_BE_env.vgaInfo.pcidev, regOffset,
442 pci_write_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
447 pci_write_config_word(_BE_env.vgaInfo.pcidev, regOffset,
451 case REG_WRITE_DWORD:
452 pci_write_config_dword(_BE_env.vgaInfo.pcidev,
460 PCIDeviceInfo pciInfo;
464 pciInfo.slot.p.Function = (_BE_env.configAddress >> 8) & 0x7;
465 pciInfo.slot.p.Device = (_BE_env.configAddress >> 11) & 0x1F;
466 pciInfo.slot.p.Bus = (_BE_env.configAddress >> 16) & 0xFF;
467 pciInfo.slot.p.Enable = 1;
469 /* Ignore accesses to all devices other than the one we're POSTing */
470 if ((pciInfo.slot.p.Function ==
471 _BE_env.vgaInfo.pciInfo->slot.p.Function)
472 && (pciInfo.slot.p.Device == _BE_env.vgaInfo.pciInfo->slot.p.Device)
473 && (pciInfo.slot.p.Bus == _BE_env.vgaInfo.pciInfo->slot.p.Bus))
474 return PCI_accessReg((_BE_env.configAddress & 0xFF) + regOffset,
475 value, func, &pciInfo);
480 /****************************************************************************
482 port - Port to read from
483 type - Type of access to perform
486 Performs an emulated read from one of the PCI configuration space registers.
487 We emulate this using our PCI_accessReg function which will access the PCI
488 configuration space registers in a portable fashion.
489 ****************************************************************************/
490 static u32 PCI_inp(int port, int type)
494 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
496 return BE_accessReg(port - 0xCFC, 0, REG_READ_BYTE);
499 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
501 return BE_accessReg(port - 0xCFC, 0, REG_READ_WORD);
505 return _BE_env.configAddress;
506 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
507 return BE_accessReg(0, 0, REG_READ_DWORD);
513 /****************************************************************************
515 port - Port to write to
516 type - Type of access to perform
519 Performs an emulated write to one of the PCI control registers.
520 ****************************************************************************/
521 static void PCI_outp(int port, u32 val, int type)
525 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
527 BE_accessReg(port - 0xCFC, val, REG_WRITE_BYTE);
530 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
532 BE_accessReg(port - 0xCFC, val, REG_WRITE_WORD);
534 case REG_WRITE_DWORD:
537 _BE_env.configAddress = val & 0x80FFFFFC;
539 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
540 BE_accessReg(0, val, REG_WRITE_DWORD);
547 /****************************************************************************
549 port - Port to write to
552 Value read from the I/O port
555 Performs an emulated 8-bit read from an I/O port. We handle special cases
556 that we need to emulate in here, and fall through to reflecting the write
557 through to the real hardware if we don't need to special case it.
558 ****************************************************************************/
559 u8 X86API BE_inb(X86EMU_pioAddr port)
563 #if defined(DEBUG) || !defined(__i386__)
564 if (IS_VGA_PORT(port)){
565 /*seems reading port 0x3c3 return the high 16 bit of io port*/
567 val = LOG_inpb(port);
569 val = VGA_inpb(port);
571 else if (IS_TIMER_PORT(port))
572 DB(printf("Can not interept TIMER port now!\n");)
573 else if (IS_SPKR_PORT(port))
574 DB(printf("Can not interept SPEAKER port now!\n");)
575 else if (IS_CMOS_PORT(port))
576 DB(printf("Can not interept CMOS port now!\n");)
577 else if (IS_PCI_PORT(port))
578 val = PCI_inp(port, REG_READ_BYTE);
579 else if (port < 0x100) {
580 DB(printf("WARN: INVALID inb.%04X -> %02X\n", (u16) port, val);)
581 val = LOG_inpb(port);
584 val = LOG_inpb(port);
588 /****************************************************************************
590 port - Port to write to
593 Value read from the I/O port
596 Performs an emulated 16-bit read from an I/O port. We handle special cases
597 that we need to emulate in here, and fall through to reflecting the write
598 through to the real hardware if we don't need to special case it.
599 ****************************************************************************/
600 u16 X86API BE_inw(X86EMU_pioAddr port)
604 #if defined(DEBUG) || !defined(__i386__)
605 if (IS_PCI_PORT(port))
606 val = PCI_inp(port, REG_READ_WORD);
607 else if (port < 0x100) {
608 DB(printf("WARN: Maybe INVALID inw.%04X -> %04X\n", (u16) port, val);)
609 val = LOG_inpw(port);
612 val = LOG_inpw(port);
616 /****************************************************************************
618 port - Port to write to
621 Value read from the I/O port
624 Performs an emulated 32-bit read from an I/O port. We handle special cases
625 that we need to emulate in here, and fall through to reflecting the write
626 through to the real hardware if we don't need to special case it.
627 ****************************************************************************/
628 u32 X86API BE_inl(X86EMU_pioAddr port)
632 #if defined(DEBUG) || !defined(__i386__)
633 if (IS_PCI_PORT(port))
634 val = PCI_inp(port, REG_READ_DWORD);
635 else if (port < 0x100) {
636 val = LOG_inpd(port);
639 val = LOG_inpd(port);
643 /****************************************************************************
645 port - Port to write to
646 val - Value to write to port
649 Performs an emulated 8-bit write to an I/O port. We handle special cases
650 that we need to emulate in here, and fall through to reflecting the write
651 through to the real hardware if we don't need to special case it.
652 ****************************************************************************/
653 void X86API BE_outb(X86EMU_pioAddr port, u8 val)
655 #if defined(DEBUG) || !defined(__i386__)
656 if (IS_VGA_PORT(port))
657 VGA_outpb(port, val);
658 else if (IS_TIMER_PORT(port))
659 DB(printf("Can not interept TIMER port now!\n");)
660 else if (IS_SPKR_PORT(port))
661 DB(printf("Can not interept SPEAKER port now!\n");)
662 else if (IS_CMOS_PORT(port))
663 DB(printf("Can not interept CMOS port now!\n");)
664 else if (IS_PCI_PORT(port))
665 PCI_outp(port, val, REG_WRITE_BYTE);
666 else if (port < 0x100) {
667 DB(printf("WARN:Maybe INVALID outb.%04X <- %02X\n", (u16) port, val);)
668 LOG_outpb(port, val);
671 LOG_outpb(port, val);
674 /****************************************************************************
676 port - Port to write to
677 val - Value to write to port
680 Performs an emulated 16-bit write to an I/O port. We handle special cases
681 that we need to emulate in here, and fall through to reflecting the write
682 through to the real hardware if we don't need to special case it.
683 ****************************************************************************/
684 void X86API BE_outw(X86EMU_pioAddr port, u16 val)
686 #if defined(DEBUG) || !defined(__i386__)
687 if (IS_VGA_PORT(port)) {
688 VGA_outpb(port, val);
689 VGA_outpb(port + 1, val >> 8);
690 } else if (IS_PCI_PORT(port))
691 PCI_outp(port, val, REG_WRITE_WORD);
692 else if (port < 0x100) {
693 DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port,
695 LOG_outpw(port, val);
698 LOG_outpw(port, val);
701 /****************************************************************************
703 port - Port to write to
704 val - Value to write to port
707 Performs an emulated 32-bit write to an I/O port. We handle special cases
708 that we need to emulate in here, and fall through to reflecting the write
709 through to the real hardware if we don't need to special case it.
710 ****************************************************************************/
711 void X86API BE_outl(X86EMU_pioAddr port, u32 val)
713 #if defined(DEBUG) || !defined(__i386__)
714 if (IS_PCI_PORT(port))
715 PCI_outp(port, val, REG_WRITE_DWORD);
716 else if (port < 0x100) {
717 DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);)
718 LOG_outpd(port, val);
721 LOG_outpd(port, val);