Updated memory functions to work with the loader

This commit is contained in:
ergo720 2019-07-12 16:00:52 +02:00 committed by RadWolfie
parent a8e8f0c071
commit 52f0d6f03b
21 changed files with 766 additions and 1082 deletions

View File

@ -20,6 +20,7 @@
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2019 ergo720
// *
// * All rights reserved
// *
@ -71,7 +72,6 @@ const struct {
#define SYSTEM_CHIHIRO (1 << 3)
// Short-hand for sets of system configurations
#define SYSTEM_ALL (SYSTEM_XBOX | SYSTEM_DEVKIT | SYSTEM_CHIHIRO)
#define SYSTEM_RETAIL (SYSTEM_XBOX | SYSTEM_DEVKIT )
#define SYSTEM_128MB ( SYSTEM_DEVKIT | SYSTEM_CHIHIRO)
#ifdef DEBUG
const char *Comment;
@ -84,31 +84,26 @@ const struct {
#endif
// See http://xboxdevwiki.net/Memory
// and http://xboxdevwiki.net/Boot_Process#Paging
// Entry : Start , End , Size , Protect , RangeFlags , Comment
RANGE_ENTRY(0x00000000, 0x03FFFFFF, MB( 64), PROT_XRW, SYSTEM_XBOX | MAY_FAIL, "MemLowVirtual (Retail Xbox) Optional (already reserved via virtual_memory_placeholder)"),
RANGE_ENTRY(0x00000000, 0x07FFFFFF, MB(128), PROT_XRW, SYSTEM_128MB | MAY_FAIL, "MemLowVirtual (Chihiro / DevKit)"),
RANGE_ENTRY(0x80000000, 0x83FFFFFF, MB( 64), PROT_XRW, SYSTEM_XBOX , "MemPhysical (Retail)"),
RANGE_ENTRY(0x80000000, 0x87FFFFFF, MB(128), PROT_XRW, SYSTEM_128MB , "MemPhysical (Chihiro / DevKit)"),
RANGE_ENTRY(0xB0000000, 0xB7FFFFFF, MB(128), PROT_NAC, SYSTEM_DEVKIT , "DevKitMemory"), // TODO : Check reserved range (might behave like MemTiled)
RANGE_ENTRY(0xC0000000, 0xC03FFFFF, MB( 4), PROT_RW, SYSTEM_ALL , "MemPageTable"), // See PAGE_TABLES_SIZE, which contains one 4 byte entry per PAGE_SIZE
RANGE_ENTRY(0xD0000000, 0xEFFFFFFF, MB(512), PROT_UNH, SYSTEM_ALL | MAY_FAIL, "SystemMemory Optional"), // TODO : Check reserved range (might behave like MemTiled)
RANGE_ENTRY(0xF0000000, 0xF3FFFFFF, MB( 64), PROT_UNH, SYSTEM_ALL | MAY_FAIL, "MemTiled Optional (even though it can't be reserved, MapViewOfFileEx to this range still works!?)"),
RANGE_ENTRY(0xFD000000, 0xFD6FFFFF, MB( 7), PROT_NAC, SYSTEM_ALL , "DeviceNV2A_a (GPU)"),
RANGE_ENTRY(0xFD700000, 0xFD7FFFFF, MB( 1), PROT_RW, SYSTEM_ALL , "MemNV2APRAMIN"),
RANGE_ENTRY(0xFD800000, 0xFDFFFFFF, MB( 8), PROT_NAC, SYSTEM_ALL , "DeviceNV2A_b (GPU)"),
RANGE_ENTRY(0xFE800000, 0xFE87FFFF, KB(512), PROT_NAC, SYSTEM_ALL , "DeviceAPU"),
RANGE_ENTRY(0xFEC00000, 0xFEC00FFF, KB( 4), PROT_NAC, SYSTEM_ALL , "DeviceAC97 (ACI)"),
RANGE_ENTRY(0xFED00000, 0xFED00FFF, KB( 4), PROT_NAC, SYSTEM_ALL , "DeviceUSB"),
RANGE_ENTRY(0xFEF00000, 0xFEF003FF, KB( 1), PROT_NAC, SYSTEM_ALL , "DeviceNVNet"),
RANGE_ENTRY(0xFF000000, 0xFF3FFFFF, MB( 4), PROT_NAC, SYSTEM_ALL , "DeviceFlash_a (Flash mirror 1)"),
RANGE_ENTRY(0xFF400000, 0xFF7FFFFF, MB( 4), PROT_NAC, SYSTEM_ALL , "DeviceFlash_b (Flash mirror 2)"),
RANGE_ENTRY(0xFF800000, 0xFFBFFFFF, MB( 4), PROT_NAC, SYSTEM_ALL , "DeviceFlash_c (Flash mirror 3)"),
RANGE_ENTRY(0xFFC00000, 0xFFFFFFFF, MB( 4), PROT_NAC, SYSTEM_ALL | MAY_FAIL, "DeviceFlash_d (Flash mirror 4) Optional (will probably fail reservation, which is acceptable - the 3 other mirrors work just fine"),
/* This region is only relevant if we were running the original Xbox boot sequence (including MCPX),
so it's completely redundant to use it: By the time the Kernel has started execution, this region is disabled
and cannot be re-enabled. Xbox software (and the kernel) have no access to this region whatsoever once 2BL has completed.
RANGE_ENTRY(0xFFFFFE00, 0xFFFFFFFF, 512 , PROT_NAC, SYSTEM_RETAIL | MAY_FAIL, "DeviceMCPX (not Chihiro, Xbox - if enabled) Optional (can safely be ignored)"),
*/
// Entry : Start , End , Size , Protect , RangeFlags , Comment
RANGE_ENTRY(0x00010000, 0x03FFFFFF, MB( 64) - KB(64), PROT_XRW, SYSTEM_XBOX | MAY_FAIL, "MemLowVirtual (Retail Xbox) Optional (already reserved via virtual_memory_placeholder)"),
RANGE_ENTRY(0x00010000, 0x07FFFFFF, MB(128) - KB(64), PROT_XRW, SYSTEM_128MB | MAY_FAIL, "MemLowVirtual (Chihiro / DevKit)"),
RANGE_ENTRY(0x80000000, 0x83FFFFFF, MB( 64) , PROT_UNH, SYSTEM_XBOX , "MemPhysical (Retail)"),
RANGE_ENTRY(0x80000000, 0x87FFFFFF, MB(128) , PROT_UNH, SYSTEM_128MB , "MemPhysical (Chihiro / DevKit)"),
RANGE_ENTRY(0xB0000000, 0xBFFFFFFF, MB(256) , PROT_NAC, SYSTEM_DEVKIT , "DevKitMemory"), // TODO : Check reserved range (might behave like MemTiled)
RANGE_ENTRY(0xC0000000, 0xC03FFFFF, MB( 4) , PROT_RW, SYSTEM_ALL , "MemPageTable"), // See PAGE_TABLES_SIZE, which contains one 4 byte entry per PAGE_SIZE
RANGE_ENTRY(0xD0000000, 0xEFFFFFFF, MB(512) , PROT_RW, SYSTEM_ALL | MAY_FAIL, "SystemMemory Optional"), // TODO : Check reserved range (might behave like MemTiled)
RANGE_ENTRY(0xF0000000, 0xF3FFFFFF, MB( 64) , PROT_UNH, SYSTEM_ALL , "MemTiled Optional (even though it can't be reserved, MapViewOfFileEx to this range still works!?)"),
RANGE_ENTRY(0xFD000000, 0xFD6FFFFF, MB( 7) , PROT_NAC, SYSTEM_ALL , "DeviceNV2A_a (GPU)"),
RANGE_ENTRY(0xFD700000, 0xFD7FFFFF, MB( 1) , PROT_RW, SYSTEM_ALL , "MemNV2APRAMIN"),
RANGE_ENTRY(0xFD800000, 0xFDFFFFFF, MB( 8) , PROT_NAC, SYSTEM_ALL , "DeviceNV2A_b (GPU)"),
RANGE_ENTRY(0xFE800000, 0xFE87FFFF, KB(512) , PROT_NAC, SYSTEM_ALL , "DeviceAPU"),
RANGE_ENTRY(0xFEC00000, 0xFEC00FFF, KB( 4) , PROT_NAC, SYSTEM_ALL , "DeviceAC97 (ACI)"),
RANGE_ENTRY(0xFED00000, 0xFED00FFF, KB( 4) , PROT_NAC, SYSTEM_ALL , "DeviceUSB"),
RANGE_ENTRY(0xFEF00000, 0xFEF003FF, KB( 1) , PROT_NAC, SYSTEM_ALL , "DeviceNVNet"),
RANGE_ENTRY(0xFF000000, 0xFF3FFFFF, MB( 4) , PROT_NAC, SYSTEM_ALL , "DeviceFlash_a (Flash mirror 1)"),
RANGE_ENTRY(0xFF400000, 0xFF7FFFFF, MB( 4) , PROT_NAC, SYSTEM_ALL , "DeviceFlash_b (Flash mirror 2)"),
RANGE_ENTRY(0xFF800000, 0xFFBFFFFF, MB( 4) , PROT_NAC, SYSTEM_ALL , "DeviceFlash_c (Flash mirror 3)"),
RANGE_ENTRY(0xFFC00000, 0xFFFFFFFF, MB( 4) , PROT_NAC, SYSTEM_ALL | MAY_FAIL, "DeviceFlash_d (Flash mirror 4) Optional (will probably fail reservation, which is acceptable - the 3 other mirrors work just fine"),
#undef RANGE_ENTRY
};
@ -119,3 +114,4 @@ extern bool VerifyWow64();
extern LPTSTR GetLastErrorString();
extern void FreeLastErrorString(LPTSTR Error);
extern void OutputMessage(const char* msg);

View File

@ -38,6 +38,7 @@ typedef enum class _IPC_UPDATE_GUI {
, XBOX_LED_COLOUR
, LOG_ENABLED
, KRNL_IS_READY
, VM_PERSIST_MEM
} IPC_UPDATE_GUI;
void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value);

