Skip to content

Commit

Permalink
Merge pull request #844 from x1nixmzeng/hle-cache-hash
Browse files Browse the repository at this point in the history
Hash the HLE database so OOVPA changes force a rescan
  • Loading branch information
PatrickvL committed Jan 10, 2018
2 parents 0709152 + 237c7d5 commit 7d79f89
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 53 deletions.
108 changes: 90 additions & 18 deletions src/CxbxKrnl/HLEDataBase.cpp
Expand Up @@ -41,8 +41,6 @@
#include "CxbxKrnl.h" // For xbaddr
#include "HLEDataBase.h" // For PairScanLibSec

extern "C" const char *szHLELastCompileTime = __TIMESTAMP__;

const char *Lib_D3D8 = "D3D8";
const char *Sec_D3D = "D3D";
const char *Lib_D3D8LTCG = "D3D8LTCG";
Expand Down Expand Up @@ -83,57 +81,131 @@ const char *Sec_XNET = "XNET";

const HLEData HLEDataBase[] = {
// Support inline functions in .text section
{ Lib_D3D8,{ Sec_text, Sec_D3D }, D3D8_OOVPAV2, D3D8_OOVPA_SIZEV2 },
{ Lib_D3D8,{ Sec_text, Sec_D3D }, D3D8_OOVPAV2, D3D8_OOVPA_COUNT },

// Cannot support LTCG in HLE
//{ Lib_D3D8LTCG,{ Sec_D3D }, _OOVPAV2, _OOVPA_SIZEV2 },
//{ Lib_D3D8LTCG,{ Sec_D3D }, _OOVPAV2, _OOVPA_COUNT },

// Jarupxx mention this is not a requirement?
//{ Lib_D3DX8,{ Sec_D3DX }, _OOVPAV2, _OOVPA_SIZEV2 },
//{ Lib_D3DX8,{ Sec_D3DX }, _OOVPAV2, _OOVPA_COUNT },

//
{ Lib_DSOUND,{ Sec_DSOUND }, DSound_OOVPAV2, DSound_OOVPA_SIZEV2 },
{ Lib_DSOUND,{ Sec_DSOUND }, DSound_OOVPAV2, DSound_OOVPA_COUNT },

// DSOUNDH is just meant to define hot fix, there is no seperate section
//{ Lib_DSOUNDH,{ Sec_DSOUND }, DSound_OOVPAV2, DSound_OOVPA_SIZEV2 },
//{ Lib_DSOUNDH,{ Sec_DSOUND }, DSound_OOVPAV2, DSound_OOVPA_COUNT },

//
{ Lib_XACTENG, { Sec_XACTENG }, XACTENG_OOVPAV2, XACTENG_OOVPA_SIZEV2 },
{ Lib_XACTENG, { Sec_XACTENG }, XACTENG_OOVPAV2, XACTENG_OOVPA_COUNT },

// test case: Power Drome (Unluckily, it use LTCG version of the library.)
//{ Lib_XACTENLT,{ Sec_XACTENG }, XACTENG_OOVPAV2, XACTENG_OOVPA_SIZEV2 },
//{ Lib_XACTENLT,{ Sec_XACTENG }, XACTENG_OOVPAV2, XACTENG_OOVPA_COUNT },

//
{ Lib_XAPILIB,{ Sec_text, Sec_XPP }, XAPILIB_OOVPAV2, XAPILIB_OOVPA_SIZEV2 },
{ Lib_XAPILIB,{ Sec_text, Sec_XPP }, XAPILIB_OOVPAV2, XAPILIB_OOVPA_COUNT },

// Support inline functions in .text section
{ Lib_XGRAPHC,{ Sec_text, Sec_XGRPH }, XGRAPHC_OOVPAV2, XGRAPHC_OOVPA_SIZEV2 },
{ Lib_XGRAPHC,{ Sec_text, Sec_XGRPH }, XGRAPHC_OOVPAV2, XGRAPHC_OOVPA_COUNT },

// Cannot support LTCG in HLE
//{ Lib_XGRAPHCL,{ Sec_XGRPH }, XGRAPHC_OOVPAV2, XGRAPHC_OOVPA_SIZEV2 },
//{ Lib_XGRAPHCL,{ Sec_XGRPH }, XGRAPHC_OOVPAV2, XGRAPHC_OOVPA_COUNT },

// Added Sec_text and Sec_XNET just in case.
// TODO: Need to find out which function is only part of XOnlines.
{ Lib_XONLINE,{ Sec_text, Sec_XONLINE, Sec_XNET }, XONLINES_OOVPAV2, XONLINES_OOVPA_SIZEV2 },
{ Lib_XONLINE,{ Sec_text, Sec_XONLINE, Sec_XNET }, XONLINES_OOVPAV2, XONLINES_OOVPA_COUNT },

// Fun fact, XONLINES are split into 2 header sections.
{ Lib_XONLINES,{ Sec_text, Sec_XONLINE, Sec_XNET }, XONLINES_OOVPAV2, XONLINES_OOVPA_SIZEV2 },
{ Lib_XONLINES,{ Sec_text, Sec_XONLINE, Sec_XNET }, XONLINES_OOVPAV2, XONLINES_OOVPA_COUNT },

// Added Sec_text just in case.
// TODO: Need to find out which function is only part of XNets.
{ Lib_XNET,{ Sec_text, Sec_XNET }, XNET_OOVPAV2, XNET_OOVPA_SIZEV2 },
{ Lib_XNET,{ Sec_text, Sec_XNET }, XNET_OOVPAV2, XNET_OOVPA_COUNT },

// XNETS only has XNET, might be true.
{ Lib_XNETS,{ Sec_text, Sec_XNET }, XNET_OOVPAV2, XNET_OOVPA_SIZEV2 },
{ Lib_XNETS,{ Sec_text, Sec_XNET }, XNET_OOVPAV2, XNET_OOVPA_COUNT },

// test case: Stake
{ Lib_XNETN,{ Sec_text, Sec_XNET }, XNET_OOVPAV2, XNET_OOVPA_SIZEV2 },
{ Lib_XNETN,{ Sec_text, Sec_XNET }, XNET_OOVPAV2, XNET_OOVPA_COUNT },
};

