#include "win32.h" #include "gl_drv.h" #include "xbox_emu.h" #include "xbox\\xbe.h" /* LibEmu (x86) includes */ #include #include #include struct xbox_emu_t xbox; int launch_bios = No; int enable_debugger = No; void emulation_uninit(); extern void show_debugger(); /* Sets the current state of the emulator */ void set_emulator_state( enum emu_state es ) { xbox.state = es; } /* Opens the bios file and determine it's size */ int open_bios( char* filename, int preload ) { struct _iobuf* f = NULL; int ret = 1; /* sanity check(s) */ if( xbox.bios.ptr ) free( xbox.bios.ptr ); /* Open the bios file, get it's file size, validate that the file size is correct and if we're not preloading it, then read it into a buffer */ f = fopen( filename, "rb" ); if(!f) { msg_box( "Could not open BIOS file!", MB_OK ); ret = 0; goto stop; } fseek(f, 0, SEEK_END); xbox.bios.size = ftell(f); /* Xbox bioses are always 256kb, 512kb or 1mb */ /* TODO: Verify that only Chihiro has a 512kb bios */ if( xbox.bios.size != 1024*256 && xbox.bios.size != 1024*512 && xbox.bios.size != 1024*1024 ) { msg_box( "BIOS file size is incorrect!", MB_OK ); ret = 0; goto stop; } /* If we're preloading, stop here */ if( preload ) goto stop; /* Put it into a buffer */ xbox.bios.ptr = malloc( xbox.bios.size ); fread( xbox.bios.ptr, xbox.bios.size, 1, f ); /* TODO: Do a CRC check to determine what version this BIOS is unless the version number is somewhere in the BIOS itself. I haven't checked so I don't know... */ stop: fclose(f); return ret; } /* Closes the bios */ void close_bios() { printf( "Closing BIOS...\n" ); if( xbox.bios.ptr ) free( xbox.bios.ptr ); memset( &xbox.bios, 0, sizeof( struct xbox_bios_t ) ); } /* */ int open_xbe( char* filename ) { /* sanity check */ if( xbox.xbe.m_bXbeHasBeenOpened ) xbe_unload( &xbox.xbe ); /* Load .xbe file */ if( !xbe_load( filename, &xbox.xbe ) ) return 0; return 1; } /* Uninitialize xbe resources */ void close_xbe() { xbe_unload( &xbox.xbe ); } /* Setup memory handlers before emulation begins */ void setup_memory_handlers() { struct emu_memory_handler m; /* NV2A (framebuffer)*/ memset( &m, 0, sizeof( m ) ); m.mem_start = fb_start; m.mem_end = fb_start + ( 640 * 480 * 4 ); m.read_only_access = 0; m.executable = 0; m.read8 = nv2a_read8; m.write8 = nv2a_write8; m.read16 = nv2a_read16; m.write16 = nv2a_write16; m.read32 = nv2a_read32; m.write32 = nv2a_write32; emu_memory_add_handler( emu_memory_get(xbox.e), &m ); m.mem_start = fb_start2; m.mem_end = fb_start2 + ( 640 * 480 * 4 ); emu_memory_add_handler( emu_memory_get(xbox.e), &m ); } /* Initializes the emulator components */ int emulation_init() { uint32_t i = 0; /* Is the emulator already running? */ if( xbox.state != emu_state_stopped ) return 0; /* Verify that the .xbe was loaded first */ if( launch_bios == No && !xbox.xbe.m_bXbeHasBeenOpened ) { msg_box( "No xbe loaded!", MB_OK ); return 0; } /* Get parent window */ if( !w32_get_parent_window( &xbox.wnd ) ) return 0; /* Initialize OpenGL */ if( !enable_ogldrv( &xbox.wnd ) ) { disable_ogldrv(); msg_box( "Error initializing OpenGL!", MB_OK ); return 0; } /* Clear the screen once */ ogl_clear_colour_buffer(); ogl_swap_buffers(); /* Create a new instance of the x86 emulator */ xbox.e = emu_new(); if(!xbox.e) { char string[128]; sprintf( string, "emu_new(): %s", emu_strerror(xbox.e) ); msg_box( string, MB_OK ); emu_free(xbox.e); return 0; } /* Set up memory handlers for memory mapped I/O devices */ setup_memory_handlers(); /* Set up the default register values */ emu_cpu_reg32_set( emu_cpu_get(xbox.e), eax, 0 ); emu_cpu_reg32_set( emu_cpu_get(xbox.e), ecx, 0 ); emu_cpu_reg32_set( emu_cpu_get(xbox.e), edx, 0x00000600 ); emu_cpu_reg32_set( emu_cpu_get(xbox.e), ebx, 0 ); emu_cpu_reg32_set( emu_cpu_get(xbox.e), esp, 1024 ); /* TODO */ emu_cpu_reg32_set( emu_cpu_get(xbox.e), ebp, 0 ); emu_cpu_reg32_set( emu_cpu_get(xbox.e), esi, 0 ); emu_cpu_reg32_set( emu_cpu_get(xbox.e), edi, 0 ); emu_cpu_eflags_set( emu_cpu_get(xbox.e), 0x00000002 ); if( launch_bios ) { /* Set EIP to 0xFFFFFFF0 */ emu_cpu_eip_set( emu_cpu_get(xbox.e), 0xFFFFFFF0 ); /* Write bios contents to 0xFF000000 and mirror as many times as appropriate */ while( i < 1024*1024*16 ) { emu_memory_write_block( emu_memory_get(xbox.e), 0xFF000000+i, xbox.bios.ptr, xbox.bios.size ); i += xbox.bios.size; } } else { /* Set EIP to entry point */ emu_cpu_eip_set( emu_cpu_get(xbox.e), xbox.xbe.m_dwActualEntryPoint ); /* Write .xbe contents starting at the base address */ emu_memory_write_block( emu_memory_get(xbox.e), xbox.xbe.m_XbeHeader.dwBaseAddr, xbox.xbe.m_pXbeData, xbox.xbe.m_lXbeFileSize ); } #if 0 /* TODO: Create patch system */ if( xbox.xbe.crc == 0x5C524785 ) { /* NOPs placed over jbe short 0x11070 @ [0x11074] */ printf( "Applying patches...\n" ); emu_memory_write_byte( emu_memory_get(xbox.e), 0x11074, 0x90 ); emu_memory_write_byte( emu_memory_get(xbox.e), 0x11075, 0x90 ); emu_memory_write_byte( emu_memory_get(xbox.e), 0x1107A, 0x90 ); emu_memory_write_byte( emu_memory_get(xbox.e), 0x1107B, 0x90 ); } #endif /* Initialize fake kernel thunk */ init_kernel_thunk(); /* Set uninitialization function to go off at exit */ //atexit( (void (__cdecl *)(void)) emulation_uninit ); xbox.state = emu_state_running; return 1; } /* Uninitialize emulator components */ void emulation_uninit() { /* Close the xbe */ close_xbe(); /* Uninitialize cpu */ emu_free(xbox.e); /* Uninitialize OpenGL */ disable_ogldrv(); } /* Executes the CPU core */ void execute_cpu() { /* Attempt to parse the instruction EIP points to */ if( emu_cpu_parse( emu_cpu_get(xbox.e) ) ) { printf( "emu_cpu_parse(): %s", emu_strerror(xbox.e) ); //msg_box( string, MB_OK ); } else { /* Now actually emulate the instruction */ if( emu_cpu_step( emu_cpu_get(xbox.e) ) ) { printf( "emu_cpu_step(): %s", emu_strerror(xbox.e) ); //msg_box( string, MB_OK ); } } } /* Emulator starts executing here */ void* emulation_thread( void* params ) { /* Initialize emulator */ if( !emulation_init() ) return NULL; /* Reset the timer */ timer_reset(); /* Emulation loop */ while( TRUE ) { /* Handle emulator states */ if( xbox.state == emu_state_stopped ) break; if( xbox.state == emu_state_halted ) {} /* Execute CPU */ execute_cpu(); /* Update screen based on the timer value */ if( (((float) timer_get_current_time()) / ( 1000.0f * 1000.0f ) ) >= XBOX_CPU_SPEED ) { /* Update frame buffer */ ogl_update_fb(); ogl_swap_buffers(); /* Reset timer */ timer_reset(); } /* Update HLEd tick count */ impl_KeTickCount = GetTickCount(); } /* Uninitialize emulator */ emulation_uninit(); msg_box( "Emulation thread terminated!", MB_OK ); /* Exit thread */ // pthread_exit(NULL); return NULL; } void populate_debugger_list( HWND hwnd, uint32_t list ) { char string[128]; void* mem = xbox.e->memory->mem; uint32_t i = 0; for( i = 0; i < (xbox.xbe.m_lXbeFileSize); i++ ) { sprintf( string, "0x%X: 0x%.02X", i+0x10000, /*((uint8_t*)mem)[i+0x11000]*/ xbox.xbe.m_pXbeData[i] ); SendDlgItemMessage( hwnd, list, LB_ADDSTRING, 0, (LPARAM) string ); } } /* Initialize the emulation thread */ int initialize_emulation_thread() { /* Initialize the emulation thread */ int ret = pthread_create( &xbox.emulation_thread_handle, NULL, emulation_thread, NULL ); if( ret ) { msg_box( "Error creating POSIX thread!", MB_OK ); return 0; } /* Enable the debugger if desired */ if( enable_debugger ) { /* Small delay */ Sleep( 500 ); show_debugger(); } return 1; }