View File

@ -20,6 +20,7 @@
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2019 ergo720
// *
// * All rights reserved
// *
@ -30,35 +31,75 @@
#include "AddressRanges.h"
// Reserve an address range up to the extend of what the host allows.
bool ReserveMemoryRange(int index)
bool ReserveMemoryRange(int index, uint32_t blocks_reserved[384])
{
uint32_t Start = XboxAddressRanges[index].Start;
int Size = XboxAddressRanges[index].Size;
bool HadAnyFailure = false;
if (Start == 0) {
// The zero page (the entire first 64 KB block) can't be reserved (if we would
// try to reserve VirtualAlloc at address zero, it would hand us another address)
Start += BLOCK_SIZE;
Size -= BLOCK_SIZE;
HadAnyFailure = true;
}
// Reserve this range in 64 Kb block increments, so that during emulation
// our memory-management code can VirtualFree() each block individually :
bool HadFailure = HadAnyFailure;
const DWORD Protect = XboxAddressRanges[index].InitialMemoryProtection;
while (Size > 0) {
SIZE_T BlockSize = (SIZE_T)(Size > BLOCK_SIZE) ? BLOCK_SIZE : Size;
LPVOID Result = VirtualAlloc((LPVOID)Start, BlockSize, MEM_RESERVE, Protect);
if (Result == NULL) {
HadFailure = true;
HadAnyFailure = true;
}
// Handle the next block
Start += BLOCK_SIZE;
Size -= BLOCK_SIZE;
const DWORD Protect = XboxAddressRanges[index].InitialMemoryProtection;
bool NeedsReservationTracking = false;
switch (Start) {
case 0x80000000:
case 0xF0000000: {
static bool NeedsInitialization = true;
static HANDLE hFileMapping;
if (NeedsInitialization) {
hFileMapping = CreateFileMapping(
INVALID_HANDLE_VALUE,
nullptr,
PAGE_EXECUTE_READWRITE,
0,
Size,
nullptr);
if (hFileMapping == nullptr) {
HadAnyFailure = true;
break;
}
NeedsInitialization = false;
}
LPVOID Result = MapViewOfFileEx(
hFileMapping,
Start == 0x80000000 ?
(FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE) : (FILE_MAP_READ | FILE_MAP_WRITE),
0,
0,
Size,
(LPVOID)Start);
if (Result == nullptr) {
HadAnyFailure = true;
}
}
break;
case 0xB0000000:
case 0xD0000000: {
NeedsReservationTracking = true;
}
[[fallthrough]];
default: {
while (Size > 0) {
static int arr_index = 0;
SIZE_T BlockSize = (SIZE_T)(Size > BLOCK_SIZE) ? BLOCK_SIZE : Size;
LPVOID Result = VirtualAlloc((LPVOID)Start, BlockSize, MEM_RESERVE, Protect);
if (Result == nullptr) {
HadAnyFailure = true;
}
// Handle the next block
Start += BLOCK_SIZE;
Size -= BLOCK_SIZE;
if (NeedsReservationTracking) {
if (Result != nullptr) {
blocks_reserved[arr_index / 32] |= (1 << (arr_index % 32));
}
arr_index++;
}
}
}
}
// Only a complete success when the entire request was reserved in a single range
@ -66,7 +107,7 @@ bool ReserveMemoryRange(int index)
return !HadAnyFailure;
}
bool ReserveAddressRanges(const int system) {
bool ReserveAddressRanges(const int system, uint32_t blocks_reserved[384]) {
// Loop over all Xbox address ranges
for (int i = 0; i < ARRAY_SIZE(XboxAddressRanges); i++) {
// Skip address ranges that don't match the given flags
@ -74,7 +115,7 @@ bool ReserveAddressRanges(const int system) {
continue;
// Try to reserve each address range
if (ReserveMemoryRange(i))
if (ReserveMemoryRange(i, blocks_reserved))
continue;
// Some ranges are allowed to fail reserving

View File

@ -26,4 +26,4 @@
// ******************************************************************
#pragma once
extern bool ReserveAddressRanges(const int system);
extern bool ReserveAddressRanges(const int system, uint32_t blocks_reserved[384]);

View File

@ -20,6 +20,7 @@
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2019 ego720
// *
// * All rights reserved
// *
@ -51,13 +52,6 @@ bool VerifyAddressRange(int index)
int Size = XboxAddressRanges[index].Size;
bool HadAnyFailure = false;
if (BaseAddress == 0) {
// The zero page (the entire first 64 KB block) can't be verified
// so to avoid verification failures, we just skip it, knowing it'll be alright
BaseAddress += BLOCK_SIZE;
Size -= BLOCK_SIZE;
}
// Safeguard against bounds overflow
if (ReservedRangeCount < ARRAY_SIZE(ReservedRanges)) {
// Initialize the reservation of a new range
@ -69,8 +63,9 @@ bool VerifyAddressRange(int index)
// Verify this range in 64 Kb block increments, as they are supposed
// to have been reserved like that too:
bool HadFailure = HadAnyFailure;
const DWORD AllocationProtect = (XboxAddressRanges[index].Start == 0) ? PAGE_EXECUTE_WRITECOPY : XboxAddressRanges[index].InitialMemoryProtection;
const DWORD AllocationProtect = (XboxAddressRanges[index].Start == 0x10000) ? PAGE_EXECUTE_WRITECOPY : XboxAddressRanges[index].InitialMemoryProtection;
MEMORY_BASIC_INFORMATION mbi;
bool Okay;
while (Size > 0) {
// Expected values
PVOID AllocationBase = (PVOID)BaseAddress;
@ -78,9 +73,9 @@ bool VerifyAddressRange(int index)
DWORD State = MEM_RESERVE;
DWORD Protect = 0;
DWORD Type = MEM_PRIVATE;
#if 0
// Allowed deviations
if (XboxAddressRanges[index].Start == 0) {
if (XboxAddressRanges[index].Start == 0x10000) {
AllocationBase = (PVOID)0x10000;
State = MEM_COMMIT;
Type = MEM_IMAGE;
@ -110,23 +105,58 @@ bool VerifyAddressRange(int index)
break;
}
}
// Verify each block
bool Okay = (VirtualQuery((LPVOID)BaseAddress, &mbi, sizeof(mbi)) != 0);
if (Okay)
Okay = (mbi.BaseAddress == (LPVOID)BaseAddress);
if (Okay)
Okay = (mbi.AllocationBase == AllocationBase);
if (Okay)
Okay = (mbi.AllocationProtect == AllocationProtect);
if (Okay)
Okay = (mbi.RegionSize == RegionSize);
if (Okay)
Okay = (mbi.State == State);
if (Okay)
Okay = (mbi.Protect == Protect);
if (Okay)
Okay = (mbi.Type == Type);
#endif
if (BaseAddress == 0x80000000 || BaseAddress == 0xF0000000) {
RegionSize = Size;
Okay = (VirtualQuery((LPVOID)BaseAddress, &mbi, sizeof(mbi)) != 0);
if (Okay)
Okay = (mbi.BaseAddress == (LPVOID)BaseAddress);
if (Okay)
Okay = (mbi.AllocationBase == AllocationBase);
if (Okay)
Okay = (mbi.AllocationProtect == (BaseAddress == 0x80000000 ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE));
if (Okay)
Okay = (mbi.RegionSize == Size);
if (Okay)
Okay = (mbi.State == MEM_COMMIT);
if (Okay)
Okay = (mbi.Protect == mbi.AllocationProtect);
if (Okay)
Okay = (mbi.Type == MEM_MAPPED);
}
else if (BaseAddress == 0x10000) {
RegionSize = 0;
while (BaseAddress <= 0x07FFFFFF) {
Okay = (VirtualQuery((LPVOID)BaseAddress, &mbi, sizeof(mbi)) != 0);
if (!Okay || mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE) {
Okay = false;
break;
}
BaseAddress += mbi.RegionSize;
RegionSize += mbi.RegionSize;
}
if (Okay) {
RegionSize = Size;
}
}
else {
// Verify each block
Okay = (VirtualQuery((LPVOID)BaseAddress, &mbi, sizeof(mbi)) != 0);
if (Okay)
Okay = (mbi.BaseAddress == (LPVOID)BaseAddress);
if (Okay)
Okay = (mbi.AllocationBase == AllocationBase);
if (Okay)
Okay = (mbi.AllocationProtect == AllocationProtect);
if (Okay)
Okay = (mbi.RegionSize == RegionSize);
if (Okay)
Okay = (mbi.State == State);
if (Okay)
Okay = (mbi.Protect == Protect);
if (Okay)
Okay = (mbi.Type == Type);
}
if (!Okay) {
HadFailure = true;
@ -154,9 +184,14 @@ bool VerifyAddressRange(int index)
}
}
// Handle the next region
BaseAddress += RegionSize;
Size -= RegionSize;
if (BaseAddress == 0x80000000 || BaseAddress == 0xF0000000 || XboxAddressRanges[index].Start == 0x10000) {
Size = 0;
}
else {
// Handle the next region
BaseAddress += RegionSize;
Size -= RegionSize;
}
}
// Safeguard against bounds overflow

View File

@ -80,7 +80,7 @@ class EmuShared : public Mutex
// * Check if parent process is emulating title
// ******************************************************************
void GetIsEmulating(bool *isEmulating) { Lock(); *isEmulating = m_bEmulating_status; Unlock(); }
void SetIsEmulating(const bool isEmulating) { Lock(); m_bEmulating_status = isEmulating; Unlock(); }
void SetIsEmulating(const bool isEmulating) { Lock(); m_bEmulating_status = isEmulating; Unlock(); }
// ******************************************************************
// * Each child process need to wait until parent process is ready
@ -199,8 +199,7 @@ class EmuShared : public Mutex
void GetLogModules(unsigned int *value)
{
Lock();
for (int i = 0; i < NUM_INTEGERS_LOG; ++i)
{
for (int i = 0; i < NUM_INTEGERS_LOG; ++i) {
value[i] = m_core.LoggedModules[i];
}
Unlock();
@ -208,12 +207,11 @@ class EmuShared : public Mutex
void SetLogModules(unsigned int *value)
{
Lock();
for (int i = 0; i < NUM_INTEGERS_LOG; ++i)
{
for (int i = 0; i < NUM_INTEGERS_LOG; ++i) {
m_core.LoggedModules[i] = value[i];
}
Unlock();
}
}
// ******************************************************************
// * File storage location

View File

@ -65,6 +65,10 @@ void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value)
cmdParam = ID_GUI_STATUS_KRNL_IS_READY;
break;
case IPC_UPDATE_GUI::VM_PERSIST_MEM:
cmdParam = ID_GUI_VM_PERSIST_MEM;
break;
default:
cmdParam = 0;
break;

View File

@ -291,6 +291,7 @@ g_EmuCDPD = {0};
/*XB_MACRO(VOID, WINAPI, D3DDevice_LoadVertexShaderProgram, (CONST DWORD*, DWORD) );*/\
/*XB_MACRO(VOID, __stdcall, D3DDevice_LoadVertexShader_0, () );*/\
/*XB_MACRO(VOID, WINAPI, D3DDevice_LoadVertexShader_4, (DWORD) );*/\
XB_MACRO(HRESULT, WINAPI, D3DDevice_PersistDisplay, (VOID) ); \
XB_MACRO(HRESULT, WINAPI, D3DDevice_Reset, (XTL::X_D3DPRESENT_PARAMETERS*) ); \
/*XB_MACRO(VOID, WINAPI, D3DDevice_SelectVertexShader, (DWORD, DWORD) );*/\
/*XB_MACRO(VOID, __stdcall, D3DDevice_SelectVertexShader_0, () );*/\
@ -8697,9 +8698,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_PersistDisplay)()
{
LOG_FUNC();
HRESULT hRet = D3D_OK;
LOG_UNIMPLEMENTED();
LOG_INCOMPLETE();
// TODO: This function simply saves a copy of the display to a surface and persists it in contiguous memory
// This function, if ever required, can be implemented as the following
@ -8711,8 +8710,11 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_PersistDisplay)()
// 5. Use MmPersistContigousMemory to persist the surface data across reboot
// 6. Call AvSetSavedDataAddress, passing the xbox surface data pointer
return hRet;
// Call the native Xbox function so that AvSetSavedDataAddress is called and the VMManager can know its correct address
if (XB_TRMP(D3DDevice_PersistDisplay)) {
return XB_TRMP(D3DDevice_PersistDisplay)();
}
return 0;
}
// ******************************************************************

View File

@ -48,6 +48,7 @@ namespace xboxkrnl
#include "devices\Xbox.h" // For g_SMBus, SMBUS_ADDRESS_SYSTEM_MICRO_CONTROLLER
#include "devices\SMCDevice.h" // For SMC_COMMAND_SCRATCH
#include "common/util/strConverter.hpp" // for utf16_to_ascii
#include "core\kernel\memory-manager\VMManager.h"
#include <algorithm> // for std::replace
#include <locale>
@ -567,6 +568,8 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur
QuickReboot |= BOOT_QUICK_REBOOT;
g_EmuShared->SetBootFlags(&QuickReboot);
g_VMManager.SavePersistentMemory();
// Some titles (Xbox Dashboard and retail/demo discs) use ";" as a current directory path seperator
// This process is handled during initialization. No speical handling here required.
@ -587,11 +590,10 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur
case ReturnFirmwareFatal:
{
// NOTE: the error code is displayed by ExDisplayFatalError by other code paths so we need to change our corresponding
// paths if we want to emulate all the possible fatal errors
xboxkrnl::HalWriteSMBusValue(SMBUS_ADDRESS_SYSTEM_MICRO_CONTROLLER, SMC_COMMAND_SCRATCH, 0, SMC_SCRATCH_DISPLAY_FATAL_ERROR);
g_VMManager.SavePersistentMemory();
std::string szProcArgsBuffer;
CxbxConvertArgToString(szProcArgsBuffer, szFilePath_CxbxReloaded_Exe, szFilePath_Xbe, CxbxKrnl_hEmuParent, CxbxKrnl_DebugMode, CxbxKrnl_DebugFileName.c_str());
@ -610,7 +612,7 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur
}
EmuShared::Cleanup();
ExitProcess(EXIT_SUCCESS);
TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS);
}
// ******************************************************************

View File

@ -53,8 +53,6 @@ namespace NtDll
// ******************************************************************
// * 0x0066 - MmGlobalData
// ******************************************************************
// ergo720: a couple of these could be implemented, but most cannot. However, I wouldn't bother with these variables
// since they are just exported but never used by the kernel
XBSYSAPI EXPORTNUM(102) xboxkrnl::PVOID xboxkrnl::MmGlobalData[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
// ******************************************************************
@ -104,7 +102,7 @@ XBSYSAPI EXPORTNUM(166) xboxkrnl::PVOID NTAPI xboxkrnl::MmAllocateContiguousMemo
LOG_FUNC_ARG_TYPE(PROTECTION_TYPE, ProtectionType)
LOG_FUNC_END;
PVOID pRet = (PVOID)g_VMManager.AllocateContiguous(NumberOfBytes, LowestAcceptableAddress, HighestAcceptableAddress, Alignment, ProtectionType);
PVOID pRet = (PVOID)g_VMManager.AllocateContiguousMemory(NumberOfBytes, LowestAcceptableAddress, HighestAcceptableAddress, Alignment, ProtectionType);
RETURN(pRet);
}
@ -206,7 +204,7 @@ XBSYSAPI EXPORTNUM(171) xboxkrnl::VOID NTAPI xboxkrnl::MmFreeContiguousMemory
{
LOG_FUNC_ONE_ARG(BaseAddress);
g_VMManager.DeallocateContiguous((VAddr)BaseAddress);
g_VMManager.DeallocateContiguousMemory((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
@ -486,9 +484,6 @@ XBSYSAPI EXPORTNUM(374) xboxkrnl::PVOID NTAPI xboxkrnl::MmDbgAllocateMemory
LOG_FUNC_ARG_TYPE(PROTECTION_TYPE, Protect)
LOG_FUNC_END;
// This should only be called by debug xbe's
assert(g_bIsDebug);
PVOID addr = (PVOID)g_VMManager.AllocateSystemMemory(DebuggerType, Protect, NumberOfBytes, false);
if (addr) { RtlFillMemoryUlong((void*)addr, ROUND_UP_4K(NumberOfBytes), 0); } // debugger pages are zeroed
@ -509,9 +504,6 @@ XBSYSAPI EXPORTNUM(375) xboxkrnl::ULONG NTAPI xboxkrnl::MmDbgFreeMemory
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_END;
// This should only be called by debug xbe's
assert(g_bIsDebug);
ULONG FreedPagesNumber = g_VMManager.DeallocateSystemMemory(DebuggerType, (VAddr)BaseAddress, NumberOfBytes);
RETURN(FreedPagesNumber);
@ -524,9 +516,6 @@ XBSYSAPI EXPORTNUM(376) xboxkrnl::ULONG NTAPI xboxkrnl::MmDbgQueryAvailablePages
{
LOG_FUNC();
// This should only be called by debug xbe's
assert(g_bIsDebug);
ULONG FreeDebuggerPageNumber = g_VMManager.QueryNumberOfFreeDebuggerPages();
RETURN(FreeDebuggerPageNumber);
@ -546,9 +535,6 @@ XBSYSAPI EXPORTNUM(377) xboxkrnl::VOID NTAPI xboxkrnl::MmDbgReleaseAddress
LOG_FUNC_ARG(Opaque)
LOG_FUNC_END;
// This should only be called by debug xbe's
assert(g_bIsDebug);
g_VMManager.DbgTestPte((VAddr)VirtualAddress, (PMMPTE)Opaque, false);
}
@ -566,9 +552,6 @@ XBSYSAPI EXPORTNUM(378) xboxkrnl::PVOID NTAPI xboxkrnl::MmDbgWriteCheck
LOG_FUNC_ARG(Opaque)
LOG_FUNC_END;
// This should only be called by debug xbe's
assert(g_bIsDebug);
PVOID addr = (PVOID)g_VMManager.DbgTestPte((VAddr)VirtualAddress, (PMMPTE)Opaque, true);
RETURN(addr);

View File

@ -88,8 +88,6 @@ static std::vector<HANDLE> g_hThreads;
char szFilePath_CxbxReloaded_Exe[MAX_PATH] = { 0 };
char szFolder_CxbxReloadedData[MAX_PATH] = { 0 };
char szFilePath_EEPROM_bin[MAX_PATH] = { 0 };
char szFilePath_memory_bin[MAX_PATH] = { 0 };
char szFilePath_page_tables[MAX_PATH] = { 0 };
char szFilePath_Xbe[MAX_PATH*2] = { 0 }; // NOTE: LAUNCH_DATA_HEADER's szLaunchPath is MAX_PATH*2 = 520
std::string CxbxBasePath;
@ -290,209 +288,6 @@ std::string CxbxGetLastErrorString(char * lpszFunction)
return result;
}
HANDLE CxbxRestoreContiguousMemory(char *szFilePath_memory_bin)
{
// First, try to open an existing memory.bin file :
HANDLE hFile = CreateFile(szFilePath_memory_bin,
GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
/* lpSecurityAttributes */nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, // FILE_FLAG_WRITE_THROUGH
/* hTemplateFile */nullptr);
bool NeedsInitialization = (hFile == INVALID_HANDLE_VALUE);
if (NeedsInitialization)
{
// If the memory.bin file doesn't exist yet, create it :
hFile = CreateFile(szFilePath_memory_bin,
GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
/* lpSecurityAttributes */nullptr,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, // FILE_FLAG_WRITE_THROUGH
/* hTemplateFile */nullptr);
if (hFile == INVALID_HANDLE_VALUE)
{
CxbxKrnlCleanup("%s : Couldn't create memory.bin file!\n", __func__);
return nullptr;
}
}
// Make sure memory.bin is at least 128 MB in size
SetFilePointer(hFile, CHIHIRO_MEMORY_SIZE, nullptr, FILE_BEGIN);
SetEndOfFile(hFile);
HANDLE hFileMapping = CreateFileMapping(
hFile,
/* lpFileMappingAttributes */nullptr,
PAGE_EXECUTE_READWRITE,
/* dwMaximumSizeHigh */0,
/* dwMaximumSizeLow */CHIHIRO_MEMORY_SIZE,
/**/nullptr);
if (hFileMapping == NULL)
{
CxbxKrnlCleanup("%s : Couldn't create contiguous memory.bin file mapping!\n", __func__);
return nullptr;
}
LARGE_INTEGER len_li;
GetFileSizeEx(hFile, &len_li);
unsigned int FileSize = len_li.u.LowPart;
if (FileSize != CHIHIRO_MEMORY_SIZE)
{
CxbxKrnlCleanup("%s : memory.bin file is not 128 MiB large!\n", __func__);
return nullptr;
}
#ifdef CXBX_LOADER
// TODO : Use ReserveMemoryRange / UnreserveMemoryRange(Mem??) where appropriate
#endif
// Map memory.bin contents into memory :
void *memory = (void *)MapViewOfFileEx(
hFileMapping,
FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE,
/* dwFileOffsetHigh */0,
/* dwFileOffsetLow */0,
CHIHIRO_CONTIGUOUS_MEMORY_SIZE,
(void *)CONTIGUOUS_MEMORY_BASE);
if (memory != (void *)CONTIGUOUS_MEMORY_BASE)
{
if (memory)
UnmapViewOfFile(memory);
CxbxKrnlCleanup("%s: Couldn't map contiguous memory.bin to 0x80000000!", __func__);
return nullptr;
}
EmuLogInit(LOG_LEVEL::INFO, "Mapped %d MiB of Xbox contiguous memory at 0x%.8X to 0x%.8X",
CHIHIRO_CONTIGUOUS_MEMORY_SIZE / ONE_MB, CONTIGUOUS_MEMORY_BASE, CONTIGUOUS_MEMORY_BASE + CHIHIRO_CONTIGUOUS_MEMORY_SIZE - 1);
if (NeedsInitialization)
{
memset(memory, 0, CHIHIRO_CONTIGUOUS_MEMORY_SIZE);
EmuLogInit(LOG_LEVEL::INFO, "Initialized contiguous memory");
}
else
EmuLogInit(LOG_LEVEL::INFO, "Loaded contiguous memory.bin");
size_t tiledMemorySize = XBOX_WRITE_COMBINED_SIZE;
if (g_bIsWine) {
EmuLogInit(LOG_LEVEL::INFO, "Wine detected: Using 64MB Tiled Memory Size");
// TODO: Figure out why Wine needs this and Windows doesn't.
// Perhaps it's a Wine bug, or perhaps Wine reserves this memory for it's own usage?
tiledMemorySize = XBOX_WRITE_COMBINED_SIZE / 2;
}
// Map memory.bin contents into tiled memory too :
void *tiled_memory = (void *)MapViewOfFileEx(
hFileMapping,
FILE_MAP_READ | FILE_MAP_WRITE,
/* dwFileOffsetHigh */0,
/* dwFileOffsetLow */0,
tiledMemorySize,
(void *)XBOX_WRITE_COMBINED_BASE);
if (tiled_memory != (void *)XBOX_WRITE_COMBINED_BASE)
{
if (tiled_memory)
UnmapViewOfFile(tiled_memory);
CxbxKrnlCleanup("%s: Couldn't map contiguous memory.bin into tiled memory at 0xF0000000!", __func__);
return nullptr;
}
EmuLogInit(LOG_LEVEL::INFO, "Mapped contiguous memory to Xbox tiled memory at 0x%.8X to 0x%.8X",
XBOX_WRITE_COMBINED_BASE, XBOX_WRITE_COMBINED_BASE + tiledMemorySize - 1);
return hFileMapping;
}
HANDLE CxbxRestorePageTablesMemory(char* szFilePath_page_tables)
{
// First, try to open an existing PageTables.bin file :
HANDLE hFile = CreateFile(szFilePath_page_tables,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
/* lpSecurityAttributes */nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, // FILE_FLAG_WRITE_THROUGH
/* hTemplateFile */nullptr);
bool NeedsInitialization = (hFile == INVALID_HANDLE_VALUE);
if (NeedsInitialization)
{
// If the PageTables.bin file doesn't exist yet, create it :
hFile = CreateFile(szFilePath_page_tables,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
/* lpSecurityAttributes */nullptr,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, // FILE_FLAG_WRITE_THROUGH
/* hTemplateFile */nullptr);
if (hFile == INVALID_HANDLE_VALUE)
{
CxbxKrnlCleanup("%s : Couldn't create PageTables.bin file!\n", __func__);
}
}
// Make sure PageTables.bin is at least 4 MB in size
SetFilePointer(hFile, PAGE_TABLES_SIZE, nullptr, FILE_BEGIN);
SetEndOfFile(hFile);
HANDLE hFileMapping = CreateFileMapping(
hFile,
/* lpFileMappingAttributes */nullptr,
PAGE_READWRITE,
/* dwMaximumSizeHigh */0,
/* dwMaximumSizeLow */PAGE_TABLES_SIZE,
/**/nullptr);
if (hFileMapping == NULL)
{
CxbxKrnlCleanup("%s : Couldn't create PageTables.bin file mapping!\n", __func__);
}
LARGE_INTEGER len_li;
GetFileSizeEx(hFile, &len_li);
unsigned int FileSize = len_li.u.LowPart;
if (FileSize != PAGE_TABLES_SIZE)
{
CxbxKrnlCleanup("%s : PageTables.bin file is not 4 MiB large!\n", __func__);
}
// Map PageTables.bin contents into memory :
void *memory = (void *)MapViewOfFileEx(
hFileMapping,
FILE_MAP_READ | FILE_MAP_WRITE,
/* dwFileOffsetHigh */0,
/* dwFileOffsetLow */0,
4 * ONE_MB,
(void *)PAGE_TABLES_BASE);
if (memory != (void *)PAGE_TABLES_BASE)
{
if (memory)
UnmapViewOfFile(memory);
CxbxKrnlCleanup("%s: Couldn't map PageTables.bin to 0xC0000000!", __func__);
}
EmuLogInit(LOG_LEVEL::INFO, "Mapped %d MiB of Xbox page tables memory at 0x%.8X to 0x%.8X",
4, PAGE_TABLES_BASE, PAGE_TABLES_END);
if (NeedsInitialization)
{
memset(memory, 0, 4 * ONE_MB);
EmuLogInit(LOG_LEVEL::INFO, "Initialized page tables memory");
}
else
EmuLogInit(LOG_LEVEL::INFO, "Loaded PageTables.bin");
return hFileMapping;
}
#pragma optimize("", off)
int CxbxMessageBox(const char* msg, UINT uType, HWND hWnd)
@ -954,7 +749,7 @@ bool HandleFirstLaunch()
return true;
}
void CxbxKrnlMain(int argc, char* argv[])
void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384])
{
// NOTE: This is designated for standalone kernel mode launch without GUI
if (g_Settings != nullptr) {
@ -1168,13 +963,6 @@ void CxbxKrnlMain(int argc, char* argv[])
}
#endif
#ifdef CXBX_LOADER
if (!VerifyAddressRanges(SYSTEM_XBOX)) {
CxbxPopupMessage("Cxbx-Reloaded hasn't got access to all required address ranges");
return; // TODO : Halt(0);
}
#endif
// Create a safe copy of the complete EXE header:
DWORD ExeHeaderSize = ExeOptionalHeader->SizeOfHeaders; // Should end up as 0x400
NewDosHeader = (PIMAGE_DOS_HEADER)VirtualAlloc(nullptr, ExeHeaderSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
@ -1223,9 +1011,6 @@ void CxbxKrnlMain(int argc, char* argv[])
RestoreExeImageHeader();
}
HANDLE hMemoryBin = CxbxRestoreContiguousMemory(szFilePath_memory_bin);
HANDLE hPageTables = CxbxRestorePageTablesMemory(szFilePath_page_tables);
// Load Per-Xbe Keys from the Cxbx-Reloaded AppData directory
LoadXboxKeys(szFolder_CxbxReloadedData);
@ -1326,7 +1111,7 @@ void CxbxKrnlMain(int argc, char* argv[])
}
#endif
// Initialize the virtual manager
g_VMManager.Initialize(hMemoryBin, hPageTables, BootFlags);
g_VMManager.Initialize(SYSTEM_XBOX, BootFlags, blocks_reserved);
// Commit the memory used by the xbe header
size_t HeaderSize = CxbxKrnl_Xbe->m_Header.dwSizeofHeaders;
@ -1788,8 +1573,6 @@ void CxbxInitFilePaths()
}
snprintf(szFilePath_EEPROM_bin, MAX_PATH, "%s\\EEPROM.bin", szFolder_CxbxReloadedData);
snprintf(szFilePath_memory_bin, MAX_PATH, "%s\\memory.bin", szFolder_CxbxReloadedData);
snprintf(szFilePath_page_tables, MAX_PATH, "%s\\PageTables.bin", szFolder_CxbxReloadedData);
GetModuleFileName(GetModuleHandle(nullptr), szFilePath_CxbxReloaded_Exe, MAX_PATH);
}