// ******************************************************************
// * HLEDataBaseCount
// ******************************************************************
const uint32 HLEDataBaseCount = sizeof(HLEDataBase) / sizeof(HLEData);
const uint32 HLEDataBaseCount = sizeof(HLEDataBase) / sizeof(HLEDataBase[0]);

// ******************************************************************
// * GetHLEDataBaseHash
// ******************************************************************

// TODO Write a constexpr variation on these methods
namespace HashHelpers
{
namespace Internal
{
// Adapted from https://gist.github.com/underscorediscovery/81308642d0325fd386237cfa3b44785c
const uint32 fnv1aprime = 0x1000193;
void hash_fnv1a(uint32& hash, const void* key, const uint32 len)
{
const char* data = (char*)key;
for (uint32 i = 0; i < len; ++i) {
uint8_t value = data[i];
hash ^= value;
hash *= fnv1aprime;
}
}

void HashAssumedLOOVPA(uint32& Hash, const OOVPA* pAssumedLOOVPA)
{
// Number of offset-value pairs in the "Header" LOOVPA structure
uint32 Size = pAssumedLOOVPA->Count * sizeof(OOVPA::LOVP);

// Size of "Header" structure
Size += sizeof(OOVPA);

// Part 1: The array of OOVPA::LOVP items
hash_fnv1a(Hash, pAssumedLOOVPA, Size);
}

void HashOOVPATable(uint32& Hash, const OOVPATable* pTable)
{
// Part 1: function name string
if (pTable->szFuncName != nullptr) {
hash_fnv1a(Hash, pTable->szFuncName, strlen(pTable->szFuncName));
}

// Part 2: version number
hash_fnv1a(Hash, &pTable->Version, sizeof(pTable->Version));

// Part 3: LOOVPA
if (pTable->Oovpa) {
HashAssumedLOOVPA(Hash, pTable->Oovpa);
}
}

void HashHLEData(uint32& Hash, const HLEData* pData)
{
for (uint32 i = 0; i < pData->OovpaTableCount; ++i) {
HashOOVPATable(Hash, &pData->OovpaTable[i]);
}
}
}

const uint32 HashHLEDataArray(const HLEData* pDataArray, uint32 Count)
{
uint32 Hash = 0x811c9dc5;
for (uint32 i = 0; i < Count; ++i) {
Internal::HashHLEData(Hash, pDataArray + i);
}
return Hash;
}
}

