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 ****************************************************************************/
52 #if defined(CONFIG_BIOSEMU)
56 /*------------------------- Global Variables ------------------------------*/
59 static char *BE_biosDate = "08/14/99";
60 static u8 BE_model = 0xFC;
61 static u8 BE_submodel = 0x00;
64 /*----------------------------- Implementation ----------------------------*/
66 /****************************************************************************
68 addr - Emulator memory address to convert
71 Actual memory address to read or write the data
74 This function converts an emulator memory address in a 32-bit range to
75 a real memory address that we wish to access. It handles splitting up the
76 memory address space appropriately to access the emulator BIOS image, video
77 memory and system BIOS etc.
78 ****************************************************************************/
79 static u8 *BE_memaddr(u32 addr)
81 if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
82 return (u8*)(_BE_env.biosmem_base + addr - 0xC0000);
83 } else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) {
84 DB(printf("BE_memaddr: address %#lx may be invalid!\n", addr);)
86 } else if (addr >= 0xA0000 && addr <= 0xBFFFF) {
87 return (u8*)(_BE_env.busmem_base + addr - 0xA0000);
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", addr);)
93 return _BE_env.busmem_base + addr - 0xA0000;
96 else if (addr >= 0xFFFF5 && addr < 0xFFFFE) {
97 /* Return a faked BIOS date string for non-x86 machines */
98 DB(printf("BE_memaddr - Returning BIOS date\n");)
99 return BE_biosDate + addr - 0xFFFF5;
100 } else if (addr == 0xFFFFE) {
101 /* Return system model identifier for non-x86 machines */
102 DB(printf("BE_memaddr - Returning model\n");)
104 } else if (addr == 0xFFFFF) {
105 /* Return system submodel identifier for non-x86 machines */
106 DB(printf("BE_memaddr - Returning submodel\n");)
110 else if (addr > M.mem_size - 1) {
115 return M.mem_base + addr;
118 /****************************************************************************
120 addr - Emulator memory address to read
123 Byte value read from emulator memory.
126 Reads a byte value from the emulator memory. We have three distinct memory
127 regions that are handled differently, which this function handles.
128 ****************************************************************************/
129 u8 X86API BE_rdb(u32 addr)
131 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
134 u8 val = readb_le(BE_memaddr(addr));
139 /****************************************************************************
141 addr - Emulator memory address to read
144 Word value read from emulator memory.
147 Reads a word value from the emulator memory. We have three distinct memory
148 regions that are handled differently, which this function handles.
149 ****************************************************************************/
150 u16 X86API BE_rdw(u32 addr)
152 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
155 u8 *base = BE_memaddr(addr);
156 u16 val = readw_le(base);
161 /****************************************************************************
163 addr - Emulator memory address to read
166 Long value read from emulator memory.
169 Reads a 32-bit value from the emulator memory. We have three distinct memory
170 regions that are handled differently, which this function handles.
171 ****************************************************************************/
172 u32 X86API BE_rdl(u32 addr)
174 if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
177 u8 *base = BE_memaddr(addr);
178 u32 val = readl_le(base);
183 /****************************************************************************
185 addr - Emulator memory address to read
189 Writes a byte value to emulator memory. We have three distinct memory
190 regions that are handled differently, which this function handles.
191 ****************************************************************************/
192 void X86API BE_wrb(u32 addr, u8 val)
194 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
195 writeb_le(BE_memaddr(addr), val);
199 /****************************************************************************
201 addr - Emulator memory address to read
205 Writes a word value to emulator memory. We have three distinct memory
206 regions that are handled differently, which this function handles.
207 ****************************************************************************/
208 void X86API BE_wrw(u32 addr, u16 val)
210 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
211 u8 *base = BE_memaddr(addr);
212 writew_le(base, val);
217 /****************************************************************************
219 addr - Emulator memory address to read
223 Writes a 32-bit value to emulator memory. We have three distinct memory
224 regions that are handled differently, which this function handles.
225 ****************************************************************************/
226 void X86API BE_wrl(u32 addr, u32 val)
228 if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
229 u8 *base = BE_memaddr(addr);
230 writel_le(base, val);
234 #if defined(DEBUG) || !defined(__i386__)
236 /* For Non-Intel machines we may need to emulate some I/O port accesses that
237 * the BIOS may try to access, such as the PCI config registers.
240 #define IS_TIMER_PORT(port) (0x40 <= port && port <= 0x43)
241 #define IS_CMOS_PORT(port) (0x70 <= port && port <= 0x71)
242 /*#define IS_VGA_PORT(port) (_BE_env.emulateVGA && 0x3C0 <= port && port <= 0x3DA)*/
243 #define IS_VGA_PORT(port) (0x3C0 <= port && port <= 0x3DA)
244 #define IS_PCI_PORT(port) (0xCF8 <= port && port <= 0xCFF)
245 #define IS_SPKR_PORT(port) (port == 0x61)
247 /****************************************************************************
249 port - Port to read from
250 type - Type of access to perform
253 Performs an emulated read from the Standard VGA I/O ports. If the target
254 hardware does not support mapping the VGA I/O and memory (such as some
255 PowerPC systems), we emulate the VGA so that the BIOS will still be able to
256 set NonVGA display modes such as on ATI hardware.
257 ****************************************************************************/
258 static u8 VGA_inpb (const int port)
264 /* 3C0 has funky characteristics because it can act as either
265 a data register or index register depending on the state
266 of an internal flip flop in the hardware. Hence we have
267 to emulate that functionality in here. */
268 if (_BE_env.flipFlop3C0 == 0) {
269 /* Access 3C0 as index register */
270 val = _BE_env.emu3C0;
272 /* Access 3C0 as data register */
273 if (_BE_env.emu3C0 < ATT_C)
274 val = _BE_env.emu3C1[_BE_env.emu3C0];
276 _BE_env.flipFlop3C0 ^= 1;
279 if (_BE_env.emu3C0 < ATT_C)
280 return _BE_env.emu3C1[_BE_env.emu3C0];
283 return _BE_env.emu3C2;
285 return _BE_env.emu3C4;
287 if (_BE_env.emu3C4 < ATT_C)
288 return _BE_env.emu3C5[_BE_env.emu3C4];
291 return _BE_env.emu3C6;
293 return _BE_env.emu3C7;
295 return _BE_env.emu3C8;
297 if (_BE_env.emu3C7 < PAL_C)
298 return _BE_env.emu3C9[_BE_env.emu3C7++];
301 return _BE_env.emu3CE;
303 if (_BE_env.emu3CE < GRA_C)
304 return _BE_env.emu3CF[_BE_env.emu3CE];
307 if (_BE_env.emu3C2 & 0x1)
308 return _BE_env.emu3D4;
311 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
312 return _BE_env.emu3D5[_BE_env.emu3D4];
315 _BE_env.flipFlop3C0 = 0;
316 val = _BE_env.emu3DA;
317 _BE_env.emu3DA ^= 0x9;
323 /****************************************************************************
325 port - Port to write to
326 type - Type of access to perform
329 Performs an emulated write to one of the 8253 timer registers. For now
330 we only emulate timer 0 which is the only timer that the BIOS code appears
332 ****************************************************************************/
333 static void VGA_outpb (int port, u8 val)
337 /* 3C0 has funky characteristics because it can act as either
338 a data register or index register depending on the state
339 of an internal flip flop in the hardware. Hence we have
340 to emulate that functionality in here. */
341 if (_BE_env.flipFlop3C0 == 0) {
342 /* Access 3C0 as index register */
343 _BE_env.emu3C0 = val;
345 /* Access 3C0 as data register */
346 if (_BE_env.emu3C0 < ATT_C)
347 _BE_env.emu3C1[_BE_env.emu3C0] = val;
349 _BE_env.flipFlop3C0 ^= 1;
352 _BE_env.emu3C2 = val;
355 _BE_env.emu3C4 = val;
358 if (_BE_env.emu3C4 < ATT_C)
359 _BE_env.emu3C5[_BE_env.emu3C4] = val;
362 _BE_env.emu3C6 = val;
365 _BE_env.emu3C7 = (int) val *3;
369 _BE_env.emu3C8 = (int) val *3;
373 if (_BE_env.emu3C8 < PAL_C)
374 _BE_env.emu3C9[_BE_env.emu3C8++] = val;
377 _BE_env.emu3CE = val;
380 if (_BE_env.emu3CE < GRA_C)
381 _BE_env.emu3CF[_BE_env.emu3CE] = val;
384 if (_BE_env.emu3C2 & 0x1)
385 _BE_env.emu3D4 = val;
388 if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
389 _BE_env.emu3D5[_BE_env.emu3D4] = val;
394 /****************************************************************************
396 regOffset - Offset into register space for non-DWORD accesses
397 value - Value to write to register for PCI_WRITE_* operations
398 func - Function to perform (PCIAccessRegFlags)
401 Value read from configuration register for PCI_READ_* operations
404 Accesses a PCI configuration space register by decoding the value currently
405 stored in the _BE_env.configAddress variable and passing it through to the
406 portable PCI_accessReg function.
407 ****************************************************************************/
408 static u32 BE_accessReg(int regOffset, u32 value, int func)
411 int function, device, bus;
417 /* Decode the configuration register values for the register we wish to
420 regOffset += (_BE_env.configAddress & 0xFF);
421 function = (_BE_env.configAddress >> 8) & 0x7;
422 device = (_BE_env.configAddress >> 11) & 0x1F;
423 bus = (_BE_env.configAddress >> 16) & 0xFF;
425 /* Ignore accesses to all devices other than the one we're POSTing */
426 if ((function == _BE_env.vgaInfo.function) &&
427 (device == _BE_env.vgaInfo.device) &&
428 (bus == _BE_env.vgaInfo.bus)) {
431 pci_read_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
435 pci_read_config_word(_BE_env.vgaInfo.pcidev, regOffset,
439 pci_read_config_dword(_BE_env.vgaInfo.pcidev, regOffset,
443 pci_write_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
448 pci_write_config_word(_BE_env.vgaInfo.pcidev, regOffset,
452 case REG_WRITE_DWORD:
453 pci_write_config_dword(_BE_env.vgaInfo.pcidev,
461 PCIDeviceInfo pciInfo;
465 pciInfo.slot.p.Function = (_BE_env.configAddress >> 8) & 0x7;
466 pciInfo.slot.p.Device = (_BE_env.configAddress >> 11) & 0x1F;
467 pciInfo.slot.p.Bus = (_BE_env.configAddress >> 16) & 0xFF;
468 pciInfo.slot.p.Enable = 1;
470 /* Ignore accesses to all devices other than the one we're POSTing */
471 if ((pciInfo.slot.p.Function ==
472 _BE_env.vgaInfo.pciInfo->slot.p.Function)
473 && (pciInfo.slot.p.Device == _BE_env.vgaInfo.pciInfo->slot.p.Device)
474 && (pciInfo.slot.p.Bus == _BE_env.vgaInfo.pciInfo->slot.p.Bus))
475 return PCI_accessReg((_BE_env.configAddress & 0xFF) + regOffset,
476 value, func, &pciInfo);
481 /****************************************************************************
483 port - Port to read from
484 type - Type of access to perform
487 Performs an emulated read from one of the PCI configuration space registers.
488 We emulate this using our PCI_accessReg function which will access the PCI
489 configuration space registers in a portable fashion.
490 ****************************************************************************/
491 static u32 PCI_inp(int port, int type)
495 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
497 return BE_accessReg(port - 0xCFC, 0, REG_READ_BYTE);
500 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
502 return BE_accessReg(port - 0xCFC, 0, REG_READ_WORD);
506 return _BE_env.configAddress;
507 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
508 return BE_accessReg(0, 0, REG_READ_DWORD);
514 /****************************************************************************
516 port - Port to write to
517 type - Type of access to perform
520 Performs an emulated write to one of the PCI control registers.
521 ****************************************************************************/
522 static void PCI_outp(int port, u32 val, int type)
526 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
528 BE_accessReg(port - 0xCFC, val, REG_WRITE_BYTE);
531 if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
533 BE_accessReg(port - 0xCFC, val, REG_WRITE_WORD);
535 case REG_WRITE_DWORD:
538 _BE_env.configAddress = val & 0x80FFFFFC;
540 else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
541 BE_accessReg(0, val, REG_WRITE_DWORD);
548 /****************************************************************************
550 port - Port to write to
553 Value read from the I/O port
556 Performs an emulated 8-bit read from an I/O port. We handle special cases
557 that we need to emulate in here, and fall through to reflecting the write
558 through to the real hardware if we don't need to special case it.
559 ****************************************************************************/
560 u8 X86API BE_inb(X86EMU_pioAddr port)
564 #if defined(DEBUG) || !defined(__i386__)
565 if (IS_VGA_PORT(port)){
566 /*seems reading port 0x3c3 return the high 16 bit of io port*/
568 val = LOG_inpb(port);
570 val = VGA_inpb(port);
572 else if (IS_TIMER_PORT(port))
573 DB(printf("Can not interept TIMER port now!\n");)
574 else if (IS_SPKR_PORT(port))
575 DB(printf("Can not interept SPEAKER port now!\n");)
576 else if (IS_CMOS_PORT(port))
577 DB(printf("Can not interept CMOS port now!\n");)
578 else if (IS_PCI_PORT(port))
579 val = PCI_inp(port, REG_READ_BYTE);
580 else if (port < 0x100) {
581 DB(printf("WARN: INVALID inb.%04X -> %02X\n", (u16) port, val);)
582 val = LOG_inpb(port);
585 val = LOG_inpb(port);
589 /****************************************************************************
591 port - Port to write to
594 Value read from the I/O port
597 Performs an emulated 16-bit read from an I/O port. We handle special cases
598 that we need to emulate in here, and fall through to reflecting the write
599 through to the real hardware if we don't need to special case it.
600 ****************************************************************************/
601 u16 X86API BE_inw(X86EMU_pioAddr port)
605 #if defined(DEBUG) || !defined(__i386__)
606 if (IS_PCI_PORT(port))
607 val = PCI_inp(port, REG_READ_WORD);
608 else if (port < 0x100) {
609 DB(printf("WARN: Maybe INVALID inw.%04X -> %04X\n", (u16) port, val);)
610 val = LOG_inpw(port);
613 val = LOG_inpw(port);
617 /****************************************************************************
619 port - Port to write to
622 Value read from the I/O port
625 Performs an emulated 32-bit read from an I/O port. We handle special cases
626 that we need to emulate in here, and fall through to reflecting the write
627 through to the real hardware if we don't need to special case it.
628 ****************************************************************************/
629 u32 X86API BE_inl(X86EMU_pioAddr port)
633 #if defined(DEBUG) || !defined(__i386__)
634 if (IS_PCI_PORT(port))
635 val = PCI_inp(port, REG_READ_DWORD);
636 else if (port < 0x100) {
637 val = LOG_inpd(port);
640 val = LOG_inpd(port);
644 /****************************************************************************
646 port - Port to write to
647 val - Value to write to port
650 Performs an emulated 8-bit write to an I/O port. We handle special cases
651 that we need to emulate in here, and fall through to reflecting the write
652 through to the real hardware if we don't need to special case it.
653 ****************************************************************************/
654 void X86API BE_outb(X86EMU_pioAddr port, u8 val)
656 #if defined(DEBUG) || !defined(__i386__)
657 if (IS_VGA_PORT(port))
658 VGA_outpb(port, val);
659 else if (IS_TIMER_PORT(port))
660 DB(printf("Can not interept TIMER port now!\n");)
661 else if (IS_SPKR_PORT(port))
662 DB(printf("Can not interept SPEAKER port now!\n");)
663 else if (IS_CMOS_PORT(port))
664 DB(printf("Can not interept CMOS port now!\n");)
665 else if (IS_PCI_PORT(port))
666 PCI_outp(port, val, REG_WRITE_BYTE);
667 else if (port < 0x100) {
668 DB(printf("WARN:Maybe INVALID outb.%04X <- %02X\n", (u16) port, val);)
669 LOG_outpb(port, val);
672 LOG_outpb(port, val);
675 /****************************************************************************
677 port - Port to write to
678 val - Value to write to port
681 Performs an emulated 16-bit write to an I/O port. We handle special cases
682 that we need to emulate in here, and fall through to reflecting the write
683 through to the real hardware if we don't need to special case it.
684 ****************************************************************************/
685 void X86API BE_outw(X86EMU_pioAddr port, u16 val)
687 #if defined(DEBUG) || !defined(__i386__)
688 if (IS_VGA_PORT(port)) {
689 VGA_outpb(port, val);
690 VGA_outpb(port + 1, val >> 8);
691 } else if (IS_PCI_PORT(port))
692 PCI_outp(port, val, REG_WRITE_WORD);
693 else if (port < 0x100) {
694 DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port,
696 LOG_outpw(port, val);
699 LOG_outpw(port, val);
702 /****************************************************************************
704 port - Port to write to
705 val - Value to write to port
708 Performs an emulated 32-bit write to an I/O port. We handle special cases
709 that we need to emulate in here, and fall through to reflecting the write
710 through to the real hardware if we don't need to special case it.
711 ****************************************************************************/
712 void X86API BE_outl(X86EMU_pioAddr port, u32 val)
714 #if defined(DEBUG) || !defined(__i386__)
715 if (IS_PCI_PORT(port))
716 PCI_outp(port, val, REG_WRITE_DWORD);
717 else if (port < 0x100) {
718 DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);)
719 LOG_outpd(port, val);
722 LOG_outpd(port, val);