View File

@ -150,7 +150,7 @@ extern "C" {
// fit in 51 MB. If we ever encounter an even larger XBE, this
// value will have to be increased likewise (maybe up to 64 MB
// for XBOX_MEMORY_SIZE or even 128 MB for CHIHIRO_MEMORY_SIZE).
#define XBE_MAX_VA (64 * ONE_MB)
#define XBE_MAX_VA (128 * ONE_MB)
/*! base address of Cxbx host executable, see Cxbx project options, Linker, Advanced, Base Address */
#define CXBX_BASE_ADDR XBE_IMAGE_BASE
@ -235,7 +235,7 @@ bool CreateSettings();
bool HandleFirstLaunch();
/*! Cxbx Kernel Entry Point */
void CxbxKrnlMain(int argc, char* argv[]);
void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384]);
/*! initialize emulation */
__declspec(noreturn) void CxbxKrnlInit(void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, const char *szDebugFilename, Xbe::Header *XbeHeader, uint32_t XbeHeaderSize, void (*Entry)(), int BootFlags);

View File

@ -73,13 +73,7 @@ void PhysicalMemory::InitializePageDirectory()
TempPte.Default += LARGE_PAGE_SIZE; // increase PFN
}
// NOTE: we don't need to unmap the rest of the system physical region because that mapping is done by the 2BL
// on the Xbox, which is not present here on Cxbx-Reloaded
// Here we should also reserve some system pte's for the file system cache. However, the implementation of the kernel
// file cache functions is basically non-existent at the moment and relies on ExAllocatePoolWithTag, which is not
// correctly implemented. So, for now, we keep on ignoring this allocation
// TODO: map memory for the file system cache?
}
void PhysicalMemory::WritePfn(PFN pfn_start, PFN pfn_end, PMMPTE pPte, PageType BusyType, bool bZero)
@ -380,7 +374,7 @@ void PhysicalMemory::InsertFree(PFN start, PFN end)
}
}
bool PhysicalMemory::ConvertXboxToSystemPteProtection(DWORD perms, PMMPTE pPte)
bool PhysicalMemory::ConvertXboxToSystemPtePermissions(DWORD perms, PMMPTE pPte)
{
ULONG Mask = 0;
@ -437,7 +431,7 @@ bool PhysicalMemory::ConvertXboxToSystemPteProtection(DWORD perms, PMMPTE pPte)
return false;
}
bool PhysicalMemory::ConvertXboxToPteProtection(DWORD perms, PMMPTE pPte)
bool PhysicalMemory::ConvertXboxToPtePermissions(DWORD perms, PMMPTE pPte)
{
ULONG Mask = 0;
ULONG LowNibble;
@ -504,7 +498,7 @@ bool PhysicalMemory::ConvertXboxToPteProtection(DWORD perms, PMMPTE pPte)
return false;
}
DWORD PhysicalMemory::ConvertPteToXboxProtection(ULONG PteMask)
DWORD PhysicalMemory::ConvertPteToXboxPermissions(ULONG PteMask)
{
// This routine assumes that the pte has valid protection bits. If it doesn't, it can produce invalid
// access permissions
@ -528,7 +522,7 @@ DWORD PhysicalMemory::ConvertPteToXboxProtection(ULONG PteMask)
DWORD PhysicalMemory::PatchXboxPermissions(DWORD Perms)
{
// Usage notes: this routine expects the permissions to be already sanitized by ConvertXboxToSystemPteProtection or
// Usage notes: this routine expects the permissions to be already sanitized by ConvertXboxToSystemPtePermissions or
// similar. If not, it can produce incorrect results
// ergo720: this checks if the specified Xbox permission mask has the execute flag enabled. If not, it adds it. This is
@ -581,7 +575,7 @@ DWORD PhysicalMemory::PatchXboxPermissions(DWORD Perms)
}
}
DWORD PhysicalMemory::ConvertXboxToWinProtection(DWORD Perms)
DWORD PhysicalMemory::ConvertXboxToWinPermissions(DWORD Perms)
{
// This function assumes that the supplied permissions have been sanitized already

View File

@ -19,7 +19,7 @@
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017-2018 ergo720
// * (c) 2017-2018-2019 ergo720
// *
// * All rights reserved
// *
@ -52,13 +52,11 @@ typedef unsigned int PFN_COUNT;
typedef struct _FreeBlock
{
PFN start; // starting page of the block
PFN_COUNT size; // number of pages in the block (edges included)
PFN_COUNT size; // number of pages in the block
xboxkrnl::LIST_ENTRY ListEntry;
}FreeBlock, *PFreeBlock;
// NOTE: all the bit fields below can have endianess issues...
/* The Xbox PTE, modelled around the Intel 386 PTE specification */
typedef struct _XBOX_PTE
{
@ -79,36 +77,31 @@ typedef struct _XBOX_PTE
/* PTE as used by the memory manager */
typedef struct _MMPTE
typedef union _MMPTE
{
union
{
ULONG Default;
XBOX_PTE Hardware;
};
} MMPTE, *PMMPTE;
ULONG Default;
XBOX_PTE Hardware;
}MMPTE, *PMMPTE;
/* PFN entry used by the memory manager */
typedef struct _XBOX_PFN {
union
{
ULONG Default;
struct {
ULONG LockCount : 16; // Set to prevent page relocation. Used by MmLockUnlockPhysicalPage and others
ULONG Busy : 1; // If set, PFN is in use
ULONG Unused : 1;
ULONG PteIndex : 10; // Offset in the PT that maps the pte (it seems to be needed only for page relocations)
ULONG BusyType : 4; // What the page is used for
} Busy;
struct {
ULONG LockCount : 16; // Set to prevent page relocation. Used by MmLockUnlockPhysicalPage and others
ULONG Busy : 1; // If set, PFN is in use
ULONG PtesUsed : 11; // Number of used pte's in the PT pointed by the pde
ULONG BusyType : 4; // What the page is used for (must be VirtualPageTableType or SystemPageTableType)
} PTPageFrame;
};
} XBOX_PFN, *PXBOX_PFN;
typedef union _XBOX_PFN
{
ULONG Default;
struct {
ULONG LockCount : 16; // Set to prevent page relocation. Used by MmLockUnlockPhysicalPage and others
ULONG Busy : 1; // If set, PFN is in use
ULONG Unused : 1;
ULONG PteIndex : 10; // Offset in the PT that maps the pte (it seems to be needed only for page relocations)
ULONG BusyType : 4; // What the page is used for
} Busy;
struct {
ULONG LockCount : 16; // Set to prevent page relocation. Used by MmLockUnlockPhysicalPage and others
ULONG Busy : 1; // If set, PFN is in use
ULONG PtesUsed : 11; // Number of used pte's in the PT pointed by the pde
ULONG BusyType : 4; // What the page is used for (must be VirtualPageTableType or SystemPageTableType)
} PTPageFrame;
}XBOX_PFN, *PXBOX_PFN;
/* enum describing the usage type of the memory pages */
@ -129,7 +122,7 @@ typedef enum _PageType
}PageType;
/* enum describing the memory layouts available on the Xbox */
/* enum describing the memory layouts the memory manager can use */
typedef enum _MmLayout
{
MmChihiro = 1,
@ -173,17 +166,12 @@ typedef enum _MmLayout
#define IsPteOnPdeBoundary(Pte) (((ULONG_PTR)(Pte) & (PAGE_SIZE - 1)) == 0)
#define WRITE_ZERO_PTE(pPte) ((pPte)->Default = 0)
#define WRITE_PTE(pPte, Pte) (*(pPte) = Pte)
// On real hardware, enabling only the cache disable bit would result in an effective caching type of USWC
// (uncacheable speculative write combining), so we set both to achieve it
#define DISABLE_CACHING(Pte) ((Pte).Hardware.CacheDisable = 1); ((Pte).Hardware.WriteThrough = 1)
#define SET_WRITE_COMBINE(Pte) ((Pte).Hardware.CacheDisable = 0); ((Pte).Hardware.WriteThrough = 1)
#define ValidKernelPteBits (PTE_VALID_MASK | PTE_WRITE_MASK | PTE_DIRTY_MASK | PTE_ACCESS_MASK) // 0x63
#define ValidKernelPdeBits (PTE_VALID_MASK | PTE_WRITE_MASK | PTE_OWNER_MASK | PTE_DIRTY_MASK | PTE_ACCESS_MASK) // 0x67
// This returns the VAddr in the contiguous region
#define CONVERT_PFN_TO_CONTIGUOUS_PHYSICAL(Pfn) ((PCHAR)PHYSICAL_MAP_BASE + ((Pfn) << PAGE_SHIFT))
// This works with both PAddr and VAddr in the contiguous region
#define CONVERT_CONTIGUOUS_PHYSICAL_TO_PFN(Va) (((Va) & (BYTES_IN_PHYSICAL_MAP - 1)) >> PAGE_SHIFT)
// This returns the address of the PFN entry for Xbox/Chihiro
#define XBOX_PFN_ELEMENT(pfn) (&((PXBOX_PFN)XBOX_PFN_ADDRESS)[pfn])
#define CHIHIRO_PFN_ELEMENT(pfn) (&((PXBOX_PFN)CHIHIRO_PFN_ADDRESS)[pfn])
@ -253,13 +241,13 @@ class PhysicalMemory
// release a contiguous number of pages
void InsertFree(PFN start, PFN end);
// convert from Xbox to the desired system pte protection (if possible) and return it
bool ConvertXboxToSystemPteProtection(DWORD perms, PMMPTE pPte);
bool ConvertXboxToSystemPtePermissions(DWORD perms, PMMPTE pPte);
// convert from Xbox to non-system pte protection (if possible) and return it
bool ConvertXboxToPteProtection(DWORD perms, PMMPTE pPte);
bool ConvertXboxToPtePermissions(DWORD perms, PMMPTE pPte);
// convert from pte permissions to the corresponding Xbox protection code
DWORD ConvertPteToXboxProtection(ULONG PteMask);
DWORD ConvertPteToXboxPermissions(ULONG PteMask);
// convert from Xbox to Windows permissions
DWORD ConvertXboxToWinProtection(DWORD Perms);
DWORD ConvertXboxToWinPermissions(DWORD Perms);
// add execute rights if the permission mask doesn't include it
DWORD PatchXboxPermissions(DWORD Perms);
// commit page tables (if necessary)

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017-2018 ergo720
// * (c) 2017-2018-2019 ergo720
// *
// * All rights reserved
// *
@ -28,6 +28,9 @@
#ifndef VMMANAGER_H
#define VMMANAGER_H
#define SYSTEM_XBOX (1 << 1)
#define SYSTEM_DEVKIT (1 << 2)
#define SYSTEM_CHIHIRO (1 << 3)
#include "PhysicalMemory.h"
@ -55,8 +58,6 @@ struct VirtualMemoryArea
VMAType type = FreeVma;
// initial vma permissions of the allocation, only used by XbVirtualMemoryStatistics
DWORD permissions = XBOX_PAGE_NOACCESS;
// 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;
};
@ -84,6 +85,15 @@ typedef enum _MemoryRegionType
}MemoryRegionType;
/* struct used to save the persistent memory between reboots */
typedef struct _PersistedMemory
{
size_t NumOfPtes;
VAddr LaunchFrameAddresses[2];
uint32_t Data[];
}PersistedMemory;
/* VMManager class */
class VMManager : public PhysicalMemory
{
@ -97,19 +107,9 @@ class VMManager : public PhysicalMemory
// process is killed with TerminateProcess and so it doesn't have a chance to perform a cleanup...
//DestroyMemoryRegions();
DeleteCriticalSection(&m_CriticalSection);
FlushViewOfFile((void*)CONTIGUOUS_MEMORY_BASE, CHIHIRO_MEMORY_SIZE);
FlushViewOfFile((void*)PAGE_TABLES_BASE, PAGE_TABLES_SIZE);
FlushFileBuffers(m_hContiguousFile);
FlushFileBuffers(m_hPTFile);
UnmapViewOfFile((void *)CONTIGUOUS_MEMORY_BASE);
UnmapViewOfFile((void *)PAGE_TABLES_BASE);
UnmapViewOfFile((void*)XBOX_WRITE_COMBINED_BASE);
VirtualFree((void*)PAGE_TABLES_BASE, 0, MEM_RELEASE);
CloseHandle(m_hContiguousFile);
CloseHandle(m_hPTFile);
}
// initializes the memory manager to the default configuration
void Initialize(HANDLE memory_view, HANDLE pagetables_view, int BootFlags);
void Initialize(int SystemType, int BootFlags, uint32_t blocks_reserved[384]);
// retrieves memory statistics
void MemoryStatistics(xboxkrnl::PMM_STATISTICS memory_statistics);
// allocates memory in the user region
@ -119,13 +119,13 @@ class VMManager : public PhysicalMemory
// allocates memory in the system region
VAddr AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Size, bool bAddGuardPage);
// allocates memory in the contiguous region
VAddr AllocateContiguous(size_t Size, PAddr LowestAddress, PAddr HighestAddress, ULONG Alignment, DWORD Perms);
VAddr AllocateContiguousMemory(size_t Size, PAddr LowestAddress, PAddr HighestAddress, ULONG Alignment, DWORD Perms);
// maps device memory in the system region
VAddr MapDeviceMemory(PAddr Paddr, size_t Size, DWORD Perms);
// deallocates memory in the system region
PFN_COUNT DeallocateSystemMemory(PageType BusyType, VAddr addr, size_t Size);
// deallocates memory in the contiguous region
void DeallocateContiguous(VAddr addr);
void DeallocateContiguousMemory(VAddr addr);
// unmaps device memory in the system region
void UnmapDeviceMemory(VAddr addr, size_t Size);
// deallocates memory in the user region
@ -158,43 +158,36 @@ class VMManager : public PhysicalMemory
xboxkrnl::NTSTATUS XbVirtualProtect(VAddr* addr, size_t* Size, DWORD* Protect);
// xbox implementation of NtQueryVirtualMemory
xboxkrnl::NTSTATUS XbVirtualMemoryStatistics(VAddr addr, xboxkrnl::PMEMORY_BASIC_INFORMATION memory_statistics);
// saves all persisted memory just before a quick reboot
void SavePersistentMemory();
private:
// typedef of pointer to a member function mapping a memory block
typedef VAddr (VMManager::*MappingFn) (VAddr, size_t, size_t, DWORD, PFN);
// an array of structs used to track the free/allocated vma's in the various memory regions
MemoryRegion m_MemoryRegionArray[COUNTRegion];
// handle of the contiguous file mapping
HANDLE m_hContiguousFile = NULL;
// handle of the PT file mapping
HANDLE m_hPTFile = NULL;
// critical section lock to synchronize accesses
CRITICAL_SECTION m_CriticalSection;
// the allocation granularity of the host. Needed by MapViewOfFileEx and VirtualAlloc
// the allocation granularity of the host
DWORD m_AllocationGranularity = 0;
// number of bytes reserved with XBOX_MEM_RESERVE by XbAllocateVirtualMemory
size_t m_VirtualMemoryBytesReserved = 0;
// number of persisted ptes between quick reboots
size_t m_NumPersistentPtes = 0;
// set up the pfn database
void InitializePfnDatabase();
// set up the pfn database after a quick reboot
void ReinitializePfnDatabase();
// same as AllocateContiguousMemory, but it allows to allocate beyond m_MaxContiguousPfn
VAddr AllocateContiguousMemoryInternal(PFN_COUNT NumberOfPages, PFN LowestPfn, PFN HighestPfn, PFN PfnAlignment, DWORD Perms);
// set up the system allocations
void InitializeSystemAllocations();
// initializes a memory region struct
void ConstructMemoryRegion(VAddr Start, size_t Size, MemoryRegionType Type);
// clears all memory region structs
void DestroyMemoryRegions();
// map a memory block with the supplied allocation routine
VAddr MapMemoryBlock(MappingFn MappingRoutine, MemoryRegionType Type, PFN_COUNT PteNumber, PFN pfn, VAddr HighestAddress = 0);
// helper function which maps a block with VirtualAlloc
VAddr MapBlockWithVirtualAlloc(VAddr StartingAddr, size_t Size, size_t VmaEnd, DWORD Unused, PFN Unused2);
// helper function which reserves a block of virtual memory with VirtualAlloc
VAddr ReserveBlockWithVirtualAlloc(VAddr StartingAddr, size_t Size, size_t VmaEnd, DWORD Unused, PFN Unused2);
// helper function which maps a block with MapViewOfFileEx
VAddr MapBlockWithMapViewOfFileEx(VAddr StartingAddr, size_t ViewSize, size_t VmaEnd, DWORD OffsetLow, PFN pfn);
VAddr MapMemoryBlock(MemoryRegionType Type, PFN_COUNT PteNumber, DWORD Permissions, bool b64Blocks, VAddr HighestAddress = 0);
// helper function which allocates user memory with VirtualAlloc
VAddr MapHostMemory(VAddr StartingAddr, size_t Size, size_t VmaEnd, DWORD Permissions);
// constructs a vma
void ConstructVMA(VAddr Start, size_t Size, MemoryRegionType Type, VMAType VmaType, bool bFragFlag, DWORD Perms = XBOX_PAGE_NOACCESS);
void ConstructVMA(VAddr Start, size_t Size, MemoryRegionType Type, VMAType VmaType, DWORD Perms = XBOX_PAGE_NOACCESS);
// destructs a vma
void DestructVMA(VAddr addr, MemoryRegionType Type, size_t Size);
// removes a vma block from the mapped memory
@ -215,8 +208,6 @@ class VMManager : public PhysicalMemory
void UpdateMemoryPermissions(VAddr addr, size_t Size, DWORD Perms);
// restores persistent memory
void RestorePersistentMemory();
// restores a persistent allocation
void RestorePersistentAllocation(VAddr addr, PFN StartingPfn, PFN EndingPfn, PageType Type);
// acquires the critical section
void Lock();
// releases the critical section

