938 lines
30 KiB
C
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);
|
|
}
|
|
}
|