Merge pull request #168 from PatrickvL/master

Various improvements to kernel, vertices, comments and code quality
This commit is contained in:
Luke Usher 2017-02-14 10:50:26 +00:00 committed by GitHub
commit 95687f153a
14 changed files with 687 additions and 481 deletions

View File

@ -224,7 +224,11 @@ XBSYSAPI EXPORTNUM(128) VOID NTAPI KeQuerySystemTime
// ******************************************************************
XBSYSAPI EXPORTNUM(129) UCHAR NTAPI KeRaiseIrqlToDpcLevel();
XBSYSAPI VOID *KeRaiseIrqlToSynchLevel;
// ******************************************************************
// * 0x0082 - KeRaiseIrqlToSynchLevel()
// ******************************************************************
XBSYSAPI EXPORTNUM(130) UCHAR NTAPI KeRaiseIrqlToSynchLevel();
XBSYSAPI VOID *KeReleaseMutant;
XBSYSAPI VOID *KeReleaseSemaphore;
XBSYSAPI VOID *KeRemoveByKeyDeviceQueue;

View File

@ -1903,18 +1903,19 @@ typedef struct _KPRCB
struct _KTHREAD* NextThread; // 0x04, KPCR : 0x2C
struct _KTHREAD* IdleThread; // 0x08, KPCR : 0x30
ULONG Unknown1[8]; // 0x0C, KPCR : 0x34
ULONG Unknown1[7]; // 0x0C, KPCR : 0x34
ULONG DpcRoutineActive; // 0x2C, KPCR : 0x54
LIST_ENTRY DpcListHead; // 0x28, KPCR : 0x50
ULONG DpcRoutineActive; // 0x30, KPCR : 0x58
// This is the total size of the structure (presumably)
UCHAR Unknown[0x22C];
// This completes the total size of the structure (presumably)
UCHAR Unknown[0x224];
}
KPRCB, *PKPRCB;
// ******************************************************************
// * KPCR
// * KPCR (Kernel Processor Control Region)
// ******************************************************************
// *
// * NOTE: KPCR is the structure which exists at the FS: segment.

View File