View File

@ -120,7 +120,7 @@ CommandLineToArgvA(
return argv;
}
DWORD WINAPI Emulate(int system)
DWORD WINAPI Emulate(int system, uint32_t blocks_reserved[384])
{
FUNC_EXPORTS
@ -170,7 +170,7 @@ DWORD WINAPI Emulate(int system)
return EXIT_FAILURE;
}
CxbxKrnlMain(argc, argv);
CxbxKrnlMain(argc, argv, blocks_reserved);
LocalFree(argv);

View File

@ -52,11 +52,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
return EXIT_FAILURE;
}
#ifndef CXBX_LOADER
/*! verify Cxbx.exe is loaded to base address 0x00010000 */
if (!VerifyBaseAddr()) {
CxbxShowError("Cxbx.exe is not loaded to base address 0x00010000 (which is a requirement for Xbox emulation)");
return EXIT_FAILURE;
}
#endif
DWORD guiProcessID = 0;
// TODO: Convert ALL __argc & __argv to use main(int argc, char** argv) method.
@ -74,9 +76,22 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
}
if (bHasLoadArgument) {
#ifndef CXBX_LOADER
CxbxKrnlMain(__argc, __argv);
EmuShared::Cleanup();
return EXIT_SUCCESS;
#else
std::string szProcArgsBuffer;
for (int i = 0; i < __argc; i++) {
szProcArgsBuffer.append(__argv[i]);
}
if (!CxbxExec(szProcArgsBuffer, nullptr, false)) {
CxbxShowError("Could not launch Cxbx-R loader!");
EmuShared::Cleanup();
return EXIT_FAILURE;
}
#endif
}
// If 2nd GUI executable is launched, load settings file for GUI for editable support.

