From 032eee144f949a35c56387f939a2af33f4c74ee8 Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Mon, 4 Feb 2019 13:41:11 +0100 Subject: [PATCH] Reduce clutter in Loader by splitting up functionality in task-specific source files --- projects/CxbxLoader/CMakeLists.txt | 6 +- src/CxbxLoader/loader.cpp | 7 +- src/common/AddressRanges.h | 125 +++++++++++++++ src/common/LoaderTooling.cpp | 75 +++++++++ src/common/ReserveAddressRanges.cpp | 149 +++++++++++++++++ src/common/ReserveAddressRanges.h | 38 +++++ ...ressRanges.cpp => VerifyAddressRanges.cpp} | 151 +----------------- src/common/VerifyAddressRanges.h | 40 +++++ src/common/XboxAddressRanges.h | 109 ------------- 9 files changed, 435 insertions(+), 265 deletions(-) create mode 100644 src/common/AddressRanges.h create mode 100644 src/common/LoaderTooling.cpp create mode 100644 src/common/ReserveAddressRanges.cpp create mode 100644 src/common/ReserveAddressRanges.h rename src/common/{XboxAddressRanges.cpp => VerifyAddressRanges.cpp} (54%) create mode 100644 src/common/VerifyAddressRanges.h delete mode 100644 src/common/XboxAddressRanges.h diff --git a/projects/CxbxLoader/CMakeLists.txt b/projects/CxbxLoader/CMakeLists.txt index eaa631019..d99e598a0 100644 --- a/projects/CxbxLoader/CMakeLists.txt +++ b/projects/CxbxLoader/CMakeLists.txt @@ -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" ) diff --git a/src/CxbxLoader/loader.cpp b/src/CxbxLoader/loader.cpp index 973aeeb31..d20cf8105 100644 --- a/src/CxbxLoader/loader.cpp +++ b/src/CxbxLoader/loader.cpp @@ -34,11 +34,8 @@ // * // ****************************************************************** -#include -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#include // 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, diff --git a/src/common/AddressRanges.h b/src/common/AddressRanges.h new file mode 100644 index 000000000..ef836683d --- /dev/null +++ b/src/common/AddressRanges.h @@ -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 +// * +// * All rights reserved +// * +// ****************************************************************** +#pragma once + +#include +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include // 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(!(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); diff --git a/src/common/LoaderTooling.cpp b/src/common/LoaderTooling.cpp new file mode 100644 index 000000000..3bf95f3f6 --- /dev/null +++ b/src/common/LoaderTooling.cpp @@ -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 +// * +// * 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; + } +} + diff --git a/src/common/ReserveAddressRanges.cpp b/src/common/ReserveAddressRanges.cpp new file mode 100644 index 000000000..108b7a354 --- /dev/null +++ b/src/common/ReserveAddressRanges.cpp @@ -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 +// * +// * 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; +} diff --git a/src/common/ReserveAddressRanges.h b/src/common/ReserveAddressRanges.h new file mode 100644 index 000000000..80da3029b --- /dev/null +++ b/src/common/ReserveAddressRanges.h @@ -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 +// * +// * All rights reserved +// * +// ****************************************************************** +#pragma once + +extern bool ReserveAddressRanges(const int system); diff --git a/src/common/XboxAddressRanges.cpp b/src/common/VerifyAddressRanges.cpp similarity index 54% rename from src/common/XboxAddressRanges.cpp rename to src/common/VerifyAddressRanges.cpp index fe4a18eca..05d390fce 100644 --- a/src/common/XboxAddressRanges.cpp +++ b/src/common/VerifyAddressRanges.cpp @@ -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 -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#include // 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; - } -} - diff --git a/src/common/VerifyAddressRanges.h b/src/common/VerifyAddressRanges.h new file mode 100644 index 000000000..857e3cfe9 --- /dev/null +++ b/src/common/VerifyAddressRanges.h @@ -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 +// * +// * All rights reserved +// * +// ****************************************************************** +#pragma once + +extern bool VerifyAddressRanges(const int system); +extern void UnreserveMemoryRange(const int index); +extern bool AllocateMemoryRange(const int index); diff --git a/src/common/XboxAddressRanges.h b/src/common/XboxAddressRanges.h deleted file mode 100644 index 10afcffd0..000000000 --- a/src/common/XboxAddressRanges.h +++ /dev/null @@ -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 -// * -// * 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(!(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);