Begin implementing Xbe Loader

This commit is contained in:
Luke Usher 2016-09-27 22:30:59 +01:00
parent 517d411452
commit 72d9fecd12
8 changed files with 124 additions and 75 deletions

View File

@ -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;

View File

@ -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"

View File

@ -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();

View File

@ -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);
}

View File

@ -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);
// 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());

View File

@ -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;

View File

@ -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++)

View File

@ -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,14 +1052,13 @@ 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);
return 0;