View File

@ -65,6 +65,8 @@
static int gameLogoWidth, gameLogoHeight;
static int splashLogoWidth, splashLogoHeight;
static HANDLE hPersistedMemory = NULL;
static LPVOID PersistedMemoryAddr = nullptr;
bool g_SaveOnExit = true;
@ -345,10 +347,27 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP
pCMD->dwChildProcID = lParam; // lParam is process ID.
std::thread(CrashMonitorWrapper, pCMD).detach();
g_EmuShared->SetIsEmulating(true); // NOTE: Putting in here raise to low or medium risk due to debugger will launch itself. (Current workaround)
g_EmuShared->SetIsReady(true);
break;
}
break;
case ID_GUI_VM_PERSIST_MEM: {
if (lParam) {
hPersistedMemory = OpenFileMapping(FILE_MAP_READ, FALSE, "PersistentMemory");
assert(hPersistedMemory != NULL);
PersistedMemoryAddr = MapViewOfFile(hPersistedMemory, FILE_MAP_READ, 0, 0, 0);
assert(PersistedMemoryAddr != nullptr);
}
else {
UnmapViewOfFile(PersistedMemoryAddr);
CloseHandle(hPersistedMemory);
PersistedMemoryAddr = nullptr;
hPersistedMemory = NULL;
}
}
break;
}
}
break;
@ -2224,6 +2243,8 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /
char szExeFileName[MAX_PATH];
GetModuleFileName(GetModuleHandle(nullptr), szExeFileName, MAX_PATH);
PathRemoveFileSpec(szExeFileName);
PathAppend(szExeFileName, "\\cxbxr-ldr.exe");
bool AttachLocalDebugger = (LocalDebuggerState == debuggerOn);
g_EmuShared->SetDebuggingFlag(&AttachLocalDebugger);
@ -2320,6 +2341,12 @@ void WndMain::CrashMonitor(DWORD dwChildProcID)
g_EmuShared->GetBootFlags(&iBootFlags);
if (!iBootFlags) {
if (hPersistedMemory != NULL) {
UnmapViewOfFile(PersistedMemoryAddr);
CloseHandle(hPersistedMemory);
PersistedMemoryAddr = nullptr;
hPersistedMemory = NULL;
}
if (dwExitCode == EXIT_SUCCESS) {// StopEmulation
return;
}

View File

@ -194,7 +194,8 @@
#define ID_GUI_STATUS_LLE_FLAGS 1097
#define ID_GUI_STATUS_XBOX_LED_COLOUR 1098
#define ID_GUI_STATUS_LOG_ENABLED 1099
#define IDC_AC_MUTE_ON_UNFOCUS_DISABLE 1100
#define ID_GUI_VM_PERSIST_MEM 1100
#define IDC_AC_MUTE_ON_UNFOCUS_DISABLE 1101
#define IDC_XBOX_PORT_0 1158
#define IDC_XBOX_PORT_1 1166
#define IDC_XBOX_PORT_2 1174

View File

@ -20,6 +20,7 @@
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2019 ego720
// *
// * All rights reserved
// *
@ -79,24 +80,27 @@ unsigned char virtual_memory_placeholder[VM_PLACEHOLDER_SIZE] = { 0 }; // = { OP
// /ENTRY:"rawMain"
void OutputMessage(const char *msg)
void OutputMessage(const char* msg)
{
OutputDebugStringA(msg); // Send message to debugger output too
if (msg != nullptr) {
OutputDebugStringA(msg); // Send message to debugger output too
HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD nNumberOfCharsToWrite = 0;
while (msg[nNumberOfCharsToWrite]) nNumberOfCharsToWrite++; // poor-man's strlen()
HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD nNumberOfCharsToWrite = 0;
while (msg[nNumberOfCharsToWrite]) nNumberOfCharsToWrite++; // poor-man's strlen()
// Detect output-redirection to a file
DWORD ConsoleMode;
if (!GetConsoleMode(hConsoleOutput, &ConsoleMode)) {
// Note : assume the output file accepts ANSI encoded characters
DWORD NumberOfBytesWritten;
WriteFile(hConsoleOutput, (const void *)msg, nNumberOfCharsToWrite, &NumberOfBytesWritten, /*lpOverlapped=*/NULL);
} else {
// Write message to console output
DWORD NumberOfCharsWritten;
WriteConsoleA(hConsoleOutput, (const void *)msg, nNumberOfCharsToWrite, &NumberOfCharsWritten, /*lpReserved=*/NULL);
// Detect output-redirection to a file
DWORD ConsoleMode;
if (!GetConsoleMode(hConsoleOutput, &ConsoleMode)) {
// Note : assume the output file accepts ANSI encoded characters
DWORD NumberOfBytesWritten;
WriteFile(hConsoleOutput, (const void*)msg, nNumberOfCharsToWrite, &NumberOfBytesWritten, /*lpOverlapped=*/NULL);
}
else {
// Write message to console output
DWORD NumberOfCharsWritten;
WriteConsoleA(hConsoleOutput, (const void*)msg, nNumberOfCharsToWrite, &NumberOfCharsWritten, /*lpReserved=*/NULL);
}
}
}
@ -146,7 +150,10 @@ DWORD CALLBACK rawMain()
}
}
if (!ReserveAddressRanges(system)) {
// Marking this as static to avoid an implicit call to memset, which is not availble in the loader
static uint32_t SystemDevBlocksReserved[384];
if (!ReserveAddressRanges(system, SystemDevBlocksReserved)) {
// If we get here, emulation lacks important address ranges; Don't launch
OutputMessage("Required address range couldn't be reserved!\n");
return ERROR_NOT_ENOUGH_MEMORY;
@ -166,7 +173,7 @@ DWORD CALLBACK rawMain()
}
// Find the main emulation function in our DLL
typedef void (WINAPI *Emulate_t)(int);
typedef void (WINAPI *Emulate_t)(int, uint32_t[384]);
Emulate_t pfnEmulate = (Emulate_t)GetProcAddress(hEmulationDLL, "Emulate");
if (!pfnEmulate) {
OutputMessage("Entrypoint not found!\n");
@ -175,7 +182,7 @@ DWORD CALLBACK rawMain()
// Call the main emulation function in our DLL, passing in the results
// of the address range reservations
pfnEmulate(system); // TODO : Pass along all data that we've gathered up until here (or rebuild it over there)
pfnEmulate(system, SystemDevBlocksReserved); // TODO : Pass along all data that we've gathered up until here (or rebuild it over there)
// Once emulation actually started, execution may never return here
// because all code and data that have been used up until now are