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 /*----------------------------- 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",
85 return (u8 *)M.mem_base;
86 } else if (addr >= 0xA0000 && addr <= 0xBFFFF) {
87 return (u8*)(_BE_env.busmem_base + addr - 0xA0000);
89 #ifdef CONFIG_X86EMU_RAW_IO
90 else if (addr >= 0xD0000 && addr <= 0xFFFFF) {
91 /* We map the real System BIOS directly on real PC's */
92 DB(printf("BE_memaddr: System BIOS address %#lx\n",
94 return (u8 *)_BE_env.busmem_base + addr - 0xA0000;
97 else if (addr >= 0xFFFF5 && addr < 0xFFFFE) {
98 /* Return a faked BIOS date string for non-x86 machines */
99 DB(printf("BE_memaddr - Returning BIOS date\n");)
100 return (u8 *)(BE_biosDate + addr - 0xFFFF5);
101 } else if (addr == 0xFFFFE) {
102 /* Return system model identifier for non-x86 machines */
103 DB(printf("BE_memaddr - Returning model\n");)
105 } else if (addr == 0xFFFFF) {
106 /* Return system submodel identifier for non-x86 machines */
107 DB(printf("BE_memaddr - Returning submodel\n");)
111 else if (addr > M.mem_size - 1) {
113 return (u8 *)M.mem_base;
116 return (u8 *)(M.mem_base + addr);
119 /****************************************************************************
121 addr - Emulator memory address to read
124 Byte value read from emulator memory.
127 Reads a byte value from the emulator memory. We have three distinct memory
128 regions that are handled differently, which this function handles.
129 ****************************************************************************/
130 u8 X86API BE_rdb(u32 addr)
132 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
135 u8 val = readb_le(BE_memaddr(addr));
140 /****************************************************************************
142 addr - Emulator memory address to read
145 Word value read from emulator memory.
148 Reads a word value from the emulator memory. We have three distinct memory
149 regions that are handled differently, which this function handles.
150 ****************************************************************************/
151 u16 X86API BE_rdw(u32 addr)
153 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
156 u8 *base = BE_memaddr(addr);
157 u16 val = readw_le(base);
162 /****************************************************************************
164 addr - Emulator memory address to read
167 Long value read from emulator memory.
170 Reads a 32-bit value from the emulator memory. We have three distinct memory
171 regions that are handled differently, which this function handles.
172 ****************************************************************************/
173 u32 X86API BE_rdl(u32 addr)
175 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
178 u8 *base = BE_memaddr(addr);
179 u32 val = readl_le(base);
184 /****************************************************************************
186 addr - Emulator memory address to read
190 Writes a byte value to emulator memory. We have three distinct memory
191 regions that are handled differently, which this function handles.
192 ****************************************************************************/
193 void X86API BE_wrb(u32 addr, u8 val)
195 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
196 writeb_le(BE_memaddr(addr), val);
200 /****************************************************************************
202 addr - Emulator memory address to read
206 Writes a word value to emulator memory. We have three distinct memory
207 regions that are handled differently, which this function handles.
208 ****************************************************************************/
209 void X86API BE_wrw(u32 addr, u16 val)
211 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
212 u8 *base = BE_memaddr(addr);
213 writew_le(base, val);
218 /****************************************************************************
220 addr - Emulator memory address to read
224 Writes a 32-bit value to emulator memory. We have three distinct memory
225 regions that are handled differently, which this function handles.
226 ****************************************************************************/
227 void X86API BE_wrl(u32 addr, u32 val)
229 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
230 u8 *base = BE_memaddr(addr);
231 writel_le(base, val);
235 #if !defined(CONFIG_X86EMU_RAW_IO)
237 /* For Non-Intel machines we may need to emulate some I/O port accesses that
238 * the BIOS may try to access, such as the PCI config registers.
241 #define IS_TIMER_PORT(port) (0x40 <= port && port <= 0x43)
242 #define IS_CMOS_PORT(port) (0x70 <= port && port <= 0x71)
243 /*#define IS_VGA_PORT(port) (_BE_env.emulateVGA && 0x3C0 <= port && port <= 0x3DA)*/
244 #define IS_VGA_PORT(port) (0x3C0 <= port && port <= 0x3DA)
245 #define IS_PCI_PORT(port) (0xCF8 <= port && port <= 0xCFF)
246 #define IS_SPKR_PORT(port) (port == 0x61)
248 /****************************************************************************
250 port - Port to read from
251 type - Type of access to perform
254 Performs an emulated read from the Standard VGA I/O ports. If the target
255 hardware does not support mapping the VGA I/O and memory (such as some
256 PowerPC systems), we emulate the VGA so that the BIOS will still be able to
257 set NonVGA display modes such as on ATI hardware.
258 ****************************************************************************/
259 static u8 VGA_inpb (const int port)
265 /* 3C0 has funky characteristics because it can act as either
266 a data register or index register depending on the state
267 of an internal flip flop in the hardware. Hence we have
268 to emulate that functionality in here. */
269 if (_BE_env.flipFlop3C0 == 0) {
270 /* Access 3C0 as index register */
271 val = _BE_env.emu3C0;
273 /* Access 3C0 as data register */
274 if (_BE_env.emu3C0 < ATT_C)
275 val = _BE_env.emu3C1[_BE_env.emu3C0];
277 _BE_env.flipFlop3C0 ^= 1;
280 if (_BE_env.emu3C0 < ATT_C)
281 return _BE_env.emu3C1[_BE_env.emu3C0];
284 return _BE_env.emu3C2;
286 return _BE_env.emu3C4;
288 if (_BE_env.emu3C4 < ATT_C)
289 return _BE_env.emu3C5[_BE_env.emu3C4];
292 return _BE_env.emu3C6;
294 return _BE_env.emu3C7;
296 return _BE_env.emu3C8;
298 if (_BE_env.emu3C7 < PAL_C)
299 return _BE_env.emu3C9[_BE_env.emu3C7++];
302 return _BE_env.emu3CE;
304 if (_BE_env.emu3CE < GRA_C)
305 return _BE_env.emu3CF[_BE_env.emu3CE];
308 if (_BE_env.emu3C2 & 0x1)
309 return _BE_env.emu3D4;
312 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
313 return _BE_env.emu3D5[_BE_env.emu3D4];
316 _BE_env.flipFlop3C0 = 0;
317 val = _BE_env.emu3DA;
318 _BE_env.emu3DA ^= 0x9;
324 /****************************************************************************
326 port - Port to write to
327 type - Type of access to perform
330 Performs an emulated write to one of the 8253 timer registers. For now
331 we only emulate timer 0 which is the only timer that the BIOS code appears
333 ****************************************************************************/
334 static void VGA_outpb (int port, u8 val)
338 /* 3C0 has funky characteristics because it can act as either
339 a data register or index register depending on the state
340 of an internal flip flop in the hardware. Hence we have
341 to emulate that functionality in here. */
342 if (_BE_env.flipFlop3C0 == 0) {
343 /* Access 3C0 as index register */
344 _BE_env.emu3C0 = val;
346 /* Access 3C0 as data register */
347 if (_BE_env.emu3C0 < ATT_C)
348 _BE_env.emu3C1[_BE_env.emu3C0] = val;
350 _BE_env.flipFlop3C0 ^= 1;
353 _BE_env.emu3C2 = val;
356 _BE_env.emu3C4 = val;
359 if (_BE_env.emu3C4 < ATT_C)
360 _BE_env.emu3C5[_BE_env.emu3C4] = val;
363 _BE_env.emu3C6 = val;
366 _BE_env.emu3C7 = (int) val *3;
370 _BE_env.emu3C8 = (int) val *3;
374 if (_BE_env.emu3C8 < PAL_C)
375 _BE_env.emu3C9[_BE_env.emu3C8++] = val;
378 _BE_env.emu3CE = val;
381 if (_BE_env.emu3CE < GRA_C)
382 _BE_env.emu3CF[_BE_env.emu3CE] = val;
385 if (_BE_env.emu3C2 & 0x1)
386 _BE_env.emu3D4 = val;
389 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
390 _BE_env.emu3D5[_BE_env.emu3D4] = val;
395 /****************************************************************************
397 regOffset - Offset into register space for non-DWORD accesses
398 value - Value to write to register for PCI_WRITE_* operations
399 func - Function to perform (PCIAccessRegFlags)
402 Value read from configuration register for PCI_READ_* operations
405 Accesses a PCI configuration space register by decoding the value currently
406 stored in the _BE_env.configAddress variable and passing it through to the
407 portable PCI_accessReg function.
408 ****************************************************************************/
409 static u32 BE_accessReg(int regOffset, u32 value, int func)
412 int function, device, bus;
418 /* Decode the configuration register values for the register we wish to
421 regOffset += (_BE_env.configAddress & 0xFF);
422 function = (_BE_env.configAddress >> 8) & 0x7;
423 device = (_BE_env.configAddress >> 11) & 0x1F;
424 bus = (_BE_env.configAddress >> 16) & 0xFF;
426 /* Ignore accesses to all devices other than the one we're POSTing */
427 if ((function == _BE_env.vgaInfo.function) &&
428 (device == _BE_env.vgaInfo.device) &&
429 (bus == _BE_env.vgaInfo.bus)) {
432 pci_read_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
436 pci_read_config_word(_BE_env.vgaInfo.pcidev, regOffset,
440 pci_read_config_dword(_BE_env.vgaInfo.pcidev, regOffset,
444 pci_write_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
449 pci_write_config_word(_BE_env.vgaInfo.pcidev, regOffset,
453 case REG_WRITE_DWORD:
454 pci_write_config_dword(_BE_env.vgaInfo.pcidev,
462 PCIDeviceInfo pciInfo;
466 pciInfo.slot.p.Function = (_BE_env.configAddress >> 8) & 0x7;
467 pciInfo.slot.p.Device = (_BE_env.configAddress >> 11) & 0x1F;
468 pciInfo.slot.p.Bus = (_BE_env.configAddress >> 16) & 0xFF;
469 pciInfo.slot.p.Enable = 1;
471 /* Ignore accesses to all devices other than the one we're POSTing */
472 if ((pciInfo.slot.p.Function ==
473 _BE_env.vgaInfo.pciInfo->slot.p.Function)
474 && (pciInfo.slot.p.Device == _BE_env.vgaInfo.pciInfo->slot.p.Device)
475 && (pciInfo.slot.p.Bus == _BE_env.vgaInfo.pciInfo->slot.p.Bus))
476 return PCI_accessReg((_BE_env.configAddress & 0xFF) + regOffset,
477 value, func, &pciInfo);
482 /****************************************************************************
484 port - Port to read from
485 type - Type of access to perform
488 Performs an emulated read from one of the PCI configuration space registers.
489 We emulate this using our PCI_accessReg function which will access the PCI
490 configuration space registers in a portable fashion.
491 ****************************************************************************/
492 static u32 PCI_inp(int port, int type)
496 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
498 return BE_accessReg(port - 0xCFC, 0, REG_READ_BYTE);
501 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
503 return BE_accessReg(port - 0xCFC, 0, REG_READ_WORD);
507 return _BE_env.configAddress;
508 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
509 return BE_accessReg(0, 0, REG_READ_DWORD);
515 /****************************************************************************
517 port - Port to write to
518 type - Type of access to perform
521 Performs an emulated write to one of the PCI control registers.
522 ****************************************************************************/
523 static void PCI_outp(int port, u32 val, int type)
527 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
529 BE_accessReg(port - 0xCFC, val, REG_WRITE_BYTE);
532 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
534 BE_accessReg(port - 0xCFC, val, REG_WRITE_WORD);
536 case REG_WRITE_DWORD:
539 _BE_env.configAddress = val & 0x80FFFFFC;
541 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
542 BE_accessReg(0, val, REG_WRITE_DWORD);
549 /****************************************************************************
551 port - Port to write to
554 Value read from the I/O port
557 Performs an emulated 8-bit read from an I/O port. We handle special cases
558 that we need to emulate in here, and fall through to reflecting the write
559 through to the real hardware if we don't need to special case it.
560 ****************************************************************************/
561 u8 X86API BE_inb(X86EMU_pioAddr port)
565 #if !defined(CONFIG_X86EMU_RAW_IO)
566 if (IS_VGA_PORT(port)){
567 /*seems reading port 0x3c3 return the high 16 bit of io port*/
569 val = LOG_inpb(port);
571 val = VGA_inpb(port);
573 else if (IS_TIMER_PORT(port))
574 DB(printf("Can not interept TIMER port now!\n");)
575 else if (IS_SPKR_PORT(port))
576 DB(printf("Can not interept SPEAKER port now!\n");)
577 else if (IS_CMOS_PORT(port))
578 DB(printf("Can not interept CMOS port now!\n");)
579 else if (IS_PCI_PORT(port))
580 val = PCI_inp(port, REG_READ_BYTE);
581 else if (port < 0x100) {
582 DB(printf("WARN: INVALID inb.%04X -> %02X\n", (u16) port, val);)
583 val = LOG_inpb(port);
586 val = LOG_inpb(port);
590 /****************************************************************************
592 port - Port to write to
595 Value read from the I/O port
598 Performs an emulated 16-bit read from an I/O port. We handle special cases
599 that we need to emulate in here, and fall through to reflecting the write
600 through to the real hardware if we don't need to special case it.
601 ****************************************************************************/
602 u16 X86API BE_inw(X86EMU_pioAddr port)
606 #if !defined(CONFIG_X86EMU_RAW_IO)
607 if (IS_PCI_PORT(port))
608 val = PCI_inp(port, REG_READ_WORD);
609 else if (port < 0x100) {
610 DB(printf("WARN: Maybe INVALID inw.%04X -> %04X\n", (u16) port, val);)
611 val = LOG_inpw(port);
614 val = LOG_inpw(port);
618 /****************************************************************************
620 port - Port to write to
623 Value read from the I/O port
626 Performs an emulated 32-bit read from an I/O port. We handle special cases
627 that we need to emulate in here, and fall through to reflecting the write
628 through to the real hardware if we don't need to special case it.
629 ****************************************************************************/
630 u32 X86API BE_inl(X86EMU_pioAddr port)
634 #if !defined(CONFIG_X86EMU_RAW_IO)
635 if (IS_PCI_PORT(port))
636 val = PCI_inp(port, REG_READ_DWORD);
637 else if (port < 0x100) {
638 val = LOG_inpd(port);
641 val = LOG_inpd(port);
645 /****************************************************************************
647 port - Port to write to
648 val - Value to write to port
651 Performs an emulated 8-bit write to an I/O port. We handle special cases
652 that we need to emulate in here, and fall through to reflecting the write
653 through to the real hardware if we don't need to special case it.
654 ****************************************************************************/
655 void X86API BE_outb(X86EMU_pioAddr port, u8 val)
657 #if !defined(CONFIG_X86EMU_RAW_IO)
658 if (IS_VGA_PORT(port))
659 VGA_outpb(port, val);
660 else if (IS_TIMER_PORT(port))
661 DB(printf("Can not interept TIMER port now!\n");)
662 else if (IS_SPKR_PORT(port))
663 DB(printf("Can not interept SPEAKER port now!\n");)
664 else if (IS_CMOS_PORT(port))
665 DB(printf("Can not interept CMOS port now!\n");)
666 else if (IS_PCI_PORT(port))
667 PCI_outp(port, val, REG_WRITE_BYTE);
668 else if (port < 0x100) {
669 DB(printf("WARN:Maybe INVALID outb.%04X <- %02X\n", (u16) port, val);)
670 LOG_outpb(port, val);
673 LOG_outpb(port, val);
676 /****************************************************************************
678 port - Port to write to
679 val - Value to write to port
682 Performs an emulated 16-bit write to an I/O port. We handle special cases
683 that we need to emulate in here, and fall through to reflecting the write
684 through to the real hardware if we don't need to special case it.
685 ****************************************************************************/
686 void X86API BE_outw(X86EMU_pioAddr port, u16 val)
688 #if !defined(CONFIG_X86EMU_RAW_IO)
689 if (IS_VGA_PORT(port)) {
690 VGA_outpb(port, val);
691 VGA_outpb(port + 1, val >> 8);
692 } else if (IS_PCI_PORT(port))
693 PCI_outp(port, val, REG_WRITE_WORD);
694 else if (port < 0x100) {
695 DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port,
697 LOG_outpw(port, val);
700 LOG_outpw(port, val);
703 /****************************************************************************
705 port - Port to write to
706 val - Value to write to port
709 Performs an emulated 32-bit write to an I/O port. We handle special cases
710 that we need to emulate in here, and fall through to reflecting the write
711 through to the real hardware if we don't need to special case it.
712 ****************************************************************************/
713 void X86API BE_outl(X86EMU_pioAddr port, u32 val)
715 #if !defined(CONFIG_X86EMU_RAW_IO)
716 if (IS_PCI_PORT(port)) {
717 PCI_outp(port, val, REG_WRITE_DWORD);
718 } else if (port < 0x100) {
719 DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);)
720 LOG_outpd(port, val);
723 LOG_outpd(port, val);