Dashboard fatal error + fix issue #878

This commit is contained in:
ergo720 2018-01-28 10:06:11 +01:00
parent 81b1d75b4a
commit 753d9d89c2
11 changed files with 151 additions and 97 deletions

View File

@ -1271,6 +1271,18 @@ typedef struct _LAUNCH_DATA_PAGE
}
LAUNCH_DATA_PAGE, *PLAUNCH_DATA_PAGE;
// ******************************************************************
// * DASH_LAUNCH_DATA
// ******************************************************************
typedef struct _DASH_LAUNCH_DATA
{
DWORD dwReason;
DWORD dwContext;
DWORD dwParameter1;
DWORD dwParameter2;
BYTE Reserved[3072 - 16];
} DASH_LAUNCH_DATA, *PDASH_LAUNCH_DATA;
// ******************************************************************
// * DISPATCHER_HEADER
// ******************************************************************

Binary file not shown.

View File

@ -33,15 +33,28 @@
// * All rights reserved
// *
// ******************************************************************
#define _XBOXKRNL_DEFEXTRN_
// prevent name collisions
namespace xboxkrnl
{
#include <xboxkrnl/xboxkrnl.h>
};
#include "Xbe.h"
#include "CxbxUtil.h" // For RoundUp
#include <experimental/filesystem> // filesystem related functions available on C++ 17
#include <locale> // For ctime
#include "devices\LED.h" // For LED::Sequence
#include "CxbxKrnl/CxbxKrnl.h" // For CxbxKrnlPrintUEM
#include "CxbxKrnl/EmuShared.h" // Include this to avoid including EmuXapi.h and EmuD3D8.h
namespace fs = std::experimental::filesystem;
#define PAGE_SIZE 0x1000
// construct via Xbe file
Xbe::Xbe(const char *x_szFilename)
Xbe::Xbe(const char *x_szFilename, bool bFromGUI)
{
char szBuffer[MAX_PATH];
@ -54,8 +67,38 @@ Xbe::Xbe(const char *x_szFilename)
// verify Xbe file was opened successfully
if(XbeFile == 0)
{
SetFatalError("Could not open Xbe file.");
return;
using namespace fs; // limit its scope inside here
std::string XbeName = path(x_szFilename).filename().string(); // recover the xbe name
// NOTE: the check for the existence of the child window is necessary because the user could have previously loaded the dashboard,
// removed/changed the path and attempt to load it again from the recent list, which will crash CxbxInitWindow below
// Note that GetHwnd(), CxbxKrnl_hEmuParent and HalReturnToFirmware are all not suitable here for various reasons
if (XbeName.compare(std::string("xboxdash.xbe")) == 0 && !bFromGUI)
{
// The dashboard could not be found on partition2. This is a fatal error on the Xbox so we display the UEM. The
// error code is different if we have a launch data page
XTL::CxbxInitWindow(false);
ULONG FatalErrorCode = FATAL_ERROR_XBE_DASH_GENERIC;
if (xboxkrnl::LaunchDataPage && xboxkrnl::LaunchDataPage->Header.dwLaunchDataType == LDT_FROM_DASHBOARD)
{
xboxkrnl::PDASH_LAUNCH_DATA pLaunchDashboard = (xboxkrnl::PDASH_LAUNCH_DATA)&(xboxkrnl::LaunchDataPage->LaunchData[0]);
FatalErrorCode += pLaunchDashboard->dwReason;
}
SetLEDSequence(0xE1); // green, red, red, red
CxbxKrnlPrintUEM(FatalErrorCode); // won't return
// TODO: FATAL_ERROR_XBE_DASH_X2_PASS (requires DVD drive authentication emulation...)
}
else
{
// Report which xbe could not be found
SetFatalError(std::string("Could not open the Xbe file ") + XbeName);
return;
}
}
printf("OK\n");

View File

@ -51,7 +51,7 @@ class Xbe : public Error
{
public:
// construct via Xbe file
Xbe(const char *x_szFilename);
Xbe(const char *x_szFilename, bool bFromGUI);
// deconstructor
~Xbe();

View File

@ -14,6 +14,7 @@
#define IDD_ABOUT 119
#define IDR_CONTRIBUTORS 121
#define IDR_COPYING 122
#define IDS_UEM 123
#define IDC_SET_X 1000
#define IDC_SET_Y 1001
#define IDC_SET_A 1002

View File

@ -1786,7 +1786,7 @@ void WndMain::OpenXbe(const char *x_filename)
strcpy(m_XbeFilename, x_filename);
m_Xbe = new Xbe(m_XbeFilename);
m_Xbe = new Xbe(m_XbeFilename, true);
if(m_Xbe->HasError())
{

View File

@ -571,6 +571,9 @@ void CxbxKrnlMain(int argc, char* argv[])
}
}
// We must save this handle now to keep the child window working in the case we need to display the UEM
CxbxKrnl_hEmuParent = IsWindow(hWnd) ? hWnd : NULL;
g_CurrentProcessHandle = GetCurrentProcess(); // OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
// Write a header to the log
@ -600,6 +603,7 @@ void CxbxKrnlMain(int argc, char* argv[])
g_IsWine = true;
}
}
// Now we got the arguments, start by initializing the Xbox memory map :
// PrepareXBoxMemoryMap()
{
@ -670,7 +674,7 @@ void CxbxKrnlMain(int argc, char* argv[])
{
// Load Xbe (this one will reside above WinMain's virtual_memory_placeholder)
g_EmuShared->SetXbePath(xbePath.c_str());
CxbxKrnl_Xbe = new Xbe(xbePath.c_str()); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock()
CxbxKrnl_Xbe = new Xbe(xbePath.c_str(), false); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock()
if (CxbxKrnl_Xbe->HasFatalError()) {
CxbxKrnlCleanup(CxbxKrnl_Xbe->GetError().c_str());
@ -740,7 +744,6 @@ void CxbxKrnlMain(int argc, char* argv[])
EntryPoint ^= XOR_EP_KEY[g_XbeType];
// Launch XBE
CxbxKrnlInit(
hWnd,
XbeTlsData,
XbeTls,
CxbxKrnl_Xbe->m_LibraryVersion,
@ -790,7 +793,6 @@ void LoadXboxKeys(std::string path)
__declspec(noreturn) void CxbxKrnlInit
(
HWND hwndParent,
void *pTLSData,
Xbe::TLS *pTLS,
Xbe::LibraryVersion *pLibraryVersion,
@ -804,7 +806,6 @@ __declspec(noreturn) void CxbxKrnlInit
CxbxKrnl_TLS = pTLS;
CxbxKrnl_TLSData = pTLSData;
CxbxKrnl_XbeHeader = pXbeHeader;
CxbxKrnl_hEmuParent = IsWindow(hwndParent) ? hwndParent : NULL;
CxbxKrnl_DebugMode = DbgMode;
CxbxKrnl_DebugFileName = (char*)szDebugFilename;
@ -837,7 +838,7 @@ __declspec(noreturn) void CxbxKrnlInit
" pXBEHeaderSize : 0x%.08X\n"
" Entry : 0x%.08X\n"
");\n",
GetCurrentThreadId(), hwndParent, pTLSData, pTLS, pLibraryVersion, DbgMode, szDebugFilename, pXbeHeader, dwXbeHeaderSize, Entry);
GetCurrentThreadId(), CxbxKrnl_hEmuParent, pTLSData, pTLS, pLibraryVersion, DbgMode, szDebugFilename, pXbeHeader, dwXbeHeaderSize, Entry);
#else
printf("[0x%X] INIT: Debug Trace Disabled.\n", GetCurrentThreadId());
#endif
@ -1008,7 +1009,7 @@ __declspec(noreturn) void CxbxKrnlInit
// initialize grapchics
DbgPrintf("INIT: Initializing render window.\n");
XTL::CxbxInitWindow(pXbeHeader, dwXbeHeaderSize);
XTL::CxbxInitWindow(true);
// Now process the boot flags to see if there are any special conditions to handle
int BootFlags = 0;
@ -1296,6 +1297,11 @@ void CxbxKrnlPrintUEM(ULONG ErrorCode)
xboxkrnl::XBOX_EEPROM Eeprom;
ULONG ResultSize;
int BootFlags;
g_EmuShared->GetBootFlags(&BootFlags);
BootFlags &= ~BOOT_FATAL_ERROR; // clear the fatal error flag to avoid looping here endlessly
g_EmuShared->SetBootFlags(&BootFlags);
NTSTATUS status = xboxkrnl::ExQueryNonVolatileSetting(xboxkrnl::XC_MAX_ALL, &Type, &Eeprom, sizeof(Eeprom), &ResultSize);
if (status == STATUS_SUCCESS)
@ -1329,11 +1335,6 @@ void CxbxKrnlPrintUEM(ULONG ErrorCode)
g_CxbxFatalErrorCode = ErrorCode;
g_CxbxPrintUEM = true; // print the UEM
int BootFlags;
g_EmuShared->GetBootFlags(&BootFlags);
BootFlags ^= BOOT_FATAL_ERROR; // clear the fatal error flag to avoid looping here endlessly
g_EmuShared->SetBootFlags(&BootFlags);
// Sleep forever to prevent continuing the initialization
Sleep(INFINITE);
}

View File

@ -177,7 +177,7 @@ bool CxbxKrnlVerifyVersion(const char *szVersion);
void CxbxKrnlMain(int argc, char* argv[]);
/*! initialize emulation */
__declspec(noreturn) void CxbxKrnlInit(HWND hwndParent, void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, const char *szDebugFilename, Xbe::Header *XbeHeader, uint32 XbeHeaderSize, void (*Entry)());
__declspec(noreturn) void CxbxKrnlInit(void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, const char *szDebugFilename, Xbe::Header *XbeHeader, uint32 XbeHeaderSize, void (*Entry)());
/*! cleanup emulation */
__declspec(noreturn) void CxbxKrnlCleanup(const char *szErrorMessage, ...);

View File

@ -57,6 +57,7 @@ namespace xboxkrnl
#include "Logging.h"
#include "EmuD3D8Logging.h"
#include "HLEIntercept.h" // for bLLE_GPU
#include "Cxbx\\ResCxbx.h"
#include <assert.h>
#include <process.h>
@ -97,8 +98,6 @@ static XTL::DDCAPS g_DriverCaps = { 0 };
static DWORD g_dwOverlayW = 640; // Cached Overlay Width
static DWORD g_dwOverlayH = 480; // Cached Overlay Height
static DWORD g_dwOverlayP = 640; // Cached Overlay Pitch
static Xbe::Header *g_XbeHeader = NULL; // XbeHeader
static uint32 g_XbeHeaderSize = 0; // XbeHeaderSize
static HBRUSH g_hBgBrush = NULL; // Background Brush
static volatile bool g_bRenderWindowActive = false;
static XBVideo g_XBVideo;
@ -452,18 +451,15 @@ const char *D3DErrorString(HRESULT hResult)
return buffer;
}
VOID XTL::CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize)
VOID XTL::CxbxInitWindow(bool bFullInit)
{
g_EmuShared->GetXBVideo(&g_XBVideo);
if(g_XBVideo.GetFullscreen())
CxbxKrnl_hEmuParent = NULL;
// cache XbeHeader and size of XbeHeader
g_XbeHeader = XbeHeader;
g_XbeHeaderSize = XbeHeaderSize;
// create timing thread
if (bFullInit)
{
DWORD dwThreadId;
@ -499,7 +495,8 @@ VOID XTL::CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize)
// Ported from Dxbx :
// If possible, assign this thread to another core than the one that runs Xbox1 code :
SetThreadAffinityMask(hRenderWindowThread, g_CPUOthers);
if (bFullInit)
SetThreadAffinityMask(hRenderWindowThread, g_CPUOthers);
while(!g_bRenderWindowActive)
SwitchToThread();
@ -510,6 +507,70 @@ VOID XTL::CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize)
SetFocus(g_hEmuWindow);
}
void DrawUEM(HWND hWnd)
{
// Draw the universal error message (UEM)
// See http://xboxdevwiki.net/Fatal_Error
// Only call this from WM_PAINT message!
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
HDC hDC = GetDC(hWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hUEMBmp = CreateCompatibleBitmap(hDC, 640, 480);
HBITMAP hOriUEMBmp = (HBITMAP)SelectObject(hMemDC, hUEMBmp);
int nHeight = -MulDiv(8, GetDeviceCaps(hMemDC, LOGPIXELSY), 72);
HFONT hFont = CreateFont(nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_ROMAN, "Verdana");
HGDIOBJ tmpObj = SelectObject(hMemDC, hFont);
SetBkColor(hMemDC, RGB(0, 0, 0));
SetTextColor(hMemDC, RGB(0, 204, 0));
wchar_t buff[500];
LoadStringW(GetModuleHandle(NULL), IDS_UEM, buff, sizeof(buff) / sizeof(wchar_t));
std::wstring wstr(buff);
// Unfortunately, DrawTextW doesn't support vertical alignemnt, so we have to do the calculation
// ourselves. See here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/abd89aae-16a0-41c6-8db6-b119ea90b42a/win32-drawtext-how-center-in-vertical-with-new-lines-and-tabs?forum=vclanguage
RECT rect = { 0, 0, 640, 480 };
RECT textrect = { 0, 0, 640, 480 };
DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &textrect, DT_CALCRECT);
rect.top = (rect.bottom - textrect.bottom) / 2;
DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &rect, DT_CENTER);
// Draw the Xbox error code
SetTextColor(hMemDC, RGB(255, 255, 255));
std::string err_str(std::to_string(g_CxbxFatalErrorCode));
rect.left = 20;
DrawText(hMemDC, err_str.c_str(), err_str.length(), &rect, DT_LEFT);
GetClientRect(hWnd, &rect);
SetStretchBltMode(hDC, COLORONCOLOR);
StretchBlt(hDC, rect.left, rect.top, rect.right, rect.bottom, hMemDC, 0, 0, 640, 480, SRCCOPY);
SelectObject(hMemDC, hOriUEMBmp);
SelectObject(hDC, tmpObj);
DeleteObject(hUEMBmp);
DeleteObject(hFont);
DeleteObject(hMemDC);
if (hDC != NULL)
ReleaseDC(hWnd, hDC);
EndPaint(hWnd, &ps);
}
inline DWORD GetXboxCommonResourceType(const XTL::X_D3DResource *pXboxResource)
{
// Don't pass in unassigned Xbox resources
@ -1369,75 +1430,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
{
if (g_CxbxPrintUEM)
{
// Draw the universal error message (UEM)
// See http://xboxdevwiki.net/Fatal_Error
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
HDC hDC = GetDC(hWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hUEMBmp = CreateCompatibleBitmap(hDC, 640, 480);
HBITMAP hOriUEMBmp = (HBITMAP)SelectObject(hMemDC, hUEMBmp);
int nHeight = -MulDiv(8, GetDeviceCaps(hMemDC, LOGPIXELSY), 72);
HFONT hFont = CreateFont(nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_ROMAN, "Verdana");
HGDIOBJ tmpObj = SelectObject(hMemDC, hFont);
SetBkColor(hMemDC, RGB(0, 0, 0));
SetTextColor(hMemDC, RGB(0, 204, 0));
std::wstring wstr(
L"Your Xbox requires service.\n\n\
Please call Xbox Customer Support.\n\n\n\
Ihre Xbox muss gewartet werden.\n\n\
Bitte den Xbox-Kundendienst anrufen.\n\n\n\
La consola Xbox requiere asistencia técnica.\n\n\
Llame al servicio de soporte al cliente de la Xbox.\n\n\n\
Xbox ha bisogno di manutenzione.\n\n\
Chiamare l'Assistenza Clienti di Xbox.\n\n\n\
Votre Xbox ne fonctionne pas correctement.\n\n\
Veuillez contacter le Support à la clientèle Xbox.\n\n\n\
\n\n\
Xboxカスタマー ");
// Unfortunately, DrawTextW doesn't support vertical alignemnt, so we have to do the calculation
// ourselves. See here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/abd89aae-16a0-41c6-8db6-b119ea90b42a/win32-drawtext-how-center-in-vertical-with-new-lines-and-tabs?forum=vclanguage
RECT rect = { 0, 0, 640, 480 };
RECT textrect = { 0, 0, 640, 480 };
DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &textrect, DT_CALCRECT);
rect.top = (rect.bottom - textrect.bottom) / 2;
DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &rect, DT_CENTER);
// Draw the Xbox error code
SetTextColor(hMemDC, RGB(255, 255, 255));
std::string err_str(std::to_string(g_CxbxFatalErrorCode));
rect.left = 20;
DrawText(hMemDC, err_str.c_str(), err_str.length(), &rect, DT_LEFT);
GetClientRect(hWnd, &rect);
SetStretchBltMode(hDC, COLORONCOLOR);
StretchBlt(hDC, rect.left, rect.top, rect.right, rect.bottom, hMemDC, 0, 0, 640, 480, SRCCOPY);
SelectObject(hMemDC, hOriUEMBmp);
SelectObject(hDC, tmpObj);
DeleteObject(hUEMBmp);
DeleteObject(hFont);
DeleteObject(hMemDC);
if (hDC != NULL)
ReleaseDC(hWnd, hDC);
EndPaint(hWnd, &ps);
DrawUEM(hWnd);
}
}
break;

View File

@ -43,7 +43,7 @@
#include <ddraw.h>
// initialize render window
extern VOID CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize);
extern VOID CxbxInitWindow(bool bFullInit);
extern VOID CxbxSetPixelContainerHeader
(

View File

@ -507,7 +507,11 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur
g_EmuShared->GetXbePath(szWorkingDirectoy);
snprintf(szArgsBuffer, 4096, "/load \"%s\" %u %d \"%s\"", szWorkingDirectoy, CxbxKrnl_hEmuParent, CxbxKrnl_DebugMode, CxbxKrnl_DebugFileName.c_str());
if ((int)ShellExecute(NULL, "open", szFilePath_CxbxReloaded_Exe, szArgsBuffer, szWorkingDirectoy, SW_SHOWDEFAULT) <= 32)
{
int BootFlags = 0;
g_EmuShared->SetBootFlags(&BootFlags); // clear all boot flags in the case of failure
CxbxKrnlCleanup("Could not reboot");
}
break;
}