Cleaned up of the loader project, added environment checks and documented it somewhat.

This commit is contained in:
patrickvl 2019-02-03 18:47:59 +01:00 committed by RadWolfie
parent 2295a10e77
commit 420d689d82
4 changed files with 203 additions and 116 deletions

View File

@ -28,7 +28,7 @@
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
// *
// * All rights reserved
// *
@ -46,7 +46,7 @@
// This variable *MUST* be this large, for it to take up address space
// so that all other code and data in this module are placed outside of the
// maximum virtual memory range.
#define VM_PLACEHOLDER_SIZE 128 * 1024 * 1024
#define VM_PLACEHOLDER_SIZE MB(128) // Enough to cover MemLowVirtual (Cihiro/Devkit)
// Note : In the old setup, we used #pragma section(".text"); __declspec(allocate(".text"))
// to put this variable at the exact image base address 0x00010000, but that resulted in
@ -59,58 +59,119 @@ unsigned char virtual_memory_placeholder[VM_PLACEHOLDER_SIZE] = { 0 }; // = { OP
// Note : This executable is meant to be as tiny as humanly possible.
// The C++ runtime library is removed using https://stackoverflow.com/a/39220245/12170
// This Cxbx loader is tailored to bootstrapping an Xbox environment under Windows.
// This requires :
// * user-access to the lowest possible virtual memory address (0x00010000),
// * complete access to as much as possible of the rest 32 bit address space.
//
// This implies running it as a 32 bit process under WOW64 (64 bit Windows).
// This is done by initially relying on no other code than our own and
// kernel32.DLL (which the Windows kernel loads into all it's processes).
// Also, the linker options for this loader are specified such, that the
// executable will be loaded by Windows at the pre-defined address, and
// won't contain any other code not under our control.
//
// When executed, this loader starts by validating the correct run environment,
// then reserves all memory ranges that Xbox emulation requires, and only then
// loads in the actual emulation code by dynamically loading in our library
// and transfer control to it.
//
// Note, that since the emulation code will have to overwrite the memory where
// this loader resides, no code or data may be used by the emulation code,
// nor may the emulator ever return to this code!
// Important linker flags :
// /MACHINE:X86
// /NODEFAULTLIB
// /DYNAMICBASE:NO
// /BASE:"0x00010000"
// /FIXED
// /LARGEADDRESSAWARE
// /SUBSYSTEM:CONSOLE
// /ENTRY:"rawMain"
DWORD CALLBACK rawMain()
{
(void)virtual_memory_placeholder; // prevent optimization removing this data
// Verify we're running under WOW64
BOOL bIsWow64Process;
if (!IsWow64Process(GetCurrentProcess(), &bIsWow64Process)) {
bIsWow64Process = false;
}
if (!bIsWow64Process) {
OutputDebugString("Not running as a WOW64 process!");
return ERROR_BAD_ENVIRONMENT;
}
// We have hard-code BLOCK_SIZE to 64 KiB, check this against the system's allocation granularity.
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
if (SystemInfo.dwAllocationGranularity != BLOCK_SIZE) {
OutputDebugString("Unsupported system allocation granularity!");
return ERROR_BAD_ENVIRONMENT;
}
if (SystemInfo.dwPageSize != PAGE_SIZE) {
OutputDebugString("Unsupported system page size!");
return ERROR_BAD_ENVIRONMENT;
}
if (SystemInfo.lpMaximumApplicationAddress < (void*)0xFFFEFFFF) {
// Note : If this fails, the large-address-aware linker flag must be restored
OutputDebugString("Maximum applocation address too low!");
return ERROR_BAD_ENVIRONMENT;
}
int system = SYSTEM_XBOX; // By default, we'll emulate a retail Xbox
// Note : Since we only have kernel32 API's available (not even the standard libary),
// we use the (exclusively wide-char) FindStringOrdinal() here instead of strstr():
LPWSTR CommandLine = GetCommandLineW();
if (FindStringOrdinal(FIND_FROMSTART, CommandLine, -1, L" /chihiro", -1, true) >= 0) {
system = SYSTEM_CHIHIRO;
} else {
if (FindStringOrdinal(FIND_FROMSTART, CommandLine, -1, L" /devkit", -1, true) >= 0) {
system = SYSTEM_DEVKIT;
}
}
// Note : Since we only have kernel32 API's available, use FindStringOrdinal() here instead of strstr():
int flags = (FindStringOrdinal(FIND_FROMSTART, CommandLine, -1, L" /devkit", -1, true) >= 0 ? RangeFlags::D : 0)
| (FindStringOrdinal(FIND_FROMSTART, CommandLine, -1, L" /chihiro", -1, true) >= 0 ? RangeFlags::C : 0);
if (!ReserveAddressRanges(flags)) {
if (!ReserveAddressRanges(system)) {
// If we get here, emulation lacks important address ranges; Don't launch
OutputDebugStringA("Required address range couldn't be reserved!");
OutputDebugString("Required address range couldn't be reserved!");
return ERROR_NOT_ENOUGH_MEMORY;
}
// Only after the required memory ranges are reserved, load our emulation DLL
HMODULE hEmulationDLL = LoadLibraryA("CxbxEmulator.dll");
if (!hEmulationDLL) {
// TODO : Move the following towards a tooling function
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.
}
// Free the buffer.
LPTSTR Error = GetLastErrorString();
if (Error) {
OutputDebugString(Error);
::LocalFree(Error);
Error = nullptr;
FreeLastErrorString(Error);
}
return ERROR_RESOURCE_NOT_FOUND;
}
// Find the main emulation function in our DLL
typedef DWORD (WINAPI * Emulate_t)();
typedef void (WINAPI *Emulate_t)();
Emulate_t pfnEmulate = (Emulate_t)GetProcAddress(hEmulationDLL, "Emulate");
if (!pfnEmulate) {
OutputDebugString("Entrypoint not found!");
return ERROR_RESOURCE_NOT_FOUND;
}
// Call the main emulation function in our DLL, passing in the results
// of the address range reservations
return pfnEmulate(); // TODO : Pass along the command line
pfnEmulate(); // TODO : Pass along all data that we've gathered up until here (or rebuild it over there)
// Once the Emulate function has control, it may never return here
// because all code and data that have been used up until now are
// overwritten. From now on, only emulated code is allowed to access
// this memory!
return ERROR_APP_DATA_CORRUPT;
}

