Allow XBE Section preload to fail
Since all sections in all Xbes are usually marked as preload, the Xbox kernel attempts to load them all regardless. In some titles (for example, Lego Star Wars DVD demo) the whole XBE is too large to fit in RAM, and it is *expected* for the preload to fail. Previously, when hit with this scenario, Cxbx-R would hard crash. Now it mirrors hardware behavior and gracefully continues, skipping the failed Xbe section. Q: Why is this the case? A: It's possible (and proven) that with titles such as the Lego Star Wars DVD Demo, *all* game data is contained within the XBE file, rather than on-disc as raw files. Naturally, these are too big to fit into the Xbox RAM, so certain large sections fail to allocate, and are skipped entirely by the Xbox Kernel. The game then reads data from these sections by *not* loading them to memory, but parsing the section *headers* to do raw file-io and read the Xbe file as a binary blob, parsing the virtual filesystem. This change allows Lego Star Wars DVD Demo (and other large Xbe titles) to boot. Lego Star Wars DVD Demo doesn't work yet, however, as it attempts a dashboard update and fails, but it no longer crashes the whole emulator.
This commit is contained in:
parent
2e5b9562e0
commit
4dbeab62ac
|
@ -75,11 +75,6 @@ XBSYSAPI EXPORTNUM(327) xboxkrnl::NTSTATUS NTAPI xboxkrnl::XeLoadSection
|
|||
if (sectionData != nullptr) {
|
||||
// If the reference count was zero, load the section
|
||||
if (Section->SectionReferenceCount == 0) {
|
||||
// Clear the memory the section requires
|
||||
memset(Section->VirtualAddress, 0, Section->VirtualSize);
|
||||
// Copy the section data
|
||||
memcpy(Section->VirtualAddress, sectionData, Section->FileSize);
|
||||
|
||||
// REMARK: Some titles have sections less than PAGE_SIZE, which will cause an overlap with the next section
|
||||
// since both will have the same aligned starting address.
|
||||
// Test case: Dead or Alive 3, section XGRPH has a size of 764 bytes
|
||||
|
@ -89,7 +84,15 @@ XBSYSAPI EXPORTNUM(327) xboxkrnl::NTSTATUS NTAPI xboxkrnl::XeLoadSection
|
|||
VAddr BaseAddress = (VAddr)Section->VirtualAddress;
|
||||
size_t SectionSize = (VAddr)Section->VirtualSize;
|
||||
|
||||
ret = g_VMManager.XbAllocateVirtualMemory(&BaseAddress, 0, &SectionSize, XBOX_MEM_COMMIT, XBOX_PAGE_EXECUTE_READWRITE);
|
||||
ret = g_VMManager.XbAllocateVirtualMemory(&BaseAddress, 0, &SectionSize, XBOX_MEM_COMMIT, XBOX_PAGE_EXECUTE_READWRITE);
|
||||
if (ret != STATUS_SUCCESS) {
|
||||
RETURN(ret);
|
||||
}
|
||||
|
||||
// Clear the memory the section requires
|
||||
memset(Section->VirtualAddress, 0, Section->VirtualSize);
|
||||
// Copy the section data
|
||||
memcpy(Section->VirtualAddress, sectionData, Section->FileSize);
|
||||
|
||||
// Increment the head/tail page reference counters
|
||||
(*Section->HeadReferenceCount)++;
|
||||
|
|
|
@ -1231,7 +1231,7 @@ void CxbxKrnlMain(int argc, char* argv[])
|
|||
if ((sectionHeaders[i].Flags & XBEIMAGE_SECTION_PRELOAD) != 0) {
|
||||
NTSTATUS result = xboxkrnl::XeLoadSection(§ionHeaders[i]);
|
||||
if (FAILED(result)) {
|
||||
CxbxKrnlCleanupEx(LOG_PREFIX_INIT, "Failed to preload XBE section: %s", CxbxKrnl_Xbe->m_szSectionName[i]);
|
||||
EmuLogEx(LOG_PREFIX_INIT, LOG_LEVEL::WARNING, "Failed to preload XBE section: %s", CxbxKrnl_Xbe->m_szSectionName[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1744,6 +1744,19 @@ xboxkrnl::NTSTATUS VMManager::XbAllocateVirtualMemory(VAddr* addr, ULONG ZeroBit
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
// Attempt to commit the requested range with VirtualAlloc *before* setting up and reserving the PT
|
||||
// This allows an early-out in a failure scenario (Test Case: Star Wars Battlefront DVD Demo: LA-018 v1.02)
|
||||
if (AlignedCapturedBase >= XBE_MAX_VA)
|
||||
{
|
||||
if (!VirtualAlloc((void*)AlignedCapturedBase, AlignedCapturedSize, MEM_COMMIT,
|
||||
(ConvertXboxToWinProtection(PatchXboxPermissions(Protect))) & ~(PAGE_WRITECOMBINE | PAGE_NOCACHE)))
|
||||
{
|
||||
DBG_PRINTF("%s: VirtualAlloc failed to commit the memory! The error was %d\n", __func__, GetLastError());
|
||||
status = STATUS_NO_MEMORY;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have to construct the PT's for this allocation
|
||||
|
||||
if (!AllocatePT(AlignedCapturedSize, AlignedCapturedBase))
|
||||
|
@ -1769,18 +1782,6 @@ xboxkrnl::NTSTATUS VMManager::XbAllocateVirtualMemory(VAddr* addr, ULONG ZeroBit
|
|||
PointerPte++;
|
||||
}
|
||||
|
||||
// Actually commit the requested range but don't if it's inside the placeholder or we are committing an xbe section so that
|
||||
// XeLoadSection works as expected
|
||||
|
||||
if (AlignedCapturedBase >= XBE_MAX_VA)
|
||||
{
|
||||
if (!VirtualAlloc((void*)AlignedCapturedBase, AlignedCapturedSize, MEM_COMMIT,
|
||||
(ConvertXboxToWinProtection(PatchXboxPermissions(Protect))) & ~(PAGE_WRITECOMBINE | PAGE_NOCACHE)))
|
||||
{
|
||||
DBG_PRINTF("%s: VirtualAlloc failed to commit the memory! The error was %d\n", __func__, GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
// Because VirtualAlloc always zeros the memory for us, XBOX_MEM_NOZERO is still unsupported
|
||||
|
||||
if (AllocationType & XBOX_MEM_NOZERO) { DBG_PRINTF("XBOX_MEM_NOZERO flag is not supported!\n"); }
|
||||
|
|
Loading…
Reference in New Issue