blob: 65ab8c44c6d0285a0fba7009d60f2cc7d725f17b [file] [log] [blame]
/*
* Mostly done after the Scitech Bios emulation
* Written by Hans-Jörg Frieden
* Hyperion Entertainment
*/
#include <common.h>
#include "scitech/include/x86emu/x86emu.h"
#include "glue.h"
#include "scitech/include/x86emu/regs.h"
#include "x86interface.h"
#undef DEBUG
#ifdef DEBUG
#define PRINTF(fmt, args...) printf(fmt, ## args)
#else
#define PRINTF(fmt, args...)
#endif
#define BIOS_SEG 0xFFF0
#define PCIBIOS_SUCCESSFUL 0
#define PCIBIOS_DEVICE_NOT_FOUND 0x86
typedef unsigned char UBYTE;
typedef unsigned short UWORD;
typedef unsigned long ULONG;
typedef char BYTE;
typedef short WORT;
typedef long LONG;
//#define port_to_mem(from) (CFG_ISA_IO_BASE_ADDRESS|(from))
/*
#define in_byte(from) in8( (UBYTE *)port_to_mem(from))
#define in_word(from) in16r((UWORD *)port_to_mem(from))
#define in_long(from) in32r(ULONG *)port_to_mem(from))
#define out_byte(to, val) out8((UBYTE *)port_to_mem(to), val)
#define out_word(to, val) out16r((UWORD *)port_to_mem(to), val)
#define out_long(to, val) out32r((ULONG *)port_to_mem(to), val)
*/
#define out_byte(to, val) out8((UBYTE *)port_to_mem(to), val)
static void X86API undefined_intr(int intno)
{
PRINTF("X86API undefined_intr\n");
extern u16 A1_rdw(u32 addr);
if (A1_rdw(intno * 4 + 2) == BIOS_SEG)
{
PRINTF("Undefined interrupt 0x%x called AX = 0x%x, BX = 0x%x, CX = 0x%x, DX = 0x%x\n",
intno, M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
X86EMU_halt_sys();
}
else
{
PRINTF("Calling interrupt %xh, AL=%xh, AH=%xh\n", intno, M.x86.R_AL, M.x86.R_AH);
X86EMU_prepareForInt(intno);
}
}
static void X86API int42(int intno);
static void X86API int15(int intno);
static void X86API int10(int intno)
{
PRINTF("X86API int10\n");
if (A1_rdw(intno*4+2) == BIOS_SEG)
int42(intno);
else
{
PRINTF("int10: branching to %04X:%04X, AL=%xh, AH=%xh\n", A1_rdw(intno*4+2), A1_rdw(intno*4),
M.x86.R_AL, M.x86.R_AH);
X86EMU_prepareForInt(intno);
}
}
static void X86API int1A(int intno)
{
PRINTF("X86API int1A\n");
int device;
switch(M.x86.R_AX)
{
case 0xB101: // PCI Bios Present?
M.x86.R_AL = 0x00;
M.x86.R_EDX = 0x20494350;
M.x86.R_BX = 0x0210;
M.x86.R_CL = 3;
CLEAR_FLAG(F_CF);
break;
case 0xB102: // Find device
device = mypci_find_device(M.x86.R_DX, M.x86.R_CX, M.x86.R_SI);
if (device != -1)
{
M.x86.R_AH = PCIBIOS_SUCCESSFUL;
M.x86.R_BH = mypci_bus(device);
M.x86.R_BL = mypci_devfn(device);
}
else
{
M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND;
}
CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
break;
case 0xB103: // Find PCI class code
M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND;
printf("Find by class not yet implmented");
CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
break;
case 0xB108: // read config byte
M.x86.R_CL = mypci_read_cfg_byte(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
M.x86.R_AH = PCIBIOS_SUCCESSFUL;
CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
PRINTF("read_config_byte %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CL);
break;
case 0xB109: // read config word
M.x86.R_CX = mypci_read_cfg_word(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
M.x86.R_AH = PCIBIOS_SUCCESSFUL;
CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
PRINTF("read_config_word %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CX);
break;
case 0xB10A: // read config dword
M.x86.R_ECX = mypci_read_cfg_long(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
M.x86.R_AH = PCIBIOS_SUCCESSFUL;
CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
PRINTF("read_config_long %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_ECX);
break;
case 0xB10B: // write config byte
mypci_write_cfg_byte(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CL);
M.x86.R_AH = PCIBIOS_SUCCESSFUL;
CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
PRINTF("write_config_byte %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CL);
break;
case 0xB10C: // write config word
mypci_write_cfg_word(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CX);
M.x86.R_AH = PCIBIOS_SUCCESSFUL;
CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
PRINTF("write_config_word %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CX);
break;
case 0xB10D: // write config dword
mypci_write_cfg_long(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_ECX);
M.x86.R_AH = PCIBIOS_SUCCESSFUL;
CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
PRINTF("write_config_long %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_ECX);
break;
default:
PRINTF("BIOS int %xh: Unknown function AX=%04xh\n", intno, M.x86.R_AX);
}
}
void bios_init(void)
{
int i;
X86EMU_intrFuncs bios_intr_tab[256];
PRINTF("Interrupt table\n");
for (i=0; i<256; i++)
{
out32r((volatile ULONG *)(M.mem_base+i*4), BIOS_SEG<<16);
bios_intr_tab[i] = undefined_intr;
}
bios_intr_tab[0x10] = int10;
bios_intr_tab[0x1A] = int1A;
bios_intr_tab[0x42] = int42;
bios_intr_tab[0x15] = int15;
bios_intr_tab[0x6D] = int42;
X86EMU_setupIntrFuncs(bios_intr_tab);
// why here? Because it is needed.
//PRINTF("video_init\n");
//video_init();
}
unsigned char setup_40x25[] =
{
0x38, 0x28, 0x2d, 0x0a, 0x1f, 6, 0x19,
0x1c, 2, 7, 6, 7, 0, 0, 0, 0
};
unsigned char setup_80x25[] =
{
0x71, 0x50, 0x5a, 0x0a, 0x1f, 6, 0x19,
0x1c, 2, 7, 6, 7, 0, 0, 0, 0
};
unsigned char setup_graphics[] =
{
0x38, 0x28, 0x20, 0x0a, 0x7f, 6, 0x64,
0x70, 2, 1, 6, 7, 0, 0, 0, 0
};
unsigned char setup_bw[] =
{
0x61, 0x50, 0x52, 0x0f, 0x19, 6, 0x19,
0x19, 2, 0x0d, 0x0b, 0x0c, 0, 0, 0, 0
};
unsigned char * setup_modes[] =
{
setup_40x25, // mode 0: 40x25 bw text
setup_40x25, // mode 1: 40x25 col text
setup_80x25, // mode 2: 80x25 bw text
setup_80x25, // mode 3: 80x25 col text
setup_graphics, // mode 4: 320x200 col graphics
setup_graphics, // mode 5: 320x200 bw graphics
setup_graphics, // mode 6: 640x200 bw graphics
setup_bw // mode 7: 80x25 mono text
};
unsigned int setup_cols[] =
{
40, 40, 80, 80, 40, 40, 80, 80
};
unsigned char setup_modesets[] =
{
0x2C, 0x28, 0x2D, 0x29, 0x2A, 0x2E, 0x1E, 0x29
};
unsigned int setup_bufsize[] =
{
2048, 2048, 4096, 2096, 16384, 16384, 16384, 4096
};
int reloc_mode_done = 0;
void reloc_mode_table(void *reloc_addr)
{
unsigned long delta;
int i;
if (reloc_mode_done)
return;
reloc_mode_done = 1;
PRINTF("reloc_addr = %p\n", reloc_addr);
delta = TEXT_BASE - (unsigned long)reloc_addr;
PRINTF("delta = %p\n", delta);
for (i = 0; i < sizeof(setup_modes)/sizeof(unsigned char *); i++)
setup_modes[i] = (unsigned char *) ((unsigned long)setup_modes[i] - delta);
}
void bios_set_mode(int mode)
{
int i;
unsigned char mode_set = setup_modesets[mode]; // Control register value
unsigned char *setup_regs = setup_modes[mode]; // Register 3D4 Array
flush_cache(0, 32768);
PRINTF("bios_set_mode: mode = %d, setup_regs = %p\n", mode, setup_regs);
// Switch video off
out_byte(0x3D8, mode_set & 0x37);
// Set up parameters at 3D4h
for (i=0; i<16; i++)
{
out_byte(0x3D4, (unsigned char)i);
out_byte(0x3D5, *setup_regs);
setup_regs++;
}
// Enable video
out_byte(0x3D8, mode_set);
// Set overscan
if (mode == 6) out_byte(0x3D9, 0x3F);
else out_byte(0x3D9, 0x30);
PRINTF("bios_set_mode: done\n");
}
/*
static void bios_print_string(void)
{
extern void video_bios_print_string(char *string, int x, int y, int attr, int count);
//char *s = (char *)(M.x86.R_ES<<4) + M.x86.R_BP;
int attr;
if (M.x86.R_AL & 0x02) attr = - 1;
else attr = M.x86.R_BL;
//video_bios_print_string(s, M.x86.R_DH, M.x86.R_DL, attr, M.x86.R_CX);
}
*/
static void X86API int42(int intno)
{
PRINTF("int42: AH = 0x%x, AL = 0x%x, AX = 0x%x, BX = 0x%x\n",
M.x86.R_AH, M.x86.R_AL, M.x86.R_AX, M.x86.R_BX);
switch (M.x86.R_AH)
{
case 0x00:
bios_set_mode(M.x86.R_AL);
break;
case 0x13:
//bios_print_string();
break;
default:
PRINTF("Warning: VIDEO BIOS interrupt %xh unimplemented function %xh, AL = %xh\n",
intno, M.x86.R_AH, M.x86.R_AL);
break;
}
}
static void X86API int15(int intno)
{
PRINTF("Called interrupt 15h: AX = %xh, BX = %xh, CX = %xh, DX = %xh\n",
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
//#if 0
if (M.x86.R_AX == 0x04e08)
{
switch (M.x86.R_BL)
{
/*
case 0x06: // Power Management Mode request
M.x86.R_BL = 0; // Assume APM
M.x86.R_AL = 0;
break;
case 0x05: // Get TV standard
M.x86.R_BX = 0xff; // Select No TV
M.x86.R_AL = 0;
break;
*/
case 0x01: // Get Request Display
if ((M.x86.R_BH & 0x08) == 0x08)
{
M.x86.R_BL = 0x08; // DVI
M.x86.R_BH = 0;
M.x86.R_AL = 0; // supported
PRINTF("DVI Monitor Found\n");
}
if (((M.x86.R_BH & 0x08) == 0x08) || ((M.x86.R_BH & 0x02) == 0x02))
{
M.x86.R_BL = 0x02; // CRT
M.x86.R_BH = 0;
M.x86.R_AL = 0; // supported
PRINTF("CRT Monitor Found\n");
}
if (((M.x86.R_BH & 0x08) == 0x08) || ((M.x86.R_BH & 0x04) == 0x04))
{
M.x86.R_BL = 0x04; // CRT 2
M.x86.R_BH = 0;
M.x86.R_AX = 0; // supported
PRINTF("CRT2 Monitor Found\n");
}
break;
default:
PRINTF("Subfunction %d not implemented\n", M.x86.R_BL);
M.x86.R_AL = 2; // Not supported
break;
}
PRINTF("Result: AX = %xh, BX = %xh\n", M.x86.R_AX, M.x86.R_BX);
}
//#endif
// // For now, just declare this interrupt as not implemented
// M.x86.R_AX = 2;
}