uint32 GetHLEDataBaseHash()
{
// Calculate this just once
static uint32 CalculatedHash = HashHelpers::HashHLEDataArray(HLEDataBase, HLEDataBaseCount);
return CalculatedHash;
}

// ******************************************************************
// * XRefDataBase
Expand Down
16 changes: 10 additions & 6 deletions src/CxbxKrnl/HLEDataBase.h
Expand Up @@ -36,11 +36,6 @@

#include "HLEDataBase\D3D8.OOVPA.h"

// ******************************************************************
// * szHLELastCompileTime
// ******************************************************************
extern "C" const char *szHLELastCompileTime;

//TODO: Need to remove these externs as v2 is no longer require it.
extern const char *Lib_D3D8;
extern const char *Lib_D3D8LTCG;
Expand Down Expand Up @@ -69,7 +64,7 @@ extern const struct HLEData
const PairScanLibSec LibSec;

OOVPATable *OovpaTable;
uint32 OovpaTableSize;
uint32 OovpaTableCount;
}
HLEDataBase[];

Expand All @@ -78,6 +73,15 @@ HLEDataBase[];
// ******************************************************************
extern const uint32 HLEDataBaseCount;

// ******************************************************************
// * GetHLEDataBaseHash
// ******************************************************************
// Note: The returned hash is a 32-bit FNV-1a checksum
// This checksum was chosen as the hash should approximate the database integrity - and run as fast as possible!
// In future this should be a compile-time expression - not calculated at run-time
// ******************************************************************
extern uint32 GetHLEDataBaseHash();

// ******************************************************************
// * XRefDataBaseOffset
// ******************************************************************
Expand Down
4 changes: 2 additions & 2 deletions src/CxbxKrnl/HLEDataBase/D3D8.OOVPA.inl
Expand Up @@ -434,8 +434,8 @@ OOVPATable D3D8_OOVPAV2[] = {
};

// ******************************************************************
// * D3D8_OOVPA_SIZE
// * D3D8_OOVPA_COUNT
// ******************************************************************
uint32 D3D8_OOVPA_SIZEV2 = sizeof(D3D8_OOVPAV2);
const uint32 D3D8_OOVPA_COUNT = OOVPA_TABLE_COUNT(D3D8_OOVPAV2);

#endif
4 changes: 2 additions & 2 deletions src/CxbxKrnl/HLEDataBase/DSound.OOVPA.inl
Expand Up @@ -520,8 +520,8 @@ OOVPATable DSound_OOVPAV2[] = {
};

// ******************************************************************
// * DSOUND_OOVPA_SIZE
// * DSound_OOVPA_COUNT
// ******************************************************************
uint32 DSound_OOVPA_SIZEV2 = sizeof(DSound_OOVPAV2);
const uint32 DSound_OOVPA_COUNT = OOVPA_TABLE_COUNT(DSound_OOVPAV2);

#endif
4 changes: 2 additions & 2 deletions src/CxbxKrnl/HLEDataBase/XG.OOVPA.inl
Expand Up @@ -100,8 +100,8 @@ OOVPATable XGRAPHC_OOVPAV2[] = {
};

// ******************************************************************
// * XGRAPHC_OOVPA_SIZE
// * XGRAPHC_OOVPA_COUNT
// ******************************************************************
uint32 XGRAPHC_OOVPA_SIZEV2 = sizeof(XGRAPHC_OOVPAV2);
const uint32 XGRAPHC_OOVPA_COUNT = OOVPA_TABLE_COUNT(XGRAPHC_OOVPAV2);

