uboot/drivers/bios_emulator/biosemu.c
<<
>>
Prefs
   1/****************************************************************************
   2*
   3*                        BIOS emulator and interface
   4*                      to Realmode X86 Emulator Library
   5*
   6*  Copyright (C) 2007 Freescale Semiconductor, Inc.
   7*  Jason Jin <Jason.jin@freescale.com>
   8*
   9*               Copyright (C) 1996-1999 SciTech Software, Inc.
  10*
  11*  ========================================================================
  12*
  13*  Permission to use, copy, modify, distribute, and sell this software and
  14*  its documentation for any purpose is hereby granted without fee,
  15*  provided that the above copyright notice appear in all copies and that
  16*  both that copyright notice and this permission notice appear in
  17*  supporting documentation, and that the name of the authors not be used
  18*  in advertising or publicity pertaining to distribution of the software
  19*  without specific, written prior permission.  The authors makes no
  20*  representations about the suitability of this software for any purpose.
  21*  It is provided "as is" without express or implied warranty.
  22*
  23*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  24*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  25*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  26*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  27*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  28*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  29*  PERFORMANCE OF THIS SOFTWARE.
  30*
  31*  ========================================================================
  32*
  33* Language:     ANSI C
  34* Environment:  Any
  35* Developer:    Kendall Bennett
  36*
  37* Description:  Module implementing the system specific functions. This
  38*               module is always compiled and linked in the OS depedent
  39*               libraries, and never in a binary portable driver.
  40*
  41*               Jason ported this file to u-boot to run the ATI video card BIOS
  42*               in u-boot. Made all the video memory be emulated during the
  43*               BIOS runing process which may affect the VGA function but the
  44*               frambuffer function can work after run the BIOS.
  45*
  46****************************************************************************/
  47
  48#include <malloc.h>
  49#include <common.h>
  50#include "biosemui.h"
  51
  52BE_sysEnv _BE_env = {{0}};
  53static X86EMU_memFuncs _BE_mem __section(GOT2_TYPE) = {
  54        BE_rdb,
  55        BE_rdw,
  56        BE_rdl,
  57        BE_wrb,
  58        BE_wrw,
  59        BE_wrl,
  60        };
  61
  62static X86EMU_pioFuncs _BE_pio __section(GOT2_TYPE) = {
  63        BE_inb,
  64        BE_inw,
  65        BE_inl,
  66        BE_outb,
  67        BE_outw,
  68        BE_outl,
  69        };
  70
  71#define OFF(addr)       (u16)(((addr) >> 0) & 0xffff)
  72#define SEG(addr)       (u16)(((addr) >> 4) & 0xf000)
  73
  74/****************************************************************************
  75PARAMETERS:
  76debugFlags  - Flags to enable debugging options (debug builds only)
  77memSize     - Amount of memory to allocate for real mode machine
  78info        - Pointer to default VGA device information
  79
  80REMARKS:
  81This functions initialises the BElib, and uses the passed in
  82BIOS image as the BIOS that is used and emulated at 0xC0000.
  83****************************************************************************/
  84int X86API BE_init(u32 debugFlags, int memSize, BE_VGAInfo * info, int shared)
  85{
  86#if !defined(__DRIVER__)  && !defined(__KERNEL__)
  87
  88        PM_init();
  89#endif
  90        memset(&M, 0, sizeof(M));
  91        if (memSize < 20480){
  92                printf("Emulator requires at least 20Kb of memory!\n");
  93                return 0;
  94        }
  95
  96        M.mem_base = malloc(memSize);
  97
  98        if (M.mem_base == NULL){
  99                printf("Biosemu:Out of memory!");
 100                return 0;
 101        }
 102        M.mem_size = memSize;
 103
 104        _BE_env.emulateVGA = 0;
 105        _BE_env.busmem_base = (unsigned long)malloc(128 * 1024);
 106        if ((void *)_BE_env.busmem_base == NULL){
 107                printf("Biosemu:Out of memory!");
 108                return 0;
 109        }
 110        M.x86.debug = debugFlags;
 111        _BE_bios_init((u32*)info->LowMem);
 112        X86EMU_setupMemFuncs(&_BE_mem);
 113        X86EMU_setupPioFuncs(&_BE_pio);
 114        BE_setVGA(info);
 115        return 1;
 116}
 117
 118/****************************************************************************
 119PARAMETERS:
 120info        - Pointer to VGA device information to make current
 121
 122REMARKS:
 123This function sets the VGA BIOS functions in the emulator to point to the
 124specific VGA BIOS in use. This includes swapping the BIOS interrupt
 125vectors, BIOS image and BIOS data area to the new BIOS. This allows the
 126real mode BIOS to be swapped without resetting the entire emulator.
 127****************************************************************************/
 128void X86API BE_setVGA(BE_VGAInfo * info)
 129{
 130
 131#ifdef __KERNEL__
 132        _BE_env.vgaInfo.function = info->function;
 133        _BE_env.vgaInfo.device = info->device;
 134        _BE_env.vgaInfo.bus = info->bus;
 135        _BE_env.vgaInfo.pcidev = info->pcidev;
 136#else
 137        _BE_env.vgaInfo.pciInfo = info->pciInfo;
 138#endif
 139        _BE_env.vgaInfo.BIOSImage = info->BIOSImage;
 140        if (info->BIOSImage) {
 141                _BE_env.biosmem_base = (ulong) info->BIOSImage;
 142                _BE_env.biosmem_limit = 0xC0000 + info->BIOSImageLen - 1;
 143        } else {
 144                _BE_env.biosmem_base = _BE_env.busmem_base + 0x20000;
 145                _BE_env.biosmem_limit = 0xC7FFF;
 146        }
 147        if ((info->LowMem[0] == 0) && (info->LowMem[1] == 0) &&
 148            (info->LowMem[2] == 0) && (info->LowMem[3] == 0))
 149                _BE_bios_init((u32 *) info->LowMem);
 150        memcpy((u8 *) M.mem_base, info->LowMem, sizeof(info->LowMem));
 151}
 152
 153/****************************************************************************
 154PARAMETERS:
 155info        - Pointer to VGA device information to retrieve current
 156
 157REMARKS:
 158This function returns the VGA BIOS functions currently active in the
 159emulator, so they can be restored at a later date.
 160****************************************************************************/
 161void X86API BE_getVGA(BE_VGAInfo * info)
 162{
 163#ifdef __KERNEL__
 164        info->function = _BE_env.vgaInfo.function;
 165        info->device = _BE_env.vgaInfo.device;
 166        info->bus = _BE_env.vgaInfo.bus;
 167        info->pcidev = _BE_env.vgaInfo.pcidev;
 168#else
 169        info->pciInfo = _BE_env.vgaInfo.pciInfo;
 170#endif
 171        info->BIOSImage = _BE_env.vgaInfo.BIOSImage;
 172        memcpy(info->LowMem, (u8 *) M.mem_base, sizeof(info->LowMem));
 173}
 174
 175/****************************************************************************
 176PARAMETERS:
 177r_seg   - Segment for pointer to convert
 178r_off   - Offset for pointer to convert
 179
 180REMARKS:
 181This function maps a real mode pointer in the emulator memory to a protected
 182mode pointer that can be used to directly access the memory.
 183
 184NOTE:   The memory is *always* in little endian format, son on non-x86
 185        systems you will need to do endian translations to access this
 186        memory.
 187****************************************************************************/
 188void *X86API BE_mapRealPointer(uint r_seg, uint r_off)
 189{
 190        u32 addr = ((u32) r_seg << 4) + r_off;
 191
 192        if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
 193                return (void *)(_BE_env.biosmem_base + addr - 0xC0000);
 194        } else if (addr >= 0xA0000 && addr <= 0xFFFFF) {
 195                return (void *)(_BE_env.busmem_base + addr - 0xA0000);
 196        }
 197        return (void *)(M.mem_base + addr);
 198}
 199
 200/****************************************************************************
 201PARAMETERS:
 202len     - Return the length of the VESA buffer
 203rseg    - Place to store VESA buffer segment
 204roff    - Place to store VESA buffer offset
 205
 206REMARKS:
 207This function returns the address of the VESA transfer buffer in real
 208_BE_piomode emulator memory. The VESA transfer buffer is always 1024 bytes long,
 209and located at 15Kb into the start of the real mode memory (16Kb is where
 210we put the real mode code we execute for issuing interrupts).
 211
 212NOTE:   The memory is *always* in little endian format, son on non-x86
 213        systems you will need to do endian translations to access this
 214        memory.
 215****************************************************************************/
 216void *X86API BE_getVESABuf(uint * len, uint * rseg, uint * roff)
 217{
 218        *len = 1024;
 219        *rseg = SEG(0x03C00);
 220        *roff = OFF(0x03C00);
 221        return (void *)(M.mem_base + ((u32) * rseg << 4) + *roff);
 222}
 223
 224/****************************************************************************
 225REMARKS:
 226Cleans up and exits the emulator.
 227****************************************************************************/
 228void X86API BE_exit(void)
 229{
 230        free(M.mem_base);
 231        free((void *)_BE_env.busmem_base);
 232}
 233
 234/****************************************************************************
 235PARAMETERS:
 236seg     - Segment of code to call
 237off     - Offset of code to call
 238regs    - Real mode registers to load
 239sregs   - Real mode segment registers to load
 240
 241REMARKS:
 242This functions calls a real mode far function at the specified address,
 243and loads all the x86 registers from the passed in registers structure.
 244On exit the registers returned from the call are returned in the same
 245structures.
 246****************************************************************************/
 247void X86API BE_callRealMode(uint seg, uint off, RMREGS * regs, RMSREGS * sregs)
 248{
 249        M.x86.R_EAX = regs->e.eax;
 250        M.x86.R_EBX = regs->e.ebx;
 251        M.x86.R_ECX = regs->e.ecx;
 252        M.x86.R_EDX = regs->e.edx;
 253        M.x86.R_ESI = regs->e.esi;
 254        M.x86.R_EDI = regs->e.edi;
 255        M.x86.R_DS = sregs->ds;
 256        M.x86.R_ES = sregs->es;
 257        M.x86.R_FS = sregs->fs;
 258        M.x86.R_GS = sregs->gs;
 259
 260        ((u8 *) M.mem_base)[0x4000] = 0x9A;
 261        ((u8 *) M.mem_base)[0x4001] = (u8) off;
 262        ((u8 *) M.mem_base)[0x4002] = (u8) (off >> 8);
 263        ((u8 *) M.mem_base)[0x4003] = (u8) seg;
 264        ((u8 *) M.mem_base)[0x4004] = (u8) (seg >> 8);
 265        ((u8 *) M.mem_base)[0x4005] = 0xF1;     /* Illegal op-code */
 266        M.x86.R_CS = SEG(0x04000);
 267        M.x86.R_IP = OFF(0x04000);
 268
 269        M.x86.R_SS = SEG(M.mem_size - 2);
 270        M.x86.R_SP = OFF(M.mem_size - 2) + 2;
 271
 272        X86EMU_exec();
 273
 274        regs->e.cflag = M.x86.R_EFLG & F_CF;
 275        regs->e.eax = M.x86.R_EAX;
 276        regs->e.ebx = M.x86.R_EBX;
 277        regs->e.ecx = M.x86.R_ECX;
 278        regs->e.edx = M.x86.R_EDX;
 279        regs->e.esi = M.x86.R_ESI;
 280        regs->e.edi = M.x86.R_EDI;
 281        sregs->ds = M.x86.R_DS;
 282        sregs->es = M.x86.R_ES;
 283        sregs->fs = M.x86.R_FS;
 284        sregs->gs = M.x86.R_GS;
 285}
 286
 287/****************************************************************************
 288PARAMETERS:
 289intno   - Interrupt number to execute
 290in      - Real mode registers to load
 291out     - Place to store resulting real mode registers
 292
 293REMARKS:
 294This functions calls a real mode interrupt function at the specified address,
 295and loads all the x86 registers from the passed in registers structure.
 296On exit the registers returned from the call are returned in out stucture.
 297****************************************************************************/
 298int X86API BE_int86(int intno, RMREGS * in, RMREGS * out)
 299{
 300        M.x86.R_EAX = in->e.eax;
 301        M.x86.R_EBX = in->e.ebx;
 302        M.x86.R_ECX = in->e.ecx;
 303        M.x86.R_EDX = in->e.edx;
 304        M.x86.R_ESI = in->e.esi;
 305        M.x86.R_EDI = in->e.edi;
 306        ((u8 *) M.mem_base)[0x4000] = 0xCD;
 307        ((u8 *) M.mem_base)[0x4001] = (u8) intno;
 308        ((u8 *) M.mem_base)[0x4002] = 0xF1;
 309        M.x86.R_CS = SEG(0x04000);
 310        M.x86.R_IP = OFF(0x04000);
 311
 312        M.x86.R_SS = SEG(M.mem_size - 1);
 313        M.x86.R_SP = OFF(M.mem_size - 1) - 1;
 314
 315        X86EMU_exec();
 316        out->e.cflag = M.x86.R_EFLG & F_CF;
 317        out->e.eax = M.x86.R_EAX;
 318        out->e.ebx = M.x86.R_EBX;
 319        out->e.ecx = M.x86.R_ECX;
 320        out->e.edx = M.x86.R_EDX;
 321        out->e.esi = M.x86.R_ESI;
 322        out->e.edi = M.x86.R_EDI;
 323        return out->x.ax;
 324}
 325
 326/****************************************************************************
 327PARAMETERS:
 328intno   - Interrupt number to execute
 329in      - Real mode registers to load
 330out     - Place to store resulting real mode registers
 331sregs   - Real mode segment registers to load
 332
 333REMARKS:
 334This functions calls a real mode interrupt function at the specified address,
 335and loads all the x86 registers from the passed in registers structure.
 336On exit the registers returned from the call are returned in out stucture.
 337****************************************************************************/
 338int X86API BE_int86x(int intno, RMREGS * in, RMREGS * out, RMSREGS * sregs)
 339{
 340        M.x86.R_EAX = in->e.eax;
 341        M.x86.R_EBX = in->e.ebx;
 342        M.x86.R_ECX = in->e.ecx;
 343        M.x86.R_EDX = in->e.edx;
 344        M.x86.R_ESI = in->e.esi;
 345        M.x86.R_EDI = in->e.edi;
 346        M.x86.R_DS = sregs->ds;
 347        M.x86.R_ES = sregs->es;
 348        M.x86.R_FS = sregs->fs;
 349        M.x86.R_GS = sregs->gs;
 350        ((u8 *) M.mem_base)[0x4000] = 0xCD;
 351        ((u8 *) M.mem_base)[0x4001] = (u8) intno;
 352        ((u8 *) M.mem_base)[0x4002] = 0xF1;
 353        M.x86.R_CS = SEG(0x04000);
 354        M.x86.R_IP = OFF(0x04000);
 355
 356        M.x86.R_SS = SEG(M.mem_size - 1);
 357        M.x86.R_SP = OFF(M.mem_size - 1) - 1;
 358
 359        X86EMU_exec();
 360        out->e.cflag = M.x86.R_EFLG & F_CF;
 361        out->e.eax = M.x86.R_EAX;
 362        out->e.ebx = M.x86.R_EBX;
 363        out->e.ecx = M.x86.R_ECX;
 364        out->e.edx = M.x86.R_EDX;
 365        out->e.esi = M.x86.R_ESI;
 366        out->e.edi = M.x86.R_EDI;
 367        sregs->ds = M.x86.R_DS;
 368        sregs->es = M.x86.R_ES;
 369        sregs->fs = M.x86.R_FS;
 370        sregs->gs = M.x86.R_GS;
 371        return out->x.ax;
 372}
 373