blob: abfbe1e8b1730ed5bc0661cac7e55eb1bee8957c [file] [log] [blame]
#define _STDDEF_H
#include <common.h>
#include "glue.h"
#include "scitech/include/x86emu/x86emu.h"
#include "x86interface.h"
#include "../common/misc_utils.h"
/*
* This isn't nice, but there are a lot of incompatibilities in the U-Boot and scitech include
* files that this is the only really workable solution.
* Might be cleaned out later.
*/
#undef DEBUG
#undef SINGLESTEP
#undef FORCE_SINGLESTEP
#undef IO_LOGGING
#undef MEM_LOGGING
#ifdef IO_LOGGING
#define LOGIO(port, format, args...) if (dolog(port)) printf(format , ## args)
#else
#define LOGIO(port, format, args...)
#endif
#ifdef MEM_LOGGIN
#define LOGMEM(format, args...) printf(format , ## args)
#else
#define LOGMEM(format, args...)
#endif
#define log_printf(format, args...) if (getenv("x86_log")) printf(format, ## args);
#ifdef DEBUG
#define PRINTF(format, args...) printf(format , ## args)
#else
#define PRINTF(format, argc...)
#endif
typedef unsigned char UBYTE;
typedef unsigned short UWORD;
typedef unsigned long ULONG;
typedef char BYTE;
typedef short WORT;
typedef long LONG;
#define EMULATOR_MEM_SIZE (1024*1024)
#define EMULATOR_BIOS_OFFSET 0xC0000
#define EMULATOR_STRAP_OFFSET 0x30000
#define EMULATOR_STACK_OFFSET 0x20000
#define EMULATOR_LOGO_OFFSET 0x40000 // If you change this, change the strap code, too
extern int tstc(void);
extern int getc(void);
extern unsigned char video_get_attr(void);
extern void find_radeon_values(pci_dev_t dev, u8 * rom_addr);
extern void reloc_mode_table(void *reloc_addr);
extern int onbus;
extern u32 mmio_base_phys;
extern u32 io_base_phys;
#include "x86interface.h"
extern void bios_set_mode(int mode);
void sam440_remove_init_data(void)
{
}
void setup_tlb_for_cache(int enable)
{
// not used anymore
}
//Forward declaration
void do_inout(void);
int abs(int x)
{
if (x < 0)
return -x;
return x;
}
void cons_gets(char *buffer)
{
int i = 0;
char c = 0;
buffer[0] = 0;
if (getenv("x86_runthru")) return; //FIXME:
while (c != 0x0D && c != 0x0A)
{
while (!tstc());
c = getc();
if (c>=32 && c < 127)
{
buffer[i] = c;
i++;
buffer[i] = 0;
putc(c);
}
else
{
if (c == 0x08)
{
if (i>0) i--;
buffer[i] = 0;
}
}
}
buffer[i] = '\n';
buffer[i+1] = 0;
}
char *bios_date = "08/14/02";
UBYTE model = 0xFC;
UBYTE submodel = 0x00;
static int log_init = 0;
static int log_do = 0;
static int log_low = 0;
int dolog(int port)
{
if (log_init && log_do)
{
if (log_low && port > 0x400) return 0;
return 1;
}
if (!log_init)
{
log_init = 1;
log_do = (getenv("x86_logio") != (char *)0);
log_low = (getenv("x86_loglow") != (char *)0);
if (log_do)
{
if (log_low && port > 0x400) return 0;
return 1;
}
}
return 0;
}
static u32 dummy;
u32 screen_addr(u32 addr)
{
return &dummy;
}
// Converts an emulator address to a physical address.
// Handles all special cases (bios date, model etc), and might need work
u32 memaddr(u32 addr)
{
// if (addr >= 0xF0000 && addr < 0xFFFFF) printf("WARNING: Segment F access (0x%x)\n", addr);
// printf("MemAddr=%p\n", addr);
if (addr >= 0xA0000 && addr < 0xC0000)
return screen_addr(addr); //CFG_ISA_IO_BASE_ADDRESS + addr;
else if (addr >= 0xFFFF5 && addr < 0xFFFFE)
{
return (u32)bios_date+addr-0xFFFF5;
}
else if (addr == 0xFFFFE)
return (u32)&model;
else if (addr == 0xFFFFF)
return (u32)&submodel;
else if (addr >= 0x80000000)
{
//printf("Warning: High memory access at 0x%x\n", addr);
return addr;
}
else
return (u32)M.mem_base+addr;
}
u8 A1_rdb(u32 addr)
{
u8 a = in8((UBYTE *)memaddr(addr));
LOGMEM("rdb: %x -> %x\n", addr, a);
return a;
}
u16 A1_rdw(u32 addr)
{
u16 a = in16r((UWORD *)memaddr(addr));
LOGMEM("rdw: %x -> %x\n", addr, a);
return a;
}
u32 A1_rdl(u32 addr)
{
u32 a = in32r((ULONG *)memaddr(addr));
LOGMEM("rdl: %x -> %x\n", addr, a);
return a;
}
void A1_wrb(u32 addr, u8 val)
{
LOGMEM("wrb: %x <- %x\n", addr, val);
out8((UBYTE *)memaddr(addr), val);
}
void A1_wrw(u32 addr, u16 val)
{
LOGMEM("wrw: %x <- %x\n", addr, val);
out16r((UWORD *)memaddr(addr), val);
}
void A1_wrl(u32 addr, u32 val)
{
LOGMEM("wrl: %x <- %x\n", addr, val);
out32r((ULONG *)memaddr(addr), val);
}
static X86EMU_memFuncs _A1_mem;
#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)
u32 port_to_mem(int port)
{
#ifdef CONFIG_SAM460EX
/* here we assume that a Radeon is on bus 0 (PCI) */
/* and a RadeonHD is on bus 1 or higher (PCI or PCI-E) */
if (onbus >= 1)
{
if (port >= io_base_phys) port -= io_base_phys;
return mmio_base_phys + port;
}
else
{
if (port >= 0xcfc && port <= 0xcff)
return 0xDEC00004;
else if (port >= 0xcf8 && port <= 0xcfb)
return 0xDEC00000;
return CFG_ISA_IO_BASE_ADDRESS + port;
}
#else
if (port >= 0xcfc && port <= 0xcff)
return 0xEEC00004;
else if (port >= 0xcf8 && port <= 0xcfb)
return 0xEEC00000;
return CFG_ISA_IO_BASE_ADDRESS + port;
#endif
}
u8 A1_inb(int port)
{
u8 a;
//if (port == 0x3BA) return 0;
a = in_byte(port);
LOGIO(port, "inb: %Xh -> %d (%Xh)\n", port, a, a);
return a;
}
u16 A1_inw(int port)
{
u16 a = in_word(port);
LOGIO(port, "inw: %Xh -> %d (%Xh)\n", port, a, a);
return a;
}
u32 A1_inl(int port)
{
u32 a = in_long(port);
LOGIO(port, "inl: %Xh -> %d (%Xh)\n", port, a, a);
return a;
}
void A1_outb(int port, u8 val)
{
LOGIO(port, "outb: %Xh <- %d (%Xh)\n", port, val, val);
/* if (port == 0xCF8) port = 0xCFB;
else if (port == 0xCF9) port = 0xCFA;
else if (port == 0xCFA) port = 0xCF9;
else if (port == 0xCFB) port = 0xCF8;*/
out_byte(port, val);
}
void A1_outw(int port, u16 val)
{
LOGIO(port, "outw: %Xh <- %d (%Xh)\n", port, val, val);
out_word(port, val);
}
int blocked_port = 0;
void A1_outl(int port, u32 val)
{
LOGIO(port, "outl: %Xh <- %d (%Xh)\n", port, val, val);
// Workaround
if (port != blocked_port)
out_long(port, val);
else
LOGIO(port, "blocked\n");
}
static X86EMU_pioFuncs _A1_pio;
static int reloced_ops = 0;
void reloc_ops(void *reloc_addr)
{
extern void (*x86emu_optab[256])(u8);
extern void (*x86emu_optab2[256])(u8);
extern void tables_relocate(unsigned int offset);
int i;
unsigned long delta;
if (reloced_ops == 1) return;
reloced_ops = 1;
PRINTF("reloc_addr = %p\n", reloc_addr);
delta = TEXT_BASE - (unsigned long)reloc_addr;
PRINTF("delta = %p\n", delta);
PRINTF("x86emu_optab %p\n",x86emu_optab);
PRINTF("x86emu_optab %p\n",x86emu_optab-delta);
for (i=0; i<256; i++)
{
x86emu_optab[i] -= delta;
x86emu_optab2[i] -= delta;
}
_A1_mem.rdb = A1_rdb;
_A1_mem.rdw = A1_rdw;
_A1_mem.rdl = A1_rdl;
_A1_mem.wrb = A1_wrb;
_A1_mem.wrw = A1_wrw;
_A1_mem.wrl = A1_wrl;
_A1_pio.inb = (u8 (X86APIP)(X86EMU_pioAddr))A1_inb;
_A1_pio.inw = (u16 (X86APIP)(X86EMU_pioAddr))A1_inw;
_A1_pio.inl = (u32 (X86APIP)(X86EMU_pioAddr))A1_inl;
_A1_pio.outb = (void (X86APIP)(X86EMU_pioAddr, u8))A1_outb;
_A1_pio.outw = (void (X86APIP)(X86EMU_pioAddr, u16))A1_outw;
_A1_pio.outl = (void (X86APIP)(X86EMU_pioAddr, u32))A1_outl;
tables_relocate(delta);
}
#define ANY_KEY(text) \
printf(text); \
while (!tstc());
unsigned char more_strap[] = {
0xb4, 0x0, 0xb0, 0x2, 0xcd, 0x10,
};
#define MORE_STRAP_BYTES 6 // Additional bytes of strap code
unsigned char *done_msg="VGA Initialized\0";
int execute_bios(pci_dev_t gr_dev, void *reloc_addr)
{
extern void bios_init(void);
extern void remove_init_data(void);
extern int video_rows(void);
extern int video_cols(void);
extern int video_size(int, int);
u8 *strap;
//unsigned char *logo;
//u8 cfg;
int i;
//char c;
//char *s;
#ifdef EASTEREGG
int easteregg_active = 0;
#endif
char *pal_reset;
//u8 *fb;
//unsigned char *msg;
//unsigned char current_attr;
PRINTF("Trying to remove init data\n");
sam440_remove_init_data();
PRINTF("Removed init data from cache, now in RAM\n");
reloc_ops(reloc_addr);
reloc_mode_table(reloc_addr);
PRINTF("Attempting to run emulator on %02x:%02x:%02x\n",
PCI_BUS(gr_dev), PCI_DEV(gr_dev), PCI_FUNC(gr_dev));
// Enable compatibility hole for emulator access to frame buffer
//PRINTF("Enabling compatibility hole\n");
//enable_compatibility_hole();
#ifdef DEBUG
/*
s = getenv("x86_ask_start");
if (s)
{
printf("Press 'q' to skip initialization, 'd' for dry init\n'i' for i/o session");
while (!tstc());
c = getc();
if (c == 'q') return 0;
if (c == 'd')
{
bios_set_mode(0x03);
return 0;
}
if (c == 'i') do_inout();
}
*/
#endif
// Allocate memory
// FIXME: We shouldn't use this much memory really.
memset(&M, 0, sizeof(X86EMU_sysEnv));
M.mem_base = (unsigned long)malloc(EMULATOR_MEM_SIZE);
M.mem_size = (unsigned long)EMULATOR_MEM_SIZE;
if (!M.mem_base)
{
PRINTF("Unable to allocate one megabyte for emulator\n");
return 0;
}
if (attempt_map_rom(gr_dev, (void *)(M.mem_base + EMULATOR_BIOS_OFFSET)) == 0)
{
PRINTF("Error mapping rom. Emulation terminated\n");
return 0;
}
#ifdef EASTEREGG
/* if (tstc())
{
if (getc() == 'c')
{
easteregg_active = 1;
}
}
*/
if (getenv("easteregg"))
{
easteregg_active = 1;
}
if (easteregg_active)
{
// Yay!
setenv("x86_mode", "1");
setenv("vga_fg_color", "11");
setenv("vga_bg_color", "1");
easteregg_active = 1;
}
#endif
strap = (u8*)M.mem_base + EMULATOR_STRAP_OFFSET;
/*
{
char *m = getenv("x86_mode");
if (m)
{
more_strap[3] = atoi(m);
if (more_strap[3] == 1) video_size(40, 25);
else video_size(80, 25);
}
}
*/
/*
* Poke the strap routine. This might need a bit of extending
* if there is a mode switch involved, i.e. we want to int10
* afterwards to set a different graphics mode, or alternatively
* there might be a different start address requirement if the
* ROM doesn't have an x86 image in its first image.
*/
PRINTF("Poking strap...\n");
// FAR CALL c000:0003
*strap++ = 0x9A; *strap++ = 0x03; *strap++ = 0x00;
*strap++ = 0x00; *strap++ = 0xC0;
#if 1
// insert additional strap code
for (i=0; i < MORE_STRAP_BYTES; i++)
{
*strap++ = more_strap[i];
}
#endif
// HALT
*strap++ = 0xF4;
PRINTF("Done poking strap\n");
#if 0
PRINTF("Setting up logo data\n");
logo = (unsigned char *)M.mem_base + EMULATOR_LOGO_OFFSET;
for (i=0; i<16; i++)
{
*logo++ = 0xFF;
}
#endif
/*
* Setup the init parameters.
* Per PCI specs, AH must contain the bus and AL
* must contain the devfn, encoded as (dev<<3)|fn
*/
PRINTF("Settingup init parameters\n");
// Execution starts here
M.x86.R_CS = SEG(EMULATOR_STRAP_OFFSET);
M.x86.R_IP = OFF(EMULATOR_STRAP_OFFSET);
// Stack at top of ram
M.x86.R_SS = SEG(EMULATOR_STACK_OFFSET);
M.x86.R_SP = OFF(EMULATOR_STACK_OFFSET);
// Input parameters
M.x86.R_AH = PCI_BUS(gr_dev);
M.x86.R_AL = (PCI_DEV(gr_dev)<<3) | PCI_FUNC(gr_dev);
PRINTF("Setting up I/O and memory access functions\n");
// Set the I/O and memory access functions
X86EMU_setupMemFuncs(&_A1_mem);
PRINTF("PIO\n");
X86EMU_setupPioFuncs(&_A1_pio);
#if 0
// Enable timer 2
cfg = in_byte(0x61); // Get Misc control
cfg |= 0x01; // Enable timer 2
out_byte(0x61, cfg); // output again
// Set up the timers
out_byte(0x43, 0x54);
out_byte(0x41, 0x18);
out_byte(0x43, 0x36);
out_byte(0x40, 0x00);
out_byte(0x40, 0x00);
out_byte(0x43, 0xb6);
out_byte(0x42, 0x31);
out_byte(0x42, 0x13);
#endif
// If the initializing card is an ATI card, block access to port 0x34
unsigned short vendor;
pci_read_config_word(gr_dev, PCI_VENDOR_ID, &vendor);
if (vendor == 0x1002)
{
PRINTF("Initializing a Radeon, blocking port access\n");
int bar;
for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4)
{
unsigned int val;
pci_read_config_dword(gr_dev, bar, &val);
if (val & PCI_BASE_ADDRESS_SPACE_IO)
{
blocked_port = val & PCI_BASE_ADDRESS_IO_MASK;
blocked_port += 0x34;
break;
}
}
}
else
blocked_port = 0;
PRINTF("Blocked port %x\n",blocked_port);
// Init the "BIOS".
PRINTF("BIOS init\n");
bios_init();
// Video Card Reset
PRINTF("Video card reset\n");
// out_byte(0x3D8, 0);
// out_byte(0x3B8, 1);
// (void)in_byte(0x3BA);
// (void)in_byte(0x3DA);
// out_byte(0x3C0, 0);
// out_byte(0x61, 0xFC);
PRINTF("Done resetting\n");
#if defined(DEBUG) && defined(SINGLESTEP)
#ifndef FORCE_SINGLESTEP
s = _getenv("x86_singlestep");
if (s && strcmp(s, "on")==0)
{
#endif
PRINTF("Enabling single stepping for debug\n");
X86EMU_trace_on();
#ifndef FORCE_SINGLESTEP
}
#endif
#endif
#ifdef DEBUG
// icache_disable();
// dcache_disable();
#endif
// Ready set go...
PRINTF("Running emulator\n");
setup_tlb_for_cache(1);
X86EMU_exec();
setup_tlb_for_cache(0);
// find_radeon_values(gr_dev, (u8 *)(M.mem_base + EMULATOR_BIOS_OFFSET));
PRINTF("Done running emulator\n");
/* FIXME: Remove me */
pal_reset = getenv("x86_palette_reset");
if (pal_reset && strcmp(pal_reset, "on") == 0)
{
PRINTF("Palette reset\n");
//(void)in_byte(0x3da);
//out_byte(0x3c0, 0);
out_byte(0x3C8, 0);
out_byte(0x3C9, 0);
out_byte(0x3C9, 0);
out_byte(0x3C9, 0);
for (i=0; i<254; i++)
{
out_byte(0x3C9, 63);
out_byte(0x3C9, 63);
out_byte(0x3C9, 63);
}
out_byte(0x3c0, 0x20);
}
/* FIXME: remove me */
#ifdef EASTEREGG
if (easteregg_active)
{
extern void video_easteregg(void);
video_easteregg();
}
#endif
/*
current_attr = video_get_attr();
fb = (u8 *)VIDEO_BASE;
for (i=0; i<video_rows()*video_cols()*2; i+=2)
{
*(fb+i) = ' ';
*(fb+i+1) = current_attr;
}
fb = (u8 *)VIDEO_BASE + (video_rows())-1*(video_cols()*2);
for (i=0; i<video_cols(); i++)
{
*(fb + 2*i) = 32;
*(fb + 2*i + 1) = 0x17;
}
msg = done_msg;
while (*msg)
{
*fb = *msg;
fb += 2;
msg ++;
}
*/
#ifdef DEBUG
//if (getenv("x86_do_inout")) do_inout();
#endif
return 1;
}
// Clean up the x86 mess
void shutdown_bios(void)
{
// disable_compatibility_hole();
// Free the memory associated
// free(M.mem_base);
// setup_tlb_for_cache(0);
}
int to_int(char *buffer)
{
int base = 0;
int res = 0;
if (*buffer == '$')
{
base = 16;
buffer++;
}
else base = 10;
for (;;)
{
switch(*buffer)
{
case '0' ... '9':
res *= base;
res += *buffer - '0';
break;
case 'A':
case 'a':
res *= base;
res += 10;
break;
case 'B':
case 'b':
res *= base;
res += 11;
break;
case 'C':
case 'c':
res *= base;
res += 12;
break;
case 'D':
case 'd':
res *= base;
res += 13;
break;
case 'E':
case 'e':
res *= base;
res += 14;
break;
case 'F':
case 'f':
res *= base;
res += 15;
break;
default:
return res;
}
buffer++;
}
return res;
}
/*
void one_arg(char *buffer, int *a)
{
while (*buffer && *buffer != '\n')
{
if (*buffer == ' ') buffer++;
else break;
}
*a = to_int(buffer);
}
void two_args(char *buffer, int *a, int *b)
{
while (*buffer && *buffer != '\n')
{
if (*buffer == ' ') buffer++;
else break;
}
*a = to_int(buffer);
while (*buffer && *buffer != '\n')
{
if (*buffer != ' ') buffer++;
else break;
}
while (*buffer && *buffer != '\n')
{
if (*buffer == ' ') buffer++;
else break;
}
*b = to_int(buffer);
}
*/
/*
void do_inout(void)
{
char buffer[256];
char *arg1;
//char *arg2;
int a,b;
printf("In/Out Session\nUse 'i[bwl]' for in, 'o[bwl]' for out and 'q' to quit\n");
do
{
cons_gets(buffer);
printf("\n");
arg1 = buffer;
while (*arg1 != ' ' ) arg1++;
while (*arg1 == ' ') arg1++;
if (buffer[0] == 'i')
{
one_arg(buffer+2, &a);
switch (buffer[1])
{
case 'b':
printf("in_byte(%xh) = %xh\n", a, A1_inb(a));
break;
case 'w':
printf("in_word(%xh) = %xh\n", a, A1_inw(a));
break;
case 'l':
printf("in_dword(%xh) = %xh\n", a, A1_inl(a));
break;
default:
printf("Invalid length '%c'\n", buffer[1]);
break;
}
}
else if (buffer[0] == 'o')
{
two_args(buffer+2, &a, &b);
switch (buffer[1])
{
case 'b':
printf("out_byte(%d, %d)\n", a, b);
A1_outb(a,b);
break;
case 'w':
printf("out_word(%d, %d)\n", a, b);
A1_outw(a, b);
break;
case 'l':
printf("out_long(%d, %d)\n", a, b);
A1_outl(a, b);
break;
default:
printf("Invalid length '%c'\n", buffer[1]);
break;
}
} else if (buffer[0] == 'q') return;
} while (1);
}
#include <command.h>
void do_vmode(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: %s\n", cmdtp->usage);
return;
}
int mode = simple_strtoul(argv[1], NULL, 16);
bios_set_mode(mode);
}
U_BOOT_CMD( vmode,
2, 0, do_vmode,
"vmode - set vga mode\n",
"set vga mode\n");
typedef unsigned long uint32;
// TLB definitions
typedef struct tlb440
{
// Word 0
uint32 EPN:22; // Effective page number
uint32 V:1; // Entry valid
uint32 TS:1; // Translation space
uint32 SIZE:4; // Size, see below
uint32 TPAR:4; // Tag parity
// Word 1
uint32 RPN:22; // Real (physical) page number
uint32 PAR1:2; // Parity
uint32 RES1:4; // Unused
uint32 ERPN:4; // Extended real page number, for 36 bit memory addressing
// Word 2
uint32 PAR2:2; // Parity
uint32 RES2:14; // Unused
uint32 U03:4; // Bits U0 - U3
uint32 WIMG:4; // Memory attributes
uint32 E:1; // Endian flag
uint32 RES3:1; // Unused
uint32 XWRXWR:6; // Protection bits
} tlb440_t;
void do_tlb(void)
{
int i;
uint32 tlba[3];
tlb440_t *tlb = (tlb440_t *)tlba;
printf("\nDump of all active TLB's\n");
for (i = 0; i < 64; i++)
{
__asm volatile("tlbre %0, %3, 0 \n\
tlbre %1, %3, 1 \n\
tlbre %2, %3, 2"
: "=r" (tlba[0]), "=r" (tlba[1]), "=r" (tlba[2])
: "r" (i));
if (tlb->V)
{
printf("TLB %2d: EPN = %p TS = %d, SIZE = %d\n", i, tlb->EPN, tlb->TS, tlb->SIZE);
printf(" RPN = %p, WIMG = 0x%x XWRXWR = 0x%x\n", tlb->RPN, tlb->WIMG, tlb->XWRXWR);
printf(" (Maps %p to %p)\n", tlb->EPN << 10, tlb->RPN << 10);
}
}
}
U_BOOT_CMD( tlb, 1, 0, do_tlb, "tlb - dump all tlbs\n", "dump all tlbs\n");
*/