diff --git a/src/Common/Xbe.cpp b/src/Common/Xbe.cpp index 9787df7cb..d7b3460cf 100644 --- a/src/Common/Xbe.cpp +++ b/src/Common/Xbe.cpp @@ -105,11 +105,11 @@ Xbe::Xbe(const char *x_szFilename) { printf("Xbe::Xbe: Reading Image Header Extra Bytes..."); - uint32 ExSize = RoundUp(m_Header.dwSizeofHeaders, 0x1000) - sizeof(m_Header); + m_ExSize = RoundUp(m_Header.dwSizeofHeaders, 0x1000) - sizeof(m_Header); - m_HeaderEx = new char[ExSize]; + m_HeaderEx = new char[m_ExSize]; - if(fread(m_HeaderEx, ExSize, 1, XbeFile) != 1) + if(fread(m_HeaderEx, m_ExSize, 1, XbeFile) != 1) { SetError("Unexpected end of file while reading Xbe Image Header (Ex)", true); goto cleanup; diff --git a/src/Common/Xbe.h b/src/Common/Xbe.h index b5154e550..b6291d4a5 100644 --- a/src/Common/Xbe.h +++ b/src/Common/Xbe.h @@ -117,6 +117,7 @@ class Xbe : public Error // Xbe header extra byte (used to preserve unknown data) char *m_HeaderEx; + uint32 m_ExSize; // Xbe certificate #include "AlignPrefix1.h" diff --git a/src/Cxbx/WinMain.cpp b/src/Cxbx/WinMain.cpp index ec974e792..b12128ccc 100644 --- a/src/Cxbx/WinMain.cpp +++ b/src/Cxbx/WinMain.cpp @@ -40,6 +40,8 @@ #include "CxbxKrnl/Emu.h" #include "CxbxKrnl/EmuShared.h" +unsigned char memory[XBOX_MEMORY_SIZE]; + /*! program entry point */ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { @@ -50,6 +52,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine return 1; } + if (__argc >= 2 && strcmp(__argv[1], "/load") == 0 && strlen(__argv[2]) > 0) { + CxbxKrnlMain(__argc, __argv); + return 0; + } + /*! initialize shared memory */ EmuShared::Init(); diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index a792cb894..a764ba7ff 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -45,7 +45,8 @@ /** * Silly little hack to fix link error with libjpeg on MSVC 2015 */ -FILE _iob[] = { *stdin, *stdout, *stderr }; extern "C" FILE * __cdecl __iob_func(void) { return _iob; } +FILE _iob[] = { *stdin, *stdout, *stderr }; +extern "C" FILE * __cdecl __iob_func(void) { return _iob; } WndMain::WndMain(HINSTANCE x_hInstance) : Wnd(x_hInstance), m_bCreated(false), m_Xbe(0), m_Exe(0), m_bExeChanged(false), m_bXbeChanged(false), m_bCanStart(true), m_hwndChild(NULL), m_AutoConvertToExe(AUTO_CONVERT_WINDOWS_TEMP), m_KrnlDebug(DM_NONE), m_CxbxDebug(DM_NONE), m_dwRecentXbe(0), m_dwRecentExe(0) { @@ -1832,45 +1833,6 @@ void WndMain::StartEmulation(EnumAutoConvert x_AutoConvert, HWND hwndParent) { char szBuffer[260]; - // convert xbe to exe, if necessary - if(m_ExeFilename[0] == '\0' || m_bExeChanged) - { - if(x_AutoConvert == AUTO_CONVERT_WINDOWS_TEMP) - { - char szTempPath[260]; - - GetTempPath(259, szTempPath); - - SuggestFilename(m_XbeFilename, szBuffer, ".exe"); - - int v=0, c=0; - - while(szBuffer[v] != '\0') - { - if(szBuffer[v] == '\\') - c = v+1; - v++; - } - - strcat(szTempPath, &szBuffer[c]); - - if(!ConvertToExe(szTempPath, false, hwndParent)) - return; - } - else if(x_AutoConvert == AUTO_CONVERT_XBE_PATH) - { - SuggestFilename(m_XbeFilename, szBuffer, ".exe"); - - if(!ConvertToExe(szBuffer, false, hwndParent)) - return; - } - else - { - if(!ConvertToExe(NULL, true, hwndParent)) - return; - } - } - // register xbe path with CxbxKrnl.dll g_EmuShared->SetXbePath(m_Xbe->m_szPath); @@ -1890,10 +1852,12 @@ void WndMain::StartEmulation(EnumAutoConvert x_AutoConvert, HWND hwndParent) if(spot != -1) szBuffer[spot] = '\0'; + // std::string args = "/load " + std::string("\"") + std::string(m_Xbe->m_szPath) + std::string(itoa(0)); + if((int)ShellExecute(NULL, "open", m_ExeFilename, NULL, szBuffer, SW_SHOWDEFAULT) <= 32) { m_bCanStart = true; - MessageBox(m_hwnd, "Emulation failed.\n\nTry converting again. If this message repeats, the Xbe is not supported.", "Cxbx", MB_ICONSTOP | MB_OK); + MessageBox(m_hwnd, "Emulation failed.\n\n If this message repeats, the Xbe is not supported.", "Cxbx", MB_ICONSTOP | MB_OK); printf("WndMain: %s shell failed.\n", m_Xbe->m_szAsciiTitle); } diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index ad34d9a7a..fadd58828 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -73,7 +73,7 @@ static HANDLE g_hThreads[MAXIMUM_XBOX_THREADS] = { 0 }; std::string CxbxBasePath; HANDLE CxbxBasePathHandle; -Exe* CxbxKrnl_Exe = NULL; +Xbe* CxbxKrnl_Xbe = NULL; DWORD_PTR g_CPUXbox = 0; DWORD_PTR g_CPUOthers = 0; @@ -214,6 +214,80 @@ void CxbxLaunchXbe(void(*Entry)()) } +extern "C" CXBXKRNL_API void CxbxKrnlMain(int argc, char* argv[]) +{ + std::string xbePath = argv[2]; + + MessageBoxA(NULL, xbePath.c_str(), "", 0); + HWND hWnd = (HWND)StrToInt(argv[3]); + DebugMode DbgMode = (DebugMode)StrToInt(argv[4]); + std::string DebugFileName = argv[5]; + + // Backup the area of the EXE required for WinAPI + Exe::DOSHeader* header = (Exe::DOSHeader*)0x10000; + DWORD magic = header->m_magic; + DWORD lfaNew = header->m_lfanew; + + DWORD OldProtection; + VirtualProtect((void*)0x10000, XBOX_MEMORY_SIZE, PAGE_EXECUTE_READWRITE, &OldProtection); + ZeroMemory((void*)0x10000, XBOX_MEMORY_SIZE); + + g_EmuShared->SetXbePath(xbePath.c_str()); + + CxbxKrnl_Xbe = new Xbe(xbePath.c_str()); + + // Load Xbe Headers + memcpy((void*)CxbxKrnl_Xbe->m_Header.dwBaseAddr, &CxbxKrnl_Xbe->m_Header, sizeof(Xbe::Header)); + memcpy((void*)(CxbxKrnl_Xbe->m_Header.dwBaseAddr + sizeof(Xbe::Header)), CxbxKrnl_Xbe->m_HeaderEx, CxbxKrnl_Xbe->m_ExSize); + + // Load Sections + for (int i = 0; i < CxbxKrnl_Xbe->m_Header.dwSections; i++) { + memcpy((void*)CxbxKrnl_Xbe->m_SectionHeader[i].dwVirtualAddr, CxbxKrnl_Xbe->m_bzSection[i], CxbxKrnl_Xbe->m_SectionHeader[i].dwSizeofRaw); + } + + // Fixup Kernel Imports + uint32 kt = CxbxKrnl_Xbe->m_Header.dwKernelImageThunkAddr; + + if ((kt ^ XOR_KT_DEBUG) > 0x01000000) + kt ^= XOR_KT_RETAIL; + else + kt ^= XOR_KT_DEBUG; + + uint32_t* kt_tbl = (uint32_t*)kt; + + int i = 0; + while (kt_tbl[i] != 0) { + int t = kt_tbl[i] & 0x7FFFFFFF; + kt_tbl[i] = CxbxKrnl_KernelThunkTable[t]; + i++; + } + + // Load TLS + Xbe::TLS* XbeTls = (Xbe::TLS*)CxbxKrnl_Xbe->m_Header.dwTLSAddr; + void* XbeTlsData = nullptr; + + if (XbeTls != nullptr) { + XbeTlsData = (void*)CxbxKrnl_Xbe->m_TLS->dwDataStartAddr; + } + + // Decode Entry Point + uint32_t EntryPoint = CxbxKrnl_Xbe->m_Header.dwEntryAddr; + if ((EntryPoint ^ XOR_EP_DEBUG) > 0x01000000) + EntryPoint ^= XOR_EP_RETAIL; + else + EntryPoint ^= XOR_EP_DEBUG; + + // Restore the area of the EXE required for WinAPI + header->m_magic = magic; + header->m_lfanew = lfaNew; + + // Launch XBE + CxbxKrnlInit( + hWnd, XbeTlsData, XbeTls, CxbxKrnl_Xbe->m_LibraryVersion, DbgMode, + DebugFileName.c_str(), &CxbxKrnl_Xbe->m_Header, CxbxKrnl_Xbe->m_Header.dwSizeofHeaders, (void(*)())EntryPoint + ); +} + extern "C" CXBXKRNL_API void CxbxKrnlInit ( HWND hwndParent, @@ -221,7 +295,7 @@ extern "C" CXBXKRNL_API void CxbxKrnlInit Xbe::TLS *pTLS, Xbe::LibraryVersion *pLibraryVersion, DebugMode DbgMode, - char *szDebugFilename, + const char *szDebugFilename, Xbe::Header *pXbeHeader, uint32 dwXbeHeaderSize, void(*Entry)()) @@ -357,13 +431,6 @@ extern "C" CXBXKRNL_API void CxbxKrnlInit ((Xbe::Certificate*)pXbeHeader->dwCertificateAddr)->dwAllowedMedia |= 0x00FFFFFF; } - // Load EXE structure, this is used by Xapi Section functions - { - char szBuffer[MAX_PATH]; - GetModuleFileNameA(NULL, szBuffer, MAX_PATH); - CxbxKrnl_Exe = new Exe(szBuffer); - } - // Initialize devices : char szBuffer[260]; SHGetSpecialFolderPath(NULL, szBuffer, CSIDL_APPDATA, TRUE); @@ -477,19 +544,27 @@ extern "C" CXBXKRNL_API void CxbxKrnlInit } - DbgPrintf("EmuMain : Determining CPU affinity."); // Make sure the Xbox1 code runs on one core (as the box itself has only 1 CPU, + DbgPrintf("EmuMain : Determining CPU affinity."); + + // Make sure the Xbox1 code runs on one core (as the box itself has only 1 CPU, // this will better aproximate the environment with regard to multi-threading) : - { GetProcessAffinityMask(GetCurrentProcess(), &g_CPUXbox, &g_CPUOthers); + { + GetProcessAffinityMask(GetCurrentProcess(), &g_CPUXbox, &g_CPUOthers); // For the other threads, remove one bit from the processor mask: - g_CPUOthers = ((g_CPUXbox - 1) & g_CPUXbox); + g_CPUOthers = ((g_CPUXbox - 1) & g_CPUXbox); + // Test if there are any other cores available : if (g_CPUOthers > 0) { // If so, make sure the Xbox threads run on the core NOT running Xbox code : - g_CPUXbox = g_CPUXbox & (~g_CPUOthers); } else { // Else the other threads must run on the same core as the Xbox code : - g_CPUOthers = g_CPUXbox; } + g_CPUXbox = g_CPUXbox & (~g_CPUOthers); + } else { + // Else the other threads must run on the same core as the Xbox code : + g_CPUOthers = g_CPUXbox; + } // Make sure Xbox1 code runs on one core : - SetThreadAffinityMask(GetCurrentThread(), g_CPUXbox); } + SetThreadAffinityMask(GetCurrentThread(), g_CPUXbox); +} DbgPrintf("EmuMain (0x%X): Initial thread starting.\n", GetCurrentThreadId()); diff --git a/src/CxbxKrnl/CxbxKrnl.h b/src/CxbxKrnl/CxbxKrnl.h index 5d065984a..ff14296a7 100644 --- a/src/CxbxKrnl/CxbxKrnl.h +++ b/src/CxbxKrnl/CxbxKrnl.h @@ -46,11 +46,16 @@ extern "C" { #endif +#define XBOX_MEMORY_SIZE 128 * 1024 * 1024 + /*! validate version string match */ CXBXKRNL_API bool CxbxKrnlVerifyVersion(const char *szVersion); +/*! Cxbx Kernel Entry Point */ +CXBXKRNL_API void CxbxKrnlMain(int argc, char* argv[]); + /*! initialize emulation */ -CXBXKRNL_API void CxbxKrnlInit(HWND hwndParent, void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, char *szDebugFilename, Xbe::Header *XbeHeader, uint32 XbeHeaderSize, void (*Entry)()); +CXBXKRNL_API void CxbxKrnlInit(HWND hwndParent, void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, const char *szDebugFilename, Xbe::Header *XbeHeader, uint32 XbeHeaderSize, void (*Entry)()); /*! cleanup emulation */ CXBXKRNL_API void CxbxKrnlCleanup(const char *szErrorMessage, ...); @@ -85,7 +90,7 @@ extern CXBXKRNL_API void *CxbxKrnl_TLSData; /*! xbe header structure */ extern CXBXKRNL_API Xbe::Header *CxbxKrnl_XbeHeader; -extern Exe* CxbxKrnl_Exe; +extern Xbe *CxbxKrnl_Xbe; /*! parent window handle */ extern CXBXKRNL_API HWND CxbxKrnl_hEmuParent; diff --git a/src/CxbxKrnl/EmuFS.cpp b/src/CxbxKrnl/EmuFS.cpp index f1c9ebd0d..e343a4c14 100644 --- a/src/CxbxKrnl/EmuFS.cpp +++ b/src/CxbxKrnl/EmuFS.cpp @@ -284,16 +284,16 @@ void EmuInitFS() long numberOfInstructions = fsInstructions.size(); // Iterate through each CODE section - for (int sectionIndex = 0; sectionIndex < CxbxKrnl_Exe->m_Header.m_sections; sectionIndex++) { - if (CxbxKrnl_Exe->m_SectionHeader[sectionIndex].m_characteristics & IMAGE_SCN_CNT_CODE != IMAGE_SCN_CNT_CODE) { + for (int sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { + if (!CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwFlags.bExecutable) { continue; } - std::string sectionName(CxbxKrnl_Exe->m_SectionHeader[sectionIndex].m_name, 8); + std::string sectionName(CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwSectionNameAddr, 8); DbgPrintf("Searching for FS Instruction in section %s\n", sectionName.c_str()); - uint32_t startAddr = CxbxKrnl_Exe->m_SectionHeader[sectionIndex].m_virtual_addr + CxbxKrnl_XbeHeader->dwBaseAddr; - uint32_t endAddr = startAddr + CxbxKrnl_Exe->m_SectionHeader[sectionIndex].m_sizeof_raw; + uint32_t startAddr = CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwVirtualAddr + CxbxKrnl_XbeHeader->dwBaseAddr; + uint32_t endAddr = startAddr + CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwSizeofRaw; for (uint32 addr = startAddr; addr < endAddr; addr++) { for (int i = 0; i < numberOfInstructions; i++) diff --git a/src/CxbxKrnl/EmuXapi.cpp b/src/CxbxKrnl/EmuXapi.cpp index 079de4cd0..9f57592f8 100644 --- a/src/CxbxKrnl/EmuXapi.cpp +++ b/src/CxbxKrnl/EmuXapi.cpp @@ -976,15 +976,13 @@ HANDLE WINAPI XTL::EmuXGetSectionHandleA void* pRet = NULL; // Iterate thrugh sections - for (int i = 0; i < CxbxKrnl_Exe->m_Header.m_sections; i++) { - if (!strncmp(pSectionName, CxbxKrnl_Exe->m_SectionHeader[i].m_name, 8)) { - pRet = (void*)(CxbxKrnl_Exe->m_SectionHeader[i].m_virtual_addr + CxbxKrnl_XbeHeader->dwBaseAddr); + for (int i = 0; i < CxbxKrnl_Xbe->m_Header.dwSections; i++) { + if (!strncmp(pSectionName, (char*)CxbxKrnl_Xbe->m_SectionHeader[i].dwSectionNameAddr, 8)) { + pRet = (void*)(CxbxKrnl_Xbe->m_SectionHeader[i].dwVirtualAddr + CxbxKrnl_XbeHeader->dwBaseAddr); break; } } - - return (LPVOID) pRet; } @@ -1054,13 +1052,12 @@ DWORD WINAPI XTL::EmuXGetSectionSize // Iterate thrugh sections - for (int i = 0; i < CxbxKrnl_Exe->m_Header.m_sections; i++) { - if ((HANDLE)(CxbxKrnl_Exe->m_SectionHeader[i].m_virtual_addr + CxbxKrnl_XbeHeader->dwBaseAddr) == hSection) { - return CxbxKrnl_Exe->m_SectionHeader[i].m_sizeof_raw; + for (int i = 0; i < CxbxKrnl_Xbe->m_Header.dwSections; i++) { + if ((HANDLE)(CxbxKrnl_Xbe->m_SectionHeader[i].dwVirtualAddr + CxbxKrnl_XbeHeader->dwBaseAddr) == hSection) { + return CxbxKrnl_Xbe->m_SectionHeader[i].dwRawAddr; } } - EmuWarning("EmuXApi : EmuXGetSectionSize : Could not determine section size: %x08X", hSection);