Reduce clutter in Loader by splitting up functionality in task-specific source files
This commit is contained in:
parent
420d689d82
commit
032eee144f
|
@ -23,11 +23,13 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
|||
endif()
|
||||
|
||||
file (GLOB HEADERS
|
||||
"${CXBXR_ROOT_DIR}/src/common/XboxAddressRanges.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/AddressRanges.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/ReserveAddressRanges.h"
|
||||
)
|
||||
|
||||
file (GLOB SOURCES
|
||||
"${CXBXR_ROOT_DIR}/src/common/XboxAddressRanges.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/LoaderTooling.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/ReserveAddressRanges.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/CxbxLoader/loader.cpp"
|
||||
)
|
||||
|
||||
|
|
|
@ -34,11 +34,8 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h> // For DWORD, CALLBACK, VirtualAlloc, LPVOID, SIZE_T, HMODULE
|
||||
|
||||
#include "..\Common\XboxAddressRanges.h" // For XboxAddressRangeType, XboxAddressRanges
|
||||
#include "..\Common\AddressRanges.h"
|
||||
#include "..\Common\ReserveAddressRanges.h"
|
||||
|
||||
// Reserve the first 128 MB MemLowVirtual address range without inflating the EXE size,
|
||||
// by simply declaring an array, first thing, in global scope. It gets placed in the BSS segment,
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
// 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,
|
||||
// *
|
||||
// * Common->AddressRanges.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx is free software; you can redistribute it
|
||||
// * and/or modify it 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-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h> // For DWORD, CALLBACK, VirtualAlloc, LPVOID, SIZE_T, HMODULE
|
||||
|
||||
#define KB(x) ((x) * 1024 ) // = 0x00000400
|
||||
#define MB(x) ((x) * KB(1024)) // = 0x00100000
|
||||
|
||||
// Windows' address space allocation granularity;
|
||||
// See https://blogs.msdn.microsoft.com/oldnewthing/20031008-00/?p=42223
|
||||
const int BLOCK_SIZE = KB(64);
|
||||
|
||||
// One allocation block consists of 16 pages (since PAGE_SIZE is 4 kilobytes)
|
||||
const int PAGE_SIZE = KB(4);
|
||||
|
||||
#define ARRAY_SIZE(a) \
|
||||
((sizeof(a) / sizeof(*(a))) / \
|
||||
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
|
||||
|
||||
const struct {
|
||||
unsigned __int32 Start;
|
||||
#ifdef DEBUG
|
||||
unsigned __int32 End; // TODO : Add validation that this End corresponds to specified Size
|
||||
#endif
|
||||
int Size;
|
||||
DWORD InitialMemoryProtection; // Memory page protection, for use by VirtualAlloc
|
||||
// Shortend symbol aliasses for memory page protection
|
||||
#define PROT_UNH 0 // UNHANDLED
|
||||
#define PROT_RW PAGE_READWRITE
|
||||
#define PROT_XRW PAGE_EXECUTE_READWRITE
|
||||
#define PROT_NAC PAGE_NOACCESS
|
||||
|
||||
unsigned int RangeFlags;
|
||||
// Range flags (used for system selection and optional marker)
|
||||
#define MAY_FAIL (1 << 0) // Optional (may fail address range reservation)
|
||||
#define SYSTEM_XBOX (1 << 1)
|
||||
#define SYSTEM_DEVKIT (1 << 2)
|
||||
#define SYSTEM_CHIHIRO (1 << 3)
|
||||
#ifdef INCLUDE_SYSTEM_ALPHA
|
||||
#define SYSTEM_ALPHA (1 << 4)
|
||||
#endif
|
||||
// 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;
|
||||
#endif
|
||||
} XboxAddressRanges[] = {
|
||||
#ifdef DEBUG
|
||||
#define RANGE_ENTRY(START, END, SIZE, PROT, FLAGS, COMMENT) { START, END, SIZE, PROT, FLAGS, COMMENT }
|
||||
#else
|
||||
#define RANGE_ENTRY(START, END, SIZE, PROT, FLAGS, COMMENT) { START, SIZE, PROT, FLAGS }
|
||||
#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, 0xC001FFFF, KB(128), PROT_RW, SYSTEM_ALL , "MemPageTable"), // TODO : MB(4)?
|
||||
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 , "DeviceUSB0"),
|
||||
#ifdef INCLUDE_SYSTEM_ALPHA
|
||||
RANGE_ENTRY(0xFED08000, 0xFED08FFF, KB( 4), PROT_NAC, SYSTEM_ALPHA | MAY_FAIL, "DeviceUSB1 Optional (won't be emulated for a long while?)"),
|
||||
#endif
|
||||
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"),
|
||||
RANGE_ENTRY(0xFFFFFE00, 0xFFFFFFFF, 512 , PROT_NAC, SYSTEM_RETAIL | MAY_FAIL, "DeviceMCPX (not Chihiro, Xbox - if enabled) Optional (can safely be ignored)"),
|
||||
|
||||
#undef RANGE_ENTRY
|
||||
};
|
||||
|
||||
extern bool AddressRangeMatchesFlags(const int index, const int flags);
|
||||
extern bool IsOptionalAddressRange(const int index);
|
||||
|
||||
extern LPTSTR GetLastErrorString();
|
||||
extern void FreeLastErrorString(LPTSTR Error);
|
|
@ -0,0 +1,75 @@
|
|||
// 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,
|
||||
// *
|
||||
// * Common->LoaderTooling.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx is free software; you can redistribute it
|
||||
// * and/or modify it 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-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "AddressRanges.h"
|
||||
|
||||
bool AddressRangeMatchesFlags(const int index, const int flags)
|
||||
{
|
||||
return XboxAddressRanges[index].RangeFlags & flags;
|
||||
}
|
||||
|
||||
bool IsOptionalAddressRange(const int index)
|
||||
{
|
||||
return AddressRangeMatchesFlags(index, MAY_FAIL);
|
||||
}
|
||||
|
||||
LPTSTR GetLastErrorString()
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
|
||||
// Translate ErrorCode to String.
|
||||
LPTSTR Error = nullptr;
|
||||
if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
err,
|
||||
0,
|
||||
(LPTSTR)&Error,
|
||||
0,
|
||||
NULL) == 0) {
|
||||
// Failed in translating.
|
||||
}
|
||||
|
||||
return Error;
|
||||
}
|
||||
|
||||
void FreeLastErrorString(LPTSTR Error)
|
||||
{
|
||||
if (Error) {
|
||||
::LocalFree(Error);
|
||||
Error = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
// 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,
|
||||
// *
|
||||
// * Common->ReserveAddressRanges.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx is free software; you can redistribute it
|
||||
// * and/or modify it 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-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "AddressRanges.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
// This array keeps track of which ranges have successfully been reserved.
|
||||
// Having this helps debugging, but isn't strictly necessary, as we could
|
||||
// retrieve the same information using VirtualQuery.
|
||||
struct {
|
||||
int Index;
|
||||
unsigned __int32 Start;
|
||||
int Size;
|
||||
} ReservedRanges[128];
|
||||
|
||||
int ReservedRangeCount = 0;
|
||||
#endif // DEBUG
|
||||
|
||||
// Reserve an address range up to the extend of what the host allows.
|
||||
bool ReserveMemoryRange(int index)
|
||||
{
|
||||
unsigned __int32 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;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Safeguard against bounds overflow
|
||||
if (ReservedRangeCount < ARRAY_SIZE(ReservedRanges)) {
|
||||
// Initialize the reservation of a new range
|
||||
ReservedRanges[ReservedRangeCount].Index = index;
|
||||
ReservedRanges[ReservedRangeCount].Start = Start;
|
||||
ReservedRanges[ReservedRangeCount].Size = 0;
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
// 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;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
// Safeguard against bounds overflow
|
||||
if (ReservedRangeCount < ARRAY_SIZE(ReservedRanges)) {
|
||||
if (HadFailure) {
|
||||
HadFailure = false;
|
||||
// Starting a new range - did the previous one have any size?
|
||||
if (ReservedRanges[ReservedRangeCount].Size > 0) {
|
||||
// Then start a new range, and copy over the current type
|
||||
ReservedRangeCount++;
|
||||
ReservedRanges[ReservedRangeCount].Index = index;
|
||||
}
|
||||
|
||||
// Register a new ranges starting address
|
||||
ReservedRanges[ReservedRangeCount].Start = Start;
|
||||
}
|
||||
|
||||
// Accumulate the size of each successfull reservation
|
||||
ReservedRanges[ReservedRangeCount].Size += BlockSize;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
// Handle the next block
|
||||
Start += BLOCK_SIZE;
|
||||
Size -= BLOCK_SIZE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Safeguard against bounds overflow
|
||||
if (ReservedRangeCount < ARRAY_SIZE(ReservedRanges)) {
|
||||
// Keep the current block only if it contains a successfully reserved range
|
||||
if (ReservedRanges[ReservedRangeCount].Size > 0) {
|
||||
ReservedRangeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
// Only a complete success when the entire request was reserved in a single range
|
||||
// (Otherwise, we have either a complete failure, or reserved it partially over multiple ranges)
|
||||
return !HadAnyFailure;
|
||||
}
|
||||
|
||||
bool ReserveAddressRanges(const int system) {
|
||||
// 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
|
||||
if (!AddressRangeMatchesFlags(i, system))
|
||||
continue;
|
||||
|
||||
// Try to reserve each address range
|
||||
if (ReserveMemoryRange(i))
|
||||
continue;
|
||||
|
||||
// Some ranges are allowed to fail reserving
|
||||
if (!IsOptionalAddressRange(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// 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,
|
||||
// *
|
||||
// * Common->ReserveAddressRanges.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx is free software; you can redistribute it
|
||||
// * and/or modify it 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-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
extern bool ReserveAddressRanges(const int system);
|
|
@ -9,7 +9,7 @@
|
|||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Common->XboxAddressRanges.cpp
|
||||
// * Common->VerifyAddressRanges.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
|
@ -34,126 +34,7 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h> // For DWORD, CALLBACK, VirtualAlloc, LPVOID, SIZE_T, HMODULE
|
||||
|
||||
#include "XboxAddressRanges.h"
|
||||
|
||||
typedef struct {
|
||||
int Index;
|
||||
unsigned __int32 Start;
|
||||
int Size;
|
||||
} ReservedRange;
|
||||
|
||||
// This array keeps track of which ranges have successfully been reserved.
|
||||
// Having this helps debugging, but isn't strictly necessary, as we could
|
||||
// retrieve the same information using VirtualQuery.
|
||||
ReservedRange ReservedRanges[128];
|
||||
int ReservedRangeCount = 0;
|
||||
|
||||
// Reserve an address range up to the extend of what the host allows.
|
||||
bool ReserveMemoryRange(int index)
|
||||
{
|
||||
unsigned __int32 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;
|
||||
}
|
||||
|
||||
// Safeguard against bounds overflow
|
||||
if (ReservedRangeCount < ARRAY_SIZE(ReservedRanges)) {
|
||||
// Initialize the reservation of a new range
|
||||
ReservedRanges[ReservedRangeCount].Index = index;
|
||||
ReservedRanges[ReservedRangeCount].Start = Start;
|
||||
ReservedRanges[ReservedRangeCount].Size = 0;
|
||||
}
|
||||
|
||||
// Reserve this range in 64 Kb block increments, so later on 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;
|
||||
}
|
||||
else {
|
||||
// Safeguard against bounds overflow
|
||||
if (ReservedRangeCount < ARRAY_SIZE(ReservedRanges)) {
|
||||
if (HadFailure) {
|
||||
HadFailure = false;
|
||||
// Starting a new range - did the previous one have any size?
|
||||
if (ReservedRanges[ReservedRangeCount].Size > 0) {
|
||||
// Then start a new range, and copy over the current type
|
||||
ReservedRangeCount++;
|
||||
ReservedRanges[ReservedRangeCount].Index = index;
|
||||
}
|
||||
|
||||
// Register a new ranges starting address
|
||||
ReservedRanges[ReservedRangeCount].Start = Start;
|
||||
}
|
||||
|
||||
// Accumulate the size of each successfull reservation
|
||||
ReservedRanges[ReservedRangeCount].Size += BlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the next block
|
||||
Start += BLOCK_SIZE;
|
||||
Size -= BLOCK_SIZE;
|
||||
}
|
||||
|
||||
// Safeguard against bounds overflow
|
||||
if (ReservedRangeCount < ARRAY_SIZE(ReservedRanges)) {
|
||||
// Keep the current block only if it contains a successfully reserved range
|
||||
if (ReservedRanges[ReservedRangeCount].Size > 0) {
|
||||
ReservedRangeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Only a complete success when the entire request was reserved in a single range
|
||||
// (Otherwise, we have either a complete failure, or reserved it partially over multiple ranges)
|
||||
return !HadAnyFailure;
|
||||
}
|
||||
|
||||
bool AddressRangeMatchesFlags(const int index, const int flags)
|
||||
{
|
||||
return XboxAddressRanges[index].RangeFlags & flags;
|
||||
}
|
||||
|
||||
bool IsOptionalAddressRange(const int index)
|
||||
{
|
||||
return AddressRangeMatchesFlags(index, MAY_FAIL);
|
||||
}
|
||||
|
||||
bool ReserveAddressRanges(const int system) {
|
||||
// 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
|
||||
if (!AddressRangeMatchesFlags(i, system))
|
||||
continue;
|
||||
|
||||
// Try to reserve each address range
|
||||
if (ReserveMemoryRange(i))
|
||||
continue;
|
||||
|
||||
// Some ranges are allowed to fail reserving
|
||||
if (!IsOptionalAddressRange(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#include "AddressRanges.h"
|
||||
|
||||
bool VerifyAddressRange(int index)
|
||||
{
|
||||
|
@ -285,31 +166,3 @@ bool AllocateMemoryRange(const int index)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
LPTSTR GetLastErrorString()
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
|
||||
// Translate ErrorCode to String.
|
||||
LPTSTR Error = nullptr;
|
||||
if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
err,
|
||||
0,
|
||||
(LPTSTR)&Error,
|
||||
0,
|
||||
NULL) == 0) {
|
||||
// Failed in translating.
|
||||
}
|
||||
|
||||
return Error;
|
||||
}
|
||||
|
||||
void FreeLastErrorString(LPTSTR Error)
|
||||
{
|
||||
if (Error) {
|
||||
::LocalFree(Error);
|
||||
Error = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// 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,
|
||||
// *
|
||||
// * Common->VerifyAddressRanges.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx is free software; you can redistribute it
|
||||
// * and/or modify it 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-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
extern bool VerifyAddressRanges(const int system);
|
||||
extern void UnreserveMemoryRange(const int index);
|
||||
extern bool AllocateMemoryRange(const int index);
|
|
@ -1,109 +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,
|
||||
// *
|
||||
// * Common->XboxAddressRanges.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx is free software; you can redistribute it
|
||||
// * and/or modify it 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-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#define KB(x) ((x) * 1024 ) // = 0x00000400
|
||||
#define MB(x) ((x) * KB(1024)) // = 0x00100000
|
||||
|
||||
// Windows' address space allocation granularity;
|
||||
// See https://blogs.msdn.microsoft.com/oldnewthing/20031008-00/?p=42223
|
||||
const int BLOCK_SIZE = KB(64);
|
||||
|
||||
// One allocation block consists of 16 pages (since PAGE_SIZE is 4 kilobytes)
|
||||
const int PAGE_SIZE = KB(4);
|
||||
|
||||
#define ARRAY_SIZE(a) \
|
||||
((sizeof(a) / sizeof(*(a))) / \
|
||||
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
|
||||
|
||||
typedef struct {
|
||||
const char *Name;
|
||||
unsigned __int32 Start;
|
||||
int Size;
|
||||
DWORD InitialMemoryProtection; // Memory page protection, for use by VirtualAlloc
|
||||
unsigned int RangeFlags;
|
||||
} XboxAddressRange;
|
||||
|
||||
// Shortend symbol aliasses for memory page protection
|
||||
#define PROT_UNH 0 // UNHANDLED
|
||||
#define PROT_RW PAGE_READWRITE
|
||||
#define PROT_XRW PAGE_EXECUTE_READWRITE
|
||||
#define PROT_NAC PAGE_NOACCESS
|
||||
|
||||
// Range flags (used for system selection and optional marker)
|
||||
#define SYSTEM_XBOX (1 << 0)
|
||||
#define SYSTEM_DEVKIT (1 << 1)
|
||||
#define SYSTEM_CHIHIRO (1 << 2)
|
||||
#define MAY_FAIL (1 << 3) // Optional (may fail address range reservation)
|
||||
|
||||
// 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)
|
||||
|
||||
const XboxAddressRange XboxAddressRanges[] = {
|
||||
// See http://xboxdevwiki.net/Memory
|
||||
// and http://xboxdevwiki.net/Boot_Process#Paging
|
||||
{ "MemLowVirtual", 0x00000000, MB( 64), PROT_XRW, SYSTEM_XBOX | MAY_FAIL }, // - 0x07FFFFFF (Retail Xbox) Optional (already reserved via virtual_memory_placeholder)
|
||||
{ "MemLowVirtual", 0x00000000, MB(128), PROT_XRW, SYSTEM_128MB | MAY_FAIL }, // - 0x07FFFFFF (Chihiro / DevKit)
|
||||
{ "MemPhysical", 0x80000000, MB( 64), PROT_XRW, SYSTEM_XBOX }, // - 0x87FFFFFF (Retail)
|
||||
{ "MemPhysical", 0x80000000, MB(128), PROT_XRW, SYSTEM_128MB }, // - 0x87FFFFFF (Chihiro / DevKit)
|
||||
{ "DevKitMemory", 0xB0000000, MB(128), PROT_NAC, SYSTEM_DEVKIT }, // - 0xBFFFFFFF Optional (TODO : Check reserved range (might behave like MemTiled) + Flag [O]ptional?
|
||||
{ "MemPageTable", 0xC0000000, KB(128), PROT_RW, SYSTEM_ALL }, // - 0xC001FFFF TODO : MB(4)?
|
||||
{ "SystemMemory", 0xD0000000, MB(512), PROT_UNH, SYSTEM_ALL | MAY_FAIL }, // - 0xEFFFFFFF Optional (TODO : Check reserved range (might behave like MemTiled)
|
||||
{ "MemTiled", 0xF0000000, MB( 64), PROT_UNH, SYSTEM_ALL | MAY_FAIL }, // - 0xF3FFFFFF Optional (even though it can't be reserved, MapViewOfFileEx to this range still works!?)
|
||||
{ "DeviceNV2A_a", 0xFD000000, MB( 7), PROT_NAC, SYSTEM_ALL }, // - 0xFD6FFFFF (GPU)
|
||||
{ "MemNV2APRAMIN", 0xFD700000, MB( 1), PROT_RW, SYSTEM_ALL }, // - 0xFD7FFFFF
|
||||
{ "DeviceNV2A_b", 0xFD800000, MB( 8), PROT_NAC, SYSTEM_ALL }, // - 0xFDFFFFFF (GPU)
|
||||
{ "DeviceAPU", 0xFE800000, KB(512), PROT_NAC, SYSTEM_ALL }, // - 0xFE87FFFF
|
||||
{ "DeviceAC97", 0xFEC00000, KB( 4), PROT_NAC, SYSTEM_ALL }, // - 0xFEC00FFF (ACI)
|
||||
{ "DeviceUSB0", 0xFED00000, KB( 4), PROT_NAC, SYSTEM_ALL }, // - 0xFED00FFF
|
||||
{ "DeviceUSB1", 0xFED08000, KB( 4), PROT_NAC, SYSTEM_ALL | MAY_FAIL }, // - 0xFED08FFF Optional (won't be emulated for a long while?)
|
||||
{ "DeviceNVNet", 0xFEF00000, KB( 1), PROT_NAC, SYSTEM_ALL }, // - 0xFEF003FF
|
||||
{ "DeviceFlash_a", 0xFF000000, MB( 4), PROT_NAC, SYSTEM_ALL }, // - 0xFF3FFFFF (Flash mirror 1)
|
||||
{ "DeviceFlash_b", 0xFF400000, MB( 4), PROT_NAC, SYSTEM_ALL }, // - 0xFF7FFFFF (Flash mirror 2)
|
||||
{ "DeviceFlash_c", 0xFF800000, MB( 4), PROT_NAC, SYSTEM_ALL }, // - 0xFFBFFFFF (Flash mirror 3)
|
||||
{ "DeviceFlash_d", 0xFFC00000, MB( 4), PROT_NAC, SYSTEM_ALL | MAY_FAIL }, // - 0xFFFFFFFF (Flash mirror 4) Optional (will probably fail reservation, which is acceptable - the 3 other mirrors work just fine
|
||||
{ "DeviceMCPX", 0xFFFFFE00, 512 , PROT_NAC, SYSTEM_RETAIL | MAY_FAIL }, // - 0xFFFFFFFF (not Chihiro, Xbox - if enabled) Optional (can safely be ignored)
|
||||
};
|
||||
|
||||
extern bool ReserveAddressRanges(const int system);
|
||||
extern bool VerifyAddressRanges(const int system);
|
||||
extern void UnreserveMemoryRange(const int index);
|
||||
extern bool AllocateMemoryRange(const int index);
|
||||
|
||||
extern LPTSTR GetLastErrorString();
|
||||
extern void FreeLastErrorString(LPTSTR Error);
|
Loading…
Reference in New Issue