Merge pull request #821 from ergo720/memory

Virtual memory manager + Kernel memory functions implementation
This commit is contained in:
PatrickvL 2017-12-31 23:55:38 +01:00 committed by GitHub
commit 984e2bd510
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 2032 additions and 616 deletions

View File

@ -231,11 +231,12 @@
<ClInclude Include="..\..\src\CxbxKrnl\HLEDataBase\D3D8.OOVPA.h" />
<ClInclude Include="..\..\src\CxbxKrnl\HLEIntercept.h" />
<ClInclude Include="..\..\src\CxbxKrnl\LibRc4.h" />
<ClInclude Include="..\..\src\CxbxKrnl\MemoryManager.h" />
<ClInclude Include="..\..\src\CxbxKrnl\nv2a_int.h" />
<ClInclude Include="..\..\src\CxbxKrnl\OOVPA.h" />
<ClInclude Include="..\..\src\CxbxKrnl\PhysicalMemory.h" />
<ClInclude Include="..\..\src\CxbxKrnl\ReservedMemory.h" />
<ClInclude Include="..\..\src\CxbxKrnl\ResourceTracker.h" />
<ClInclude Include="..\..\src\CxbxKrnl\VMManager.h" />
<ClInclude Include="..\..\src\CxbxVersion.h" />
<ClInclude Include="..\..\src\Cxbx\DlgAbout.h" />
<ClInclude Include="..\..\src\Cxbx\DlgAudioConfig.h" />
@ -514,13 +515,14 @@
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\..\src\CxbxKrnl\LibRc4.cpp" />
<ClCompile Include="..\..\src\CxbxKrnl\MemoryManager.cpp" />
<ClCompile Include="..\..\src\CxbxKrnl\PhysicalMemory.cpp" />
<ClCompile Include="..\..\src\CxbxKrnl\ResourceTracker.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\..\src\CxbxKrnl\VMManager.cpp" />
<ClCompile Include="..\..\src\Cxbx\DlgAbout.cpp" />
<ClCompile Include="..\..\src\Cxbx\DlgAudioConfig.cpp" />
<ClCompile Include="..\..\src\Cxbx\DlgControllerConfig.cpp">

View File

@ -187,9 +187,6 @@
<ClCompile Include="..\..\src\Common\EmuEEPROM.cpp">
<Filter>Shared</Filter>
</ClCompile>
<ClCompile Include="..\..\src\CxbxKrnl\MemoryManager.cpp">
<Filter>Emulator</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Cxbx\DlgAbout.cpp">
<Filter>GUI</Filter>
</ClCompile>
@ -205,6 +202,12 @@
<ClCompile Include="..\..\src\Common\Win32\XBAudio.cpp">
<Filter>Shared</Filter>
</ClCompile>
<ClCompile Include="..\..\src\CxbxKrnl\PhysicalMemory.cpp">
<Filter>Emulator</Filter>
</ClCompile>
<ClCompile Include="..\..\src\CxbxKrnl\VMManager.cpp">
<Filter>Emulator</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\Cxbx\DlgControllerConfig.h">
@ -369,9 +372,6 @@
<ClInclude Include="..\..\src\CxbxVersion.h">
<Filter>Shared</Filter>
</ClInclude>
<ClInclude Include="..\..\src\CxbxKrnl\MemoryManager.h">
<Filter>Emulator</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Cxbx\DlgAbout.h">
<Filter>GUI</Filter>
</ClInclude>
@ -396,6 +396,12 @@
<ClInclude Include="..\..\src\CxbxKrnl\HLEDataBase\D3D8.OOVPA.h">
<Filter>HLEDatabase\D3D8</Filter>
</ClInclude>
<ClInclude Include="..\..\src\CxbxKrnl\PhysicalMemory.h">
<Filter>Emulator</Filter>
</ClInclude>
<ClInclude Include="..\..\src\CxbxKrnl\VMManager.h">
<Filter>Emulator</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\resource\Splash.jpg">

View File

@ -71,8 +71,8 @@ XBSYSAPI EXPORTNUM(169) PVOID NTAPI MmCreateKernelStack
// ******************************************************************
XBSYSAPI EXPORTNUM(170) VOID NTAPI MmDeleteKernelStack
(
IN PVOID EndAddress,
IN PVOID BaseAddress
IN PVOID StackBase,
IN PVOID StackLimit
);
// ******************************************************************

View File

@ -229,6 +229,11 @@ typedef long NTSTATUS;
// Xbox pages are (1 << 12) = 0x00001000 = 4096 bytes in size.
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE - 1)
#define MAX_NUM_OF_PAGES 1 << (32 - PAGE_SHIFT) // 1048576 (1024^2) max virtual pages possible, = 4GiB / 4096
#define XBOX_CONTIGUOUS_MEMORY_LIMIT XBOX_MEMORY_SIZE - 32 * PAGE_SIZE // upper limit available for contiguous allocations (xbox)
#define CHIHIRO_CONTIGUOUS_MEMORY_LIMIT CHIHIRO_MEMORY_SIZE - 48 * PAGE_SIZE // upper limit available for contiguous allocations (chihiro)
#define ZERO_PAGE_ADDR 0
#define FIRST_PAGE_ADDR PAGE_SIZE
// Convert a physical frame number to its corresponding physical address.
#define MI_CONVERT_PFN_TO_PHYSICAL(Pfn) \
@ -2484,8 +2489,8 @@ typedef struct _XBE_SECTION // Was _XBE_SECTIONHEADER
ULONG FileSize; // File size (size of the section in the XBE file)
PCSZ SectionName; // Pointer to section name
ULONG SectionReferenceCount; // Section reference count - when >= 1, section is loaded
ULONG HeadReferenceCount; // Pointer to head shared page reference count
ULONG TailReferenceCount; // Pointer to tail shared page reference count
PUSHORT HeadReferenceCount; // Pointer to head shared page reference counter
PUSHORT TailReferenceCount; // Pointer to tail shared page reference counter
BYTE ShaHash[20]; // SHA hash. Hash DWORD containing FileSize, then hash section.
}
XBEIMAGE_SECTION, *PXBEIMAGE_SECTION;

View File

@ -138,6 +138,7 @@ EmuShared::EmuShared()
{
Load();
m_bMultiXbe = false;
m_LaunchDataPAddress = NULL;
}
// ******************************************************************

View File