#endif
4 changes: 2 additions & 2 deletions src/CxbxKrnl/HLEDataBase/XNet.OOVPA.inl
Expand Up @@ -79,8 +79,8 @@ OOVPATable XNET_OOVPAV2[] = {
};

// ******************************************************************
// * XNET_OOVPA_SIZE
// * XNET_OOVPA_COUNT
// ******************************************************************
uint32 XNET_OOVPA_SIZEV2 = sizeof(XNET_OOVPAV2);
const uint32 XNET_OOVPA_COUNT = OOVPA_TABLE_COUNT(XNET_OOVPAV2);

#endif
4 changes: 2 additions & 2 deletions src/CxbxKrnl/HLEDataBase/XOnline.OOVPA.inl
Expand Up @@ -93,8 +93,8 @@ OOVPATable XONLINES_OOVPAV2[] = {
};

// ******************************************************************
// * XONLINES_OOVPA_SIZE
// * XONLINES_OOVPA_COUNT
// ******************************************************************
uint32 XONLINES_OOVPA_SIZEV2 = sizeof(XONLINES_OOVPAV2);
const uint32 XONLINES_OOVPA_COUNT = OOVPA_TABLE_COUNT(XONLINES_OOVPAV2);

#endif
4 changes: 2 additions & 2 deletions src/CxbxKrnl/HLEDataBase/XactEng.OOVPA.inl
Expand Up @@ -105,8 +105,8 @@ OOVPATable XACTENG_OOVPAV2[] = {
};

// ******************************************************************
// * XACTENG_OOVPA_SIZE
// * XACTENG_OOVPA_COUNT
// ******************************************************************
uint32 XACTENG_OOVPA_SIZEV2 = sizeof(XACTENG_OOVPAV2);
const uint32 XACTENG_OOVPA_COUNT = OOVPA_TABLE_COUNT(XACTENG_OOVPAV2);

#endif
4 changes: 2 additions & 2 deletions src/CxbxKrnl/HLEDataBase/Xapi.OOVPA.inl
Expand Up @@ -186,8 +186,8 @@ OOVPATable XAPILIB_OOVPAV2[] = {
};

// ******************************************************************
// * XAPILIB_OOVPA_SIZE
// * XAPILIB_OOVPA_COUNT
// ******************************************************************
uint32 XAPILIB_OOVPA_SIZEV2 = sizeof(XAPILIB_OOVPAV2);
const uint32 XAPILIB_OOVPA_COUNT = OOVPA_TABLE_COUNT(XAPILIB_OOVPAV2);

#endif
34 changes: 19 additions & 15 deletions src/CxbxKrnl/HLEIntercept.cpp
Expand Up @@ -165,7 +165,7 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader)

printf("\n");
printf("*******************************************************************************\n");
printf("* Cxbx-Reloaded High Level Emulation database last modified %s\n", szHLELastCompileTime);
printf("* Cxbx-Reloaded High Level Emulation database\n");
printf("*******************************************************************************\n");
printf("\n");