@ -46,11 +46,16 @@
extern "C" {
#endif
// Opcodes
#define OPCODE_NOP_90 0x90
#define OPCODE_INT3_CC 0xCC
#define OPCODE_CALL_E8 0xE8
#define OPCODE_JMP_E9 0xE9
// Thread Information Block offsets - see https://www.microsoft.com/msj/archive/S2CE.aspx
#define TIB_ArbitraryDataSlot 0x14
#define TIB_LinearSelfAddress 0x18
/*! xbaddr is the type of a physical address */
typedef uint32 xbaddr;

View File

@ -504,124 +504,122 @@ bool XTL::VertexPatcher::PatchStream(VertexPatchDesc *pPatchDesc,
for (uint32 uiVertex = 0; uiVertex < pPatchDesc->dwVertexCount; uiVertex++)
{
DWORD dwPosOrig = 0;
uint08 *pOrigVertex = &pOrigData[uiVertex * uiStride];
uint08 *pNewDataPos = &pNewData[uiVertex * pStreamPatch->ConvertedStride];
for (UINT uiType = 0; uiType < pStreamPatch->NbrTypes; uiType++)
{
// Dxbx note : The following code handles only the D3DVSDT enums that need conversion;
// All other cases are catched by the memcpy in the default-block.
switch (pStreamPatch->pTypes[uiType])
{
case X_D3DVSDT_NORMPACKED3: // 0x16:
{
DWORD dwPacked = ((DWORD *)&pOrigData[uiVertex * uiStride + dwPosOrig])[0];
((FLOAT *)pNewDataPos)[0] = ((FLOAT)(dwPacked & 0x7ff)) / 1023.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((dwPacked >> 11) & 0x7ff)) / 1023.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((dwPacked >> 22) & 0x3ff)) / 511.0f;
dwPosOrig += sizeof(DWORD);
case X_D3DVSDT_NORMPACKED3: { // 0x16: // Make it FLOAT3
// Hit by Dashboard
int32 iPacked = ((int32 *)pOrigVertex)[0];
// Cxbx note : to make each component signed, two need to be shifted towards the sign-bit first :
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((iPacked << 21) >> 21)) / 1023.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((iPacked << 10) >> 21)) / 1023.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((iPacked ) >> 22)) / 511.0f;
pOrigVertex += 1 * sizeof(int32);
break;
}
case X_D3DVSDT_SHORT1: // 0x15:
// Make it a SHORT2
((SHORT *)pNewDataPos)[0] = *(SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig];
case X_D3DVSDT_SHORT1: { // 0x15: // Make it SHORT2 and set the second short to 0
((SHORT *)pNewDataPos)[0] = ((SHORT*)pOrigVertex)[0];
((SHORT *)pNewDataPos)[1] = 0x00;
dwPosOrig += 1 * sizeof(SHORT);
pOrigVertex += 1 * sizeof(SHORT);
break;
case X_D3DVSDT_SHORT3: // 0x35:
memcpy(pNewDataPos,
&pOrigData[uiVertex * uiStride + dwPosOrig],
3 * sizeof(SHORT));
// Make it a SHORT4 and set the last short to 1
//(*((SHORT *)&pNewData[uiVertex * pStreamPatch->ConvertedStride + dwPosNew + 3 * sizeof(SHORT)])) = 0x01;
}
case X_D3DVSDT_SHORT3: { // 0x35: // Make it a SHORT4 and set the fourth short to 1
// Hit by Turok
memcpy(pNewDataPos, pOrigVertex, 3 * sizeof(SHORT));
((SHORT *)pNewDataPos)[3] = 0x01;
dwPosOrig += 3 * sizeof(SHORT);
pOrigVertex += 3 * sizeof(SHORT);
break;
case X_D3DVSDT_PBYTE1: // 0x14:
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0]) / 255.0f;
dwPosOrig += 1 * sizeof(BYTE);
}
case X_D3DVSDT_PBYTE1: { // 0x14: // Make it FLOAT1
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((BYTE*)pOrigVertex)[0]) / 255.0f;
pOrigVertex += 1 * sizeof(BYTE);
break;
case X_D3DVSDT_PBYTE2: // 0x24:
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0]) / 255.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[1]) / 255.0f;
dwPosOrig += 2 * sizeof(BYTE);
}
case X_D3DVSDT_PBYTE2: { // 0x24: // Make it FLOAT2
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((BYTE*)pOrigVertex)[0]) / 255.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((BYTE*)pOrigVertex)[1]) / 255.0f;
pOrigVertex += 2 * sizeof(BYTE);
break;
case X_D3DVSDT_PBYTE3: // 0x34:
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0]) / 255.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[1]) / 255.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[2]) / 255.0f;
dwPosOrig += 3 * sizeof(BYTE);
}
case X_D3DVSDT_PBYTE3: { // 0x34: // Make it FLOAT3
// Hit by Turok
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((BYTE*)pOrigVertex)[0]) / 255.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((BYTE*)pOrigVertex)[1]) / 255.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((BYTE*)pOrigVertex)[2]) / 255.0f;
pOrigVertex += 3 * sizeof(BYTE);
break;
case X_D3DVSDT_PBYTE4: // 0x44:
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0]) / 255.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[1]) / 255.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[2]) / 255.0f;
((FLOAT *)pNewDataPos)[3] = ((FLOAT)((BYTE*)&pOrigData[uiVertex * uiStride + dwPosOrig])[3]) / 255.0f;
dwPosOrig += 4 * sizeof(BYTE);
}
case X_D3DVSDT_PBYTE4: { // 0x44: // Make it FLOAT4
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((BYTE*)pOrigVertex)[0]) / 255.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((BYTE*)pOrigVertex)[1]) / 255.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((BYTE*)pOrigVertex)[2]) / 255.0f;
((FLOAT *)pNewDataPos)[3] = ((FLOAT)((BYTE*)pOrigVertex)[3]) / 255.0f;
pOrigVertex += 4 * sizeof(BYTE);
break;
case X_D3DVSDT_NORMSHORT1: // 0x11:
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0]) / 32767.0f;
dwPosOrig += 1 * sizeof(SHORT);
}
case X_D3DVSDT_NORMSHORT1: { // 0x11: // Make it FLOAT1
// UNTESTED - Need test-case!
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((SHORT*)pOrigVertex)[0]) / 32767.0f;
pOrigVertex += 1 * sizeof(SHORT);
break;
case X_D3DVSDT_NORMSHORT2: // 0x21:
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0]) / 32767.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[1]) / 32767.0f;
dwPosOrig += 2 * sizeof(SHORT);
}
case X_D3DVSDT_NORMSHORT2: { // 0x21: // Make it FLOAT2
// UNTESTED - Need test-case!
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((SHORT*)pOrigVertex)[0]) / 32767.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((SHORT*)pOrigVertex)[1]) / 32767.0f;
pOrigVertex += 2 * sizeof(SHORT);
break;
case X_D3DVSDT_NORMSHORT3: // 0x31:
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0]) / 32767.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[1]) / 32767.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[2]) / 32767.0f;
dwPosOrig += 3 * sizeof(SHORT);
}
case X_D3DVSDT_NORMSHORT3: { // 0x31: // Make it FLOAT3
// UNTESTED - Need test-case!
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((SHORT*)pOrigVertex)[0]) / 32767.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((SHORT*)pOrigVertex)[1]) / 32767.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((SHORT*)pOrigVertex)[2]) / 32767.0f;
pOrigVertex += 3 * sizeof(SHORT);
break;
case X_D3DVSDT_NORMSHORT4: // 0x41:
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0]) / 32767.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[1]) / 32767.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[2]) / 32767.0f;
((FLOAT *)pNewDataPos)[3] = ((FLOAT)((SHORT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[3]) / 32767.0f;
dwPosOrig += 4 * sizeof(SHORT);
}
case X_D3DVSDT_NORMSHORT4: { // 0x41: // Make it FLOAT4
// UNTESTED - Need test-case!
((FLOAT *)pNewDataPos)[0] = ((FLOAT)((SHORT*)pOrigVertex)[0]) / 32767.0f;
((FLOAT *)pNewDataPos)[1] = ((FLOAT)((SHORT*)pOrigVertex)[1]) / 32767.0f;
((FLOAT *)pNewDataPos)[2] = ((FLOAT)((SHORT*)pOrigVertex)[2]) / 32767.0f;
((FLOAT *)pNewDataPos)[3] = ((FLOAT)((SHORT*)pOrigVertex)[3]) / 32767.0f;
pOrigVertex += 4 * sizeof(SHORT);
break;
case X_D3DVSDT_FLOAT2H: // 0x72:
((FLOAT *)pNewDataPos)[0] = ((FLOAT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[0];
((FLOAT *)pNewDataPos)[1] = ((FLOAT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[1];
}
case X_D3DVSDT_FLOAT2H: { // 0x72: // Make it FLOAT4 and set the third float to 0.0
((FLOAT *)pNewDataPos)[0] = ((FLOAT*)pOrigVertex)[0];
((FLOAT *)pNewDataPos)[1] = ((FLOAT*)pOrigVertex)[1];
((FLOAT *)pNewDataPos)[2] = 0.0f;
((FLOAT *)pNewDataPos)[3] = ((FLOAT*)&pOrigData[uiVertex * uiStride + dwPosOrig])[2];
((FLOAT *)pNewDataPos)[3] = ((FLOAT*)pOrigVertex)[2];
pOrigVertex += 3 * sizeof(FLOAT);
break;
/*TODO
case X_D3DVSDT_NONE: // 0x02:
printf("D3DVSDT_NONE / xbox ext. nsp /");
dwNewDataType = 0xFF;
break;
*/
default:
}
/*TODO
case X_D3DVSDT_NONE: { // 0x02:
printf("D3DVSDT_NONE / xbox ext. nsp /");
dwNewDataType = 0xFF;
break;
}
*/
default: {
// Generic 'conversion' - just make a copy :
memcpy(pNewDataPos,
&pOrigData[uiVertex * uiStride + dwPosOrig],
pStreamPatch->pSizes[uiType]);
dwPosOrig += pStreamPatch->pSizes[uiType];
memcpy(pNewDataPos, pOrigVertex, pStreamPatch->pSizes[uiType]);
pOrigVertex += pStreamPatch->pSizes[uiType];
break;
}
} // switch
// Increment the new pointer :
pNewDataPos += pStreamPatch->pSizes[uiType];
}
}
if(!pPatchDesc->pVertexStreamZeroData)
{
//if(pNewVertexBuffer != nullptr) // Dxbx addition
@ -651,6 +649,7 @@ bool XTL::VertexPatcher::PatchStream(VertexPatchDesc *pPatchDesc,
m_pNewVertexStreamZeroData = pNewData;
}
}
pStream->uiOrigStride = uiStride;
pStream->uiNewStride = pStreamPatch->ConvertedStride;
m_bPatched = true;

View File

@ -1551,22 +1551,22 @@ DWORD Xb2PCRegisterType(DWORD VertexRegister)
static inline DWORD VshGetTokenType(DWORD Token)
{
return (Token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT;
return (Token & X_D3DVSD_TOKENTYPEMASK) >> X_D3DVSD_TOKENTYPESHIFT;
}
static inline DWORD VshGetVertexRegister(DWORD Token)
{
return (Token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT;
return (Token & X_D3DVSD_VERTEXREGMASK) >> X_D3DVSD_VERTEXREGSHIFT;
}
static inline DWORD VshGetVertexRegisterIn(DWORD Token)
{
return (Token & D3DVSD_VERTEXREGINMASK) >> D3DVSD_VERTEXREGINSHIFT;
return (Token & X_D3DVSD_VERTEXREGINMASK) >> X_D3DVSD_VERTEXREGINSHIFT;
}
static inline DWORD VshGetVertexStream(DWORD Token)
{
return (Token & D3DVSD_STREAMNUMBERMASK) >> D3DVSD_STREAMNUMBERSHIFT;
return (Token & X_D3DVSD_STREAMNUMBERMASK) >> X_D3DVSD_STREAMNUMBERSHIFT;
}
static void VshConvertToken_NOP(DWORD *pToken)
@ -1584,8 +1584,8 @@ static DWORD VshConvertToken_CONSTMEM(DWORD *pToken)
// D3DVSD_CONST
DbgVshPrintf("\tD3DVSD_CONST(");
DWORD ConstantAddress = ((*pToken >> D3DVSD_CONSTADDRESSSHIFT) & 0xFF);
DWORD Count = (*pToken & D3DVSD_CONSTCOUNTMASK) >> D3DVSD_CONSTCOUNTSHIFT;
DWORD ConstantAddress = (*pToken & X_D3DVSD_CONSTADDRESSMASK) >> X_D3DVSD_CONSTADDRESSSHIFT;
DWORD Count = (*pToken & X_D3DVSD_CONSTCOUNTMASK) >> X_D3DVSD_CONSTCOUNTSHIFT;
DbgVshPrintf("%d, %d),\n", ConstantAddress, Count);
@ -1717,7 +1717,7 @@ static void VshConvertToken_STREAMDATA_SKIP(DWORD *pToken)
{
using namespace XTL;
XTL::DWORD SkipCount = (*pToken & D3DVSD_SKIPCOUNTMASK) >> D3DVSD_SKIPCOUNTSHIFT;
XTL::DWORD SkipCount = (*pToken & X_D3DVSD_SKIPCOUNTMASK) >> X_D3DVSD_SKIPCOUNTSHIFT;
DbgVshPrintf("\tD3DVSD_SKIP(%d),\n", SkipCount);
}
@ -1725,7 +1725,7 @@ static void VshConvertToken_STREAMDATA_SKIPBYTES(DWORD *pToken)
{
using namespace XTL;
XTL::DWORD SkipBytesCount = (*pToken & D3DVSD_SKIPCOUNTMASK) >> D3DVSD_SKIPCOUNTSHIFT;
XTL::DWORD SkipBytesCount = (*pToken & X_D3DVSD_SKIPCOUNTMASK) >> X_D3DVSD_SKIPCOUNTSHIFT;
DbgVshPrintf("\tD3DVSD_SKIPBYTES(%d), /* xbox ext. */\n", SkipBytesCount);
if(SkipBytesCount % sizeof(XTL::DWORD))
{
@ -1757,7 +1757,7 @@ static void VshConvertToken_STREAMDATA_REG(DWORD *pToken,
DbgVshPrintf(", ");
XTL::DWORD DataType = (*pToken >> D3DVSD_DATATYPESHIFT) & 0xFF;
XTL::DWORD DataType = (*pToken & X_D3DVSD_DATATYPEMASK) >> X_D3DVSD_DATATYPESHIFT;
XTL::DWORD NewDataType = 0;
XTL::DWORD NewSize = 0;
@ -1800,31 +1800,31 @@ static void VshConvertToken_STREAMDATA_REG(DWORD *pToken,
break;
case X_D3DVSDT_NORMSHORT1: // 0x11:
DbgVshPrintf("D3DVSDT_NORMSHORT1 /* xbox ext. */");
NewDataType = D3DVSDT_SHORT2; // hmm, emulation?
NewSize = 2*sizeof(XTL::SHORT);
NewDataType = D3DVSDT_FLOAT1;
NewSize = sizeof(FLOAT);
pPatchData->NeedPatching = TRUE;
break;
case X_D3DVSDT_NORMSHORT2: // 0x21:
DbgVshPrintf("D3DVSDT_NORMSHORT2 /* xbox ext. */");
NewDataType = D3DVSDT_SHORT2;
NewSize = 2*sizeof(XTL::SHORT);
NewDataType = D3DVSDT_FLOAT2;
NewSize = 2*sizeof(FLOAT);
pPatchData->NeedPatching = TRUE;
break;
case X_D3DVSDT_NORMSHORT3: // 0x31:
DbgVshPrintf("D3DVSDT_NORMSHORT3 /* xbox ext. nsp */");
NewDataType = D3DVSDT_SHORT4;
NewSize = 4*sizeof(XTL::SHORT);
NewDataType = D3DVSDT_FLOAT3;
NewSize = 3*sizeof(FLOAT);
pPatchData->NeedPatching = TRUE;
break;
case X_D3DVSDT_NORMSHORT4: // 0x41:
DbgVshPrintf("D3DVSDT_NORMSHORT4 /* xbox ext. */");
NewDataType = D3DVSDT_SHORT4;
NewSize = 4*sizeof(XTL::SHORT);
NewDataType = D3DVSDT_FLOAT4;
NewSize = 4*sizeof(FLOAT);
pPatchData->NeedPatching = TRUE;
break;
case X_D3DVSDT_NORMPACKED3: // 0x16:
DbgVshPrintf("D3DVSDT_NORMPACKED3 /* xbox ext. nsp */");
NewDataType = D3DVSDT_FLOAT3;//0xFF; //32bit
NewDataType = D3DVSDT_FLOAT3;
NewSize = 3*sizeof(FLOAT);
pPatchData->NeedPatching = TRUE;
break;
@ -1837,7 +1837,7 @@ static void VshConvertToken_STREAMDATA_REG(DWORD *pToken,
case X_D3DVSDT_SHORT3: // 0x35:
DbgVshPrintf("D3DVSDT_SHORT3 /* xbox ext. nsp */");
NewDataType = D3DVSDT_SHORT4;
NewSize = 4 * sizeof(XTL::SHORT);
NewSize = 4*sizeof(XTL::SHORT);
pPatchData->NeedPatching = TRUE;
break;
case X_D3DVSDT_PBYTE1: // 0x14:
@ -1858,11 +1858,12 @@ static void VshConvertToken_STREAMDATA_REG(DWORD *pToken,
NewSize = 3*sizeof(FLOAT);
pPatchData->NeedPatching = TRUE;
break;
case X_D3DVSDT_PBYTE4: // 0x44:
case X_D3DVSDT_PBYTE4: // 0x44: // Hit by Panzer
DbgVshPrintf("D3DVSDT_PBYTE4 /* xbox ext. */");
NewDataType = D3DVSDT_FLOAT4;
NewSize = 4*sizeof(FLOAT);
break;
pPatchData->NeedPatching = TRUE;
break;
case X_D3DVSDT_FLOAT2H: // 0x72:
DbgVshPrintf("D3DVSDT_FLOAT2H /* xbox ext. */");
NewDataType = D3DVSDT_FLOAT3;

View File

@ -722,4 +722,40 @@ const int X_D3DVSDT_NONE = 0x02; // xbox ext. nsp
const int MAX_NBR_STREAMS = 16;
#define X_D3DVSD_TOKENTYPESHIFT 29
#define X_D3DVSD_TOKENTYPEMASK (7 << X_D3DVSD_TOKENTYPESHIFT)
#define X_D3DVSD_STREAMNUMBERSHIFT 0
#define X_D3DVSD_STREAMNUMBERMASK (0xF << X_D3DVSD_STREAMNUMBERSHIFT)
#define X_D3DVSD_DATALOADTYPESHIFT 28
#define X_D3DVSD_DATALOADTYPEMASK (0x1 << X_D3DVSD_DATALOADTYPESHIFT)
#define X_D3DVSD_DATATYPESHIFT 16
#define X_D3DVSD_DATATYPEMASK (0xFF << X_D3DVSD_DATATYPESHIFT)
#define X_D3DVSD_SKIPCOUNTSHIFT 16
#define X_D3DVSD_SKIPCOUNTMASK (0xF << X_D3DVSD_SKIPCOUNTSHIFT)
#define X_D3DVSD_VERTEXREGSHIFT 0
#define X_D3DVSD_VERTEXREGMASK (0x1F << X_D3DVSD_VERTEXREGSHIFT)
#define X_D3DVSD_VERTEXREGINSHIFT 20
#define X_D3DVSD_VERTEXREGINMASK (0xF << X_D3DVSD_VERTEXREGINSHIFT)
#define X_D3DVSD_CONSTCOUNTSHIFT 25
#define X_D3DVSD_CONSTCOUNTMASK (0xF << X_D3DVSD_CONSTCOUNTSHIFT)
#define X_D3DVSD_CONSTADDRESSSHIFT 0
#define X_D3DVSD_CONSTADDRESSMASK (0xFF << X_D3DVSD_CONSTADDRESSSHIFT)
#define X_D3DVSD_CONSTRSSHIFT 16
#define X_D3DVSD_CONSTRSMASK (0x1FFF << X_D3DVSD_CONSTRSSHIFT)
#define X_D3DVSD_EXTCOUNTSHIFT 24
#define X_D3DVSD_EXTCOUNTMASK (0x1F << X_D3DVSD_EXTCOUNTSHIFT)
#define X_D3DVSD_EXTINFOSHIFT 0
#define X_D3DVSD_EXTINFOMASK (0xFFFFFF << X_D3DVSD_EXTINFOSHIFT)
#endif

View File

@ -42,6 +42,7 @@ namespace xboxkrnl
#include <xboxkrnl/xboxkrnl.h>
};
#include "EmuKrnl.h" // For InitializeListHead(), etc.
#include "EmuFS.h"
#include "EmuAlloc.h" // For CxbxCalloc()
#include "CxbxKrnl.h"
@ -51,193 +52,228 @@ namespace xboxkrnl
#include <windows.h>
#include <cstdio>
__declspec(naked) void EmuCmpEsiFs00()
NT_TIB *GetNtTib()
{
NT_TIB *NtTib;
__asm
{
mov eax, fs : [TIB_LinearSelfAddress]
mov NtTib, eax
}
return NtTib;
}
void EmuKeSetPcr(xboxkrnl::KPCR *Pcr)
{
// Store the Xbox KPCR pointer in FS (See KeGetPcr())
//
// Note : Cxbx currently doesn't do preemptive thread switching,
// which implies that thread-state management is done by Windows.
//
// Xbox executable code expects thread-specific state data to
// be available via the FS segment register. To emulate this,
// Cxbx uses the user data-slot feature of Windows threads.
//
// Cxbx puts a pointer to a thread-specific copy of an entire
// Kernel Processor Control Region (KPCR) into this data-slot.
//
// In the Xbox there's only be KPCR (as it's a per-processor-
// structure, and the Xbox has only one processor).
//
// Since Cxbx doesn't control thread-swiches (yet), each thread
// must have a thread-specific copy of the KPCR, to contain all
// thread-specific data that can be reached via this structure
// (like the NT_TIB structure and ETHREAD CurrentThread pointer).
//
// For this to work, Cxbx patches all executable code accessing
// the FS segment register, so that the KPCR is accessed via
// the user data-slot of each Windows thread Cxbx uses for an
// Xbox thread.
//
__asm {
mov eax, Pcr
mov fs : [TIB_ArbitraryDataSlot], eax
}
}
__declspec(naked) void EmuFS_CmpEsiFs00()
{
// Note : eax must be preserved here, hence the push/pop
__asm
{
push eax
mov eax, fs : [0x14]
mov eax, fs : [TIB_ArbitraryDataSlot]
cmp esi, [eax]
pop eax
ret
}
}
__declspec(naked) void EmuMEaxFs00()
__declspec(naked) void EmuFS_MovEaxFs00()
{
__asm
{
mov eax, fs : [0x14]
mov eax, fs : [TIB_ArbitraryDataSlot]
mov eax, [eax]
ret
ret
}
}
__declspec(naked) void EmuMEaxFs20()
__declspec(naked) void EmuFS_MovEaxFs20()
{
__asm
{
mov eax, fs : [0x14]
mov eax, fs : [TIB_ArbitraryDataSlot]
mov eax, [eax + 20h]
ret
ret
}
}
__declspec(naked) void EmuMEaxFs28()
__declspec(naked) void EmuFS_MovEaxFs28()
{
__asm
{
mov eax, fs : [0x14]
mov eax, fs : [TIB_ArbitraryDataSlot]
mov eax, [eax + 28h]
ret
ret
}
}
__declspec(naked) void EmuMEaxFs58()
__declspec(naked) void EmuFS_MovEaxFs58()
{
__asm
{
mov eax, fs : [0x14]
mov eax, fs : [TIB_ArbitraryDataSlot]
mov eax, [eax + 58h]
ret
ret
}
}
__declspec(naked) void EmuMEbxFs00()
__declspec(naked) void EmuFS_MovEbxFs00()
{
__asm
{
mov ebx, fs : [0x14]
mov ebx, fs : [TIB_ArbitraryDataSlot]
mov ebx, [ebx]
ret
ret
}
}
__declspec(naked) void EmuMEcxFs00()
__declspec(naked) void EmuFS_MovEcxFs00()
{
__asm
{
mov ecx, fs : [0x14]
mov ecx, fs : [TIB_ArbitraryDataSlot]
mov ecx, [ecx]
ret
ret
}
}
__declspec(naked) void EmuMEcxFs04()
__declspec(naked) void EmuFS_MovEcxFs04()
{
__asm
{
mov ecx, fs : [0x14]
mov ecx, fs : [TIB_ArbitraryDataSlot]
mov ecx, [ecx + 04h]
ret
ret
}
}
__declspec(naked) void EmuMEdiFs00()
__declspec(naked) void EmuFS_MovEdiFs00()
{
__asm
{
mov edi, fs : [0x14]
mov edi, fs : [TIB_ArbitraryDataSlot]
mov edi, [edi]
ret
ret
}
}
__declspec(naked) void EmuMEdiFs04()
__declspec(naked) void EmuFS_MovEdiFs04()
{
__asm
{
mov edi, fs : [0x14]
mov edi, fs : [TIB_ArbitraryDataSlot]
mov edi, [edi + 04h]
ret
ret
}
}
__declspec(naked) void EmuMEsiFs00()
__declspec(naked) void EmuFS_MovEsiFs00()
{
__asm
{
mov esi, fs : [0x14]
mov esi, fs : [TIB_ArbitraryDataSlot]
mov esi, [esi]
ret
ret
}
}
__declspec(naked) void EmuMzxEaxBytePtrFs24()
__declspec(naked) void EmuFS_MovzxEaxBytePtrFs24()
{
__asm
{
mov eax, fs : [0x14]
mov eax, fs : [TIB_ArbitraryDataSlot]
movzx eax, byte ptr[eax + 24h]
ret
ret
}
}
__declspec(naked) void EmuMFs00Eax()
__declspec(naked) void EmuFS_MovFs00Eax()
{
// Note : ebx must be preserved here, hence the push/pop
__asm
{
push ebx
mov ebx, fs : [0x14]
mov[ebx], eax
pop ebx
ret
mov ebx, fs : [TIB_ArbitraryDataSlot]
mov [ebx], eax
pop ebx
ret
}
}
__declspec(naked) void EmuMFs00Ebx()
__declspec(naked) void EmuFS_MovFs00Ebx()
{
// Note : eax must be preserved here, hence the push/pop
__asm
{
push eax
mov eax, fs : [0x14]
mov[eax], ebx
pop eax
ret
mov eax, fs : [TIB_ArbitraryDataSlot]
mov [eax], ebx
pop eax
ret
}
}
__declspec(naked) void EmuMFs00Ecx()
__declspec(naked) void EmuFS_MovFs00Ecx()
{
// Note : eax must be preserved here, hence the push/pop
__asm
{
push eax
mov eax, fs : [0x14]
mov[eax], ecx
pop eax
ret
mov eax, fs : [TIB_ArbitraryDataSlot]
mov [eax], ecx
pop eax
ret
}
}
__declspec(naked) void EmuMFs00Esp()
__declspec(naked) void EmuFS_MovFs00Esp()
{
// Note : eax must be preserved here, hence the push/pop
__asm
{
push eax
mov eax, fs : [0x14]
mov[eax], esp
pop eax
ret
mov eax, fs : [TIB_ArbitraryDataSlot]
mov [eax], esp
pop eax
ret
}
}
__declspec(naked) void EmuPushDwordPtrFs00()
{
uint32 returnAddr;
uint32 temp;
__asm
{
pop returnAddr
mov temp, eax
mov eax, fs : [0x14]
push[eax]
mov eax, temp
push returnAddr
ret
}
}
__declspec(naked) void EmuPopDwordPtrFs00()
__declspec(naked) void EmuFS_PushDwordPtrFs00()
{
uint32 returnAddr;
uint32 temp;
@ -246,11 +282,28 @@ __declspec(naked) void EmuPopDwordPtrFs00()
{
pop returnAddr
mov temp, eax
mov eax, fs : [0x14]
pop[eax]
mov eax, temp
push returnAddr
ret
mov eax, fs : [TIB_ArbitraryDataSlot]
push [eax]
mov eax, temp
push returnAddr
ret
}
}
__declspec(naked) void EmuFS_PopDwordPtrFs00()
{
uint32 returnAddr;
uint32 temp;
__asm
{
pop returnAddr
mov temp, eax
mov eax, fs : [TIB_ArbitraryDataSlot]
pop [eax]
mov eax, temp
push returnAddr
ret
}
}
@ -262,24 +315,24 @@ void EmuInitFS()
* The entries must be in order of size, to keep the chance of false positives to a minimum.
*/
std::vector<fs_instruction_t> fsInstructions;
fsInstructions.push_back({ { 0x64, 0x0F, 0xB6, 0x05, 0x24, 0x00, 0x00, 0x00 }, &EmuMzxEaxBytePtrFs24 });// movzx eax, large byte ptr fs:24
fsInstructions.push_back({ { 0x64, 0x3B, 0x35, 0x00, 0x00, 0x00, 0x00 }, &EmuCmpEsiFs00 }); // cmp esi, large fs:0
fsInstructions.push_back({ { 0x64, 0x8B, 0x1D, 0x00, 0x00, 0x00, 0x00 }, &EmuMEbxFs00 }); // mov ebx, large fs:0
fsInstructions.push_back({ { 0x64, 0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00 }, &EmuMEcxFs00 }); // mov ecx, large fs:0
fsInstructions.push_back({ { 0x64, 0x8B, 0x0D, 0x04, 0x00, 0x00, 0x00 }, &EmuMEcxFs04 }); // mov ecx, large fs:4
fsInstructions.push_back({ { 0x64, 0x8B, 0x3D, 0x00, 0x00, 0x00, 0x00 }, &EmuMEdiFs00 }); // mov edi, large fs:0
fsInstructions.push_back({ { 0x64, 0x8B, 0x3D, 0x04, 0x00, 0x00, 0x00 }, &EmuMEdiFs04 }); // mov edi, large fs:4
fsInstructions.push_back({ { 0x64, 0x8B, 0x35, 0x00, 0x00, 0x00, 0x00 }, &EmuMEsiFs00 }); // mov esi, large fs:0
fsInstructions.push_back({ { 0x64, 0x89, 0x1D, 0x00, 0x00, 0x00, 0x00 }, &EmuMFs00Ebx }); // mov large fs:0, ebx
fsInstructions.push_back({ { 0x64, 0x89, 0x0D, 0x00, 0x00, 0x00, 0x00 }, &EmuMFs00Ecx }); // mov large fs:0, ecx
fsInstructions.push_back({ { 0x64, 0x89, 0x25, 0x00, 0x00, 0x00, 0x00 }, &EmuMFs00Esp }); // mov large fs:0, esp
fsInstructions.push_back({ { 0x64, 0x8F, 0x05, 0x00, 0x00, 0x00, 0x00 }, &EmuPopDwordPtrFs00 }); // pop large dword ptr fs:0
fsInstructions.push_back({ { 0x64, 0xFF, 0x35, 0x00, 0x00, 0x00, 0x00 }, &EmuPushDwordPtrFs00 }); // push large dword ptr fs:0
fsInstructions.push_back({ { 0x64, 0xA1, 0x00, 0x00, 0x00, 0x00 }, &EmuMEaxFs00 }); // mov eax, large fs:0
fsInstructions.push_back({ { 0x64, 0xA1, 0x20, 0x00, 0x00, 0x00 }, &EmuMEaxFs20 }); // mov eax, large fs:20
fsInstructions.push_back({ { 0x64, 0xA1, 0x28, 0x00, 0x00, 0x00 }, &EmuMEaxFs28 }); // mov eax, large fs:28
fsInstructions.push_back({ { 0x64, 0xA1, 0x58, 0x00, 0x00, 0x00 }, &EmuMEaxFs58 }); // mov eax, large fs:58
fsInstructions.push_back({ { 0x64, 0xA3, 0x00, 0x00, 0x00, 0x00 }, &EmuMFs00Eax }); // mov large fs:0, eax
fsInstructions.push_back({ { 0x64, 0x0F, 0xB6, 0x05, 0x24, 0x00, 0x00, 0x00 }, &EmuFS_MovzxEaxBytePtrFs24 });// movzx eax, large byte ptr fs:24
fsInstructions.push_back({ { 0x64, 0x3B, 0x35, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_CmpEsiFs00 }); // cmp esi, large fs:0
fsInstructions.push_back({ { 0x64, 0x8B, 0x1D, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovEbxFs00 }); // mov ebx, large fs:0
fsInstructions.push_back({ { 0x64, 0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovEcxFs00 }); // mov ecx, large fs:0
fsInstructions.push_back({ { 0x64, 0x8B, 0x0D, 0x04, 0x00, 0x00, 0x00 }, &EmuFS_MovEcxFs04 }); // mov ecx, large fs:4
fsInstructions.push_back({ { 0x64, 0x8B, 0x3D, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovEdiFs00 }); // mov edi, large fs:0
fsInstructions.push_back({ { 0x64, 0x8B, 0x3D, 0x04, 0x00, 0x00, 0x00 }, &EmuFS_MovEdiFs04 }); // mov edi, large fs:4
fsInstructions.push_back({ { 0x64, 0x8B, 0x35, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovEsiFs00 }); // mov esi, large fs:0
fsInstructions.push_back({ { 0x64, 0x89, 0x1D, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovFs00Ebx }); // mov large fs:0, ebx
fsInstructions.push_back({ { 0x64, 0x89, 0x0D, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovFs00Ecx }); // mov large fs:0, ecx
fsInstructions.push_back({ { 0x64, 0x89, 0x25, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovFs00Esp }); // mov large fs:0, esp
fsInstructions.push_back({ { 0x64, 0x8F, 0x05, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_PopDwordPtrFs00 }); // pop large dword ptr fs:0
fsInstructions.push_back({ { 0x64, 0xFF, 0x35, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_PushDwordPtrFs00 }); // push large dword ptr fs:0
fsInstructions.push_back({ { 0x64, 0xA1, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovEaxFs00 }); // mov eax, large fs:0
fsInstructions.push_back({ { 0x64, 0xA1, 0x20, 0x00, 0x00, 0x00 }, &EmuFS_MovEaxFs20 }); // mov eax, large fs:20
fsInstructions.push_back({ { 0x64, 0xA1, 0x28, 0x00, 0x00, 0x00 }, &EmuFS_MovEaxFs28 }); // mov eax, large fs:28
fsInstructions.push_back({ { 0x64, 0xA1, 0x58, 0x00, 0x00, 0x00 }, &EmuFS_MovEaxFs58 }); // mov eax, large fs:58
fsInstructions.push_back({ { 0x64, 0xA3, 0x00, 0x00, 0x00, 0x00 }, &EmuFS_MovFs00Eax }); // mov large fs:0, eax
DbgPrintf("Patching FS Register Accesses\n");
DWORD sizeOfImage = CxbxKrnl_XbeHeader->dwSizeofImage;
@ -335,103 +388,105 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData)
return;
}
NT_TIB *OrgNtTib;
xboxkrnl::KPCR *NewPcr;
uint08 *pNewTLS = NULL;
uint16 NewFS = -1, OrgFS = -1;
void *pNewTLS = nullptr;
// copy global TLS to the current thread
{
uint32 dwCopySize = pTLS->dwDataEndAddr - pTLS->dwDataStartAddr;
uint32 dwZeroSize = pTLS->dwSizeofZeroFill;
pNewTLS = (uint08*)CxbxCalloc(1, dwCopySize + dwZeroSize + 0x100 /* + HACK: extra safety padding 0x100*/);
pNewTLS = CxbxCalloc(1, dwCopySize + dwZeroSize + 0x100 /* + HACK: extra safety padding 0x100*/);
memcpy(pNewTLS, pTLSData, dwCopySize);
}
// dump raw TLS data
{
#ifdef _DEBUG_TRACE
if (pNewTLS == 0)
{
// dump raw TLS data
if (pNewTLS == nullptr)
DbgPrintf("EmuFS: TLS Non-Existant (OK)\n");
}
else
{
DbgPrintf("EmuFS: TLS Data Dump...\n");
DbgPrintf("EmuFS: 0x%.08X: ", pNewTLS);
uint32 stop = pTLS->dwDataEndAddr - pTLS->dwDataStartAddr + pTLS->dwSizeofZeroFill;
// Note : Use printf instead of DbgPrintf here, which prefixes with GetCurrentThreadId() :
for (uint32 v = 0;v<stop;v++)
if (g_bPrintfOn)
{
uint08 *bByte = (uint08*)pNewTLS + v;
for (uint32 v = 0; v < dwCopySize; v++) // Note : Don't dump dwZeroSize
{
uint08 *bByte = (uint08*)pNewTLS + v;
if (g_bPrintfOn) printf("%.01X", (uint32)*bByte);
if (v % 0x10 == 0)
DbgPrintf("EmuFS: 0x%.08X: ", (xbaddr)bByte);
if ((v + 1) % 0x10 == 0 && v + 1<stop)
if (g_bPrintfOn) printf("\nEmuFS (0x%X): 0x%.08X: ", GetCurrentThreadId(), ((uint32)pNewTLS + v));
// Note : Use printf instead of DbgPrintf here, which prefixes with GetCurrentThreadId() :
printf("%.01X", (uint32)(*bByte));
}
printf("\n");
}
if (g_bPrintfOn) printf("\n");
}
#endif
}
__asm
{
// Obtain "OrgFS"
mov ax, fs
mov OrgFS, ax
// Obtain "OrgNtTib"
mov eax, fs:[0x18]
mov OrgNtTib, eax
}
// allocate KPCR structure
{
uint32 dwSize = sizeof(xboxkrnl::KPCR);
NewPcr = (xboxkrnl::KPCR*)CxbxCalloc(1, dwSize);
}
// generate TIB
xboxkrnl::ETHREAD *EThread = (xboxkrnl::ETHREAD*)CxbxCalloc(1, sizeof(xboxkrnl::ETHREAD)); // Clear, to prevent side-effects on random contents
EThread->Tcb.TlsData = (void*)pNewTLS;
EThread->UniqueThread = GetCurrentThreadId();
memcpy(&NewPcr->NtTib, OrgNtTib, sizeof(NT_TIB));
NewPcr->NtTib.Self = &NewPcr->NtTib;
NewPcr->PrcbData.CurrentThread = (xboxkrnl::KTHREAD*)EThread;
NewPcr->Prcb = &NewPcr->PrcbData;
// Set the stack base
NewPcr->NtTib.StackBase = pNewTLS;
// prepare TLS
{
// TLS Index Address := 0
*(uint32*)pTLS->dwTLSIndexAddr = 0;
*(xbaddr*)pTLS->dwTLSIndexAddr = (xbaddr)nullptr;
// dword @ pTLSData := pTLSData
if (pNewTLS != 0)
if (pNewTLS != nullptr)
*(void**)pNewTLS = pNewTLS;
}
// Store the new KPCR pointer in FS
__asm {
mov eax, NewPcr
mov fs : [0x14], eax
// Allocate the xbox KPCR structure
xboxkrnl::KPCR *NewPcr = (xboxkrnl::KPCR*)CxbxCalloc(1, sizeof(xboxkrnl::KPCR));
xboxkrnl::NT_TIB *XbTib = &(NewPcr->NtTib);
xboxkrnl::PKPRCB Prcb = &(NewPcr->PrcbData);
// Note : As explained above (at EmuKeSetPcr), Cxbx cannot allocate one NT_TIB and KPRCB
// structure per thread, since Cxbx currently doesn't do thread-switching.
// Thus, the only way to give each thread it's own PrcbData.CurrentThread, is to put the
// KPCR pointer in the TIB_ArbitraryDataSlot, which is read by the above EmuFS_* patches.
//
// Once we simulate thread switching ourselves, we can update PrcbData.CurrentThread
// and simplify this initialization, by using only one KPCR for the single Xbox processor.
//
// One way to do our own (preemprive) thread-switching would be to use this technique :
// http://www.eran.io/implementing-a-preemptive-kernel-within-a-single-windows-thread/
// See https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/146 for more info.
// Copy the Nt TIB over to the emulated TIB :
{
memcpy(XbTib, GetNtTib(), sizeof(NT_TIB));
// Fixup the TIB self pointer :
NewPcr->NtTib.Self = XbTib;
// Set the stack base - TODO : Verify this, doesn't look right?
NewPcr->NtTib.StackBase = pNewTLS;
}
DbgPrintf("EmuFS: OrgFS=%d NewFS=%d pTLS=0x%.08X\n", OrgFS, NewFS, pTLS);
// Set flat address of this PCR
NewPcr->SelfPcr = NewPcr;
// Set pointer to Prcb
NewPcr->Prcb = Prcb;
// Initialize the prcb :
{
// TODO : Once we do our own thread-switching (as mentioned above),
// we can also start using Prcb->DpcListHead instead of DpcQueue :
InitializeListHead(&(Prcb->DpcListHead));
Prcb->DpcRoutineActive = 0;
// TODO : Should Irql be set? And if so, to what - PASSIVE_LEVEL, or perhaps better : APC_LEVEL?
// NewPcr->Irql = PASSIVE_LEVEL; // See KeLowerIrql;
}
// Initialize a fake PrcbData.CurrentThread
{
xboxkrnl::ETHREAD *EThread = (xboxkrnl::ETHREAD*)CxbxCalloc(1, sizeof(xboxkrnl::ETHREAD)); // Clear, to prevent side-effects on random contents
EThread->Tcb.TlsData = pNewTLS;
EThread->UniqueThread = GetCurrentThreadId();
// Set PrcbData.CurrentThread
Prcb->CurrentThread = (xboxkrnl::KTHREAD*)EThread;
}
// Make the KPCR struct available to KeGetPcr()
EmuKeSetPcr(NewPcr);
DbgPrintf("EmuFS: Installed KPCR in TIB_ArbitraryDataSlot (with pTLS = 0x%.08X)\n", pTLS);
}

View File

@ -57,6 +57,72 @@ namespace NtDll
#include "EmuNtDll.h"
};
// See also :
// https://github.com/reactos/reactos/blob/40a16a9cf1cdfca399e9154b42d32c30b63480f5/reactos/drivers/filesystems/udfs/Include/env_spec_w32.h
void InitializeListHead(xboxkrnl::PLIST_ENTRY pListHead)
{
pListHead->Flink = pListHead->Blink = pListHead;
}
bool IsListEmpty(xboxkrnl::PLIST_ENTRY pListHead)
{
return (pListHead->Flink == pListHead);
}
void InsertHeadList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntry)
{
xboxkrnl::PLIST_ENTRY _EX_ListHead = pListHead;
xboxkrnl::PLIST_ENTRY _EX_Flink = _EX_ListHead->Flink;
pEntry->Flink = _EX_Flink;
pEntry->Blink = _EX_ListHead;
_EX_Flink->Blink = pEntry;
_EX_ListHead->Flink = pEntry;
}
void InsertTailList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntry)
{
xboxkrnl::PLIST_ENTRY _EX_ListHead = pListHead;
xboxkrnl::PLIST_ENTRY _EX_Blink = _EX_ListHead->Blink;
pEntry->Flink = _EX_ListHead;
pEntry->Blink = _EX_Blink;
_EX_Blink->Flink = pEntry;
_EX_ListHead->Blink = pEntry;
}
//#define RemoveEntryList(e) do { PLIST_ENTRY f = (e)->Flink, b = (e)->Blink; f->Blink = b; b->Flink = f; (e)->Flink = (e)->Blink = NULL; } while (0)
void RemoveEntryList(xboxkrnl::PLIST_ENTRY pEntry)
{
xboxkrnl::PLIST_ENTRY _EX_Flink = pEntry->Flink;
xboxkrnl::PLIST_ENTRY _EX_Blink = pEntry->Blink;
if (_EX_Flink != nullptr) {
_EX_Blink->Flink = _EX_Flink;
}
if (_EX_Flink != nullptr) {
_EX_Flink->Blink = _EX_Blink;
}
}
xboxkrnl::PLIST_ENTRY RemoveHeadList(xboxkrnl::PLIST_ENTRY pListHead)
{
xboxkrnl::PLIST_ENTRY Result = pListHead->Flink;
RemoveEntryList(pListHead->Flink);
return Result;
}
xboxkrnl::PLIST_ENTRY RemoveTailList(xboxkrnl::PLIST_ENTRY pListHead)
{
xboxkrnl::PLIST_ENTRY Result = pListHead->Blink;
RemoveEntryList(pListHead->Blink);
return Result;
}
// ******************************************************************
// * Declaring this in a header causes errors with xboxkrnl
// * namespace, so we must declare it within any file that uses it

View File

@ -34,4 +34,23 @@
#ifndef EMUKRNL_H
#define EMUKRNL_H
// CONTAINING_RECORD macro
// Gets the value of structure member (field - num1),given the type(MYSTRUCT, in this code) and the List_Entry head(temp, in this code)
// See http://stackoverflow.com/questions/8240273/a-portable-way-to-calculate-pointer-to-the-whole-structure-using-pointer-to-a-fi
//#define CONTAINING_RECORD(ptr, type, field) \
// (((type) *)((char *)(ptr) - offsetof((type), member)))
#define OBJECT_TO_OBJECT_HEADER(Object) \
CONTAINING_RECORD(Object, OBJECT_HEADER, Body)
void InitializeListHead(xboxkrnl::PLIST_ENTRY pListHead);
bool IsListEmpty(xboxkrnl::PLIST_ENTRY pListHead);
void InsertHeadList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntry);
void InsertTailList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntry);
//#define RemoveEntryList(e) do { PLIST_ENTRY f = (e)->Flink, b = (e)->Blink; f->Blink = b; b->Flink = f; (e)->Flink = (e)->Blink = NULL; } while (0)
void RemoveEntryList(xboxkrnl::PLIST_ENTRY pEntry);
xboxkrnl::PLIST_ENTRY RemoveHeadList(xboxkrnl::PLIST_ENTRY pListHead);
xboxkrnl::PLIST_ENTRY RemoveTailList(xboxkrnl::PLIST_ENTRY pListHead);
#endif

View File

@ -54,87 +54,25 @@ namespace NtDll
#include "CxbxKrnl.h" // For CxbxKrnlCleanup
#include "Emu.h" // For EmuWarning()
#include "EmuKrnl.h" // For InitializeListHead(), etc.
#include "EmuFile.h" // For IsEmuHandle(), NtStatusToString()
#include <chrono>
#include <thread>
// Copied over from Dxbx.
// TODO : Move towards thread-simulation based Dpc emulation
typedef struct _DpcData {
CRITICAL_SECTION Lock;
HANDLE DpcThread;
HANDLE DpcEvent;
xboxkrnl::LIST_ENTRY DpcQueue;
xboxkrnl::LIST_ENTRY DpcQueue; // TODO : Use KeGetCurrentPrcb()->DpcListHead instead
xboxkrnl::LIST_ENTRY TimerQueue;
} DpcData;
DpcData g_DpcData = { 0 }; // TODO : InitializeCriticalSection(Lock)
DpcData g_DpcData = { 0 }; // Note : g_DpcData is initialized in InitDpcAndTimerThread()
// See also :
// https://github.com/reactos/reactos/blob/40a16a9cf1cdfca399e9154b42d32c30b63480f5/reactos/drivers/filesystems/udfs/Include/env_spec_w32.h
void InitializeListHead(xboxkrnl::PLIST_ENTRY pListHead)
{
pListHead->Flink = pListHead->Blink = pListHead;
}
bool IsListEmpty(xboxkrnl::PLIST_ENTRY pListHead)
{
return (pListHead->Flink == pListHead);
}
void InsertHeadList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntry)
{
xboxkrnl::PLIST_ENTRY _EX_ListHead = pListHead;
xboxkrnl::PLIST_ENTRY _EX_Flink = _EX_ListHead->Flink;
pEntry->Flink = _EX_Flink;
pEntry->Blink = _EX_ListHead;
_EX_Flink->Blink = pEntry;
_EX_ListHead->Flink = pEntry;
}
void InsertTailList(xboxkrnl::PLIST_ENTRY pListHead, xboxkrnl::PLIST_ENTRY pEntry)
{
xboxkrnl::PLIST_ENTRY _EX_ListHead = pListHead;
xboxkrnl::PLIST_ENTRY _EX_Blink = _EX_ListHead->Blink;
pEntry->Flink = _EX_ListHead;
pEntry->Blink = _EX_Blink;
_EX_Blink->Flink = pEntry;
_EX_ListHead->Blink = pEntry;
}
//#define RemoveEntryList(e) do { PLIST_ENTRY f = (e)->Flink, b = (e)->Blink; f->Blink = b; b->Flink = f; (e)->Flink = (e)->Blink = NULL; } while (0)
void RemoveEntryList(xboxkrnl::PLIST_ENTRY pEntry)
{
xboxkrnl::PLIST_ENTRY _EX_Flink = pEntry->Flink;
xboxkrnl::PLIST_ENTRY _EX_Blink = pEntry->Blink;
if (_EX_Flink != nullptr) {
_EX_Blink->Flink = _EX_Flink;
}
if (_EX_Flink != nullptr) {
_EX_Flink->Blink = _EX_Blink;
}
}
xboxkrnl::PLIST_ENTRY RemoveHeadList(xboxkrnl::PLIST_ENTRY pListHead)
{
xboxkrnl::PLIST_ENTRY Result = pListHead->Flink;
RemoveEntryList(pListHead->Flink);
return Result;
}
xboxkrnl::PLIST_ENTRY RemoveTailList(xboxkrnl::PLIST_ENTRY pListHead)
{
xboxkrnl::PLIST_ENTRY Result = pListHead->Blink;
RemoveEntryList(pListHead->Blink);
return Result;
}
// TODO : Move all Ki* functions to EmuKrnlKi.h/cpp :
#define KiRemoveTreeTimer(Timer) \
(Timer)->Header.Inserted = FALSE; \
@ -190,11 +128,10 @@ xboxkrnl::KPCR* KeGetPcr()
{
xboxkrnl::KPCR* Pcr;
// See EmuKeSetPcr()
__asm {
push eax
mov eax, fs:[0x14]
mov eax, fs : [TIB_ArbitraryDataSlot]
mov Pcr, eax
pop eax
}
return Pcr;
@ -208,6 +145,14 @@ xboxkrnl::KPRCB *KeGetCurrentPrcb()
return &(KeGetPcr()->PrcbData);
}
// Forward KeLowerIrql() to KfLowerIrql()
#define KeLowerIrql(NewIrql) \
KfLowerIrql(NewIrql)
// Forward KeRaiseIrql() to KfRaiseIrql()
#define KeRaiseIrql(NewIrql, OldIrql) \
*OldIrql = KfRaiseIrql(NewIrql)
DWORD BootTickCount = 0;
// The Xbox GetTickCount is measured in milliseconds, just like the native GetTickCount.
@ -218,12 +163,6 @@ DWORD CxbxXboxGetTickCount()
return GetTickCount() - BootTickCount;
}
// CONTAINING_RECORD macro
// Gets the value of structure member (field - num1),given the type(MYSTRUCT, in this code) and the List_Entry head(temp, in this code)
// See http://stackoverflow.com/questions/8240273/a-portable-way-to-calculate-pointer-to-the-whole-structure-using-pointer-to-a-fi
//#define CONTAINING_RECORD(ptr, type, field) \
// (((type) *)((char *)(ptr) - offsetof((type), member)))
DWORD __stdcall EmuThreadDpcHandler(LPVOID lpVoid)
{
xboxkrnl::PKDPC pkdpc;
@ -251,7 +190,7 @@ DWORD __stdcall EmuThreadDpcHandler(LPVOID lpVoid)
// Extract the head entry and retrieve the containing KDPC pointer for it:
pkdpc = CONTAINING_RECORD(RemoveHeadList(&(g_DpcData.DpcQueue)), xboxkrnl::KDPC, DpcListEntry);
// Mark it as no longer linked into the DpcQueue
pkdpc->DpcListEntry.Flink = NULL;
pkdpc->Inserted = FALSE;
// Set DpcRoutineActive to support KeIsExecutingDpc:
KeGetCurrentPrcb()->DpcRoutineActive = TRUE; // Experimental
// Call the Deferred Procedure :
@ -578,9 +517,7 @@ XBSYSAPI EXPORTNUM(103) xboxkrnl::KIRQL NTAPI xboxkrnl::KeGetCurrentIrql(void)
{
LOG_FUNC();
KIRQL Irql;
Irql = KeGetPcr()->Irql;
KIRQL Irql = KeGetPcr()->Irql;
RETURN(Irql);
}
@ -592,9 +529,11 @@ XBSYSAPI EXPORTNUM(104) xboxkrnl::PKTHREAD NTAPI xboxkrnl::KeGetCurrentThread(vo
{
LOG_FUNC();
LOG_UNIMPLEMENTED();
RETURN(NULL);
// Probably correct, but untested and currently faked in EmuGenerateFS
// (to make this correct, we need to improve our thread emulation)
KTHREAD *ret = KeGetCurrentPrcb()->CurrentThread;
RETURN(ret);
}
// ******************************************************************
@ -663,16 +602,22 @@ XBSYSAPI EXPORTNUM(109) xboxkrnl::VOID NTAPI xboxkrnl::KeInitializeInterrupt
LOG_FUNC_ARG(Vector)
LOG_FUNC_ARG(Irql)
LOG_FUNC_ARG(InterruptMode)
LOG_FUNC_ARG(ShareVector)
LOG_FUNC_ARG(ShareVector)
LOG_FUNC_END;
// TODO : Untested :
Interrupt->ServiceRoutine = (PVOID)ServiceRoutine;
Interrupt->ServiceContext = ServiceContext;
Interrupt->BusInterruptLevel = Vector - 0x30;
Interrupt->BusInterruptLevel = Vector - 0x30; // TODO : Constantify 0x30
Interrupt->Irql = Irql;
Interrupt->Connected = FALSE;
// Unused : Interrupt->ShareVector = ShareVector;
Interrupt->Mode = InterruptMode;
Interrupt->ShareVector = ShareVector;
// Interrupt->rsvd1 = 0; // not neccesary?
// Interrupt->ServiceCount = 0; // not neccesary?
// Interrupt->DispatchCode = ?; //TODO : Populate this interrupt dispatch
// code block, patch it up so it works with the address of this Interrupt
// struct and calls the right dispatch routine (depending on InterruptMode).
}
// ******************************************************************
@ -718,26 +663,30 @@ XBSYSAPI EXPORTNUM(119) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeInsertQueueDpc
LOG_FUNC_ARG(SystemArgument2)
LOG_FUNC_END;
// Before going thread-save, check if the Dpc is not linked yet?
if (Dpc->DpcListEntry.Flink == NULL)
{
// For thread safety, enter the Dpc lock:
EnterCriticalSection(&(g_DpcData.Lock));
// Is the Dpc still not linked yet ?
if (Dpc->DpcListEntry.Flink == NULL)
{
// Remember the arguments and link it into our DpcQueue :
Dpc->SystemArgument1 = SystemArgument1;
Dpc->SystemArgument2 = SystemArgument2;
InsertTailList(&(g_DpcData.DpcQueue), &(Dpc->DpcListEntry));
// Signal the Dpc handling code there's work to do
SetEvent(g_DpcData.DpcEvent);
}
// Thread-safety is no longer required anymore
LeaveCriticalSection(&(g_DpcData.Lock));
// For thread safety, enter the Dpc lock:
EnterCriticalSection(&(g_DpcData.Lock));
// TODO : Instead, disable interrupts - use KeRaiseIrql(HIGH_LEVEL, &(KIRQL)OldIrql) ?
BOOLEAN NeedsInsertion = (Dpc->Inserted == FALSE);
if (NeedsInsertion) {
// Remember the arguments and link it into our DpcQueue :
Dpc->Inserted = TRUE;
Dpc->SystemArgument1 = SystemArgument1;
Dpc->SystemArgument2 = SystemArgument2;
InsertTailList(&(g_DpcData.DpcQueue), &(Dpc->DpcListEntry));
// TODO : Instead of DpcQueue, add the DPC to KeGetCurrentPrcb()->DpcListHead
// TODO : Once that's done, use an apropriate signalling mechanism instead of this :
// Signal the Dpc handling code there's work to do
SetEvent(g_DpcData.DpcEvent);
}
RETURN(TRUE);
// Thread-safety is no longer required anymore
LeaveCriticalSection(&(g_DpcData.Lock));
// TODO : Instead, enable interrupts - use KeLowerIrql(&OldIrql) ?
RETURN(NeedsInsertion);
}
// ******************************************************************
@ -880,7 +829,9 @@ XBSYSAPI EXPORTNUM(129) xboxkrnl::UCHAR NTAPI xboxkrnl::KeRaiseIrqlToDpcLevel()
CxbxKrnlCleanup("Bugcheck: Caller of KeRaiseIrqlToDpcLevel is higher than DISPATCH_LEVEL!");
KIRQL kRet = NULL;
KeGetPcr()->Irql = DISPATCH_LEVEL;
KPCR* Pcr = KeGetPcr();
Pcr->Irql = DISPATCH_LEVEL;
#ifdef _DEBUG_TRACE
DbgPrintf("Raised IRQL to DISPATCH_LEVEL (2).\n");
@ -893,6 +844,19 @@ XBSYSAPI EXPORTNUM(129) xboxkrnl::UCHAR NTAPI xboxkrnl::KeRaiseIrqlToDpcLevel()
RETURN(kRet);
}
// ******************************************************************
// * 0x0082 - KeRaiseIrqlToSynchLevel()
// ******************************************************************
XBSYSAPI EXPORTNUM(130) xboxkrnl::UCHAR NTAPI xboxkrnl::KeRaiseIrqlToSynchLevel()
{
LOG_FUNC();
LOG_UNIMPLEMENTED();
// See KfRaiseIrql / KeRaiseIrqlToDpcLevel - use APC_LEVEL?
RETURN(0);
}
// ******************************************************************
// * 0x0089 - KeRemoveQueueDpc()
// ******************************************************************
@ -903,19 +867,23 @@ XBSYSAPI EXPORTNUM(137) xboxkrnl::BOOLEAN NTAPI xboxkrnl::KeRemoveQueueDpc
{
LOG_FUNC_ONE_ARG(Dpc);
if (Dpc->DpcListEntry.Flink != NULL)
{
EnterCriticalSection(&(g_DpcData.Lock));
if (Dpc->DpcListEntry.Flink != NULL)
{
RemoveEntryList(&(Dpc->DpcListEntry));
Dpc->DpcListEntry.Flink = NULL;
}
// TODO : Instead of using a lock, emulate the Clear Interrupt Flag (cli) instruction
// See https://msdn.microsoft.com/is-is/library/y14401ab(v=vs.80).aspx
EnterCriticalSection(&(g_DpcData.Lock));
LeaveCriticalSection(&(g_DpcData.Lock));
BOOLEAN Inserted = Dpc->Inserted;
if (Inserted)
{
RemoveEntryList(&(Dpc->DpcListEntry));
Dpc->Inserted = FALSE;
}
return TRUE;
// TODO : Instead of using a lock, emulate the Set Interrupt Flag (sti) instruction
// See https://msdn.microsoft.com/en-us/library/ad820yz3(v=vs.80).aspx
LeaveCriticalSection(&(g_DpcData.Lock));
RETURN(Inserted);
}
// ******************************************************************

View File

@ -53,16 +53,14 @@ namespace NtDll
};
#include "CxbxKrnl.h" // For CxbxKrnlCleanup
#include "EmuFile.h" // For EmuNtSymbolicLinkObject, NtStatusToString(), etc.
#include "Emu.h" // For EmuWarning()
#include "EmuKrnl.h" // For OBJECT_TO_OBJECT_HEADER()
#include "EmuFile.h" // For EmuNtSymbolicLinkObject, NtStatusToString(), etc.
#pragma warning(disable:4005) // Ignore redefined status values
#include <ntstatus.h>
#pragma warning(default:4005)
#define OBJECT_TO_OBJECT_HEADER(Object) \
CONTAINING_RECORD(Object, OBJECT_HEADER, Body)
#define OB_FLAG_NAMED_OBJECT 1
// ******************************************************************
@ -118,6 +116,18 @@ XBSYSAPI EXPORTNUM(239) xboxkrnl::NTSTATUS NTAPI xboxkrnl::ObCreateObject
if (NameSize == 0)
ObjectHeader->Flags = 0;
else {
// TODO : For other Ob* API's it must become possible to get from
// and Object(Header) address to the Name. Right now, this requires
// adding ObjectSize to ObjectHeader. This won't be available outside
// this function, so we need a better solution for this.
// It might be possible to put the OBJECT_STRING struct BEFORE the
// ObjectHeader (and the NameBuffer itself before that), which would
// make it possible to simply offset everything off an Object.
// It might also be possible to insert a linked list struct, so
// ObReferenceObjectByName can iterate over all named objects.
// (It's probably wise to use one list per pool, to reduce the number
// of objects to walk through.)
// Copy name after object (we've reserved NameSize bytes there) :
OBJECT_STRING *Name = (OBJECT_STRING *)((char *)ObjectHeader + ObjectSize);
char *NameBuffer = (char *)Name + sizeof(OBJECT_STRING);
@ -253,9 +263,26 @@ XBSYSAPI EXPORTNUM(244) xboxkrnl::NTSTATUS NTAPI xboxkrnl::ObOpenObjectByPointer
LOG_FUNC_ARG_OUT(Handle)
LOG_FUNC_END;
LOG_UNIMPLEMENTED();
HANDLE new_handle;
NTSTATUS result = ObReferenceObjectByPointer(Object, ObjectType);
RETURN(S_OK);
if (!NT_SUCCESS(result))
new_handle = (HANDLE)0;
else {
LOG_UNIMPLEMENTED();
// TODO : Create a new_handle for this object
// if that fails, do something like :
// {
// // Detected out of memory
// ObDereferenceObject(Object);
// result = STATUS_INSUFFICIENT_RESOURCES;
// }
}
// Set the new handle and return the correct status
*Handle = new_handle;
RETURN(result);
}
// ******************************************************************
@ -286,10 +313,12 @@ XBSYSAPI EXPORTNUM(246) xboxkrnl::NTSTATUS NTAPI xboxkrnl::ObReferenceObjectByHa
LOG_FUNC_ARG_OUT(ReturnedObject)
LOG_FUNC_END;
LOG_UNIMPLEMENTED();
// This is probably incorrect
// This is most certainly incorrect
*ReturnedObject = Handle;
LOG_UNIMPLEMENTED();
// TODO : Implement and use a handle registration data structure
RETURN(STATUS_SUCCESS);
}
@ -314,6 +343,7 @@ XBSYSAPI EXPORTNUM(247) xboxkrnl::NTSTATUS NTAPI xboxkrnl::ObReferenceObjectByNa
LOG_FUNC_END;
LOG_UNIMPLEMENTED();
// TODO : Implement a mechanism by which all named objects can be queried. See comments in ObCreateObject
RETURN(S_OK);
}
@ -373,7 +403,7 @@ XBSYSAPI EXPORTNUM(250) xboxkrnl::VOID FASTCALL xboxkrnl::ObfDereferenceObject
if (ObjectHeader->Type->DeleteProcedure != NULL)
ObjectHeader->Type->DeleteProcedure(Object);
// TODO : How to handle named objects?
// TODO : How to handle named objects? See comments in ObCreateObject
ObjectHeader->Type->FreeProcedure(ObjectHeader); // TODO : Is this ever something else than ExFreePool ?
}
}

View File

@ -74,7 +74,7 @@ extern PVOID g_pfnThreadNotification[PSP_MAX_CREATE_THREAD_NOTIFY] = { NULL };
extern int g_iThreadNotificationCount = 0;
// Separate function for logging, otherwise in PCSTProxy __try wont work (Compiler Error C2712)
void PCSTProxy_log
void LOG_PCSTProxy
(
PVOID StartRoutine,
PVOID StartContext,
@ -112,16 +112,25 @@ static unsigned int WINAPI PCSTProxy
// Once deleted, unable to directly access iPCSTProxyParam in remainder of function.
delete iPCSTProxyParam;
PCSTProxy_log(StartRoutine, StartContext, SystemRoutine, StartSuspended, hStartedEvent);
LOG_PCSTProxy(
StartRoutine,
StartContext,
SystemRoutine,
StartSuspended,
hStartedEvent);
// Do minimal thread initialization
{
EmuGenerateFS(CxbxKrnl_TLS, CxbxKrnl_TLSData);
_controlfp(_PC_53, _MCW_PC); // Set Precision control to 53 bits (verified setting)
_controlfp(_RC_NEAR, _MCW_RC); // Set Rounding control to near (unsure about this)
}
if (StartSuspended == TRUE)
// Suspend right before calling the thread notification routines
SuspendThread(GetCurrentThread());
EmuGenerateFS(CxbxKrnl_TLS, CxbxKrnl_TLSData);
_controlfp(_PC_53, _MCW_PC); // Set Precision control to 53 bits (verified setting)
_controlfp(_RC_NEAR, _MCW_RC); // Set Rounding control to near (unsure about this)
// call thread notification routine(s)
if (g_iThreadNotificationCount != 0)
{

View File

@ -606,12 +606,6 @@ static inline void EmuInstallPatch(xbaddr FunctionAddr, void *Patch)
*(uint32*)&FuncBytes[1] = (uint32)Patch - FunctionAddr - 5;
}
static inline void GetOovpaEntry(OOVPA *oovpa, int index, OUT uint32 &offset, OUT uint08 &value)
{
offset = (uint32)((LOOVPA<1>*)oovpa)->Lovp[index].Offset;
value = ((LOOVPA<1>*)oovpa)->Lovp[index].Value;
}
static inline void GetXRefEntry(OOVPA *oovpa, int index, OUT uint32 &xref, OUT uint08 &offset)
{
// Note : These are stored swapped by the XREF_ENTRY macro, hence this difference from GetOovpaEntry :
@ -619,13 +613,75 @@ static inline void GetXRefEntry(OOVPA *oovpa, int index, OUT uint32 &xref, OUT u
offset = ((LOOVPA<1>*)oovpa)->Lovp[index].Value;
}
static inline void GetOovpaEntry(OOVPA *oovpa, int index, OUT uint32 &offset, OUT uint08 &value)
{
offset = (uint32)((LOOVPA<1>*)oovpa)->Lovp[index].Offset;
value = ((LOOVPA<1>*)oovpa)->Lovp[index].Value;
}
static boolean CompareOOVPAToAddress(OOVPA *Oovpa, xbaddr cur)
{
uint32 v = 0; // verification counter
// Check all XRefs, stop if any does not match
for (; v < Oovpa->XRefCount; v++)
{
uint32 XRef;
uint08 Offset;
// get currently registered (un)known address
GetXRefEntry(Oovpa, v, XRef, Offset);
xbaddr XRefAddr = XRefDataBase[XRef];
// Undetermined XRef cannot be checked yet
// (EmuLocateFunction already checked this, but this check
// is cheap enough to keep, and keep this function generic).
if (XRefAddr == XREF_ADDR_UNDETERMINED)
return false;
xbaddr ActualAddr = *(xbaddr*)(cur + Offset);
// check if PC-relative or direct reference matches XRef
if ((ActualAddr + cur + Offset + 4 != XRefAddr) && (ActualAddr != XRefAddr))
return false;
}
// Check all (Offset,Value)-pairs, stop if any does not match
for (; v < Oovpa->Count; v++)
{
uint32 Offset;
uint08 ExpectedValue;
// get offset + value pair
GetOovpaEntry(Oovpa, v, Offset, ExpectedValue);
uint08 ActualValue = *(uint08*)(cur + Offset);
if (ActualValue != ExpectedValue)
return false;
}
// all offsets matched
return true;
}
// locate the given function, searching within lower and upper bounds
static xbaddr EmuLocateFunction(OOVPA *Oovpa, xbaddr lower, xbaddr upper)
{
uint32 xref_count = Oovpa->XRefCount;
// skip out if this is an unnecessary search
if(!bXRefFirstPass && xref_count == XRefZero && Oovpa->XRefSaveIndex == XRefNoSaveIndex)
return (xbaddr)nullptr;
// skip out if this is an unnecessary search
if (!bXRefFirstPass && Oovpa->XRefCount == XRefZero && Oovpa->XRefSaveIndex == XRefNoSaveIndex)
return (xbaddr)nullptr;
// Check all XRefs are known (if not, don't do a useless scan) :
for (uint32 v = 0; v < Oovpa->XRefCount; v++)
{
uint32 XRef;
uint08 Offset;
// get currently registered (un)known address
GetXRefEntry(Oovpa, v, XRef, Offset);
xbaddr XRefAddr = XRefDataBase[XRef];
// Undetermined XRef cannot be checked yet
if (XRefAddr == XREF_ADDR_UNDETERMINED)
// Skip this scan over the address range
return (xbaddr)nullptr;
}
// correct upper bound with highest Oovpa offset
uint32 count = Oovpa->Count;
@ -639,70 +695,27 @@ static xbaddr EmuLocateFunction(OOVPA *Oovpa, xbaddr lower, xbaddr upper)
// search all of the image memory
for (xbaddr cur = lower; cur < upper; cur++)
{
uint32 v; // verification counter
// check all cross references
for (v = 0; v < xref_count; v++)
if (CompareOOVPAToAddress(Oovpa, cur))
{
uint32 XRef;
uint08 Offset;
// get XRef offset + value pair and currently registered (un)known address
GetXRefEntry(Oovpa, v, XRef, Offset);
xbaddr XRefValue = XRefDataBase[XRef];
// unknown XRef cannot be checked yet
if (XRefValue == XREF_ADDR_UNDETERMINED)
break;
xbaddr RealValue = *(xbaddr*)(cur + Offset);
// check if PC-relative or direct reference matches XRef
if ((RealValue + cur + Offset + 4 != XRefValue) && (RealValue != XRefValue))
break;
}
// did all xrefs match?
if (v == xref_count)
{
// check all OV pairs, moving on if any do not match
for (; v < count; v++)
// do we need to save the found address?
if (Oovpa->XRefSaveIndex != XRefNoSaveIndex)
{
uint32 Offset;
uint08 Value;
GetOovpaEntry(Oovpa, v, Offset, Value);
uint08 RealValue = *(uint08*)(cur + Offset);
if (RealValue != Value)
break;
}
// success if we found all pairs
if (v == count)
{
// do we need to save the found address?
if (Oovpa->XRefSaveIndex != XRefNoSaveIndex)
// is the XRef not saved yet?
if (XRefDataBase[Oovpa->XRefSaveIndex] == XREF_ADDR_UNDETERMINED)
{
// is the XRef not saved yet?
if (XRefDataBase[Oovpa->XRefSaveIndex] == XREF_ADDR_UNDETERMINED)
{
// save and count the found address
UnResolvedXRefs--;
XRefDataBase[Oovpa->XRefSaveIndex] = cur;
}
else
{
// TODO : Check identical result?
// already found, no bother patching again
return XRefDataBase[Oovpa->XRefSaveIndex];
}
// save and count the found address
UnResolvedXRefs--;
XRefDataBase[Oovpa->XRefSaveIndex] = cur;
}
else
{
if (XRefDataBase[Oovpa->XRefSaveIndex] != cur)
EmuWarning("Found OOVPA on other address than in XRefDataBase!");
}
// return found address
return cur;
}
return cur;
}
}
// found nothing
return (xbaddr)nullptr;

View File

@ -197,8 +197,8 @@ extern "C" CXBXKRNL_API uint32 CxbxKrnl_KernelThunkTable[379] =
(uint32)FUNC(&xboxkrnl::KeQueryPerformanceFrequency), // 0x007F (127)
(uint32)FUNC(&xboxkrnl::KeQuerySystemTime), // 0x0080 (128)
(uint32)FUNC(&xboxkrnl::KeRaiseIrqlToDpcLevel), // 0x0081 (129)
(uint32)PANIC(0x0082), // 0x0082 (130) KeRaiseIrqlToSynchLevel
(uint32)PANIC(0x0083), // 0x0083 (131) KeRaiseIrqlToSynchLevel
(uint32)FUNC(&xboxkrnl::KeRaiseIrqlToSynchLevel), // 0x0082 (130)
(uint32)PANIC(0x0083), // 0x0083 (131) KeReleaseMutant
(uint32)PANIC(0x0084), // 0x0084 (132) KeReleaseSemaphore
(uint32)PANIC(0x0085), // 0x0085 (133) KeRemoveByKeyDeviceQueue
(uint32)PANIC(0x0086), // 0x0086 (134) KeRemoveDeviceQueue