@ -1005,7 +1005,7 @@ void *Xbe::FindSection(char *zsSectionName)
return NULL;
}
void Xbe::PurgeBadChar(std::string &s, const std::string &illegalChars)
void Xbe::PurgeBadChar(std::string& s, const std::string& illegalChars)
{
for (auto it = s.begin(); it < s.end(); ++it)
{

View File

@ -72,7 +72,7 @@ class Xbe : public Error
void ExportLogoBitmap(uint08 x_Gray[100*17]);
// purge illegal characters in Windows filenames or other OS's
void PurgeBadChar(std::string &s, const std::string &illegalChars = "\\/:?\"<>|");
void PurgeBadChar(std::string& s, const std::string& illegalChars = "\\/:?\"<>|");
// Xbe header
#include "AlignPrefix1.h"

View File

@ -119,6 +119,9 @@ extern XbeType g_XbeType;
/*! indicates emulation of an Chihiro (arcade, instead of Xbox console) executable */
extern bool g_bIsChihiro;
/*! indicates emulation of a Debug xbe executable */
extern bool g_bIsDebug;
/*! maximum number of threads cxbx can handle */
#define MAXIMUM_XBOX_THREADS 256

View File

@ -55,7 +55,7 @@ namespace xboxkrnl
#include "EmuNV2A.h" // For InitOpenGLContext
#include "HLEIntercept.h"
#include "ReservedMemory.h" // For virtual_memory_placeholder
#include "MemoryManager.h"
#include "VMManager.h"
#include <shlobj.h>
#include <clocale>
@ -89,7 +89,6 @@ static HANDLE g_hThreads[MAXIMUM_XBOX_THREADS] = { 0 };
char szFilePath_CxbxReloaded_Exe[MAX_PATH] = { 0 };
char szFolder_CxbxReloadedData[MAX_PATH] = { 0 };
char szFilePath_LaunchDataPage_bin[MAX_PATH] = { 0 };
char szFilePath_EEPROM_bin[MAX_PATH] = { 0 };
char szFilePath_memory_bin[MAX_PATH] = { 0 };
@ -98,6 +97,7 @@ HANDLE CxbxBasePathHandle;
Xbe* CxbxKrnl_Xbe = NULL;
XbeType g_XbeType = xtRetail;
bool g_bIsChihiro = false;
bool g_bIsDebug = false;
DWORD_PTR g_CPUXbox = 0;
DWORD_PTR g_CPUOthers = 0;
@ -303,14 +303,12 @@ void *CxbxRestoreContiguousMemory(char *szFilePath_memory_bin)
}
}
// TODO : Make sure memory.bin is at least 64 MB in size - FileSeek(hFile, CONTIGUOUS_MEMORY_SIZE, soFromBeginning);
HANDLE hFileMapping = CreateFileMapping(
hFile,
/* lpFileMappingAttributes */nullptr,
PAGE_EXECUTE_READWRITE,
/* dwMaximumSizeHigh */0,
/* dwMaximumSizeLow */CONTIGUOUS_MEMORY_SIZE,
/* dwMaximumSizeLow */CHIHIRO_MEMORY_SIZE,
/**/nullptr);
if (hFileMapping == NULL)
{
@ -318,13 +316,22 @@ void *CxbxRestoreContiguousMemory(char *szFilePath_memory_bin)
return nullptr;
}
LARGE_INTEGER len_li;
GetFileSizeEx(hFile, &len_li);
unsigned int FileSize = len_li.u.LowPart;
if (FileSize != CHIHIRO_MEMORY_SIZE)
{
CxbxKrnlCleanup("CxbxRestoreContiguousMemory : memory.bin file is not 128 MiB large!\n");
return nullptr;
}
// Map memory.bin contents into memory :
void *memory = (void *)MapViewOfFileEx(
hFileMapping,
FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE,
/* dwFileOffsetHigh */0,
/* dwFileOffsetLow */0,
CONTIGUOUS_MEMORY_SIZE,
CONTIGUOUS_MEMORY_CHIHIRO_SIZE,
(void *)CONTIGUOUS_MEMORY_BASE);
if (memory != (void *)CONTIGUOUS_MEMORY_BASE)
{
@ -336,11 +343,11 @@ void *CxbxRestoreContiguousMemory(char *szFilePath_memory_bin)
}
printf("[0x%.4X] INIT: Mapped %d MiB of Xbox contiguous memory at 0x%.8X to 0x%.8X\n",
GetCurrentThreadId(), CONTIGUOUS_MEMORY_SIZE / ONE_MB, CONTIGUOUS_MEMORY_BASE, CONTIGUOUS_MEMORY_BASE + CONTIGUOUS_MEMORY_SIZE - 1);
GetCurrentThreadId(), CONTIGUOUS_MEMORY_CHIHIRO_SIZE / ONE_MB, CONTIGUOUS_MEMORY_BASE, CONTIGUOUS_MEMORY_BASE + CONTIGUOUS_MEMORY_CHIHIRO_SIZE - 1);
if (NeedsInitialization)
{
memset(memory, 0, CONTIGUOUS_MEMORY_SIZE);
memset(memory, 0, CONTIGUOUS_MEMORY_CHIHIRO_SIZE);
printf("[0x%.4X] INIT: Initialized contiguous memory\n", GetCurrentThreadId());
}
else
@ -352,7 +359,7 @@ void *CxbxRestoreContiguousMemory(char *szFilePath_memory_bin)
FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE,
/* dwFileOffsetHigh */0,
/* dwFileOffsetLow */0,
TILED_MEMORY_SIZE,
TILED_MEMORY_CHIHIRO_SIZE,
(void *)TILED_MEMORY_BASE);
if (tiled_memory != (void *)TILED_MEMORY_BASE)
{
@ -362,9 +369,12 @@ void *CxbxRestoreContiguousMemory(char *szFilePath_memory_bin)
CxbxKrnlCleanup("CxbxRestoreContiguousMemory: Couldn't map contiguous memory.bin into tiled memory at 0xF0000000!");
return nullptr;
}
printf("[0x%.4X] INIT: Mapped contiguous memory to Xbox tiled memory at 0x%.8X to 0x%.8X\n",
GetCurrentThreadId(), TILED_MEMORY_BASE, TILED_MEMORY_BASE + TILED_MEMORY_SIZE - 1);
GetCurrentThreadId(), TILED_MEMORY_BASE, TILED_MEMORY_BASE + TILED_MEMORY_CHIHIRO_SIZE - 1);
// Initialize the virtual manager :
g_VMManager.Initialize(hFileMapping);
return memory;
}
@ -575,8 +585,6 @@ void CxbxKrnlMain(int argc, char* argv[])
CxbxRestoreContiguousMemory(szFilePath_memory_bin);
CxbxRestorePersistentMemoryRegions();
EEPROM = CxbxRestoreEEPROM(szFilePath_EEPROM_bin);
if (EEPROM == nullptr)
{
@ -602,11 +610,17 @@ void CxbxKrnlMain(int argc, char* argv[])
// Detect XBE type :
g_XbeType = GetXbeType(&CxbxKrnl_Xbe->m_Header);
// Register if we're running an Chihiro executable (otherwise it's an Xbox executable)
// Register if we're running an Chihiro executable or a debug xbe (otherwise it's an Xbox retail executable)
g_bIsChihiro = (g_XbeType == xtChihiro);
g_bIsDebug = (g_XbeType == xtDebug);
// Determine memory size accordingly :
SIZE_T memorySize = (g_bIsChihiro ? CHIHIRO_MEMORY_SIZE : XBOX_MEMORY_SIZE);
if (g_bIsChihiro || g_bIsDebug)
{
// Initialize the Chihiro/Debug - specific memory ranges
g_VMManager.InitializeChihiroDebug();
}
CxbxRestorePersistentMemoryRegions();
// Copy over loaded Xbe Headers to specified base address
memcpy((void*)CxbxKrnl_Xbe->m_Header.dwBaseAddr, &CxbxKrnl_Xbe->m_Header, sizeof(Xbe::Header));
@ -887,7 +901,7 @@ __declspec(noreturn) void CxbxKrnlInit
// Assign the running Xbe path, so it can be accessed via the kernel thunk 'XeImageFileName' :
xboxkrnl::XeImageFileName.MaximumLength = MAX_PATH;
xboxkrnl::XeImageFileName.Buffer = (PCHAR)g_MemoryManager.Allocate(MAX_PATH);
xboxkrnl::XeImageFileName.Buffer = (PCHAR)g_VMManager.Allocate(MAX_PATH);
sprintf(xboxkrnl::XeImageFileName.Buffer, "%c:\\%s", CxbxDefaultXbeDriveLetter, fileName.c_str());
xboxkrnl::XeImageFileName.Length = (USHORT)strlen(xboxkrnl::XeImageFileName.Buffer);
printf("[0x%.4X] INIT: XeImageFileName = %s\n", GetCurrentThreadId(), xboxkrnl::XeImageFileName.Buffer);
@ -1014,15 +1028,14 @@ void CxbxInitFilePaths()
CxbxKrnlCleanup("CxbxInitFilePaths : Couldn't create Cxbx-Reloaded EmuDisk folder!");
}
snprintf(szFilePath_LaunchDataPage_bin, MAX_PATH, "%s\\CxbxLaunchDataPage.bin", szFolder_CxbxReloadedData);
snprintf(szFilePath_EEPROM_bin, MAX_PATH, "%s\\EEPROM.bin", szFolder_CxbxReloadedData);
snprintf(szFilePath_memory_bin, MAX_PATH, "%s\\memory.bin", szFolder_CxbxReloadedData);
GetModuleFileName(GetModuleHandle(NULL), szFilePath_CxbxReloaded_Exe, MAX_PATH);
}
// TODO : Is DefaultLaunchDataPage really necessary? (No-one assigns it yet to LaunchDataPage)
xboxkrnl::LAUNCH_DATA_PAGE DefaultLaunchDataPage =
// REMARK: the following is useless, but PatrickvL has asked to keep it for documentation purposes
/*xboxkrnl::LAUNCH_DATA_PAGE DefaultLaunchDataPage =
{
{ // header
2, // 2: dashboard, 0: title
@ -1030,27 +1043,20 @@ xboxkrnl::LAUNCH_DATA_PAGE DefaultLaunchDataPage =
"D:\\default.xbe",
0
}
};
};*/
void CxbxRestoreLaunchDataPage()
{
// If CxbxLaunchDataPage.bin exist, load it into "persistent" memory
FILE* fp = fopen(szFilePath_LaunchDataPage_bin, "rb");
if (fp)
PAddr LaunchDataPAddr;
g_EmuShared->GetLaunchDataPAddress(&LaunchDataPAddr);
if (LaunchDataPAddr)
{
// Make sure LaunchDataPage is writeable :
if (xboxkrnl::LaunchDataPage == &DefaultLaunchDataPage)
xboxkrnl::LaunchDataPage = NULL;
if (xboxkrnl::LaunchDataPage == NULL)
xboxkrnl::LaunchDataPage = (xboxkrnl::LAUNCH_DATA_PAGE *)xboxkrnl::MmAllocateContiguousMemory(sizeof(xboxkrnl::LAUNCH_DATA_PAGE));
// Read in the contents.
fseek(fp, 0, SEEK_SET);
fread(xboxkrnl::LaunchDataPage, sizeof(xboxkrnl::LAUNCH_DATA_PAGE), 1, fp);
fclose(fp);
// Delete the file once we're done.
remove(szFilePath_LaunchDataPage_bin);
xboxkrnl::LaunchDataPage = (xboxkrnl::LAUNCH_DATA_PAGE*)CONTIGUOUS_MEMORY_BASE + LaunchDataPAddr;
// Mark the launch page as allocated to prevent other allocations from overwriting it
xboxkrnl::MmAllocateContiguousMemoryEx(PAGE_SIZE, LaunchDataPAddr, LaunchDataPAddr + PAGE_SIZE - 1, PAGE_SIZE, PAGE_READWRITE);
LaunchDataPAddr = NULL;
g_EmuShared->SetLaunchDataPAddress(&LaunchDataPAddr);
DbgPrintf("INIT: Restored LaunchDataPage\n");
}

View File

@ -54,6 +54,7 @@ extern "C" {
// Sizes
#define ONE_KB 1024
#define ONE_MB (1024 * 1024)
#define X64KB 64 * ONE_KB
// Thread Information Block offsets - see https://www.microsoft.com/msj/archive/S2CE.aspx
#define TIB_ArbitraryDataSlot 0x14
@ -67,16 +68,41 @@ extern "C" {
// Define virtual base addresses for physical memory windows.
#define MM_SYSTEM_PHYSICAL_MAP KSEG0_BASE // = 0x80000000
#define MM_HIGHEST_PHYSICAL_PAGE 0x07FFF
#define KERNEL_SIZE sizeof(DUMMY_KERNEL)
#define MM_XBOX_HIGHEST_PHYSICAL_PAGE 0x03FFF
#define MM_CHIHIRO_HIGHEST_PHYSICAL_PAGE 0x07FFF
#define MM_64M_PHYSICAL_PAGE 0x04000
#define MM_INSTANCE_PHYSICAL_PAGE 0x03FE0 // Chihiro arcade should use 0x07FF0
#define MM_XBOX_INSTANCE_PHYSICAL_PAGE 0x03FE0
#define MM_CHIHIRO_INSTANCE_PHYSICAL_PAGE 0x07FF0
#define MM_INSTANCE_PAGE_COUNT 16
#define CONTIGUOUS_MEMORY_BASE MM_SYSTEM_PHYSICAL_MAP // = 0x80000000
#define CONTIGUOUS_MEMORY_SIZE (64 * ONE_MB)
#define CONTIGUOUS_MEMORY_XBOX_SIZE (64 * ONE_MB)
#define CONTIGUOUS_MEMORY_CHIHIRO_SIZE (128 * ONE_MB)
#define TILED_MEMORY_BASE 0xF0000000 // Tiled memory is a mirror of contiguous memory, residing at 0xF0000000
#define TILED_MEMORY_SIZE CONTIGUOUS_MEMORY_SIZE
#define TILED_MEMORY_XBOX_SIZE CONTIGUOUS_MEMORY_XBOX_SIZE
#define TILED_MEMORY_CHIHIRO_SIZE CONTIGUOUS_MEMORY_CHIHIRO_SIZE
#define NV2A_MEMORY_BASE 0xFD000000 // See NV2A_ADDR
#define NV2A_MEMORY_SIZE 0x01000000 // See NV2A_SIZE
#define NV2A_PRAMIN_ADDR 0xFD700000
#define NV2A_PRAMIN_SIZE 0x100000
#define NV2A_USER_ADDR 0xFD800000
#define NV2A_USER_SIZE 0x800000
#define APU_BASE 0xFE800000
#define APU_SIZE 0x80000
#define AC97_BASE 0xFEC00000
#define AC97_SIZE 0x1000
#define USB0_BASE 0xFED00000
#define USB0_SIZE 0x1000
#define USB1_BASE 0xFED08000
#define USB1_SIZE 0x1000
#define NVNet_BASE 0xFEF00000
#define NVNet_SIZE 0x400
#define BIOS_BASE 0xFF000000
#define BIOS_XBOX_SIZE 0xFFFE00
#define BIOS_CHIHIRO_SIZE 0x1000000
#define MCPX_BASE 0xFFFFFE00
#define MCPX_SIZE 0x200
#define MAX_VIRTUAL_ADDRESS 0xFFFFFFFF
/*! memory size per system */
#define XBOX_MEMORY_SIZE (64 * ONE_MB)
@ -97,6 +123,10 @@ extern "C" {
#define XBOX_FLASH_ROM_BASE 0xFFF00000
#define XBOX_FLASH_ROM_SIZE 0x00100000 // - 0xFFFFFFF
#define HIGHEST_USER_ADDRESS 0x7FFEFFFF
#define HIGHEST_VAD_ADDRESS HIGHEST_USER_ADDRESS - X64KB // for NtAllocateVirtualMemory
// For now, virtual addresses are somewhat limited, as we use
// these soley for loading XBE sections. The largest that we
// know of, is "BLiNX: the time sweeper", which has a section
@ -194,7 +224,6 @@ extern char* CxbxKrnl_DebugFileName;
/*! file paths */
extern char szFilePath_CxbxReloaded_Exe[MAX_PATH];
extern char szFolder_CxbxReloadedData[MAX_PATH];
extern char szFilePath_LaunchDataPage_bin[MAX_PATH];
extern char szFilePath_EEPROM_bin[MAX_PATH];
#ifdef __cplusplus

View File

@ -52,7 +52,7 @@ namespace xboxkrnl
#include "EmuShared.h"
#include "DbgConsole.h"
#include "ResourceTracker.h"
#include "MemoryManager.h"
#include "VMManager.h"
#include "EmuXTL.h"
#include "HLEDatabase.h"
#include "Logging.h"
@ -862,49 +862,49 @@ int GetD3DResourceRefCount(XTL::IDirect3DResource8 *EmuResource)
XTL::X_D3DSurface *EmuNewD3DSurface()
{
XTL::X_D3DSurface *result = (XTL::X_D3DSurface *)g_MemoryManager.AllocateZeroed(1, sizeof(XTL::X_D3DSurface));
XTL::X_D3DSurface *result = (XTL::X_D3DSurface *)g_VMManager.AllocateZeroed(sizeof(XTL::X_D3DSurface));
result->Common = X_D3DCOMMON_D3DCREATED | X_D3DCOMMON_TYPE_SURFACE | 1; // Set refcount to 1
return result;
}
XTL::X_D3DTexture *EmuNewD3DTexture()
{
XTL::X_D3DTexture *result = (XTL::X_D3DTexture *)g_MemoryManager.AllocateZeroed(1, sizeof(XTL::X_D3DTexture));
XTL::X_D3DTexture *result = (XTL::X_D3DTexture *)g_VMManager.AllocateZeroed(sizeof(XTL::X_D3DTexture));
result->Common = X_D3DCOMMON_D3DCREATED | X_D3DCOMMON_TYPE_TEXTURE | 1; // Set refcount to 1
return result;
}
XTL::X_D3DVolumeTexture *EmuNewD3DVolumeTexture()
{
XTL::X_D3DVolumeTexture *result = (XTL::X_D3DVolumeTexture *)g_MemoryManager.AllocateZeroed(1, sizeof(XTL::X_D3DVolumeTexture));
XTL::X_D3DVolumeTexture *result = (XTL::X_D3DVolumeTexture *)g_VMManager.AllocateZeroed(sizeof(XTL::X_D3DVolumeTexture));
result->Common = X_D3DCOMMON_D3DCREATED | X_D3DCOMMON_TYPE_TEXTURE | 1; // Set refcount to 1
return result;
}
XTL::X_D3DCubeTexture *EmuNewD3DCubeTexture()
{
XTL::X_D3DCubeTexture *result = (XTL::X_D3DCubeTexture *)g_MemoryManager.AllocateZeroed(1, sizeof(XTL::X_D3DCubeTexture));
XTL::X_D3DCubeTexture *result = (XTL::X_D3DCubeTexture *)g_VMManager.AllocateZeroed(sizeof(XTL::X_D3DCubeTexture));
result->Common = X_D3DCOMMON_D3DCREATED | X_D3DCOMMON_TYPE_TEXTURE | 1; // Set refcount to 1
return result;
}
XTL::X_D3DIndexBuffer *EmuNewD3DIndexBuffer()
{
XTL::X_D3DIndexBuffer *result = (XTL::X_D3DIndexBuffer *)g_MemoryManager.AllocateZeroed(1, sizeof(XTL::X_D3DIndexBuffer));
XTL::X_D3DIndexBuffer *result = (XTL::X_D3DIndexBuffer *)g_VMManager.AllocateZeroed(sizeof(XTL::X_D3DIndexBuffer));
result->Common = X_D3DCOMMON_D3DCREATED | X_D3DCOMMON_TYPE_INDEXBUFFER | 1; // Set refcount to 1
return result;
}
XTL::X_D3DVertexBuffer *EmuNewD3DVertexBuffer()
{
XTL::X_D3DVertexBuffer *result = (XTL::X_D3DVertexBuffer *)g_MemoryManager.AllocateZeroed(1, sizeof(XTL::X_D3DVertexBuffer));
XTL::X_D3DVertexBuffer *result = (XTL::X_D3DVertexBuffer *)g_VMManager.AllocateZeroed(sizeof(XTL::X_D3DVertexBuffer));
result->Common = X_D3DCOMMON_D3DCREATED | X_D3DCOMMON_TYPE_VERTEXBUFFER | 1; // Set refcount to 1
return result;
}
XTL::X_D3DPalette *EmuNewD3DPalette()
{
XTL::X_D3DPalette *result = (XTL::X_D3DPalette *)g_MemoryManager.AllocateZeroed(1, sizeof(XTL::X_D3DPalette));
XTL::X_D3DPalette *result = (XTL::X_D3DPalette *)g_VMManager.AllocateZeroed(sizeof(XTL::X_D3DPalette));
result->Common = X_D3DCOMMON_D3DCREATED | X_D3DCOMMON_TYPE_PALETTE | 1; // Set refcount to 1
return result;
}
@ -3398,8 +3398,8 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateVertexShader)
LOG_FUNC_END;
// create emulated shader struct
X_D3DVertexShader *pD3DVertexShader = (X_D3DVertexShader*)g_MemoryManager.AllocateZeroed(1, sizeof(X_D3DVertexShader));
VERTEX_SHADER *pVertexShader = (VERTEX_SHADER*)g_MemoryManager.AllocateZeroed(1, sizeof(VERTEX_SHADER));
X_D3DVertexShader *pD3DVertexShader = (X_D3DVertexShader*)g_VMManager.AllocateZeroed(sizeof(X_D3DVertexShader));
VERTEX_SHADER *pVertexShader = (VERTEX_SHADER*)g_VMManager.AllocateZeroed(sizeof(VERTEX_SHADER));
// TODO: Intelligently fill out these fields as necessary
@ -3501,7 +3501,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateVertexShader)
free(pRecompiledDeclaration);
pVertexShader->pDeclaration = (DWORD*)g_MemoryManager.Allocate(DeclarationSize);
pVertexShader->pDeclaration = (DWORD*)g_VMManager.Allocate(DeclarationSize);
memcpy(pVertexShader->pDeclaration, pDeclaration, DeclarationSize);
pVertexShader->FunctionSize = 0;
@ -3514,7 +3514,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateVertexShader)
{
if(pFunction != NULL)
{
pVertexShader->pFunction = (DWORD*)g_MemoryManager.Allocate(VertexShaderSize);
pVertexShader->pFunction = (DWORD*)g_VMManager.Allocate(VertexShaderSize);
memcpy(pVertexShader->pFunction, pFunction, VertexShaderSize);
pVertexShader->FunctionSize = VertexShaderSize;
}
@ -4035,7 +4035,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateTexture)
// If YUY2 is not supported in hardware, we'll actually mark this as a special fake texture
Texture_Data = X_D3DRESOURCE_DATA_YUV_SURFACE;
pTexture->Lock = (DWORD)g_MemoryManager.Allocate(g_dwOverlayP * g_dwOverlayH);
pTexture->Lock = (DWORD)g_VMManager.Allocate(g_dwOverlayP * g_dwOverlayH);
g_pCachedYuvSurface = (X_D3DSurface*)pTexture;
@ -4185,7 +4185,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateVolumeTexture)
// If YUY2 is not supported in hardware, we'll actually mark this as a special fake texture
(*ppVolumeTexture)->Data = X_D3DRESOURCE_DATA_YUV_SURFACE;
(*ppVolumeTexture)->Lock = (DWORD)g_MemoryManager.Allocate(g_dwOverlayP * g_dwOverlayH);
(*ppVolumeTexture)->Lock = (DWORD)g_VMManager.Allocate(g_dwOverlayP * g_dwOverlayH);
(*ppVolumeTexture)->Format = Format << X_D3DFORMAT_FORMAT_SHIFT;
(*ppVolumeTexture)->Size = (g_dwOverlayW & X_D3DSIZE_WIDTH_MASK)
@ -4644,7 +4644,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_Begin)
if(g_IVBTable == nullptr)
{
g_IVBTable = (struct XTL::_D3DIVB*)g_MemoryManager.Allocate(sizeof(XTL::_D3DIVB)*IVB_TABLE_SIZE);
g_IVBTable = (struct XTL::_D3DIVB*)g_VMManager.Allocate(sizeof(XTL::_D3DIVB)*IVB_TABLE_SIZE);
}
g_IVBTblOffs = 0;
@ -4655,7 +4655,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_Begin)
if(g_pIVBVertexBuffer == nullptr)
{
g_pIVBVertexBuffer = (DWORD*)g_MemoryManager.Allocate(IVB_BUFFER_SIZE);
g_pIVBVertexBuffer = (DWORD*)g_VMManager.Allocate(IVB_BUFFER_SIZE);
}
}
@ -5209,7 +5209,7 @@ VOID WINAPI XTL::EMUPATCH(D3DResource_Register)
// create vertex buffer
{
DWORD dwSize = g_MemoryManager.QueryAllocationSize(pBase);
DWORD dwSize = g_VMManager.QuerySize((VAddr)pBase);
if(dwSize == -1)
{
@ -5273,7 +5273,7 @@ VOID WINAPI XTL::EMUPATCH(D3DResource_Register)
// create push buffer
{
DWORD dwSize = g_MemoryManager.QueryAllocationSize(pBase);
DWORD dwSize = g_VMManager.QuerySize((VAddr)pBase);
if(dwSize == -1)
{
@ -5425,7 +5425,7 @@ VOID WINAPI XTL::EMUPATCH(D3DResource_Register)
// If YUY2 is not supported in hardware, we'll actually mark this as a special fake texture
// Note : This is the only change to the pResource argument passed into D3DResource_Register !
pPixelContainer->Data = X_D3DRESOURCE_DATA_YUV_SURFACE;
pPixelContainer->Lock = (DWORD)g_MemoryManager.Allocate(g_dwOverlayP * g_dwOverlayH);
pPixelContainer->Lock = (DWORD)g_VMManager.Allocate(g_dwOverlayP * g_dwOverlayH);
}
else
{
@ -5955,7 +5955,7 @@ ULONG WINAPI XTL::EMUPATCH(D3DResource_Release)
g_pCachedYuvSurface = NULL;
// free memory associated with this special resource handle
g_MemoryManager.Free((PVOID)pThis->Lock);
g_VMManager.Deallocate((VAddr)pThis->Lock);
}
EMUPATCH(D3DDevice_EnableOverlay)(FALSE);
@ -5970,7 +5970,7 @@ ULONG WINAPI XTL::EMUPATCH(D3DResource_Release)
if(pThis->Lock == X_D3DRESOURCE_LOCK_PALETTE)
{
g_MemoryManager.Free((void*)pThis->Data);
g_VMManager.Deallocate((VAddr)pThis->Data);
uRet = --pThis->Lock; // TODO : This makes no sense (as it mangles X_D3DRESOURCE_LOCK_PALETTE) but crashes otherwise?!
}
else if(pHostResource != nullptr)
@ -8527,7 +8527,7 @@ XTL::X_D3DPalette * WINAPI XTL::EMUPATCH(D3DDevice_CreatePalette2)
X_D3DPalette *pPalette = EmuNewD3DPalette();
pPalette->Common |= (Size << X_D3DPALETTE_COMMON_PALETTESIZE_SHIFT);
pPalette->Data = (DWORD)g_MemoryManager.AllocateContiguous(XboxD3DPaletteSizeToBytes(Size), PAGE_SIZE);
pPalette->Data = (DWORD)g_VMManager.Allocate(XboxD3DPaletteSizeToBytes(Size), 0, (~((::ULONG_PTR)0)), PAGE_SIZE, PAGE_EXECUTE_READWRITE, false);
pPalette->Lock = X_D3DRESOURCE_LOCK_PALETTE; // emulated reference count for palettes
// TODO: Should't we register the palette with a call to
@ -8701,17 +8701,17 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_DeleteVertexShader)
VERTEX_SHADER *pVertexShader = (VERTEX_SHADER *)pD3DVertexShader->Handle;
RealHandle = pVertexShader->Handle;
g_MemoryManager.Free(pVertexShader->pDeclaration);
g_VMManager.Deallocate((VAddr)pVertexShader->pDeclaration);
if(pVertexShader->pFunction)
{
g_MemoryManager.Free(pVertexShader->pFunction);
g_VMManager.Deallocate((VAddr)pVertexShader->pFunction);
}
FreeVertexDynamicPatch(pVertexShader);
g_MemoryManager.Free(pVertexShader);
g_MemoryManager.Free(pD3DVertexShader);
g_VMManager.Deallocate((VAddr)pVertexShader);
g_VMManager.Deallocate((VAddr)pD3DVertexShader);
}
HRESULT hRet = g_pD3DDevice8->DeleteVertexShader(RealHandle);

View File

@ -72,7 +72,6 @@
#include "CxbxKrnl/Emu.h"
#include "CxbxKrnl/EmuFS.h"
#include "CxbxKrnl/EmuXTL.h"
#include <CxbxKrnl/MemoryManager.h>
//#include <CxbxKrnl/EmuD3D8Types.h> // X_PSH_COMBINECOUNT

View File

@ -40,7 +40,6 @@
#include "CxbxKrnl/EmuXTL.h"
#include "CxbxKrnl/EmuD3D8Types.h" // For X_D3DFORMAT
#include "CxbxKrnl/ResourceTracker.h"
#include "CxbxKrnl/MemoryManager.h"
uint32 XTL::g_dwPrimaryPBCount = 0;
uint32 *XTL::g_pPrimaryPB = 0;

View File

@ -37,11 +37,11 @@
#define _CXBXKRNL_INTERNAL
#define _XBOXKRNL_DEFEXTRN_
#include "CxbxKrnl/VMManager.h"
#include "CxbxKrnl/xxhash32.h" // For XXHash32::hash()
#include "CxbxKrnl/Emu.h"
#include "CxbxKrnl/EmuXTL.h"
#include "CxbxKrnl/ResourceTracker.h"
#include "CxbxKrnl/MemoryManager.h"
#include <ctime>
@ -468,7 +468,7 @@ bool XTL::VertexPatcher::PatchStream(VertexPatchDesc *pPatchDesc,
uiVertexCount = pPatchDesc->dwVertexCount;
dwNewSize = uiVertexCount * pStreamPatch->ConvertedStride;
pNewVertexBuffer = NULL;
pNewData = (uint08*)g_MemoryManager.Allocate(dwNewSize);
pNewData = (uint08*)g_VMManager.Allocate(dwNewSize);
if(!pNewData)
{
CxbxKrnlCleanup("Couldn't allocate the new stream zero buffer");

View File

@ -41,7 +41,6 @@
#include "CxbxKrnl/Emu.h"
#include "CxbxKrnl/EmuFS.h"
#include "CxbxKrnl/EmuXTL.h"
#include "CxbxKrnl/MemoryManager.h"
#include "CxbxKrnl/EmuD3D8Types.h" // For X_D3DVSDE_*
// ****************************************************************************

View File

@ -49,7 +49,6 @@ namespace xboxkrnl {
#include "EmuFS.h"
#include "EmuShared.h"
#include "EmuXTL.h"
#include "MemoryManager.h"
#include "Logging.h"
#include <mmreg.h>

View File

@ -47,7 +47,7 @@ namespace xboxkrnl
#include "EmuKrnl.h" // For InitializeListHead(), etc.
#include "EmuFS.h"
#include "CxbxKrnl.h"
#include "MemoryManager.h"
#include "VMManager.h"
#undef FIELD_OFFSET // prevent macro redefinition warnings
#include <windows.h>
@ -404,7 +404,9 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData)
}
}
pNewTLS = g_MemoryManager.AllocateZeroed(1, dwCopySize + dwZeroSize + 0x100 /* + HACK: extra safety padding 0x100*/);
/* + HACK: extra safety padding 0x100 */
pNewTLS = (void*)g_VMManager.AllocateZeroed(dwCopySize + dwZeroSize + 0x100);
if (dwCopySize > 0) {
memcpy(pNewTLS, pTLSData, dwCopySize);
@ -446,7 +448,7 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData)
}
// Allocate the xbox KPCR structure
xboxkrnl::KPCR *NewPcr = (xboxkrnl::KPCR*)g_MemoryManager.AllocateZeroed(1, sizeof(xboxkrnl::KPCR));
xboxkrnl::KPCR *NewPcr = (xboxkrnl::KPCR*)g_VMManager.AllocateZeroed(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
@ -488,7 +490,7 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData)
// Initialize a fake PrcbData.CurrentThread
{
xboxkrnl::ETHREAD *EThread = (xboxkrnl::ETHREAD*)g_MemoryManager.AllocateZeroed(1, sizeof(xboxkrnl::ETHREAD)); // Clear, to prevent side-effects on random contents
xboxkrnl::ETHREAD *EThread = (xboxkrnl::ETHREAD*)g_VMManager.AllocateZeroed(sizeof(xboxkrnl::ETHREAD)); // Clear, to prevent side-effects on random contents
EThread->Tcb.TlsData = pNewTLS;
EThread->UniqueThread = GetCurrentThreadId();

View File

@ -49,7 +49,7 @@
#include <ntstatus.h>
#pragma warning(default:4005)
#include "CxbxKrnl.h"
#include "MemoryManager.h"
#include "VMManager.h"
#include <experimental/filesystem>
@ -710,7 +710,7 @@ EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(const HANDLE Handl
void _CxbxPVOIDDeleter(PVOID *ptr)
{
if (*ptr)
g_MemoryManager.Free(*ptr);
g_VMManager.Deallocate((VAddr)*ptr);
}
// ----------------------------------------------------------------------------
@ -728,7 +728,7 @@ NtDll::FILE_LINK_INFORMATION * _XboxToNTLinkInfo(xboxkrnl::FILE_LINK_INFORMATION
// Build the native FILE_LINK_INFORMATION struct
*Length = sizeof(NtDll::FILE_LINK_INFORMATION) + convertedFileName.size() * sizeof(wchar_t);
NtDll::FILE_LINK_INFORMATION *ntLinkInfo = (NtDll::FILE_LINK_INFORMATION *) g_MemoryManager.AllocateZeroed(1, *Length);
NtDll::FILE_LINK_INFORMATION *ntLinkInfo = (NtDll::FILE_LINK_INFORMATION *) g_VMManager.AllocateZeroed(*Length);
ntLinkInfo->ReplaceIfExists = xboxLinkInfo->ReplaceIfExists;
ntLinkInfo->RootDirectory = RootDirectory;
ntLinkInfo->FileNameLength = convertedFileName.size() * sizeof(wchar_t);
@ -748,7 +748,7 @@ NtDll::FILE_RENAME_INFORMATION * _XboxToNTRenameInfo(xboxkrnl::FILE_RENAME_INFOR
// Build the native FILE_RENAME_INFORMATION struct
*Length = sizeof(NtDll::FILE_RENAME_INFORMATION) + convertedFileName.size() * sizeof(wchar_t);
NtDll::FILE_RENAME_INFORMATION *ntRenameInfo = (NtDll::FILE_RENAME_INFORMATION *) g_MemoryManager.AllocateZeroed(1, *Length);
NtDll::FILE_RENAME_INFORMATION *ntRenameInfo = (NtDll::FILE_RENAME_INFORMATION *) g_VMManager.AllocateZeroed(*Length);
ntRenameInfo->ReplaceIfExists = xboxRenameInfo->ReplaceIfExists;
ntRenameInfo->RootDirectory = RootDirectory;
ntRenameInfo->FileNameLength = convertedFileName.size() * sizeof(wchar_t);

View File

@ -47,7 +47,6 @@ namespace xboxkrnl
#include "Logging.h" // For LOG_FUNC()
#include "EmuKrnlLogging.h"
#include "MemoryManager.h"
// prevent name collisions
namespace NtDll

View File

@ -42,13 +42,13 @@
// prevent name collisions
namespace xboxkrnl
{
#include <xboxkrnl/xboxkrnl.h> // For ExAllocatePool, etc.
#include <xboxkrnl/xboxkrnl.h> // For ExAllocatePool, etc.
};
#include "Logging.h" // For LOG_FUNC()
#include "EmuEEPROM.h" // For EmuFindEEPROMInfo, EEPROM, XboxFactoryGameRegion
#include "EmuKrnlLogging.h"
#include "MemoryManager.h"
#include "VMManager.h"
// prevent name collisions
namespace NtDll
@ -128,7 +128,7 @@ XBSYSAPI EXPORTNUM(15) xboxkrnl::PVOID NTAPI xboxkrnl::ExAllocatePoolWithTag
LOG_FUNC_ARG(Tag)
LOG_FUNC_END;
PVOID pRet = g_MemoryManager.AllocateZeroed(1, NumberOfBytes); // Clear, to prevent side-effects on random contents
PVOID pRet = (xboxkrnl::PVOID)g_VMManager.AllocateZeroed(NumberOfBytes); // Clear, to prevent side-effects on random contents
LOG_INCOMPLETE(); // TODO : Actually implement ExAllocatePoolWithTag
@ -159,7 +159,7 @@ XBSYSAPI EXPORTNUM(17) xboxkrnl::VOID NTAPI xboxkrnl::ExFreePool
{
LOG_FUNC_ONE_ARG(P);
g_MemoryManager.Free(P);
g_VMManager.Deallocate((VAddr)P);
}
// ******************************************************************

View File

@ -30,6 +30,7 @@
// *
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
// * (c) 2016 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2017 ergo720
// *
// * All rights reserved
// *
@ -50,7 +51,8 @@ namespace xboxkrnl
#include "EmuKrnlLogging.h"
#include "CxbxKrnl.h" // For CxbxKrnlCleanup
#include "Emu.h" // For EmuWarning()
#include "MemoryManager.h"
#include "VMManager.h"
#include "EmuShared.h"
// prevent name collisions
namespace NtDll
@ -70,7 +72,7 @@ XBSYSAPI EXPORTNUM(102) xboxkrnl::PVOID xboxkrnl::MmGlobalData[8] = { NULL, NULL
// the xbox kernel. Kernel code accessses this as a normal variable.
// XAPI code however, reference to the address of this kernel variable,
// thus use indirection (*LaunchDataPage) to get to the same contents.
XBSYSAPI EXPORTNUM(164) xboxkrnl::PLAUNCH_DATA_PAGE xboxkrnl::LaunchDataPage = NULL;
XBSYSAPI EXPORTNUM(164) xboxkrnl::PLAUNCH_DATA_PAGE xboxkrnl::LaunchDataPage = xbnull;
// ******************************************************************
// * 0x00A5 - MmAllocateContiguousMemory()
@ -110,30 +112,34 @@ XBSYSAPI EXPORTNUM(166) xboxkrnl::PVOID NTAPI xboxkrnl::MmAllocateContiguousMemo
LOG_FUNC_ARG(HighestAcceptableAddress)
LOG_FUNC_ARG(Alignment)
LOG_FUNC_ARG_TYPE(PROTECTION_TYPE, ProtectionType)
LOG_FUNC_END;
LOG_FUNC_END;
PVOID pRet = (PVOID)1; // Marker, never returned, overwritten with NULL on input error
// size must be > 0
if (NumberOfBytes == 0)
pRet = xbnull;
if (Alignment < PAGE_SIZE)
Alignment = PAGE_SIZE; // page boundary at least
// Only known flags are allowed
if ((ProtectionType & ~PAGE_KNOWN_FLAGS) != 0)
pRet = NULL;
pRet = xbnull;
// Either PAGE_READONLY or PAGE_READWRITE must be set (not both, nor none)
if (((ProtectionType & PAGE_READONLY) > 0) == ((ProtectionType & PAGE_READWRITE) > 0))
pRet = NULL;
pRet = xbnull;
// Combining PAGE_NOCACHE and PAGE_WRITECOMBINE isn't allowed
if ((ProtectionType & (PAGE_NOCACHE | PAGE_WRITECOMBINE)) == (PAGE_NOCACHE | PAGE_WRITECOMBINE))
pRet = NULL;
pRet = xbnull;
// Allocate when input arguments are valid
if (pRet != NULL)
if (pRet != xbnull)
{
// TODO : Allocate differently if(ProtectionType & PAGE_WRITECOMBINE)
pRet = g_MemoryManager.AllocateContiguous(NumberOfBytes, Alignment);
pRet = (PVOID)g_VMManager.Allocate(NumberOfBytes, LowestAcceptableAddress, HighestAcceptableAddress, Alignment, ProtectionType, false);
}
RETURN(pRet);
@ -151,10 +157,10 @@ XBSYSAPI EXPORTNUM(167) xboxkrnl::PVOID NTAPI xboxkrnl::MmAllocateSystemMemory
LOG_FUNC_BEGIN
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_ARG(Protect)
LOG_FUNC_END;
LOG_FUNC_END;
// TODO: should this be aligned?
PVOID pRet = g_MemoryManager.Allocate(NumberOfBytes);
// TODO: this should probably allocate the memory at a specific system virtual address region...
PVOID pRet = (PVOID)g_VMManager.Allocate(NumberOfBytes, 0, MAXULONG_PTR, PAGE_SIZE, Protect);
RETURN(pRet);
}
@ -171,13 +177,18 @@ XBSYSAPI EXPORTNUM(168) xboxkrnl::PVOID NTAPI xboxkrnl::MmClaimGpuInstanceMemory
LOG_FUNC_BEGIN
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_ARG_OUT(NumberOfPaddingBytes)
LOG_FUNC_END;
LOG_FUNC_END;
if (g_bIsChihiro)
unsigned int highest_physical_page = MM_XBOX_HIGHEST_PHYSICAL_PAGE;
unsigned int instance_physical_page = MM_XBOX_INSTANCE_PHYSICAL_PAGE;
if (g_bIsChihiro || g_bIsDebug)
{
*NumberOfPaddingBytes = 0;
highest_physical_page = MM_CHIHIRO_HIGHEST_PHYSICAL_PAGE;
}
else
*NumberOfPaddingBytes = MI_CONVERT_PFN_TO_PHYSICAL(MM_64M_PHYSICAL_PAGE) -
MI_CONVERT_PFN_TO_PHYSICAL(MM_INSTANCE_PHYSICAL_PAGE + MM_INSTANCE_PAGE_COUNT);
MI_CONVERT_PFN_TO_PHYSICAL(instance_physical_page + MM_INSTANCE_PAGE_COUNT);
DbgPrintf("KNRL: MmClaimGpuInstanceMemory : *NumberOfPaddingBytes = 0x%.8X\n", *NumberOfPaddingBytes);
@ -189,7 +200,7 @@ XBSYSAPI EXPORTNUM(168) xboxkrnl::PVOID NTAPI xboxkrnl::MmClaimGpuInstanceMemory
}
#endif
PVOID Result = (PUCHAR)MI_CONVERT_PFN_TO_PHYSICAL(MM_HIGHEST_PHYSICAL_PAGE + 1)
PVOID Result = (PUCHAR)MI_CONVERT_PFN_TO_PHYSICAL(highest_physical_page + 1)
- *NumberOfPaddingBytes;
RETURN(Result);
@ -209,41 +220,21 @@ XBSYSAPI EXPORTNUM(169) xboxkrnl::PVOID NTAPI xboxkrnl::MmCreateKernelStack
LOG_FUNC_BEGIN
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_ARG(DebuggerThread)
LOG_FUNC_END;
LOG_FUNC_END;
NtDll::PVOID BaseAddress = NULL;
if (!NumberOfBytes) {
// NumberOfBytes cannot be zero when passed to NtAllocateVirtualMemory() below
CxbxKrnlCleanup("Assertion: 'NumberOfBytes != 0' in MmCreateKernelStack()");
}
if (NumberOfBytes & 0xFF) {
// Validate NumberOfBytes for alignment with the page size
CxbxKrnlCleanup("Assertion: '(NumberOfBytes & (PAGE_SIZE -1)) == 0' in MmCreateKernelStack()");
}
VAddr addr = xbnull;
/**
* Function at present does not:
* - Create an additional guard PAGE_SIZE after allocation,
* - Fill allocation with any values
* - Treat DebuggerThread any differently
*/
NTSTATUS ret = NtDll::NtAllocateVirtualMemory(
/*ProcessHandle=*/g_CurrentProcessHandle,
/*BaseAddress=*/&BaseAddress,
/*ZeroBits=*/0,
/*RegionSize=*/&NumberOfBytes,
/*AllocationType=*/MEM_COMMIT,
/*Protect=*/PAGE_READWRITE);
if (NumberOfBytes)
{
addr = g_VMManager.AllocateStack(NumberOfBytes);
}
if (FAILED(ret))
EmuWarning("MmCreateKernelStack failed!");
else
BaseAddress = (PVOID)((ULONG)BaseAddress + NumberOfBytes);
RETURN(BaseAddress);
RETURN((PVOID)addr);
}
// ******************************************************************
@ -251,25 +242,20 @@ XBSYSAPI EXPORTNUM(169) xboxkrnl::PVOID NTAPI xboxkrnl::MmCreateKernelStack
// ******************************************************************
XBSYSAPI EXPORTNUM(170) xboxkrnl::VOID NTAPI xboxkrnl::MmDeleteKernelStack
(
PVOID EndAddress,
PVOID BaseAddress
PVOID StackBase,
PVOID StackLimit
)
{
LOG_FUNC_BEGIN
LOG_FUNC_ARG(EndAddress)
LOG_FUNC_ARG(BaseAddress)
LOG_FUNC_END;
LOG_FUNC_ARG(StackBase)
LOG_FUNC_ARG(StackLimit)
LOG_FUNC_END;
// TODO : Untested
ULONG RegionSize = 0;
NTSTATUS ret = NtDll::NtFreeVirtualMemory(
/*ProcessHandle=*/g_CurrentProcessHandle,
&BaseAddress,
&RegionSize,
/*FreeType=*/MEM_RELEASE);
size_t ActualSize = ((VAddr)StackBase - (VAddr)StackLimit) + PAGE_SIZE;
if (FAILED(ret))
EmuWarning("MmDeleteKernelStack failed!");
VAddr StackBottom = (VAddr)StackBase - ActualSize;
g_VMManager.DeallocateStack(StackBottom);
}
// ******************************************************************
@ -285,13 +271,7 @@ XBSYSAPI EXPORTNUM(171) xboxkrnl::VOID NTAPI xboxkrnl::MmFreeContiguousMemory
{
LOG_FUNC_ONE_ARG(BaseAddress);
if (BaseAddress == &DefaultLaunchDataPage) {
DbgPrintf("KNRL: Ignored MmFreeContiguousMemory(&DefaultLaunchDataPage)\n");
LOG_IGNORED();
return;
}
g_MemoryManager.Free(BaseAddress);
g_VMManager.Deallocate((VAddr)BaseAddress);
// TODO -oDxbx: Sokoban crashes after this, at reset time (press Black + White to hit this).
// Tracing in assembly shows the crash takes place quite a while further, so it's probably
@ -311,9 +291,9 @@ XBSYSAPI EXPORTNUM(172) xboxkrnl::NTSTATUS NTAPI xboxkrnl::MmFreeSystemMemory
LOG_FUNC_BEGIN
LOG_FUNC_ARG(BaseAddress)
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_END;
LOG_FUNC_END;
g_MemoryManager.Free(BaseAddress);
g_VMManager.Deallocate((VAddr)BaseAddress);
RETURN(STATUS_SUCCESS);
}
@ -335,8 +315,7 @@ XBSYSAPI EXPORTNUM(173) xboxkrnl::PHYSICAL_ADDRESS NTAPI xboxkrnl::MmGetPhysical
// MmLockUnlockBufferPages, emulate this???
LOG_INCOMPLETE();
// We emulate Virtual/Physical memory 1:1
return (PHYSICAL_ADDRESS)BaseAddress;
return g_VMManager.TranslateVAddr((VAddr)BaseAddress);
}
// ******************************************************************
@ -349,9 +328,14 @@ XBSYSAPI EXPORTNUM(174) xboxkrnl::BOOLEAN NTAPI xboxkrnl::MmIsAddressValid
{
LOG_FUNC_ONE_ARG_OUT(VirtualAddress);
LOG_UNIMPLEMENTED();
BOOLEAN Ret = FALSE;
RETURN(TRUE);
if (g_VMManager.QueryVAddr((VAddr)VirtualAddress))
{
Ret = TRUE;
}
RETURN(Ret);
}
// ******************************************************************
@ -368,8 +352,9 @@ XBSYSAPI EXPORTNUM(175) xboxkrnl::VOID NTAPI xboxkrnl::MmLockUnlockBufferPages
LOG_FUNC_ARG(BaseAddress)
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_ARG(Protect)
LOG_FUNC_END;
LOG_FUNC_END;
// REMARK: all the pages inside the main memory pool are non-relocatable so, for the moment, this function is pointless
LOG_IGNORED();
}
@ -385,8 +370,9 @@ XBSYSAPI EXPORTNUM(176) xboxkrnl::VOID NTAPI xboxkrnl::MmLockUnlockPhysicalPage
LOG_FUNC_BEGIN
LOG_FUNC_ARG(PhysicalAddress)
LOG_FUNC_ARG(UnlockPage)
LOG_FUNC_END;
LOG_FUNC_END;
// REMARK: all the pages inside the main memory pool are non-relocatable so, for the moment, this function is pointless
LOG_IGNORED();
}
@ -412,7 +398,7 @@ XBSYSAPI EXPORTNUM(177) xboxkrnl::PVOID NTAPI xboxkrnl::MmMapIoSpace
LOG_FUNC_ARG(PhysicalAddress)
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_ARG(ProtectionType)
LOG_FUNC_END;
LOG_FUNC_END;
PVOID pRet;
@ -422,8 +408,7 @@ XBSYSAPI EXPORTNUM(177) xboxkrnl::PVOID NTAPI xboxkrnl::MmMapIoSpace
pRet = (PVOID)PhysicalAddress;
}
else {
// TODO: should this be aligned?
pRet = g_MemoryManager.Allocate(NumberOfBytes);
g_VMManager.Allocate(NumberOfBytes, 0, MAXULONG_PTR, PAGE_SIZE, ProtectionType);
LOG_INCOMPLETE();
}
@ -444,27 +429,21 @@ XBSYSAPI EXPORTNUM(178) xboxkrnl::VOID NTAPI xboxkrnl::MmPersistContiguousMemory
LOG_FUNC_ARG(BaseAddress)
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_ARG(Persist)
LOG_FUNC_END;
LOG_FUNC_END;
if (BaseAddress == LaunchDataPage)
{
PAddr LaunchDataPAddr = g_VMManager.TranslateVAddr((VAddr)BaseAddress);
if (Persist)
{
FILE* fp = fopen(szFilePath_LaunchDataPage_bin, "wb"); // TODO : Support wide char paths using _wfopen
if (fp)
{
DbgPrintf("KNRL: Persisting LaunchDataPage\n");
fseek(fp, 0, SEEK_SET);
fwrite(LaunchDataPage, sizeof(LAUNCH_DATA_PAGE), 1, fp);
fclose(fp);
}
else
DbgPrintf("KNRL: Can't persist LaunchDataPage to %s!\n", szFilePath_LaunchDataPage_bin);
g_EmuShared->SetLaunchDataPAddress(&LaunchDataPAddr);
DbgPrintf("KNRL: Persisting LaunchDataPage\n");
}
else
{
LaunchDataPAddr = NULL;
g_EmuShared->SetLaunchDataPAddress(&LaunchDataPAddr);
DbgPrintf("KNRL: Forgetting LaunchDataPage\n");
remove(szFilePath_LaunchDataPage_bin);
}
}
else
@ -494,12 +473,7 @@ XBSYSAPI EXPORTNUM(179) xboxkrnl::ULONG NTAPI xboxkrnl::MmQueryAddressProtect
{
LOG_FUNC_ONE_ARG(VirtualAddress);
// Assume read/write when page is allocated :
ULONG Result = PAGE_NOACCESS;
if (g_MemoryManager.IsAllocated(VirtualAddress)) {
Result = PAGE_READWRITE;
}
ULONG Result = g_VMManager.QueryProtection((VAddr)VirtualAddress);
LOG_INCOMPLETE(); // TODO : Improve the MmQueryAddressProtect implementation
@ -516,9 +490,7 @@ XBSYSAPI EXPORTNUM(180) xboxkrnl::ULONG NTAPI xboxkrnl::MmQueryAllocationSize
{
LOG_FUNC_ONE_ARG(BaseAddress);
LOG_INCOMPLETE(); // TODO : Free PAGE_WRITECOMBINE differently
ULONG uiSize = g_MemoryManager.QueryAllocationSize(BaseAddress);
ULONG uiSize = g_VMManager.QuerySize((VAddr)BaseAddress);
RETURN(uiSize);
}
@ -533,30 +505,20 @@ XBSYSAPI EXPORTNUM(181) xboxkrnl::NTSTATUS NTAPI xboxkrnl::MmQueryStatistics
{
LOG_FUNC_ONE_ARG_OUT(MemoryStatistics);
MEMORYSTATUSEX MemoryStatus;
SYSTEM_INFO SysInfo;
NTSTATUS ret;
#ifdef _DEBUG_TRACE
if (!MemoryStatistics)
{
DbgPrintf("KNRL: MmQueryStatistics : PMM_STATISTICS MemoryStatistics is nullptr!\n");
LOG_IGNORED();
RETURN(STATUS_SUCCESS);
}
#endif
if (MemoryStatistics->Length == sizeof(MM_STATISTICS))
{
GlobalMemoryStatusEx(&MemoryStatus);
GetSystemInfo(&SysInfo);
/**
* When each of the PMM_STATISTICS MemoryStatistics elements
* are setup correctly below, these two lines become redundant
*/
ZeroMemory(MemoryStatistics, sizeof(MM_STATISTICS));
//MemoryStatistics->Length = sizeof(MM_STATISTICS);
MemoryStatistics->TotalPhysicalPages = (ULONG)(MemoryStatus.ullTotalPhys / SysInfo.dwPageSize);
MemoryStatistics->AvailablePages = (ULONG)(MemoryStatus.ullAvailPhys / SysInfo.dwPageSize);
MemoryStatistics->VirtualMemoryBytesCommitted = (ULONG)(MemoryStatus.ullTotalVirtual - MemoryStatus.ullAvailVirtual);
MemoryStatistics->VirtualMemoryBytesReserved = (ULONG)(MemoryStatus.ullAvailVirtual);
// MemoryStatistics->CachePagesCommitted = [ ];
// MemoryStatistics->PoolPagesCommitted = [ ];
// MemoryStatistics->StackPagesCommitted = [ ];
// MemoryStatistics->ImagePagesCommitted = [ ];
g_VMManager.MemoryStatistics(MemoryStatistics);
DbgPrintf(" MemoryStatistics->Length = 0x%.08X\n", MemoryStatistics->Length);
DbgPrintf(" MemoryStatistics->TotalPhysicalPages = 0x%.08X\n", MemoryStatistics->TotalPhysicalPages);
@ -593,14 +555,9 @@ XBSYSAPI EXPORTNUM(182) xboxkrnl::VOID NTAPI xboxkrnl::MmSetAddressProtect
LOG_FUNC_ARG(BaseAddress)
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_ARG(NewProtect)
LOG_FUNC_END;
LOG_FUNC_END;
DWORD dwOldProtect;
if (!VirtualProtect(BaseAddress, NumberOfBytes, NewProtect & (~PAGE_WRITECOMBINE), &dwOldProtect))
EmuWarning("VirtualProtect Failed!");
DbgPrintf("KRNL: VirtualProtect was 0x%.8X -> 0x%.8X\n", dwOldProtect, NewProtect & (~PAGE_WRITECOMBINE));
g_VMManager.Protect((VAddr)BaseAddress, NumberOfBytes, NewProtect);
}
// ******************************************************************
@ -618,13 +575,13 @@ XBSYSAPI EXPORTNUM(183) xboxkrnl::NTSTATUS NTAPI xboxkrnl::MmUnmapIoSpace
LOG_FUNC_BEGIN
LOG_FUNC_ARG(BaseAddress)
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_END;
LOG_FUNC_END;
if ((xbaddr)BaseAddress >= XBOX_WRITE_COMBINED_BASE) { // 0xF0000000
// Don't free hardware devices (flash, NV2A, etc)
}
else {
g_MemoryManager.Free(BaseAddress);
g_VMManager.Deallocate((VAddr)BaseAddress);
LOG_INCOMPLETE();
}

View File

@ -57,7 +57,6 @@ namespace NtDll
#include "CxbxKrnl.h" // For CxbxKrnlCleanup
#include "Emu.h" // For EmuWarning()
#include "EmuFile.h" // For EmuNtSymbolicLinkObject, NtStatusToString(), etc.
#include "MemoryManager.h"
#pragma warning(disable:4005) // Ignore redefined status values
#include <ntstatus.h>

View File

@ -49,6 +49,7 @@ namespace xboxkrnl
#include "Logging.h" // For LOG_FUNC()
#include "EmuKrnlLogging.h"
#include "Emu.h" // For EmuWarning()
#include "VMManager.h"
// ******************************************************************
// * 0x0146 - XeImageFileName
@ -79,7 +80,7 @@ XBSYSAPI EXPORTNUM(327) xboxkrnl::NTSTATUS NTAPI xboxkrnl::XeLoadSection
LOG_FUNC_ARG(Section)
LOG_FUNC_END;
NTSTATUS ret = STATUS_INVALID_HANDLE;
NTSTATUS ret = STATUS_SUCCESS;
void* sectionData = CxbxKrnl_Xbe->FindSection((char*)std::string(Section->SectionName, 9).c_str());
if (sectionData != nullptr) {
@ -89,12 +90,46 @@ XBSYSAPI EXPORTNUM(327) xboxkrnl::NTSTATUS NTAPI xboxkrnl::XeLoadSection
memset(Section->VirtualAddress, 0, Section->VirtualSize);
// Copy the section data
memcpy(Section->VirtualAddress, sectionData, Section->FileSize);
// ergo720: I can't just +/- PAGE_SIZE the VirtualAddress and the VirtualSize of a section because some titles have
// sections less than PAGE_SIZE, which will cause again an overlap with the next section since both will have the
// same aligned starting address.
// Test case: Dead or Alive 3, section XGRPH has a size of 764 bytes
// XGRPH DSOUND
// 1F18A0 + 2FC -> aligned_start = 1F1000 1F1BA0 -> aligned_start = 1F1000 <- collision
// The following just increases the amount of physical/virtual memory consumed but doesn't actually allocate anything
// inside the manager. This is done so that, because we now have fewer physical allocations, we also get more free contiguous
// space that can be used by MmAllocateContiguousMemoryEx, which is problematic to map in the case of fragmentation. Also
// note that the manager physical allocation routines check the free memory left before attempting a new allocation and bail out
// immediately if not enough is available, this prevents exceeding the max memory on the Xbox
VAddr BaseAddress = (VAddr)Section->VirtualAddress;
VAddr EndingAddress = (VAddr)Section->VirtualAddress + Section->VirtualSize;
if ((*Section->TailReferenceCount) != 0)
{
EndingAddress &= ~PAGE_MASK;
}
if ((*Section->HeadReferenceCount) != 0)
{
BaseAddress = (BaseAddress + PAGE_SIZE) & ~PAGE_MASK;
}
if (EndingAddress > BaseAddress)
{
size_t RegionSize = EndingAddress - BaseAddress;
ret = XbAllocateVirtualMemoryStub(&BaseAddress, 0, &RegionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
// Increment the head/tail page reference counters
(*Section->HeadReferenceCount)++;
(*Section->TailReferenceCount)++;
}
// Increment the reference count
Section->SectionReferenceCount++;
ret = STATUS_SUCCESS;
}
RETURN(ret);
@ -123,9 +158,34 @@ XBSYSAPI EXPORTNUM(328) xboxkrnl::NTSTATUS NTAPI xboxkrnl::XeUnloadSection
// Decrement the reference count
Section->SectionReferenceCount -= 1;
// Free the section if necessary
// Free the section and the physical memory in use if necessary
if (Section->SectionReferenceCount == 0) {
memset(Section->VirtualAddress, 0, Section->VirtualSize);
// REMARK: the following can be tested with Broken Sword - The Sleeping Dragon, RalliSport Challenge, ...
VAddr BaseAddress = (VAddr)Section->VirtualAddress;
VAddr EndingAddress = (VAddr)Section->VirtualAddress + Section->VirtualSize;
// Decrement the head/tail page reference counters
(*Section->HeadReferenceCount)--;
(*Section->TailReferenceCount)--;
if ((*Section->TailReferenceCount) != 0)
{
EndingAddress &= ~PAGE_MASK;
}
if ((*Section->HeadReferenceCount) != 0)
{
BaseAddress = (BaseAddress + PAGE_SIZE) & ~PAGE_MASK;
}
if (EndingAddress > BaseAddress)
{
size_t RegionSize = EndingAddress - BaseAddress;
XbFreeVirtualMemoryStub(&BaseAddress, &RegionSize, MEM_DECOMMIT);
}
}
ret = STATUS_SUCCESS;

View File

@ -82,6 +82,7 @@ namespace xboxkrnl
#include <cassert>
//#include <gl\glut.h>
// Public Domain ffs Implementation
// See: http://snipplr.com/view/22147/stringsh-implementation/
int ffs(int v)
@ -2764,8 +2765,11 @@ DEVICE_READ32(PFB)
result = 3; // = NV_PFB_CFG0_PART_4
break;
case NV_PFB_CSTATUS:
result = CONTIGUOUS_MEMORY_SIZE;
break;
{
if (g_bIsChihiro || g_bIsDebug) { result = CONTIGUOUS_MEMORY_CHIHIRO_SIZE; break; }
result = CONTIGUOUS_MEMORY_XBOX_SIZE;
}
break;
case NV_PFB_WBC:
result = 0; // = !NV_PFB_WBC_FLUSH
break;

View File

@ -47,6 +47,8 @@ enum {
LLE_JIT = 1 << 2,
};
typedef UINT_PTR PAddr;
// ******************************************************************
// * EmuShared : Shared memory
// ******************************************************************
@ -122,6 +124,12 @@ class EmuShared : public Mutex
void GetMultiXbeFlag(bool *value) { Lock(); *value = m_bMultiXbe; Unlock(); }
void SetMultiXbeFlag(bool *value) { Lock(); m_bMultiXbe = *value; Unlock(); }
// ******************************************************************
// * Launch data physical address Accessors
// ******************************************************************
void GetLaunchDataPAddress(PAddr *value) { Lock(); *value = m_LaunchDataPAddress; Unlock(); }
void SetLaunchDataPAddress(PAddr *value) { Lock(); m_LaunchDataPAddress = *value; Unlock(); }
private:
// ******************************************************************
@ -142,6 +150,7 @@ class EmuShared : public Mutex
float m_MSpF;
float m_FPS;
bool m_bMultiXbe;
PAddr m_LaunchDataPAddress;
};
// ******************************************************************

View File

@ -50,7 +50,7 @@ namespace xboxkrnl
#include "EmuFS.h"
#include "EmuShared.h"
#include "EmuXTL.h"
#include "MemoryManager.h"
#include "VMManager.h"
#include <mmreg.h>
#include <msacm.h>
@ -82,7 +82,7 @@ HRESULT WINAPI XTL::EMUPATCH(XACTEngineCreate)
// TODO: Any other form of initialization?
*ppEngine = (X_XACTEngine*)g_MemoryManager.AllocateZeroed(1, sizeof( X_XACTEngine ) );
*ppEngine = (X_XACTEngine*)g_VMManager.AllocateZeroed(sizeof( X_XACTEngine ));
@ -130,7 +130,7 @@ HRESULT WINAPI XTL::EMUPATCH(IXACTEngine_RegisterWaveBank)
// TODO: Implement
*ppWaveBank = (X_XACTWaveBank*)g_MemoryManager.AllocateZeroed(1, sizeof( X_XACTWaveBank ) );
*ppWaveBank = (X_XACTWaveBank*)g_VMManager.AllocateZeroed(sizeof( X_XACTWaveBank ));
RETURN(S_OK);
}
@ -155,7 +155,7 @@ HRESULT WINAPI XTL::EMUPATCH(IXACTEngine_RegisterStreamedWaveBank)
// TODO: Implement
*ppWaveBank = (X_XACTWaveBank*)g_MemoryManager.AllocateZeroed(1, sizeof( X_XACTWaveBank ) );
*ppWaveBank = (X_XACTWaveBank*)g_VMManager.AllocateZeroed(sizeof( X_XACTWaveBank ));
RETURN(S_OK);
}
@ -182,7 +182,7 @@ HRESULT WINAPI XTL::EMUPATCH(IXACTEngine_CreateSoundBank)
// TODO: Implement
*ppSoundBank = (X_XACTSoundBank*)g_MemoryManager.AllocateZeroed(1, sizeof( X_XACTSoundBank ) );
*ppSoundBank = (X_XACTSoundBank*)g_VMManager.AllocateZeroed(sizeof( X_XACTSoundBank ));
RETURN(S_OK);
}
@ -232,7 +232,7 @@ HRESULT WINAPI XTL::EMUPATCH(IXACTEngine_CreateSoundSource)
LOG_FUNC_ARG(ppSoundSource)
LOG_FUNC_END;
*ppSoundSource = (X_XACTSoundSource*)g_MemoryManager.AllocateZeroed(1, sizeof( X_XACTSoundSource ) );
*ppSoundSource = (X_XACTSoundSource*)g_VMManager.AllocateZeroed(sizeof( X_XACTSoundSource ));
RETURN(S_OK);
}

