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.

428 lines
9.3 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. peldr.c
  5. Abstract:
  6. This module implements the code to load a PE format image into memory
  7. and relocate it if necessary.
  8. Author:
  9. David N. Cutler (davec) 10-May-1991
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "bldr.h"
  15. #include "string.h"
  16. #include "ntimage.h"
  17. #if defined(_GAMBIT_)
  18. #include "ssc.h"
  19. #endif // defined(_GAMBIT_)
  20. //
  21. // Define image prefetch cache structure used in BlLoadImage. Images
  22. // are read as a whole into an allocated buffer and read requests in
  23. // BlLoadImage are satisfied by copying from this buffer if the
  24. // prefetch is successful. I chose to read the whole file in at once
  25. // to simplify code but it limits [although not in practice] the size of
  26. // files that can be prefetched this way, as opposed to prefetching chunks
  27. // of the file at a time.
  28. //
  29. typedef struct _IMAGE_PREFETCH_CACHE {
  30. ULONG FileId; // FileId that has been prefetched.
  31. LARGE_INTEGER Position; // Current position in the file.
  32. ULONG ValidDataLength; // Length of data that was prefetched.
  33. PUCHAR Data; // Pointer to cached data.
  34. } IMAGE_PREFETCH_CACHE, *PIMAGE_PREFETCH_CACHE;
  35. //
  36. // The next two defines are used in allocating memory for the image
  37. // cache to direct the allocator into using memory above 1MB and to make
  38. // the allocated memory 64KB aligned. They are in terms of number of pages.
  39. //
  40. #define BL_IMAGE_ABOVE_1MB (0x200000 >> PAGE_SHIFT)
  41. #define BL_IMAGE_64KB_ALIGNED (0x10000 >> PAGE_SHIFT)
  42. //
  43. // Define forward referenced prototypes.
  44. //
  45. USHORT
  46. ChkSum(
  47. ULONG PartialSum,
  48. PUSHORT Source,
  49. ULONG Length
  50. );
  51. ARC_STATUS
  52. BlImageInitCache(
  53. IN PIMAGE_PREFETCH_CACHE pCache,
  54. ULONG FileId
  55. );
  56. ARC_STATUS
  57. BlImageRead(
  58. IN PIMAGE_PREFETCH_CACHE pCache,
  59. IN ULONG FileId,
  60. OUT PVOID Buffer,
  61. IN ULONG Length,
  62. OUT PULONG pCount
  63. );
  64. ARC_STATUS
  65. BlImageSeek(
  66. IN PIMAGE_PREFETCH_CACHE pCache,
  67. IN ULONG FileId,
  68. IN PLARGE_INTEGER pOffset,
  69. IN SEEK_MODE SeekMode
  70. );
  71. VOID
  72. BlImageFreeCache(
  73. IN PIMAGE_PREFETCH_CACHE pCache,
  74. ULONG FileId
  75. );
  76. #include "peldrt.c"
  77. ARC_STATUS
  78. BlImageInitCache(
  79. IN PIMAGE_PREFETCH_CACHE pCache,
  80. ULONG FileId
  81. )
  82. /*++
  83. Routine Description:
  84. Attempt to allocate memory and prefetch a file. Setup pCache
  85. structure so it can be passed to BlImageRead/Seek to either copy
  86. from the cache if prefetch was successful or read from the disk as
  87. normal. The file must be opened read only and should not be closed
  88. or modified before calling BlImageFreeCache. The file position of
  89. FileId is reset to the beginning of the file on success, and is
  90. undefined on failure. pCache is always setup so it can be used in
  91. BlImage* I/O functions. If the file could not be prefetched, the
  92. cache's ValidDataLength will be set to 0 and the I/O functions
  93. will simply call the Bl* I/O functions [e.g. BlImageRead calls
  94. BlRead]. Note that the whole file is prefetched at once and this
  95. puts a limit on the size of files that can be prefetched via this
  96. cache since boot loader memory is limited. This limit is not hit
  97. in practice though.
  98. Arguments:
  99. pCache - Cache structure to setup.
  100. FileId - File to prefetch.
  101. Return Value:
  102. ESUCCESS if everything was successful .
  103. Appropriate ARC_STATUS if there was a problem.
  104. --*/
  105. {
  106. ARC_STATUS Status = ESUCCESS;
  107. FILE_INFORMATION FileInfo;
  108. ULONG FileSize;
  109. ULONG ActualBase;
  110. ULONG_PTR NewImageBase;
  111. PVOID CacheBufBase = NULL;
  112. ULONG ReadCount;
  113. LARGE_INTEGER SeekPosition;
  114. ALLOCATION_POLICY OldPolicy;
  115. //
  116. // Initialize fields of the cache structure.
  117. //
  118. pCache->Data = 0;
  119. pCache->ValidDataLength = 0;
  120. pCache->Position.QuadPart = 0;
  121. pCache->FileId = FileId;
  122. //
  123. // Get file size.
  124. //
  125. Status = BlGetFileInformation(FileId, &FileInfo);
  126. if (Status != ESUCCESS) {
  127. goto cleanup;
  128. }
  129. //
  130. // Check if file is too big. File size is at
  131. // FileInfo.EndingAddress.
  132. //
  133. if (FileInfo.EndingAddress.HighPart != 0) {
  134. Status = E2BIG;
  135. goto cleanup;
  136. }
  137. FileSize = FileInfo.EndingAddress.LowPart;
  138. //
  139. // Allocate memory for the cache. In order to avoid fragmenting memory
  140. // terribly, temporarily change the allocation policy to HighestFit. This
  141. // causes the drivers to get loaded from the bottom up, while the cache
  142. // is always at the top of free memory.
  143. //
  144. Status = BlAllocateAlignedDescriptor(LoaderFirmwareTemporary,
  145. 0,
  146. (FileSize >> PAGE_SHIFT) + 1,
  147. BL_IMAGE_64KB_ALIGNED,
  148. &ActualBase);
  149. if (Status != ESUCCESS) {
  150. Status = ENOMEM;
  151. goto cleanup;
  152. }
  153. CacheBufBase = (PVOID) (KSEG0_BASE | (ActualBase << PAGE_SHIFT));
  154. //
  155. // Read the file into the prefetch buffer.
  156. //
  157. SeekPosition.QuadPart = 0;
  158. Status = BlSeek(FileId, &SeekPosition, SeekAbsolute);
  159. if (Status != ESUCCESS) {
  160. goto cleanup;
  161. }
  162. Status = BlRead(FileId, CacheBufBase, FileSize, &ReadCount);
  163. if (Status != ESUCCESS) {
  164. goto cleanup;
  165. }
  166. if (ReadCount != FileSize) {
  167. Status = EIO;
  168. goto cleanup;
  169. }
  170. //
  171. // Reset file position back to beginning.
  172. //
  173. SeekPosition.QuadPart = 0;
  174. Status = BlSeek(FileId, &SeekPosition, SeekAbsolute);
  175. if (Status != ESUCCESS) {
  176. goto cleanup;
  177. }
  178. //
  179. // The file was successfully prefetched.
  180. //
  181. pCache->Data = CacheBufBase;
  182. CacheBufBase = NULL;
  183. pCache->ValidDataLength = FileSize;
  184. cleanup:
  185. if (CacheBufBase != NULL) {
  186. BlFreeDescriptor(ActualBase);
  187. }
  188. return Status;
  189. }
  190. ARC_STATUS
  191. BlImageRead(
  192. IN PIMAGE_PREFETCH_CACHE pCache,
  193. IN ULONG FileId,
  194. OUT PVOID Buffer,
  195. IN ULONG Length,
  196. OUT PULONG pCount
  197. )
  198. /*++
  199. Routine Description:
  200. A wrapper for BlRead. Checks to see if the request can be
  201. satisfied from pCache first. If not calls BlRead.
  202. Arguments:
  203. pCache - Prefetch Cache for FileId
  204. FileId, Buffer, Length, Count - BlRead parameters
  205. Return Value:
  206. Status that would be returned by BlRead.
  207. --*/
  208. {
  209. ARC_STATUS Status;
  210. LONG AdjustedLength;
  211. //
  212. // If the cache buffer does not exist or the cached size is 0,
  213. // hand over the call to BlRead.
  214. //
  215. if (!pCache->Data || !pCache->ValidDataLength) {
  216. return BlRead(FileId, Buffer, Length, pCount);
  217. }
  218. //
  219. // Clear read bytes count.
  220. //
  221. *pCount = 0;
  222. //
  223. // Determine how many bytes we can copy from our current position till
  224. // EOF, if there is not Length bytes.
  225. //
  226. AdjustedLength = (LONG)pCache->ValidDataLength - (LONG)pCache->Position.LowPart;
  227. if (AdjustedLength < 0) {
  228. AdjustedLength = 0;
  229. }
  230. AdjustedLength = ((ULONG)AdjustedLength < Length) ? AdjustedLength : Length;
  231. //
  232. // Copy AdjustedLength bytes into target buffer and advance the file position.
  233. //
  234. RtlCopyMemory(Buffer, pCache->Data + pCache->Position.LowPart, AdjustedLength);
  235. pCache->Position.LowPart += AdjustedLength;
  236. //
  237. // Update number of bytes read.
  238. //
  239. *pCount = AdjustedLength;
  240. return ESUCCESS;
  241. }
  242. ARC_STATUS
  243. BlImageSeek(
  244. IN PIMAGE_PREFETCH_CACHE pCache,
  245. IN ULONG FileId,
  246. IN PLARGE_INTEGER pOffset,
  247. IN SEEK_MODE SeekMode
  248. )
  249. /*++
  250. Routine Description:
  251. A wrapper for BlSeek. Calls BlSeek and if successful, updates the
  252. position in the cache structure as well. We call BlSeek to update
  253. the file position as well because at any time the cache may be
  254. freed or invalidated and we have to be able to continue calling on
  255. Bl* I/O functions transparently.
  256. Arguments:
  257. pCache - Prefetch Cache for FileId.
  258. FileId, Offset, SeekMode - BlSeek parameters.
  259. Return Value:
  260. Status that would be returned by BlSeek.
  261. --*/
  262. {
  263. ARC_STATUS Status;
  264. //
  265. // Do not allow setting position to too big. We do not open such
  266. // files anyway and the boot loader file systems and other places
  267. // in the boot loader I/O system do not handle it.
  268. //
  269. if (pOffset->HighPart != 0) {
  270. return E2BIG;
  271. }
  272. //
  273. // Try to update file position.
  274. //
  275. Status = BlSeek(FileId, pOffset, SeekMode);
  276. if (Status != ESUCCESS) {
  277. return Status;
  278. }
  279. //
  280. // Update the position in cached buffer. We don't perform
  281. // checks since BlSeek accepted the new offset.
  282. //
  283. pCache->Position.QuadPart = pOffset->QuadPart;
  284. return Status;
  285. }
  286. VOID
  287. BlImageFreeCache(
  288. IN PIMAGE_PREFETCH_CACHE pCache,
  289. ULONG FileId
  290. )
  291. /*++
  292. Routine Description:
  293. Free the memory allocated for the prefetch cache for FileId in
  294. pCache. Sets ValidDataLength to 0 to stop caching.
  295. Arguments:
  296. pCache - Cache structure to setup
  297. FileId - File that was opened read-only to be cached.
  298. Return Value:
  299. None.
  300. --*/
  301. {
  302. ULONG DescBase;
  303. //
  304. // NOTE: ValidDataLength may be zero, but we still allocate at least
  305. // a page and we have to free that.
  306. //
  307. if (pCache->Data) {
  308. DescBase = (ULONG)((ULONG_PTR)pCache->Data & (~KSEG0_BASE));
  309. BlFreeDescriptor(DescBase >> PAGE_SHIFT);
  310. pCache->Data = NULL;
  311. }
  312. pCache->ValidDataLength = 0;
  313. return;
  314. }