Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
13 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. file.c
  5. Abstract:
  6. This module contains kd host machine file I/O support.
  7. Author:
  8. Matt Holle (matth) April-2001
  9. Revision History:
  10. --*/
  11. #include "bd.h"
  12. #include "bootlib.h"
  13. #include "kddll.h"
  14. #define TRANSFER_LENGTH 8192
  15. #define KD_MAX_REMOTE_FILES 16
  16. //
  17. // Keep track of all the remote files.
  18. typedef struct _KD_REMOTE_FILE {
  19. ULONG64 RemoteHandle;
  20. } KD_REMOTE_FILE, *PKD_REMOTE_FILE;
  21. KD_REMOTE_FILE BdRemoteFiles[KD_MAX_REMOTE_FILES];
  22. // KD_CONTEXT KdContext;
  23. // temporary buffer used for transferring data back and forth.
  24. // UCHAR TransferBuffer[TRANSFER_LENGTH];
  25. UCHAR BdFileTransferBuffer[TRANSFER_LENGTH];
  26. ARC_STATUS
  27. BdCreateRemoteFile(
  28. OUT PHANDLE Handle,
  29. OUT PULONG64 Length, OPTIONAL
  30. IN PCHAR FileName,
  31. IN ACCESS_MASK DesiredAccess,
  32. IN ULONG FileAttributes,
  33. IN ULONG ShareAccess,
  34. IN ULONG CreateDisposition,
  35. IN ULONG CreateOptions
  36. )
  37. {
  38. DBGKD_FILE_IO Irp;
  39. ULONG DownloadedFileIndex;
  40. ULONG Index;
  41. STRING MessageData;
  42. STRING MessageHeader;
  43. ULONG ReturnCode;
  44. ULONG PacketLength;
  45. ANSI_STRING aString;
  46. UNICODE_STRING uString;
  47. if( !BdDebuggerEnabled ) {
  48. return STATUS_DEBUGGER_INACTIVE;
  49. }
  50. if( (!FileName) ||
  51. (strlen(FileName) > PACKET_MAX_SIZE) ) {
  52. DbgPrint( "BdCreateRemoteFile: Bad parameter\n" );
  53. return STATUS_INVALID_PARAMETER;
  54. }
  55. if (BdDebuggerNotPresent != FALSE) {
  56. Irp.Status = STATUS_DEBUGGER_INACTIVE;
  57. goto Exit;
  58. }
  59. //
  60. // Look for an open slot.
  61. //
  62. for (DownloadedFileIndex = 0; DownloadedFileIndex < KD_MAX_REMOTE_FILES; DownloadedFileIndex++) {
  63. if (BdRemoteFiles[DownloadedFileIndex].RemoteHandle == 0) {
  64. break;
  65. }
  66. }
  67. if (DownloadedFileIndex >= KD_MAX_REMOTE_FILES) {
  68. DbgPrint( "BdCreateRemoteFile: No more empty handles available for this file.\n" );
  69. Irp.Status = STATUS_NO_MEMORY;
  70. goto Exit;
  71. }
  72. //
  73. // Fix up the packet that we'll send to the kernel debugger.
  74. //
  75. Irp.ApiNumber = DbgKdCreateFileApi;
  76. Irp.u.CreateFile.DesiredAccess = DesiredAccess;
  77. Irp.u.CreateFile.FileAttributes = FileAttributes;
  78. Irp.u.CreateFile.ShareAccess = ShareAccess;
  79. Irp.u.CreateFile.CreateDisposition = CreateDisposition;
  80. Irp.u.CreateFile.CreateOptions = CreateOptions;
  81. Irp.u.CreateFile.Handle = 0;
  82. Irp.u.CreateFile.Length = 0;
  83. MessageHeader.Length = sizeof(Irp);
  84. MessageHeader.MaximumLength = sizeof(Irp);
  85. MessageHeader.Buffer = (PCHAR)&Irp;
  86. //
  87. // Send him a unicode file name.
  88. //
  89. RtlInitString( &aString, FileName );
  90. uString.Buffer = (PWCHAR)BdFileTransferBuffer;
  91. uString.MaximumLength = sizeof(BdFileTransferBuffer);
  92. RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
  93. MessageData.Length = (USHORT)((strlen(FileName)+1) * sizeof(WCHAR));
  94. MessageData.Buffer = BdFileTransferBuffer;
  95. //
  96. // Send packet to the kernel debugger on the host machine and ask him to
  97. // send us a handle to the file.
  98. //
  99. BdSendPacket(PACKET_TYPE_KD_FILE_IO,
  100. &MessageHeader,
  101. &MessageData);
  102. if (BdDebuggerNotPresent != FALSE) {
  103. Irp.Status = STATUS_DEBUGGER_INACTIVE;
  104. goto Exit;
  105. }
  106. //
  107. // We asked for the handle, now receive it.
  108. //
  109. MessageData.MaximumLength = sizeof(BdFileTransferBuffer);
  110. MessageData.Buffer = (PCHAR)BdFileTransferBuffer;
  111. ReturnCode = BD_PACKET_TIMEOUT;
  112. Index = 0;
  113. while( (ReturnCode == BD_PACKET_TIMEOUT) &&
  114. (Index < 10) ) {
  115. ReturnCode = BdReceivePacket(PACKET_TYPE_KD_FILE_IO,
  116. &MessageHeader,
  117. &MessageData,
  118. &PacketLength);
  119. Index++;
  120. }
  121. //
  122. // BdReceivePacket *may* return BD_PACKET_RECEIVED eventhough the kernel
  123. // debugger failed to actually find the file we wanted. Therefore, we
  124. // need to check the Irp.Status value too before assuming we got the
  125. // information we wanted.
  126. //
  127. // Note: don't check for Irp.u.CreateFile.Length == 0 because we don't
  128. // want to exclude downloading zero-length files.
  129. //
  130. if( (ReturnCode == BD_PACKET_RECEIVED) &&
  131. (NT_SUCCESS(Irp.Status)) ) {
  132. Irp.Status = STATUS_SUCCESS;
  133. } else {
  134. Irp.Status = STATUS_INVALID_PARAMETER;
  135. }
  136. Exit:
  137. if (NT_SUCCESS(Irp.Status)) {
  138. BdRemoteFiles[DownloadedFileIndex].RemoteHandle = Irp.u.CreateFile.Handle;
  139. // Add one so that zero is reserved for invalid-handle.
  140. *Handle = UlongToHandle(DownloadedFileIndex + 1);
  141. if (ARGUMENT_PRESENT(Length)) {
  142. *Length = Irp.u.CreateFile.Length;
  143. }
  144. }
  145. return Irp.Status;
  146. }
  147. ARC_STATUS
  148. BdReadRemoteFile(
  149. IN HANDLE Handle,
  150. IN ULONG64 Offset,
  151. OUT PVOID Buffer,
  152. IN ULONG Length,
  153. OUT PULONG Completed
  154. )
  155. {
  156. DBGKD_FILE_IO Irp;
  157. ULONG Index;
  158. ULONG _Completed = 0;
  159. if( !BdDebuggerEnabled ) {
  160. return STATUS_DEBUGGER_INACTIVE;
  161. }
  162. Index = HandleToUlong(Handle) - 1;
  163. if( (Index >= KD_MAX_REMOTE_FILES) ||
  164. (BdRemoteFiles[Index].RemoteHandle == 0) ) {
  165. DbgPrint( "BdReadRemoteFile: Bad parameters!\n" );
  166. Irp.Status = STATUS_INVALID_PARAMETER;
  167. goto Exit;
  168. }
  169. Irp.ApiNumber = DbgKdReadFileApi;
  170. Irp.Status = STATUS_SUCCESS;
  171. Irp.u.ReadFile.Handle = BdRemoteFiles[Index].RemoteHandle;
  172. Irp.u.ReadFile.Offset = Offset;
  173. while (Length > 0) {
  174. STRING MessageData;
  175. STRING MessageHeader;
  176. ULONG ReturnCode;
  177. ULONG RecvLength;
  178. if (Length > PACKET_MAX_SIZE - sizeof(Irp)) {
  179. Irp.u.ReadFile.Length = PACKET_MAX_SIZE - sizeof(Irp);
  180. } else {
  181. Irp.u.ReadFile.Length = Length;
  182. }
  183. MessageHeader.Length = sizeof(Irp);
  184. MessageHeader.MaximumLength = sizeof(Irp);
  185. MessageHeader.Buffer = (PCHAR)&Irp;
  186. //
  187. // Send packet to the kernel debugger on the host machine.
  188. //
  189. BdSendPacket(PACKET_TYPE_KD_FILE_IO,
  190. &MessageHeader,
  191. NULL);
  192. //
  193. // Receive packet from the kernel debugger on the host machine.
  194. //
  195. MessageData.MaximumLength = (USHORT)Irp.u.ReadFile.Length;
  196. MessageData.Buffer = Buffer;
  197. do {
  198. ReturnCode = BdReceivePacket(PACKET_TYPE_KD_FILE_IO,
  199. &MessageHeader,
  200. &MessageData,
  201. &RecvLength);
  202. } while (ReturnCode == BD_PACKET_TIMEOUT);
  203. if (ReturnCode == BD_PACKET_RECEIVED) {
  204. if (!NT_SUCCESS(Irp.Status)) {
  205. break;
  206. }
  207. _Completed += RecvLength;
  208. Buffer = (PVOID)((PUCHAR)Buffer + RecvLength);
  209. Irp.u.ReadFile.Offset += RecvLength;
  210. Length -= RecvLength;
  211. }
  212. }
  213. *Completed = _Completed;
  214. Exit:
  215. return Irp.Status;
  216. }
  217. ARC_STATUS
  218. BdCloseRemoteFile(
  219. IN HANDLE Handle
  220. )
  221. {
  222. DBGKD_FILE_IO Irp;
  223. ULONG Index;
  224. if( !BdDebuggerEnabled ) {
  225. return STATUS_DEBUGGER_INACTIVE;
  226. }
  227. Index = HandleToUlong(Handle) - 1;
  228. if (Index >= KD_MAX_REMOTE_FILES) {
  229. return STATUS_INVALID_PARAMETER;
  230. }
  231. if (BdRemoteFiles[Index].RemoteHandle == 0) {
  232. Irp.Status = STATUS_INVALID_PARAMETER;
  233. goto Exit;
  234. }
  235. Irp.ApiNumber = DbgKdCloseFileApi;
  236. Irp.u.CloseFile.Handle = BdRemoteFiles[Index].RemoteHandle;
  237. for (;;) {
  238. STRING MessageData;
  239. STRING MessageHeader;
  240. ULONG ReturnCode;
  241. ULONG RecvLength;
  242. MessageHeader.Length = sizeof(Irp);
  243. MessageHeader.MaximumLength = sizeof(Irp);
  244. MessageHeader.Buffer = (PCHAR)&Irp;
  245. //
  246. // Send packet to the kernel debugger on the host machine.
  247. //
  248. BdSendPacket(PACKET_TYPE_KD_FILE_IO,
  249. &MessageHeader,
  250. NULL);
  251. //
  252. // Receive packet from the kernel debugger on the host machine.
  253. //
  254. MessageData.MaximumLength = BD_MESSAGE_BUFFER_SIZE;
  255. MessageData.Buffer = (PCHAR)BdMessageBuffer;
  256. do {
  257. ReturnCode = BdReceivePacket(PACKET_TYPE_KD_FILE_IO,
  258. &MessageHeader,
  259. &MessageData,
  260. &RecvLength);
  261. } while (ReturnCode == BD_PACKET_TIMEOUT);
  262. if (ReturnCode == BD_PACKET_RECEIVED) {
  263. break;
  264. }
  265. }
  266. if (NT_SUCCESS(Irp.Status)) {
  267. BdRemoteFiles[Index].RemoteHandle = 0;
  268. }
  269. Exit:
  270. return Irp.Status;
  271. }
  272. ARC_STATUS
  273. BdPullRemoteFile(
  274. IN PCHAR FileName,
  275. IN ULONG FileAttributes,
  276. IN ULONG CreateDisposition,
  277. IN ULONG CreateOptions,
  278. IN ULONG FileId
  279. )
  280. {
  281. ARC_STATUS Status = ESUCCESS;
  282. PUCHAR BaseFilePointer = NULL;
  283. PUCHAR WorkingMemoryPointer = NULL;
  284. ULONG64 Length = 0;
  285. HANDLE RemoteHandle = NULL;
  286. ULONG64 Offset = 0;
  287. ULONG basePage = 0;
  288. PBL_FILE_TABLE fileTableEntry = NULL;
  289. if( !BdDebuggerEnabled ) {
  290. return STATUS_DEBUGGER_INACTIVE;
  291. }
  292. // Open the remote file for reading.
  293. Status = BdCreateRemoteFile(&RemoteHandle, &Length, FileName,
  294. FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL,
  295. FILE_SHARE_READ, FILE_OPEN, 0);
  296. if (!NT_SUCCESS(Status)) {
  297. //
  298. // File probably doesn't exist on the debugger.
  299. //
  300. goto Exit;
  301. }
  302. //
  303. // Allocate memory for the file, then download it.
  304. //
  305. Status = BlAllocateAlignedDescriptor( LoaderFirmwareTemporary,
  306. 0,
  307. (ULONG)((Length + PAGE_SIZE - 1) >> PAGE_SHIFT),
  308. 0,
  309. &basePage );
  310. if ( Status != ESUCCESS ) {
  311. DbgPrint( "BdPullRemoteFile: BlAllocateAlignedDescriptor failed! (%x)\n", Status );
  312. goto Exit;
  313. }
  314. //
  315. // Keep track of our pointers.
  316. // BaseFilePointer will point to the starting address of the block
  317. // we're about to download the file into.
  318. //
  319. // Working MemoryPointer will move through memory as we download small
  320. // chunks of the file.
  321. //
  322. BaseFilePointer = (PUCHAR)ULongToPtr( (basePage << PAGE_SHIFT) );
  323. WorkingMemoryPointer = BaseFilePointer;
  324. //
  325. // Download the file.
  326. //
  327. Offset = 0;
  328. while( Offset < Length ) {
  329. ULONG ReqLength, ReqCompleted;
  330. if((Length - Offset) > TRANSFER_LENGTH) {
  331. ReqLength = TRANSFER_LENGTH;
  332. } else {
  333. ReqLength = (ULONG)(Length - Offset);
  334. }
  335. Status = BdReadRemoteFile( RemoteHandle,
  336. Offset,
  337. WorkingMemoryPointer,
  338. ReqLength,
  339. &ReqCompleted );
  340. if (!NT_SUCCESS(Status) || ReqCompleted == 0) {
  341. DbgPrint( "BdPullRemoteFile: BdReadRemoteFile failed! (%x)\n", Status );
  342. goto Exit;
  343. }
  344. // Increment our working pointer so we copy the next chunk
  345. // into the next spot in memory.
  346. WorkingMemoryPointer += ReqLength;
  347. Offset += ReqLength;
  348. }
  349. //
  350. // We got the file, so setup the BL_FILE_TABLE
  351. // entry for this file. We'll pretend that we got this file
  352. // off the network because that's pretty close, and it allows
  353. // us to conveniently record the memory block where we're about
  354. // to download this file.
  355. //
  356. {
  357. extern BL_DEVICE_ENTRY_TABLE NetDeviceEntryTable;
  358. fileTableEntry = &BlFileTable[FileId];
  359. fileTableEntry->Flags.Open = 1;
  360. fileTableEntry->DeviceId = NET_DEVICE_ID;
  361. fileTableEntry->u.NetFileContext.FileSize = (ULONG)Length;
  362. fileTableEntry->u.NetFileContext.InMemoryCopy = BaseFilePointer;
  363. fileTableEntry->Position.QuadPart = 0;
  364. fileTableEntry->Flags.Read = 1;
  365. fileTableEntry->DeviceEntryTable = &NetDeviceEntryTable;
  366. RtlZeroMemory( fileTableEntry->StructureContext, sizeof(NET_STRUCTURE_CONTEXT) );
  367. //
  368. // If we've called NetIntialize before (like if we're really booting from
  369. // the net, or if we've come through here before), then he returns immediately
  370. // so the call isn't expensive.
  371. //
  372. // If we're not booting from the net, and we've never called NetInitialize before,
  373. // then this will do nothing but setup his function table and return quickly.
  374. //
  375. NetInitialize();
  376. }
  377. DbgPrint( "BD: Loaded remote file %s\n", FileName );
  378. Exit:
  379. if (RemoteHandle != NULL) {
  380. BdCloseRemoteFile(RemoteHandle);
  381. }
  382. return Status;
  383. }