View File

@ -1042,21 +1042,27 @@ DWORD WINAPI XTL::EMUPATCH(XLaunchNewImageA)
// Update the kernel's LaunchDataPage :
{
if (xboxkrnl::LaunchDataPage == &DefaultLaunchDataPage)
xboxkrnl::LaunchDataPage = NULL;
if (xboxkrnl::LaunchDataPage == NULL)
xboxkrnl::LaunchDataPage = (xboxkrnl::LAUNCH_DATA_PAGE *)xboxkrnl::MmAllocateContiguousMemory(sizeof(xboxkrnl::LAUNCH_DATA_PAGE));
if (xboxkrnl::LaunchDataPage == xbnull)
{
PVOID LaunchDataVAddr = xboxkrnl::MmAllocateContiguousMemory(sizeof(xboxkrnl::LAUNCH_DATA_PAGE));
if (!LaunchDataVAddr)
{
RETURN(STATUS_NO_MEMORY);
}
xboxkrnl::LaunchDataPage = (xboxkrnl::LAUNCH_DATA_PAGE*)LaunchDataVAddr;
}
xboxkrnl::LaunchDataPage->Header.dwTitleId = g_pCertificate->dwTitleId;
xboxkrnl::LaunchDataPage->Header.dwFlags = 0; // TODO : What to put in here?
xboxkrnl::LaunchDataPage->Header.dwLaunchDataType = LDT_TITLE;
if (pLaunchData != NULL)
xboxkrnl::MmPersistContiguousMemory((PVOID)xboxkrnl::LaunchDataPage, PAGE_SIZE, TRUE);
if (pLaunchData != xbnull)
// Save the launch data
memcpy(&(xboxkrnl::LaunchDataPage->LaunchData[0]), pLaunchData, sizeof(LAUNCH_DATA));
if (lpTitlePath == NULL)
if (lpTitlePath == xbnull)
{
// If no path is specified, then the xbe is rebooting to dashboard
char szDashboardPath[MAX_PATH] = { 0 };
@ -1089,8 +1095,6 @@ DWORD WINAPI XTL::EMUPATCH(XLaunchNewImageA)
RETURN(ERROR_GEN_FAILURE);
}
DWORD g_XGetLaunchInfo_Status = -1;
#if 0 // patch disabled
// ******************************************************************
// * patch: XGetLaunchInfo

View File

@ -1,286 +0,0 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// ******************************************************************
// *
// * .,-::::: .,:: .::::::::. .,:: .:
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
// * $$$ Y$$$P $$""""Y$$ Y$$$P
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
// *
// * Cxbx->Win32->CxbxKrnl->MemoryManager.cpp
// *
// * This file is part of the Cxbx project.
// *
// * Cxbx and Cxbe are free software; you can redistribute them
// * and/or modify them under the terms of the GNU General Public
// * License as published by the Free Software Foundation; either
// * version 2 of the license, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have recieved a copy of the GNU General Public License
// * along with this program; see the file COPYING.
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
// *
// * All rights reserved
// *
// ******************************************************************
#define LOG_PREFIX "XMEM"
#include <assert.h> // For assert()
#include <malloc.h> // For _aligned_malloc()
#include "CxbxKrnl.h"
#include "Emu.h"
#include "Logging.h"
#include "MemoryManager.h"
MemoryManager g_MemoryManager;
MemoryManager::MemoryManager()
{
InitializeCriticalSectionAndSpinCount(&m_CriticalSection, 0x400);
}
MemoryManager::~MemoryManager()
{
DeleteCriticalSection(&m_CriticalSection);
}
// Acquire m_CriticalSection before calling FindContainingTypedMemoryBlock!
TypedMemoryBlock *MemoryManager::FindContainingTypedMemoryBlock(void* addr)
{
// Find the first block whose key (upper_bound) is not less than the requested address (thus: upper_bound >= addr)
auto low = m_MemoryBlockInfo.lower_bound(addr);
if (low == m_MemoryBlockInfo.end())
return nullptr;
// Check if the requested address lies inside this block
TypedMemoryBlock *info = &(low->second);
if (addr < info->block.addr)
return nullptr;
assert((uintptr_t)addr <= ((uintptr_t)info->block.upper_bound));
return info;
}
void* MemoryManager::Allocate(size_t size)
{
LOG_FUNC_ONE_ARG(size);
assert(size > 0);
void * addr = malloc(size);
if (addr != NULL) {
TypedMemoryBlock info;
info.type = MemoryType::STANDARD;
info.block.init(addr, size);
EnterCriticalSection(&m_CriticalSection);
m_MemoryBlockInfo[info.block.upper_bound] = info;
LeaveCriticalSection(&m_CriticalSection);
} else {
#if 1 // TODO : Only log this in DEBUG builds (as a failure is already indicated by a null result)
EmuWarning("MemoryManager::Allocate Failed!");
#endif
}
RETURN((void*)addr);
}
void* MemoryManager::AllocateAligned(size_t size, size_t alignment)
{
LOG_FUNC_BEGIN
LOG_FUNC_ARG(size) ;
LOG_FUNC_ARG(alignment);
LOG_FUNC_END;
assert(size > 0);
void * addr = _aligned_malloc(size, alignment);
if (addr != NULL) {
TypedMemoryBlock info;
info.type = MemoryType::ALIGNED;
info.block.init(addr, size);
EnterCriticalSection(&m_CriticalSection);
m_MemoryBlockInfo[info.block.upper_bound] = info;
LeaveCriticalSection(&m_CriticalSection);
}
RETURN((void*)addr);
}
void* MemoryManager::AllocateContiguous(size_t size, size_t alignment)
{
LOG_FUNC_BEGIN
LOG_FUNC_ARG(size);
LOG_FUNC_ARG(alignment);
LOG_FUNC_END;
assert(size > 0);
assert(alignment >= 4096); // TODO : Pull PAGE_SIZE in scope for this?
assert((alignment & (alignment - 1)) == 0);
xbaddr alignMask = (xbaddr)(alignment - 1);
xbaddr addr = NULL;
EnterCriticalSection(&m_CriticalSection);
// Is the contiguous allocation table empty?
if (m_ContiguousMemoryBlocks.empty()) {
// Start allocating Contiguous Memory after the Kernel image header to prevent overwriting our dummy Kernel
addr = XBOX_KERNEL_BASE + sizeof(DUMMY_KERNEL);
addr = (addr + alignMask) & ~alignMask;
} else {
// Locate the first available Memory Region with enough space for the requested buffer
// TODO : This could be improved later on by always locating the smallest block with enough space
// in order to reduce memory fragmentation.
for (auto it = m_ContiguousMemoryBlocks.begin(); it != m_ContiguousMemoryBlocks.end(); ++it) {
MemoryBlock current = it->second;
xbaddr after_current = (xbaddr)current.upper_bound + 1;
after_current = (after_current + alignMask) & ~alignMask;
// Is this the last entry?
if (std::next(it) == m_ContiguousMemoryBlocks.end()) {
// Continue allocating after the last block :
addr = after_current;
break;
}
// Is there an empty gap after the current entry?
MemoryBlock next = std::next(it)->second;
if (after_current < (xbaddr)next.addr) {
// does this allocation fit inside the gap?
if (after_current + size < (xbaddr)next.addr) {
addr = after_current;
break;
}
}
}
}
if (addr + size > CONTIGUOUS_MEMORY_BASE + CONTIGUOUS_MEMORY_SIZE) {
EmuWarning("MemoryManager::AllocateContiguous exhausted it's allowed memory buffer");
addr = NULL;
}
if (addr != NULL) {
MemoryBlock block;
block.init((void *)addr, size);
m_ContiguousMemoryBlocks[(void *)addr] = block;
TypedMemoryBlock info;
info.type = MemoryType::CONTIGUOUS;
info.block = block;
m_MemoryBlockInfo[info.block.upper_bound] = info;
}
LeaveCriticalSection(&m_CriticalSection);
RETURN((void*)addr);
}
void* MemoryManager::AllocateZeroed(size_t num, size_t size)
{
LOG_FORWARD(Allocate); // Log AllocateZeroed as the origin of the following RETURN log message
void* addr = Allocate(num * size);
if (addr != nullptr) {
memset(addr, 0, num * size);
}
return addr; // Dont use RETURN, as Allocate already logs the result with that
}
bool MemoryManager::IsAllocated(void* addr)
{
bool result;
LOG_FUNC_ONE_ARG(addr);
EnterCriticalSection(&m_CriticalSection);
result = (FindContainingTypedMemoryBlock(addr) != nullptr);
LeaveCriticalSection(&m_CriticalSection);
RETURN(result);
}
void MemoryManager::Free(void* addr)
{
LOG_FUNC_ONE_ARG(addr);
EnterCriticalSection(&m_CriticalSection);
TypedMemoryBlock *info = FindContainingTypedMemoryBlock(addr);
if (info != nullptr) {
if (info->block.addr == addr) {
switch (info->type) {
case MemoryType::ALIGNED:
_aligned_free((void*)info->block.addr);
break;
case MemoryType::STANDARD:
free((void*)info->block.addr);
break;
case MemoryType::CONTIGUOUS:
m_ContiguousMemoryBlocks.erase(info->block.addr);
break;
default:
CxbxKrnlCleanup("Fatal: MemoryManager attempted to free memory of an unknown type");
break;
}
m_MemoryBlockInfo.erase(info->block.upper_bound);
}
else {
__debugbreak();
CxbxKrnlCleanup("Fatal: MemoryManager attempted to free only a part of a block");
}
} else {
__debugbreak();
CxbxKrnlCleanup("Fatal: Attempted to free memory that was not allocated via MemoryManager");
}
LeaveCriticalSection(&m_CriticalSection);
}
size_t MemoryManager::QueryAllocationSize(void* addr)
{
LOG_FUNC_ONE_ARG(addr);
size_t ret = 0;
EnterCriticalSection(&m_CriticalSection);
TypedMemoryBlock *info = FindContainingTypedMemoryBlock(addr);
if (info != nullptr) {
// Return the available size in this block
ret = (uintptr_t)info->block.upper_bound - (uintptr_t)addr + 1;
}
else {
#if 1 // TODO : Only log this in DEBUG builds (as a failure is already indicated by a null result)?
EmuWarning("MemoryManager: Attempted to query memory that was not allocated via MemoryManager");
#endif
}
LeaveCriticalSection(&m_CriticalSection);
RETURN(ret);
}

View File

@ -1,83 +0,0 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// ******************************************************************
// *
// * .,-::::: .,:: .::::::::. .,:: .:
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
// * $$$ Y$$$P $$""""Y$$ Y$$$P
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
// *
// * Cxbx->Win32->CxbxKrnl->MemoryManager.h
// *
// * This file is part of the Cxbx project.
// *
// * Cxbx and Cxbe are free software; you can redistribute them
// * and/or modify them under the terms of the GNU General Public
// * License as published by the Free Software Foundation; either
// * version 2 of the license, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have recieved a copy of the GNU General Public License
// * along with this program; see the file COPYING.
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
// *
// * All rights reserved
// *
// ******************************************************************
#ifndef MEMORY_MANAGER_H
#define MEMORY_MANAGER_H
#include <Windows.h>
#include <cstdint>
#include <map>
#include <unordered_map>
typedef struct {
void *addr;
void *upper_bound;
void init(void * base, size_t size) { addr = base; upper_bound = (void *)((uintptr_t)base + size - 1); }
} MemoryBlock;
enum struct MemoryType {
STANDARD = 0,
ALIGNED,
CONTIGUOUS
};
typedef struct {
MemoryType type;
MemoryBlock block;
} TypedMemoryBlock;
class MemoryManager
{
public:
MemoryManager();
~MemoryManager();
void* Allocate(size_t size);
void* AllocateAligned(size_t size, size_t alignment);
void* AllocateContiguous(size_t size, size_t alignment);
void* AllocateZeroed(size_t num, size_t size);
bool IsAllocated(void* addr);
void Free(void* addr);
size_t QueryAllocationSize(void* addr);
private:
std::map<void *, TypedMemoryBlock> m_MemoryBlockInfo;
std::map<void *, MemoryBlock> m_ContiguousMemoryBlocks;
CRITICAL_SECTION m_CriticalSection;
TypedMemoryBlock *FindContainingTypedMemoryBlock(void* addr);
};
extern MemoryManager g_MemoryManager;
#endif

View File

@ -0,0 +1,340 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// ******************************************************************
// *
// * .,-::::: .,:: .::::::::. .,:: .:
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
// * $$$ Y$$$P $$""""Y$$ Y$$$P
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
// *
// * Cxbx->Win32->CxbxKrnl->PhysicalMemory.cpp
// *
// * This file is part of the Cxbx project.
// *
// * Cxbx and Cxbe are free software; you can redistribute them
// * and/or modify them under the terms of the GNU General Public
// * License as published by the Free Software Foundation; either
// * version 2 of the license, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have recieved a copy of the GNU General Public License
// * along with this program; see the file COPYING.
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017 ergo720
// *
// * All rights reserved
// *
// ******************************************************************
#include "PhysicalMemory.h"
PMEMORY_STATUS PhysicalMemory::GetError() const
{
return m_Status;
}
PAddr PhysicalMemory::AllocatePhysicalMemory(size_t size)
{
PAddr addr = m_MaxContiguousAddress;
ClearError();
size_t FreeMemory = m_MaxContiguousAddress - m_PhysicalMemoryInUse;
if (size > FreeMemory)
{
EmuWarning("Out of physical memory!");
SetError(PMEMORY_INSUFFICIENT_MEMORY);
return addr;
}
// Allocate the block wherever possible
// This attempts to counter external fragmentation by allocating big blocks top-down and small blocks bottom-up
if (size > m_AllocationThreshold)
{
if (m_Mem_map.empty())
{
addr = m_MaxContiguousAddress - size;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
}
else
{
// Allocate the block starting from the top of memory
for (auto rit = m_Mem_map.rbegin(); ; ++rit)
{
if (std::next(rit) == m_Mem_map.rend())
{
if (rit->first >= size)
{
addr = rit->first - size;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
break;
}
if (FreeMemory >= size) // fragmentation
{
addr = AllocateFragmented(size);
break;
}
}
// Reinstate this if the nv2a instance memory allocation is found to be ever deallocated after being
// mapped during initialization. The only one that could do it is MmClaimGpuInstanceMemory, however it doesn't seem
// to deallocate the region, just to repurpose it...
//u32 offset = std::next(rit)->first + std::next(rit)->second;
/*if (rit == max_contiguous_it && m_MaxContiguousAddress - offset >= size)
{
addr = m_MaxContiguousAddress - size;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
break;
}*/
if (rit->first - (std::next(rit)->first + std::next(rit)->second) >= size)
{
addr = rit->first - size;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
break;
}
}
}
}
else
{
if (m_Mem_map.empty())
{
addr = 0;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
}
else
{
// Allocate the block starting from the bottom of memory
auto max_contiguous_it = m_Mem_map.lower_bound(m_MaxContiguousAddress); // skip the nv2a/PFN allocation
for (auto it = m_Mem_map.begin(); ; ++it)
{
if (it == m_Mem_map.begin() && it->first >= size)
{
addr = 0;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
break;
}
u32 offset = it->first + it->second;
if (std::next(it) == max_contiguous_it)
{
if (m_MaxContiguousAddress - offset >= size)
{
addr = offset;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
break;
}
if (FreeMemory >= size) // fragmentation
{
addr = AllocateFragmented(size);
break;
}
}
if (std::next(it)->first - offset >= size)
{
addr = offset;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
break;
}
}
}
}
return addr;
}
PAddr PhysicalMemory::AllocatePhysicalMemoryRange(size_t size, PAddr low_addr, PAddr high_addr)
{
PAddr addr = m_MaxContiguousAddress;
ClearError();
size_t FreeMemory = m_MaxContiguousAddress - m_PhysicalMemoryInUse;
if (size > FreeMemory)
{
EmuWarning("Out of physical memory!");
SetError(PMEMORY_INSUFFICIENT_MEMORY);
return addr;
}
// TODO: it's a bit complex to properly allocate the blocks inside the requested range using the iterators,
// a better approch would be to implement an actual PFN database and search free blocks with that, but unfortunately
// with the current code it's not possible to relocate already allocated blocks
// Allocate the block inside the specified range if possible, going from the top-down
if (m_Mem_map.empty())
{
addr = low_addr;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
}
else
{
size_t FreeMemoryInRange = 0;
auto low_pair = m_Mem_map.emplace(low_addr, 0);
PAddr lower_bound = low_addr;
if (low_pair.first != m_Mem_map.begin())
{
auto low_it = std::prev(low_pair.first);
if (low_it->first + low_it->second > low_addr)
{
lower_bound = low_it->first + low_it->second;
}
}
if (!low_pair.second)
{
lower_bound = low_addr + low_pair.first->second;
}
auto high_pair = m_Mem_map.emplace(high_addr, 0);
auto high_it = high_pair.first;
{
auto prev_it = std::prev(high_pair.first);
if (prev_it->first + prev_it->second >= high_pair.first->first)
{
high_it = prev_it;
if (high_it == low_pair.first)
{
SetError(PMEMORY_INSUFFICIENT_MEMORY);
EmuWarning("Not enough memory in range 0x%.8X - 0x%.8X", low_addr, high_addr);
if (high_pair.first->second == 0) { m_Mem_map.erase(high_addr); }
if (low_pair.first->second == 0) { m_Mem_map.erase(low_addr); }
return addr;
}
}
}
for (auto it = high_it; ; --it)
{
if (std::prev(it) == low_pair.first)
{
if (it->first - lower_bound >= size)
{
addr = it->first - size;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
break;
}
FreeMemoryInRange += (it->first - lower_bound);
if (FreeMemoryInRange >= size) // fragmentation
{
addr = AllocateFragmented(size);
break;
}
SetError(PMEMORY_INSUFFICIENT_MEMORY);
EmuWarning("Not enough memory in range 0x%.8X - 0x%.8X", low_addr, high_addr);
break;
}
size_t FreeBetween = it->first - (std::prev(it)->first + std::prev(it)->second);
if (FreeBetween >= size)
{
addr = it->first - size;
m_Mem_map[addr] = size;
m_PhysicalMemoryInUse += size;
break;
}
FreeMemoryInRange += FreeBetween;
}
if (high_pair.first->second == 0) { m_Mem_map.erase(high_addr); }
if (low_pair.first->second == 0) { m_Mem_map.erase(low_addr); }
}
return addr;
}
VAddr PhysicalMemory::AllocateFragmented(size_t size)
{
PAddr addr_ptr = (PAddr)VirtualAlloc(NULL, size + PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!addr_ptr)
{
EmuWarning("AllocateFragmented: VirtualAlloc could not allocate the memory!");
SetError(PMEMORY_INSUFFICIENT_MEMORY);
return m_MaxContiguousAddress;
}
VAddr aligned_start = addr_ptr & ~(UINT_PTR)PAGE_MASK;
m_Fragmented_mem_map[addr_ptr] = size;
EmuWarning("Warning: allocated memory via AllocateFragmented.");
SetError(PMEMORY_ALLOCATE_FRAGMENTED);
m_PhysicalMemoryInUse += size;
return aligned_start;
}
void PhysicalMemory::ShrinkPhysicalAllocation(PAddr addr, size_t offset, bool bFragmentedMap, bool bStart)
{
if (!offset) { return; } // nothing to do
if (bFragmentedMap)
{
auto it = std::prev(m_Fragmented_mem_map.upper_bound(addr));
PAddr old_base = it->first;
size_t old_size = it->second;
m_Fragmented_mem_map.erase(old_base);
if (old_size - offset)
{
if (bStart) { m_Fragmented_mem_map.emplace(old_base + offset, old_size - offset); }
else { m_Fragmented_mem_map.emplace(old_base, old_size - offset); }
}
m_PhysicalMemoryInUse -= offset;
}
else
{
auto it = m_Mem_map.lower_bound(addr);
PAddr old_base = it->first;
size_t old_size = it->second;
m_Mem_map.erase(old_base);
if (old_size - offset)
{
if (bStart) { m_Mem_map.emplace(old_base + offset, old_size - offset); }
else { m_Mem_map.emplace(old_base, old_size - offset); }
}
m_PhysicalMemoryInUse -= offset;
}
}
void PhysicalMemory::DeAllocatePhysicalMemory(PAddr addr)
{
auto it = m_Mem_map.lower_bound(addr);
m_PhysicalMemoryInUse -= it->second;
m_Mem_map.erase(addr);
}
void PhysicalMemory::DeAllocateFragmented(VAddr addr)
{
auto it = std::prev(m_Fragmented_mem_map.upper_bound(addr));
VirtualFree((void*)it->first, 0, MEM_RELEASE);
m_PhysicalMemoryInUse -= it->second;
m_Fragmented_mem_map.erase(it->first);
}
void PhysicalMemory::SetError(PMEMORY_STATUS err)
{
m_Status = err;
}
void PhysicalMemory::ClearError()
{
m_Status = PMEMORY_SUCCESS;
}

View File

@ -0,0 +1,121 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// ******************************************************************
// *
// * .,-::::: .,:: .::::::::. .,:: .:
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
// * $$$ Y$$$P $$""""Y$$ Y$$$P
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
// *
// * Cxbx->Win32->CxbxKrnl->PhysicalMemory.h
// *
// * This file is part of the Cxbx project.
// *
// * Cxbx and Cxbe are free software; you can redistribute them
// * and/or modify them under the terms of the GNU General Public
// * License as published by the Free Software Foundation; either
// * version 2 of the license, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have recieved a copy of the GNU General Public License
// * along with this program; see the file COPYING.
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017 ergo720
// *
// * All rights reserved
// *
// ******************************************************************
#ifndef PHYSICAL_MEMORY_H
#define PHYSICAL_MEMORY_H
#define _CXBXKRNL_INTERNAL
#define _XBOXKRNL_DEFEXTRN_
namespace xboxkrnl
{
#include <xboxkrnl/xboxkrnl.h>
};
#include "Emu.h"
#include "CxbxKrnl.h"
#include <windows.h>
#include <map>
/* PhysicalMemory class error codes */
#define PMEMORY_STATUS unsigned int
#define PMEMORY_SUCCESS 0x0
#define PMEMORY_INSUFFICIENT_MEMORY 0x1
#define PMEMORY_ALLOCATE_FRAGMENTED 0x2
/* Global typedefs */
typedef UINT_PTR VAddr;
typedef UINT_PTR PAddr;
typedef std::uint32_t u32;
typedef DWORD PTEflags;
/* PhysicalMemory class */
class PhysicalMemory
{
protected:
// if the block to allocate is smaller than AllocationThreshold, then it will be mapped starting from the bottom of the memory,
// otherwise it's mapped from the top. AllocationThreshold is 64KiB, the allocation granularity of the Xbox
const unsigned int m_AllocationThreshold = 1024 * 64;
// amount of physical memory in use
size_t m_PhysicalMemoryInUse = 0;
// max physical memory available on the Xbox/Chihiro
size_t m_MaxPhysicalMemory = XBOX_MEMORY_SIZE;
// map tracking the physical memory currently in use
std::map<PAddr, size_t> m_Mem_map;
// map tracking the blocks allocated with VirtualAlloc
std::map<VAddr, size_t> m_Fragmented_mem_map;
// current error status code of the PhysicalMemory class
PMEMORY_STATUS m_Status = PMEMORY_SUCCESS;
// highest address available for contiguous allocations
PAddr m_MaxContiguousAddress = XBOX_CONTIGUOUS_MEMORY_LIMIT;
// protected constructor so PhysicalMemory can only be inherited from
PhysicalMemory() {};
// destructor
~PhysicalMemory()
{
for (auto it = m_Fragmented_mem_map.begin(); it != m_Fragmented_mem_map.end(); ++it)
{
VirtualFree((void*)it->first, 0, MEM_RELEASE);
}
}
// allocates a block of the mapped file, returns m_MaxContiguousAddress and sets an error code if unsuccessful
PAddr AllocatePhysicalMemory(size_t size);
// allocates a block of the mapped file between the specified range if possible
PAddr AllocatePhysicalMemoryRange(size_t size, PAddr low_addr, PAddr high_addr);
// allocates a block of memory with VirtualAlloc when the main memory is fragmented and sets an error code
VAddr AllocateFragmented(size_t size);
// shrinks the size af an allocation
void ShrinkPhysicalAllocation(PAddr addr, size_t offset, bool bFragmentedMap, bool bStart);
// deallocates a block of the mapped file
void DeAllocatePhysicalMemory(PAddr addr);
// deallocates a block allocated with VirtualAlloc
void DeAllocateFragmented(VAddr addr);
// retrieves the current error code of the PhysicalMemory class
PMEMORY_STATUS GetError() const;
// sets the error code of the PhysicalMemory class
void SetError(PMEMORY_STATUS err);
// clears the error code of the PhysicalMemory class
void ClearError();
};
#endif

1016
src/CxbxKrnl/VMManager.cpp Normal file

File diff suppressed because it is too large Load Diff

226
src/CxbxKrnl/VMManager.h Normal file
View File

@ -0,0 +1,226 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// ******************************************************************
// *
// * .,-::::: .,:: .::::::::. .,:: .:
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
// * $$$ Y$$$P $$""""Y$$ Y$$$P
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
// *
// * Cxbx->Win32->CxbxKrnl->VMManager.h
// *
// * This file is part of the Cxbx project.
// *
// * Cxbx and Cxbe are free software; you can redistribute them
// * and/or modify them under the terms of the GNU General Public
// * License as published by the Free Software Foundation; either
// * version 2 of the license, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have recieved a copy of the GNU General Public License
// * along with this program; see the file COPYING.
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017 ergo720
// *
// * All rights reserved
// *
// ******************************************************************
#ifndef VMMANAGER_H
#define VMMANAGER_H
#include "PhysicalMemory.h"
#define XbAllocateVirtualMemoryStub(addr, zero_bits, size, allocation_type, protect) \
g_VMManager.XbAllocateVirtualMemory(addr, zero_bits, size, allocation_type, protect, true)
#define XbAllocateVirtualMemoryReal(addr, zero_bits, size, allocation_type, protect) \
g_VMManager.XbAllocateVirtualMemory(addr, zero_bits, size, allocation_type, protect, false)
#define XbFreeVirtualMemoryStub(addr, size, free_type) \
g_VMManager.XbFreeVirtualMemory(addr, size, free_type, true)
#define XbFreeVirtualMemoryReal(addr, size, free_type) \
g_VMManager.XbFreeVirtualMemory(addr, size, free_type, false)
/* VMATypes */
enum class VMAType : u32
{
// vma represents an unmapped region of the address space
Free,
// vma represents allocated memory
Allocated,
// stack allocation
Stack,
// tiled memory
MemTiled,
// nv2a
IO_DeviceNV2A,
// nv2a pramin memory
MemNV2A_PRAMIN,
// apu
IO_DeviceAPU,
// ac97
IO_DeviceAC97,
// usb0
IO_DeviceUSB0,
// usb1
IO_DeviceUSB1,
// ethernet controller
IO_DeviceNVNet,
// bios
DeviceBIOS,
// mcpx rom (retail xbox only)
DeviceMCPX,
// mark this vma as non-mergeable
Lock,
};
/* VirtualMemoryArea struct */
struct VirtualMemoryArea
{
// vma starting address
VAddr base = 0;
// vma size
size_t size = 0;
// vma kind of memory
VMAType type = VMAType::Free;
// vma permissions
DWORD permissions = PAGE_NOACCESS;
// addr of the memory backing this block, if any
PAddr backing_block = NULL;
// this allocation was served by VirtualAlloc
bool bFragmented = false;
// tests if this area can be merged to the right with 'next'
bool CanBeMergedWith(const VirtualMemoryArea& next) const;
};
/* VMManager class */
class VMManager : public PhysicalMemory
{
public:
// constructor
VMManager() { InitializeCriticalSectionAndSpinCount(&m_CriticalSection, 0x400); };
// destructor
~VMManager()
{
DeleteCriticalSection(&m_CriticalSection);
FlushViewOfFile((void*)CONTIGUOUS_MEMORY_BASE, CHIHIRO_MEMORY_SIZE);
FlushFileBuffers(m_hAliasedView);
UnmapViewOfFile((void *)m_Base);
UnmapViewOfFile((void *)CONTIGUOUS_MEMORY_BASE);
UnmapViewOfFile((void*)TILED_MEMORY_BASE);
CloseHandle(m_hAliasedView);
}
// initializes the page table to the default configuration
void Initialize(HANDLE file_view);
// initialize chihiro/debug - specifc memory ranges
void InitializeChihiroDebug();
// maps the virtual memory region used by a device
void MapHardwareDevice(VAddr base, size_t size, VMAType type);
// retrieves memory statistics
void MemoryStatistics(xboxkrnl::PMM_STATISTICS memory_statistics);
// allocates a block of memory
VAddr Allocate(size_t size, PAddr low_addr = 0, PAddr high_addr = MAXULONG_PTR, ULONG Alignment = PAGE_SIZE,
DWORD protect = PAGE_EXECUTE_READWRITE, bool bNonContiguous = true);
// allocates a block of memory and zeros it
VAddr AllocateZeroed(size_t size);
// allocates stack memory
VAddr AllocateStack(size_t size);
// deallocate a block of memory
void Deallocate(VAddr addr);
// deallocate stack memory
void DeallocateStack(VAddr addr);
// changes the protections of a memory region
void Protect(VAddr target, size_t size, DWORD new_perms);
// query if a VAddr is valid
bool QueryVAddr(VAddr addr);
// translate a VAddr
PAddr TranslateVAddr(VAddr addr);
// retrieves the protection status of an address
DWORD QueryProtection(VAddr addr);
// retrieves the size of an allocation
size_t QuerySize(VAddr addr);
// xbox implementation of NtAllocateVirtualMemory
xboxkrnl::NTSTATUS XbAllocateVirtualMemory(VAddr* addr, ULONG zero_bits, size_t* size, DWORD allocation_type,
DWORD protect, bool bStub);
// xbox implementation of NtFreeVirtualMemory
xboxkrnl::NTSTATUS XbFreeVirtualMemory(VAddr* addr, size_t* size, DWORD free_type, bool bStub);
private:
// m_Vma_map iterator
typedef std::map<VAddr, VirtualMemoryArea>::iterator VMAIter;
// map covering the entire 32 bit virtual address space as seen by the guest
std::map<VAddr, VirtualMemoryArea> m_Vma_map;
// handle of the second file view region
HANDLE m_hAliasedView = NULL;
// start address of the memory region to which map non-contiguous allocations in the virtual space
VAddr m_Base = 0;
// critical section lock to synchronize accesses
CRITICAL_SECTION m_CriticalSection;
// amount of image virtual memory in use
size_t m_ImageMemoryInUse = 0;
// amount of non - image virtual memory in use
size_t m_NonImageMemoryInUse = 0;
// amount of stack virtual memory in use
size_t m_StackMemoryInUse = 0;
// creates a vma block to be mapped in memory at the specified VAddr, if requested
VAddr MapMemoryBlock(size_t* size, PAddr low_addr, PAddr high_addr, ULONG Alignment = PAGE_SIZE, bool bNonContiguous = true);
// creates a vma representing the memory block to remove
void UnmapRange(VAddr target);
// changes access permissions for a range of vma's, splitting them if necessary
void ReprotectVMARange(VAddr target, size_t size, DWORD new_perms);
// checks if a VAddr is valid; returns false if not
bool IsValidVirtualAddress(const VAddr addr);
// translates a VAddr to its corresponding PAddr; it must be valid
PAddr TranslateVAddrToPAddr(const VAddr addr);
// maps a new allocation in the virtual address space
void MapMemoryRegion(VAddr base, size_t size, PAddr target);
// removes an allocation from the virtual address space
void UnmapRegion(VAddr base, size_t size);
// removes a vma block from the mapped memory
VMAIter Unmap(VMAIter vma_handle);
// updates the page table with a new vma entry
void MapPages(u32 page_num, u32 page_count, PAddr memory, PTEflags type);
// carves a vma of a specific size at the specified address by splitting free vma's
VMAIter CarveVMA(VAddr base, size_t size);
// splits the edges of the given range of non-free vma's so that there is a vma split at each end of the range
VMAIter CarveVMARange(VAddr base, size_t size);
// gets the iterator of a vma in m_Vma_map
VMAIter GetVMAIterator(VAddr target);
// splits a parent vma into two children
VMAIter SplitVMA(VMAIter vma_handle, u32 offset_in_vma);
// merges the specified vma with adjacent ones if possible
VMAIter MergeAdjacentVMA(VMAIter vma_handle);
// changes access permissions for a vma
VMAIter ReprotectVMA(VMAIter vma_handle, DWORD new_perms);
// updates the page table
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
// acquires the critical section
void Lock();
// releases the critical section
void Unlock();
// destructs a vma if not free already
VMAIter DestructVMA(VMAIter vma_handle, VAddr addr, size_t size);
// changes the size/base of a vma
void ResizeVMA(VMAIter vma_handle, size_t offset, bool bStart);
};
extern VMManager g_VMManager;
#endif