2020-09-30 17:17:25 +02:00

938 lines
30 KiB
C

/*++
Copyright (c) 1999-2002 Microsoft Corporation
Module Name:
init.c
Abstract:
Initialization code for the win32 api equivalents in kernel mode for xbox
--*/
#include "dllp.h"
#include <xboxverp.h>
#define DASHBOARD_TITLE_ID 0xFFFE0000
#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
#include "xmeta.h"
COBJECT_STRING DDrive = CONSTANT_OBJECT_STRING( OTEXT("\\??\\D:") );
COBJECT_STRING CdDevice = CONSTANT_OBJECT_STRING( OTEXT("\\Device\\CdRom0") );
COBJECT_STRING MainVol = CONSTANT_OBJECT_STRING( OTEXT("\\Device\\Harddisk0\\partition1\\") );
COBJECT_STRING TDrive = CONSTANT_OBJECT_STRING( OTEXT("\\??\\T:") );
COBJECT_STRING TitleData = CONSTANT_OBJECT_STRING( OTEXT("\\Device\\Harddisk0\\partition1\\TDATA") );
COBJECT_STRING UDrive = CONSTANT_OBJECT_STRING( OTEXT("\\??\\U:") );
COBJECT_STRING UserData = CONSTANT_OBJECT_STRING( OTEXT("\\Device\\Harddisk0\\partition1\\UDATA") );
NTSTATUS
XapiValidateDiskPartition(
POBJECT_STRING PartitionName
)
{
return XapiValidateDiskPartitionEx(PartitionName, 16384);
}
NTSTATUS
XapiValidateDiskPartitionEx(
POBJECT_STRING PartitionName,
ULONG BytesPerCluster
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
IO_STATUS_BLOCK IoStatusBlock;
FILE_FS_SIZE_INFORMATION SizeInfo;
InitializeObjectAttributes(
&Obja,
PartitionName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Open the partition
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
);
if (NT_SUCCESS(Status))
{
//
// Determine the size parameters of the volume.
//
Status = NtQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
&SizeInfo,
sizeof(SizeInfo),
FileFsSizeInformation
);
NtClose(Handle);
if (NT_SUCCESS(Status))
{
if (SizeInfo.BytesPerSector * SizeInfo.SectorsPerAllocationUnit !=
BytesPerCluster)
{
Status = STATUS_UNRECOGNIZED_VOLUME;
}
}
}
return Status;
}
NTSTATUS
XapiCopySectionToFile(
HANDLE SectionHandle,
PSTR pszPathBuffer,
UINT cchPathBuffer,
PCSTR pcszFileName
)
{
OBJECT_STRING MetaFilePathString;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
HANDLE MetaHandle;
int nPathLen;
ASSERT((INVALID_HANDLE_VALUE != SectionHandle) && pszPathBuffer && pcszFileName);
nPathLen = ocslen(pszPathBuffer);
lstrcpynO(&(pszPathBuffer[nPathLen]),
pcszFileName,
cchPathBuffer - nPathLen);
RtlInitObjectString(&MetaFilePathString, pszPathBuffer);
InitializeObjectAttributes(
&Obja,
&MetaFilePathString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateFile(&MetaHandle,
SYNCHRONIZE | GENERIC_WRITE,
&Obja,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_SYSTEM,
FILE_SHARE_READ,
FILE_OPEN_IF,
FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT
);
pszPathBuffer[nPathLen] = OBJECT_NULL;
if (NT_SUCCESS(Status))
{
FILE_NETWORK_OPEN_INFORMATION NetworkInfo;
Status = NtQueryInformationFile(
MetaHandle,
&IoStatusBlock,
&NetworkInfo,
sizeof(NetworkInfo),
FileNetworkOpenInformation
);
if (NT_SUCCESS(Status))
{
//
// Only write if this is an empty file (first creation or first time
// after an invalid, failed creation)
//
if (0 == NetworkInfo.EndOfFile.QuadPart)
{
PBYTE pbSection;
//
// Attempt to load the title info section
//
pbSection = XLoadSectionByHandle(SectionHandle);
if (pbSection)
{
Status = NtWriteFile(MetaHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
pbSection,
XGetSectionSize(SectionHandle),
NULL
);
if (!NT_SUCCESS(Status))
{
XDBGWRN("XAPI", "XapiCopySectionToFile() failed to write to file");
}
//
// Unload the title info section (we're done with it)
//
XFreeSectionByHandle(SectionHandle);
}
}
}
else
{
XDBGERR("XAPI", "XapiCopySectionToFile() failed to get meta file size");
}
NtClose(MetaHandle);
}
else if (STATUS_OBJECT_NAME_COLLISION == Status)
{
//
// If the meta data image file already exists, we should continue
// as if everything is fine (no need to rewrite this data)
//
Status = STATUS_SUCCESS;
}
return Status;
}
NTSTATUS
XapiMapLetterToDirectory(
PCOBJECT_STRING pcDriveString,
PCOBJECT_STRING pcPathString,
PCOSTR pcszTitleId,
BOOL fCreateDirectory,
LPCWSTR pcszTitleName,
BOOL fUpdateTimestamp
)
{
NTSTATUS Status;
OCHAR szPathTemp[MAX_PATH];
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_STRING PerTitlePathString;
HANDLE DirHandle;
ASSERT(pcDriveString && pcPathString && pcszTitleId);
InitializeObjectAttributes(
&Obja,
(POBJECT_STRING) pcPathString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// The parent of the subirectory may not already exist
// so we open it first with 'FILE_OPEN_IF' to create it,
// just in case. This mainly occurs when running
// recovery.
//
Status = NtCreateFile(
&DirHandle,
FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
);
if (NT_SUCCESS(Status))
{
NtClose(DirHandle);
}
else if (STATUS_NOT_A_DIRECTORY == Status)
{
//
// XMountAlternateTitle when called on an MU passes a volume (not the
// volume's root directory) for pcDriveString. So the above call will
// fail with STATUS_NOT_A_DIRECTORY. This is OK though, so we change
// to success and continue. Note that if we remove FILE_DIRECTORY_FILE
// from the above NtCreateFile, then recovery creates a file named UDATA
// instead of a directory and promptly crashes.
//
Status = STATUS_SUCCESS;
}
else
{
XDBGWRN("XAPI",
"XapiMapLetterToDirectory(): NtCreateFile() \"%Z\" failed with 0x%08x",
pcPathString,
Status);
}
if (NT_SUCCESS(Status))
{
ASSERT(ocslen(pcszTitleId) < CCHMAX_HEX_DWORD);
ASSERT(pcPathString->Length < (sizeof(szPathTemp) - (CCHMAX_HEX_DWORD * sizeof(OCHAR))));
ocscpy(szPathTemp, pcPathString->Buffer);
//
// Usually, pcDriveString usually does not have a '\\' on the end, the exception
// is on mounting MU's. So here we check for '\\' and only append if necessary.
//
if(szPathTemp[(pcPathString->Length / sizeof(OCHAR))-1] != OTEXT('\\'))
{
szPathTemp[pcPathString->Length / sizeof(OCHAR)] = OTEXT('\\');
} else
{
pcPathString->Length--;
}
ocscpy(&(szPathTemp[(pcPathString->Length + sizeof(OCHAR)) / sizeof(OCHAR)]), pcszTitleId);
RtlInitObjectString(&PerTitlePathString, szPathTemp);
InitializeObjectAttributes(
&Obja,
&PerTitlePathString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateFile(
&DirHandle,
FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_GENERIC_WRITE,
&Obja,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
fCreateDirectory ? FILE_OPEN_IF : FILE_OPEN,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
);
if (NT_SUCCESS(Status))
{
if (fUpdateTimestamp)
{
FILE_BASIC_INFORMATION BasicInfo;
//
// Zero all the time values we can set.
//
RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
//
// Set the last write times
//
KeQuerySystemTime(&BasicInfo.LastWriteTime);
NtSetInformationFile(
DirHandle,
&IoStatusBlock,
&BasicInfo,
sizeof(BasicInfo),
FileBasicInformation
);
}
//
// Only attempt to write meta data if non-null titlename and pubname strings were passed in
// (these are not passed in if we're mounting another title's drive)
//
if (pcszTitleName)
{
HANDLE TitleInfoSection;
HANDLE TitleImageSection;
HANDLE SaveImageSection;
TitleInfoSection = XGetSectionHandle("$$XTINFO");
TitleImageSection = XGetSectionHandle("$$XTIMAGE");
SaveImageSection = XGetSectionHandle("$$XSIMAGE");
if ((INVALID_HANDLE_VALUE != TitleInfoSection) ||
(L'\0' != *pcszTitleName))
{
//
// Create TITLEMETA.XBX file underneath the save game directory and
// write metadata information there
//
OBJECT_STRING MetaFilePathString;
HANDLE MetaHandle;
int nPathLen = ocslen(szPathTemp);
lstrcpynO(&(szPathTemp[nPathLen]),
g_cszTitleMetaFileName,
ARRAYSIZE(szPathTemp) - nPathLen);
RtlInitObjectString(&MetaFilePathString, szPathTemp);
InitializeObjectAttributes(
&Obja,
&MetaFilePathString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateFile(&MetaHandle,
SYNCHRONIZE | GENERIC_WRITE,
&Obja,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_SYSTEM,
FILE_SHARE_READ,
FILE_OPEN_IF,
FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT
);
szPathTemp[nPathLen] = OBJECT_NULL;
if (NT_SUCCESS(Status))
{
FILE_NETWORK_OPEN_INFORMATION NetworkInfo;
Status = NtQueryInformationFile(
MetaHandle,
&IoStatusBlock,
&NetworkInfo,
sizeof(NetworkInfo),
FileNetworkOpenInformation
);
if (NT_SUCCESS(Status))
{
//
// Only write if this is an empty file (first creation or first time
// after an invalid, failed creation)
//
if (0 == NetworkInfo.EndOfFile.QuadPart)
{
PVOID pvTitleInfo = NULL;
//
// Attempt to load the title info section
//
if (INVALID_HANDLE_VALUE != TitleInfoSection)
{
pvTitleInfo = XLoadSectionByHandle(TitleInfoSection);
}
if (pvTitleInfo)
{
//
// Write TITLEMETA.XBX as a copy of the title info section
//
Status = NtWriteFile(MetaHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
pvTitleInfo,
XGetSectionSize(TitleInfoSection),
NULL
);
if (!NT_SUCCESS(Status))
{
XDBGWRN("XAPI", "XapiMapLetterToDirectory() failed to write title info file");
}
XFreeSectionByHandle(TitleInfoSection);
}
else
{
//
// Write TITLEMETA.XBX with the title name value from the cert
//
//
// szBuffer size is: 1 signature WCHAR plus one line of metadata
//
WCHAR szBuffer[1 + MAX_METADATA_LINE];
DWORD dwSize;
dwSize = _snwprintf(szBuffer,
ARRAYSIZE(szBuffer),
L"%lc%ls%lc%ls%ls",
g_chUnicodeSignature,
g_cszTitleNameTag,
g_chEqual,
pcszTitleName,
g_cszCRLF);
dwSize *= sizeof(WCHAR);
Status = NtWriteFile(MetaHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
szBuffer,
dwSize,
NULL
);
if (!NT_SUCCESS(Status))
{
XDBGWRN("XAPI", "XapiMapLetterToDirectory() failed to write title info file");
}
}
}
}
else
{
XDBGERR("XAPI", "XapiMapLetterToDirectory() failed to get meta file size");
}
NtClose(MetaHandle);
}
else if (STATUS_OBJECT_NAME_COLLISION == Status)
{
//
// If the meta data file already exists, we should continue
// as if everything is fine (no need to rewrite this data)
//
Status = STATUS_SUCCESS;
}
}
if (NT_SUCCESS(Status) && (INVALID_HANDLE_VALUE != TitleImageSection))
{
Status = XapiCopySectionToFile(TitleImageSection,
szPathTemp,
ARRAYSIZE(szPathTemp),
g_cszTitleImageFileName);
}
if (NT_SUCCESS(Status) && (INVALID_HANDLE_VALUE != SaveImageSection))
{
Status = XapiCopySectionToFile(SaveImageSection,
szPathTemp,
ARRAYSIZE(szPathTemp),
g_cszSaveImageFileName);
}
}
NtClose(DirHandle);
}
else if (fCreateDirectory)
{
XDBGWRN("XAPI",
"XapiMapLetterToDirectory(): NtCreateFile() \"%s\" failed with 0x%08x",
szPathTemp,
Status);
}
}
if (NT_SUCCESS(Status))
{
Status = IoCreateSymbolicLink((POBJECT_STRING) pcDriveString, &PerTitlePathString);
if (!NT_SUCCESS(Status))
{
XDBGERR("XAPI",
"XapiMapLetterToDirectory(): IoCreateSymbolicLink() failed \"%Z\"->\"%Z\"",
pcDriveString,
pcPathString);
}
}
return Status;
}
NTSTATUS
XapiSetupPerTitleDriveLetters(
DWORD dwTitleId,
LPCWSTR pcszTitleName
)
{
NTSTATUS Status;
OCHAR szTitleId[CCHMAX_HEX_DWORD];
DwordToStringO(dwTitleId, szTitleId);
Status = XapiMapLetterToDirectory(&TDrive,
&TitleData,
szTitleId,
TRUE,
NULL,
FALSE);
if (NT_SUCCESS(Status))
{
Status = XapiMapLetterToDirectory(&UDrive,
&UserData,
szTitleId,
TRUE,
pcszTitleName,
FALSE);
}
return Status;
}
VOID
XapiBootToDash(
DWORD dwReason,
DWORD dwParameter1,
DWORD dwParameter2
)
{
if (DASHBOARD_TITLE_ID != XeImageHeader()->Certificate->TitleID)
{
LD_LAUNCH_DASHBOARD LaunchDash;
ZeroMemory(&LaunchDash, sizeof(LD_LAUNCH_DASHBOARD));
LaunchDash.dwReason = dwReason;
LaunchDash.dwContext = 0;
LaunchDash.dwParameter1 = dwParameter1;
LaunchDash.dwParameter2 = dwParameter2;
XLaunchNewImage(NULL, (PLAUNCH_DATA) &LaunchDash);
}
else
{
//
// Display Universal Error Message
//
HalReturnToFirmware(HalFatalErrorRebootRoutine);
}
}
//
// Macros to swap the byte order of a USHORT or ULONG at compile time.
//
#define XapiConstantUshortByteSwap(ushort) \
((((USHORT)ushort) >> 8) + ((((USHORT)ushort) & 0x00FF) << 8))
#define XapiConstantUlongByteSwap(ulong) \
((((ULONG)ulong) >> 24) + ((((ULONG)ulong) & 0x00FF0000) >> 8) + \
((((ULONG)ulong) & 0x0000FF00) << 8) + ((((ULONG)ulong) & 0x000000FF) << 24))
NTSTATUS
XapiVerifyMediaInDrive(
VOID
)
/*++
Routine Description:
Verifies that the DVD drive has in fact authenticated X2 media.
Arguments:
None.
Return Value:
None.
--*/
{
NTSTATUS status;
SCSI_PASS_THROUGH_DIRECT PassThrough;
PCDB Cdb = (PCDB)&PassThrough.Cdb;
DVDX2_AUTHENTICATION Authentication;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
IO_STATUS_BLOCK IoStatusBlock;
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
InitializeObjectAttributes(
&Obja,
(POBJECT_STRING) &CdDevice,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Open the CD/DVD device
//
status = NtOpenFile(
&Handle,
(ACCESS_MASK) GENERIC_READ | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT
);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Prepare the SCSI pass through structure.
//
RtlZeroMemory(&PassThrough, sizeof(SCSI_PASS_THROUGH_DIRECT));
PassThrough.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
//
// Request the authentication page from the DVD-X2 drive.
//
PassThrough.DataIn = SCSI_IOCTL_DATA_IN;
PassThrough.DataBuffer = &Authentication;
PassThrough.DataTransferLength = sizeof(DVDX2_AUTHENTICATION);
RtlZeroMemory(Cdb, sizeof(CDB));
Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
Cdb->MODE_SENSE10.PageCode = DVDX2_MODE_PAGE_AUTHENTICATION;
*((PUSHORT)&Cdb->MODE_SENSE10.AllocationLength) =
(USHORT)XapiConstantUshortByteSwap(sizeof(DVDX2_AUTHENTICATION));
RtlZeroMemory(&Authentication, sizeof(DVDX2_AUTHENTICATION));
status = NtDeviceIoControlFile(Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
&PassThrough,
sizeof(SCSI_PASS_THROUGH_DIRECT),
NULL,
0);
NtClose(Handle);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Check if the DVD-X2 drive thinks that this is a valid CDF header.
//
if (Authentication.AuthenticationPage.CDFValid != DVDX2_CDF_VALID) {
return STATUS_UNRECOGNIZED_MEDIA;
}
//
// Check if the DVD-X2 drive already thinks that we're authenticated.
//
if ((Authentication.AuthenticationPage.PartitionArea != 0) &&
(Authentication.AuthenticationPage.Authentication != 0)) {
return STATUS_SUCCESS;
}
//
// The DVD-X2 drive does not think that we're authenticated.
//
return STATUS_UNSUCCESSFUL;
}
VOID
XapiInitProcess(
VOID
)
/*++
Routine Description:
Initializes the Xapi process, loads the title and starts its first thread.
Arguments:
None.
Return Value:
None.
--*/
{
HANDLE ThreadHandle;
/* ULONG_PTR EntryPoint; */
ULONG ProcessHeapFlags;
RTL_HEAP_PARAMETERS HeapParameters;
HANDLE hthread;
USHORT CharIndex;
DWORD dwReason = XLD_LAUNCH_DASHBOARD_MAIN_MENU;
DWORD dwParameter1;
DWORD dwParameter2 = 0;
NTSTATUS status;
// Initialize the auto-power-down feature.
XapiInitAutoPowerDown();
RtlZeroMemory( &HeapParameters, sizeof( HeapParameters ) );
ProcessHeapFlags = HEAP_GROWABLE | HEAP_CLASS_0;
HeapParameters.Length = sizeof( HeapParameters );
// Note: there are some more parameters in the image that normal Win32 apps use to
// modify ProcessHeapFlags and HeapParameters. Here, we just use the heap reserve/commit
// sizes specified
XapiProcessHeap = RtlCreateHeap(ProcessHeapFlags,
NULL,
XeImageHeader()->SizeOfHeapReserve,
XeImageHeader()->SizeOfHeapCommit,
NULL,
&HeapParameters);
if (XapiProcessHeap == NULL)
{
dwReason = XLD_LAUNCH_DASHBOARD_ERROR;
dwParameter1 = XLD_ERROR_INVALID_XBE;
goto handle_error;
}
if ((XeImageHeader()->Certificate->AllowedMediaTypes & XBEIMAGE_MEDIA_TYPE_MEDIA_MASK)
== XBEIMAGE_MEDIA_TYPE_DVD_X2)
{
//
// This title is only allowed to run on X2 media - double check that the drive
// has mounted X2 media:
//
if (!NT_SUCCESS(XapiVerifyMediaInDrive()))
{
//
// Don't display a dash error message - we want to avoid showing an
// inapplicable errorduring race conditions where valid media was ejected
// while this code was verifying the media
//
XapiBootToDash(XLD_LAUNCH_DASHBOARD_MAIN_MENU, 0, 0);
return;
}
}
if (!(XeImageHeader()->InitFlags & XINIT_NO_SETUP_HARD_DISK))
{
// Get the hard disk ready
if (!NT_SUCCESS(XapiValidateDiskPartition((POBJECT_STRING) &MainVol)))
{
dwReason = XLD_LAUNCH_DASHBOARD_ERROR;
dwParameter1 = XLD_ERROR_INVALID_HARD_DISK;
goto handle_error;
}
}
// Give the DVD/CD drive a drive letter
if (!NT_SUCCESS(status = IoCreateSymbolicLink((POBJECT_STRING) &DDrive,
(POBJECT_STRING) &CdDevice)))
{
XDBGWRN("XAPI",
"The D: drive is not assigned to the CD/DVD device - error 0x%08x",
status);
//
// Devkits will tend to already have the D: drive assigned, so we'll ignore
// this error, but reboot to the dash in all other cases...
//
if (STATUS_OBJECT_NAME_COLLISION != status)
{
dwReason = XLD_LAUNCH_DASHBOARD_ERROR;
dwParameter1 = XLD_ERROR_INVALID_XBE;
goto handle_error;
}
}
if ((!(XeImageHeader()->InitFlags & XINIT_NO_SETUP_HARD_DISK)) &&
(!(XeImageHeader()->InitFlags & XINIT_DONT_MODIFY_HARD_DISK)))
{
// After we've initialized everything, start the process
if (!NT_SUCCESS(status = XapiSetupPerTitleDriveLetters(
XeImageHeader()->Certificate->TitleID,
XeImageHeader()->Certificate->TitleName)))
{
XDBGWRN("XAPI", "Could not set up per-title drive letters");
if (STATUS_DISK_FULL == status)
{
dwReason = XLD_LAUNCH_DASHBOARD_MEMORY;
dwParameter1 = (DWORD) 'T'; // drive letter
dwParameter2 = 16; // blocks needed
}
else
{
dwReason = XLD_LAUNCH_DASHBOARD_ERROR;
dwParameter1 = XLD_ERROR_INVALID_HARD_DISK;
}
goto handle_error;
}
}
if ((!(XeImageHeader()->InitFlags & XINIT_NO_SETUP_HARD_DISK)) &&
(XeImageHeader()->InitFlags & XINIT_MOUNT_UTILITY_DRIVE))
{
if (!XMountUtilityDrive(XeImageHeader()->InitFlags & XINIT_FORMAT_UTILITY_DRIVE))
{
XapiBootToDash(XLD_LAUNCH_DASHBOARD_ERROR,
XLD_ERROR_INVALID_HARD_DISK,
0);
}
}
//
// Check to see if parental control settings should prevent this title from
// running on this box
//
if (XeImageHeader()->Certificate->GameRatings < XGetParentalControlSetting())
{
XDBGWRN("XAPI", "The box's parental control setting prohibits this title from starting");
XDBGWRN("XAPI", "Go to the Xbox dashboard to change the box's parental control setting");
dwReason = XLD_LAUNCH_DASHBOARD_ERROR;
dwParameter1 = XLD_ERROR_XBE_PARENTAL_CONTROL;
dwParameter2 = XeImageHeader()->Certificate->GameRatings;
goto handle_error;
}
XDBGTRC("XAPI", "InitProcess: SizeOfStack=%d", XeImageHeader()->SizeOfStackCommit);
handle_error:
if (XLD_LAUNCH_DASHBOARD_MAIN_MENU != dwReason)
{
XapiBootToDash(dwReason,
dwParameter1,
dwParameter2);
}
}