Expand All @@ -190,15 +190,17 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader)
if (PathFileExists(filename.c_str())) {
printf("Found HLE Cache File: %08X.ini\n", uiHash);

// Verify the version of the cache file against the HLE Database
char buffer[SHRT_MAX] = { 0 };
char* bufferPtr = buffer;

GetPrivateProfileString("Info", "HLEDatabaseVersion", NULL, buffer, sizeof(buffer), filename.c_str());
g_BuildVersion = GetPrivateProfileInt("Libs", "D3D8_BuildVersion", 0, filename.c_str());

if (strcmp(buffer, szHLELastCompileTime) == 0) {
// Verify the version of the cache file against the HLE Database
const uint32 HLECacheHash = GetPrivateProfileInt("Info", "HLECacheHash", 0, filename.c_str());

if (HLECacheHash == GetHLEDataBaseHash()) {
char buffer[SHRT_MAX] = { 0 };
char* bufferPtr = buffer;

printf("Using HLE Cache\n");

GetPrivateProfileSection("Symbols", buffer, sizeof(buffer), filename.c_str());

// Parse the .INI file into the map of symbol addresses
Expand Down Expand Up @@ -597,7 +599,7 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader)
if (bPrintSkip) printf("Found\n");
bPrintSkip = false;

EmuInstallPatches(HLEDataBase[d2].OovpaTable, HLEDataBase[d2].OovpaTableSize, pSectionScan, BuildVersion);
EmuInstallPatches(HLEDataBase[d2].OovpaTable, HLEDataBase[d2].OovpaTableCount, pSectionScan, BuildVersion);
break;
}
}
Expand All @@ -624,7 +626,10 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader)
printf("\n");

// Write the HLE Database version string
WritePrivateProfileString("Info", "HLEDatabaseVersion", szHLELastCompileTime, filename.c_str());
{
std::string HLECacheHashString = std::to_string(GetHLEDataBaseHash());
WritePrivateProfileString("Info", "HLECacheHash", HLECacheHashString.c_str(), filename.c_str());
}

// Write the Certificate Details to the cache file
WritePrivateProfileString("Certificate", "Name", tAsciiTitle, filename.c_str());
Expand Down Expand Up @@ -887,15 +892,15 @@ xbaddr EmuLocateFunction(OOVPA *Oovpa, xbaddr lower, xbaddr upper)
}

// install function interception wrappers
void EmuInstallPatches(OOVPATable *OovpaTable, uint32 OovpaTableSize, Xbe::SectionHeader *pSectionHeader, uint16_t buildVersion)
void EmuInstallPatches(OOVPATable *OovpaTable, uint32 OovpaTableCount, Xbe::SectionHeader *pSectionHeader, uint16_t buildVersion)
{
xbaddr lower = pSectionHeader->dwVirtualAddr;

// Find the highest address contained within an executable segment
xbaddr upper = pSectionHeader->dwVirtualAddr + pSectionHeader->dwVirtualSize;

// traverse the full OOVPA table
OOVPATable *pLoopEnd = &OovpaTable[OovpaTableSize / sizeof(OOVPATable)];
OOVPATable *pLoopEnd = &OovpaTable[OovpaTableCount];
OOVPATable *pLoop = OovpaTable;
OOVPATable *pLastKnownSymbol = nullptr;
xbaddr pLastKnownFunc = 0;
Expand Down Expand Up @@ -1087,7 +1092,7 @@ void VerifyHLEOOVPA(HLEVerifyContext *context, uint16_t buildVersion, OOVPA *oov
}
}

void VerifyHLEDataEntry(HLEVerifyContext *context, const OOVPATable *table, uint32 index, uint32 count)
void VerifyHLEDataEntry(HLEVerifyContext *context, const OOVPATable *table, uint32 index)
{
if (context->against == nullptr) {
context->main_index = index;
Expand Down Expand Up @@ -1134,9 +1139,8 @@ void VerifyHLEData(HLEVerifyContext *context, const HLEData *data)
}

// verify each entry in this HLEData
uint32 count = data->OovpaTableSize / sizeof(OOVPATable);
for (uint32 e = 0; e < count; e++) {
VerifyHLEDataEntry(context, data->OovpaTable, e, count);
for (uint32 e = 0; e < data->OovpaTableCount; e++) {
VerifyHLEDataEntry(context, data->OovpaTable, e);
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/CxbxKrnl/OOVPA.h
Expand Up @@ -43,6 +43,11 @@
#define STRINGIZEX(x) #x
#define STRINGIZE(x) STRINGIZEX(x)

#include <iterator>

// http://en.cppreference.com/w/cpp/iterator/size
#define OOVPA_TABLE_COUNT(x) std::size(x)

#pragma pack(1)

// ******************************************************************
Expand Down

0 comments on commit 7d79f89

Please sign in to comment.