Leaked source code of windows server 2003
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.

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