View File

@ -28,7 +28,7 @@
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
// *
// * All rights reserved
// *
@ -40,21 +40,6 @@
#include "XboxAddressRanges.h"
// Maps an XboxAddressRangeType to page protection flags, for use by VirtualAlloc
DWORD XboxAddressRangeTypeToVirtualAllocPageProtectionFlags(int type)
{
if (XboxAddressRanges[type].Flags & RangeFlags::E)
return PAGE_EXECUTE_READWRITE;
if (XboxAddressRanges[type].Flags & RangeFlags::R)
return PAGE_READWRITE;
if (XboxAddressRanges[type].Flags & RangeFlags::N)
return PAGE_NOACCESS;
return 0; // UNHANDLED
}
typedef struct {
int Index;
unsigned __int32 Start;
@ -68,13 +53,12 @@ ReservedRange ReservedRanges[128];
int ReservedRangeCount = 0;
// Reserve an address range up to the extend of what the host allows.
bool ReserveMemoryRange(int xart)
bool ReserveMemoryRange(int index)
{
// assert(XboxAddressRanges[xart].Type == xart);
unsigned __int32 Start = XboxAddressRanges[xart].Start;
int Size = XboxAddressRanges[xart].Size;
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)
@ -86,7 +70,7 @@ bool ReserveMemoryRange(int xart)
// Safeguard against bounds overflow
if (ReservedRangeCount < ARRAY_SIZE(ReservedRanges)) {
// Initialize the reservation of a new range
ReservedRanges[ReservedRangeCount].Index = xart;
ReservedRanges[ReservedRangeCount].Index = index;
ReservedRanges[ReservedRangeCount].Start = Start;
ReservedRanges[ReservedRangeCount].Size = 0;
}
@ -94,7 +78,7 @@ bool ReserveMemoryRange(int xart)
// 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 = XboxAddressRangeTypeToVirtualAllocPageProtectionFlags(xart);
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);
@ -111,7 +95,7 @@ bool ReserveMemoryRange(int xart)
if (ReservedRanges[ReservedRangeCount].Size > 0) {
// Then start a new range, and copy over the current type
ReservedRangeCount++;
ReservedRanges[ReservedRangeCount].Index = xart;
ReservedRanges[ReservedRangeCount].Index = index;
}
// Register a new ranges starting address
@ -141,21 +125,21 @@ bool ReserveMemoryRange(int xart)
return !HadAnyFailure;
}
bool AddressRangeMatchesFlags(const int xart, const int flags)
bool AddressRangeMatchesFlags(const int index, const int flags)
{
return XboxAddressRanges[xart].Flags & flags;
return XboxAddressRanges[index].RangeFlags & flags;
}
bool IsOptionalAddressRange(const int xart)
bool IsOptionalAddressRange(const int index)
{
return AddressRangeMatchesFlags(xart, RangeFlags::O);
return AddressRangeMatchesFlags(index, MAY_FAIL);
}
bool ReserveAddressRanges(const int flags) {
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, flags))
if (!AddressRangeMatchesFlags(i, system))
continue;
// Try to reserve each address range
@ -171,12 +155,10 @@ bool ReserveAddressRanges(const int flags) {
return true;
}
bool VerifyAddressRange(int xart)
bool VerifyAddressRange(int index)
{
const int PAGE_SIZE = KB(4);
unsigned __int32 BaseAddress = XboxAddressRanges[xart].Start;
int Size = XboxAddressRanges[xart].Size;
unsigned __int32 BaseAddress = XboxAddressRanges[index].Start;
int Size = XboxAddressRanges[index].Size;
if (BaseAddress == 0) {
// The zero page (the entire first 64 KB block) can't be verified
@ -186,7 +168,7 @@ bool VerifyAddressRange(int xart)
// Verify this range in 64 Kb block increments, as they are supposed
// to have been reserved like that too:
const DWORD AllocationProtect = (XboxAddressRanges[xart].Start == 0) ? PAGE_EXECUTE_WRITECOPY : XboxAddressRangeTypeToVirtualAllocPageProtectionFlags(xart);
const DWORD AllocationProtect = (XboxAddressRanges[index].Start == 0) ? PAGE_EXECUTE_WRITECOPY : XboxAddressRanges[index].InitialMemoryProtection;
MEMORY_BASIC_INFORMATION mbi;
while (Size > 0) {
// Expected values
@ -197,7 +179,7 @@ bool VerifyAddressRange(int xart)
DWORD Type = MEM_PRIVATE;
// Allowed deviations
if (XboxAddressRanges[xart].Start == 0) {
if (XboxAddressRanges[index].Start == 0) {
AllocationBase = (PVOID)0x10000;
switch (BaseAddress) {
case 0x10000: // Image Header
@ -245,7 +227,7 @@ bool VerifyAddressRange(int xart)
Okay = (mbi.Type == Type);
if (!Okay)
if (!IsOptionalAddressRange(xart))
if (!IsOptionalAddressRange(index))
return false;
// Handle the next region
@ -256,10 +238,14 @@ bool VerifyAddressRange(int xart)
return true;
}
bool VerifyAddressRanges()
bool VerifyAddressRanges(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;
if (!VerifyAddressRange(i)) {
if (!IsOptionalAddressRange(i)) {
return false;
@ -270,23 +256,22 @@ bool VerifyAddressRanges()
return true;
}
void UnreserveMemoryRange(int xart)
void UnreserveMemoryRange(const int index)
{
unsigned __int32 Start = XboxAddressRanges[xart].Start;
int Size = XboxAddressRanges[xart].Size;
unsigned __int32 Start = XboxAddressRanges[index].Start;
int Size = XboxAddressRanges[index].Size;
while (Size > 0) {
// To release, dwSize must be zero!
VirtualFree((LPVOID)Start, (SIZE_T)0, MEM_RELEASE);
VirtualFree((LPVOID)Start, (SIZE_T)0, MEM_RELEASE); // To release, dwSize must be zero!
Start += BLOCK_SIZE;
Size -= BLOCK_SIZE;
}
}
bool AllocateMemoryRange(int xart)
bool AllocateMemoryRange(const int index)
{
unsigned __int32 Start = XboxAddressRanges[xart].Start;
int Size = XboxAddressRanges[xart].Size;
unsigned __int32 Start = XboxAddressRanges[index].Start;
int Size = XboxAddressRanges[index].Size;
while (Size > 0) {
int BlockSize = (Size > BLOCK_SIZE) ? BLOCK_SIZE : Size;
@ -300,3 +285,31 @@ bool AllocateMemoryRange(int xart)
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;
}
}

View File

@ -28,7 +28,7 @@
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017 Patrick van Logchem <pvanlogchem@gmail.com>
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
// *
// * All rights reserved
// *
@ -38,59 +38,72 @@
#define KB(x) ((x) * 1024 ) // = 0x00000400
#define MB(x) ((x) * KB(1024)) // = 0x00100000
// TODO : Instead of hard-coding the blocksize, read it from system's allocation granularity.
// In practice though, nearly all will be using 64 Kib.
// 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)))))
// Range Flags
typedef enum {
X = (1 << 0), // Xbox (Retail)
C = (1 << 1), // Chihro (Console)
D = (1 << 2), // DevKit
O = (1 << 3), // Optional (may fail address range reservation)
E = (1 << 4), // PAGE_EXECUTE_READWRITE
R = (1 << 5), // PAGE_READWRITE
N = (1 << 6), // PAGE_NOACCESS
} RangeFlags;
typedef struct {
const char *Name;
unsigned __int32 Start;
int Size;
unsigned int Flags;
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), X | O | E }, // - 0x07FFFFFF (Retail Xbox) Optional (already reserved via virtual_memory_placeholder)
{ "MemLowVirtual", 0x00000000, MB(128), C | D | O | E }, // - 0x07FFFFFF (Chihiro / DevKit)
{ "MemPhysical", 0x80000000, MB( 64), X | E }, // - 0x87FFFFFF (Retail)
{ "MemPhysical", 0x80000000, MB(128), C | D | E }, // - 0x87FFFFFF (Chihiro / DevKit)
{ "DevKitMemory", 0xB0000000, MB(128), D | N }, // - 0xBFFFFFFF Optional (TODO : Check reserved range (might behave like MemTiled) + Flag [O]ptional?
{ "MemPageTable", 0xC0000000, KB(128), X | C | D | R }, // - 0xC001FFFF TODO : MB(4)?
{ "SystemMemory", 0xD0000000, MB(512), X | C | D | O | 0 }, // - 0xEFFFFFFF Optional (TODO : Check reserved range (might behave like MemTiled)
{ "MemTiled", 0xF0000000, MB( 64), X | C | D | O | 0 }, // - 0xF3FFFFFF Optional (even though it can't be reserved, MapViewOfFileEx to this range still works!?)
{ "DeviceNV2A_a", 0xFD000000, MB( 7), X | C | D | N }, // - 0xFD6FFFFF (GPU)
{ "MemNV2APRAMIN", 0xFD700000, MB( 1), X | C | D | R }, // - 0xFD7FFFFF
{ "DeviceNV2A_b", 0xFD800000, MB( 8), X | C | D | N }, // - 0xFDFFFFFF (GPU)
{ "DeviceAPU", 0xFE800000, KB(512), X | C | D | N }, // - 0xFE87FFFF
{ "DeviceAC97", 0xFEC00000, KB( 4), X | C | D | N }, // - 0xFEC00FFF (ACI)
{ "DeviceUSB0", 0xFED00000, KB( 4), X | C | D | N }, // - 0xFED00FFF
{ "DeviceUSB1", 0xFED08000, KB( 4), X | C | D | N }, // - 0xFED08FFF Optional (won't be emulated for a long while?)
{ "DeviceNVNet", 0xFEF00000, KB( 1), X | C | D | N }, // - 0xFEF003FF
{ "DeviceFlash_a", 0xFF000000, MB( 4), X | C | D | N }, // - 0xFF3FFFFF (Flash mirror 1)
{ "DeviceFlash_b", 0xFF400000, MB( 4), X | C | D | N }, // - 0xFF7FFFFF (Flash mirror 2)
{ "DeviceFlash_c", 0xFF800000, MB( 4), X | C | D | N }, // - 0xFFBFFFFF (Flash mirror 3)
{ "DeviceFlash_d", 0xFFC00000, MB( 4), X | C | D | O | N }, // - 0xFFFFFFFF (Flash mirror 4) Optional (will probably fail reservation, which is acceptable - the 3 other mirrors work just fine
{ "DeviceMCPX", 0xFFFFFE00, 512 , X | D | O | N }, // - 0xFFFFFFFF (not Chihiro, Xbox - if enabled) Optional (can safely be ignored)
{ "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 flags);
extern bool VerifyAddressRanges();
extern void UnreserveMemoryRange(XboxAddressRange& xart);
extern bool AllocateMemoryRange(XboxAddressRange& xart);
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);

View File

@ -1063,7 +1063,7 @@ void CxbxKrnlMain(int argc, char* argv[])
#endif
#ifdef CXBX_LOADER
if (!VerifyAddressRanges()) {
if (!VerifyAddressRanges(SYSTEM_XBOX)) {
CxbxPopupMessage("Cxbx-Reloaded hasn't got access to all required address ranges");
return; // TODO : Halt(0);
}