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.

1766 lines
51 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. blmemory.c
  5. Abstract:
  6. This module implements the OS loader memory allocation routines.
  7. Author:
  8. David N. Cutler (davec) 19-May-1991
  9. Revision History:
  10. --*/
  11. #include "bldr.h"
  12. #if defined(_X86_)
  13. #include "bldrx86.h"
  14. #endif
  15. #if defined(_IA64_)
  16. #include "bldria64.h"
  17. #endif
  18. #include <stdlib.h>
  19. #include <ntverp.h>
  20. #define MIN(_a,_b) (((_a) <= (_b)) ? (_a) : (_b))
  21. #define MAX(_a,_b) (((_a) >= (_b)) ? (_a) : (_b))
  22. #define IsTrackMem(t) ((t != LoaderFree) && \
  23. (t != LoaderBad) && \
  24. (t != LoaderFirmwareTemporary) && \
  25. (t != LoaderOsloaderStack) && \
  26. (t != LoaderXIPRom) && \
  27. (t != LoaderReserve))
  28. //
  29. // The first PDE page is always mapped, on PAE this is the bottom 2MB
  30. //
  31. #define ALWAYS_MAPPED ((2*1024*1024) >> PAGE_SHIFT)
  32. #define IsValidTrackingRange(b,n) (((b+n) > ALWAYS_MAPPED) ? TRUE :FALSE)
  33. ALLOCATION_POLICY BlMemoryAllocationPolicy = BlAllocateBestFit;
  34. ALLOCATION_POLICY BlHeapAllocationPolicy = BlAllocateBestFit;
  35. //
  36. // Define memory allocation descriptor listhead and heap storage variables.
  37. //
  38. ULONG_PTR BlHeapFree;
  39. ULONG_PTR BlHeapLimit;
  40. PLOADER_PARAMETER_BLOCK BlLoaderBlock;
  41. ULONG BlHighestPage;
  42. ULONG BlLowestPage;
  43. //
  44. // Global Value for where to load the kernel
  45. //
  46. BOOLEAN BlOldKernel = FALSE;
  47. BOOLEAN BlRestoring = FALSE;
  48. BOOLEAN BlKernelChecked = FALSE;
  49. //
  50. // Define the lowest and highest usable pages
  51. //
  52. #if defined(_X86_)
  53. //
  54. // X86 is limited to the first 512MB of physical address space
  55. // Until BlMemoryInitialize has happened, we want to limit things
  56. // to the first 16MB as that is all that has been mapped.
  57. //
  58. ULONG BlUsableBase=0;
  59. ULONG BlUsableLimit=((16*1024*1024)/PAGE_SIZE); // 16MB
  60. #elif defined(_IA64_)
  61. //
  62. // IA64 only has enough TRs to map the region between 16MB and
  63. // 80MB.
  64. //
  65. ULONG BlUsableBase = _16MB;
  66. ULONG BlUsableLimit = _80MB;
  67. #else
  68. ULONG BlUsableBase = 0;
  69. ULONG BlUsableLimit = 0xffffffff;
  70. #endif
  71. TYPE_OF_MEMORY
  72. BlpDetermineAllocationPolicy (
  73. TYPE_OF_MEMORY MemoryType,
  74. ULONG BasePage,
  75. ULONG PageCount,
  76. BOOLEAN Retry
  77. );
  78. void
  79. BlpTrackUsage (
  80. MEMORY_TYPE MemoryType,
  81. ULONG ActualBase,
  82. ULONG NumberPages
  83. );
  84. #if DBG
  85. ULONG_PTR TotalHeapAbandoned = 0;
  86. #endif
  87. //
  88. // WARNING: (x86 only) Use this carefully. Currently only temporary buffers
  89. // are allocated top down. The kernel and drivers are loaded bottom up
  90. // this has an effect on PAE. Since the PAE kernel loads at 16MB
  91. // only temp buffers can be above 16MB. If drivers are loaded there the
  92. // system will fail
  93. //
  94. VOID
  95. BlSetAllocationPolicy (
  96. IN ALLOCATION_POLICY MemoryAllocationPolicy,
  97. IN ALLOCATION_POLICY HeapAllocationPolicy
  98. )
  99. {
  100. BlMemoryAllocationPolicy = MemoryAllocationPolicy;
  101. BlHeapAllocationPolicy = HeapAllocationPolicy;
  102. return;
  103. }
  104. VOID
  105. BlInsertDescriptor (
  106. IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
  107. )
  108. /*++
  109. Routine Description:
  110. This routine inserts a memory descriptor in the memory allocation list.
  111. It inserts the new descriptor in sorted order, based on the starting
  112. page of the block. It also merges adjacent blocks of free memory.
  113. Arguments:
  114. ListHead - Supplies the address of the memory allocation list head.
  115. NewDescriptor - Supplies the address of the descriptor that is to be
  116. inserted.
  117. Return Value:
  118. None.
  119. --*/
  120. {
  121. PLIST_ENTRY ListHead = &BlLoaderBlock->MemoryDescriptorListHead;
  122. PLIST_ENTRY PreviousEntry;
  123. PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor;
  124. PLIST_ENTRY NextEntry;
  125. PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
  126. //
  127. // Find the first descriptor in the list that starts above the new
  128. // descriptor. The new descriptor goes in front of this descriptor.
  129. //
  130. PreviousEntry = ListHead;
  131. NextEntry = ListHead->Flink;
  132. while (NextEntry != ListHead) {
  133. NextDescriptor = CONTAINING_RECORD(NextEntry,
  134. MEMORY_ALLOCATION_DESCRIPTOR,
  135. ListEntry);
  136. if (NewDescriptor->BasePage < NextDescriptor->BasePage) {
  137. break;
  138. }
  139. PreviousEntry = NextEntry;
  140. PreviousDescriptor = NextDescriptor;
  141. NextEntry = NextEntry->Flink;
  142. }
  143. //
  144. // If the new descriptor doesn't describe free memory, just insert it
  145. // in the list in front of the previous entry. Otherwise, check to see
  146. // if free blocks can be merged.
  147. //
  148. if (NewDescriptor->MemoryType != LoaderFree) {
  149. InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
  150. } else {
  151. //
  152. // If the previous block also describes free memory, and it's
  153. // contiguous with the new block, merge them by adding the
  154. // page count from the new
  155. //
  156. if ((PreviousEntry != ListHead) &&
  157. ((PreviousDescriptor->MemoryType == LoaderFree) ||
  158. (PreviousDescriptor->MemoryType == LoaderReserve) ) &&
  159. ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
  160. NewDescriptor->BasePage)) {
  161. PreviousDescriptor->PageCount += NewDescriptor->PageCount;
  162. NewDescriptor = PreviousDescriptor;
  163. } else {
  164. InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
  165. }
  166. if ((NextEntry != ListHead) &&
  167. ((NextDescriptor->MemoryType == LoaderFree) ||
  168. (NextDescriptor->MemoryType == LoaderReserve)) &&
  169. ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage)) {
  170. NewDescriptor->PageCount += NextDescriptor->PageCount;
  171. NewDescriptor->MemoryType = NextDescriptor->MemoryType;
  172. BlRemoveDescriptor(NextDescriptor);
  173. }
  174. }
  175. return;
  176. }
  177. ARC_STATUS
  178. BlMemoryInitialize (
  179. VOID
  180. )
  181. /*++
  182. Routine Description:
  183. This routine allocates stack space for the OS loader, initializes
  184. heap storage, and initializes the memory allocation list.
  185. Arguments:
  186. None.
  187. Return Value:
  188. ESUCCESS is returned if the initialization is successful. Otherwise,
  189. ENOMEM is returned.
  190. --*/
  191. {
  192. PMEMORY_ALLOCATION_DESCRIPTOR AllocationDescriptor;
  193. PMEMORY_DESCRIPTOR HeapDescriptor;
  194. PMEMORY_DESCRIPTOR MemoryDescriptor;
  195. PMEMORY_DESCRIPTOR ProgramDescriptor;
  196. ULONG EndPage;
  197. ULONG HeapAndStackPages;
  198. ULONG StackPages;
  199. ULONG StackBasePage;
  200. ULONG i;
  201. CHAR versionBuffer[64];
  202. PCHAR major;
  203. PCHAR minor;
  204. //
  205. // This code doesn't work under EFI -- we can have multiple
  206. // MemoryLoadedProgram descriptors under EFI. We also cannot make the
  207. // same assumptions about finding a free descriptor below
  208. // the os loader for a stack and heap as under ARC. Instead, we'll just
  209. // search for any suitable place for a heap and stack
  210. //
  211. #ifndef EFI
  212. //
  213. // Find the memory descriptor that describes the allocation for the OS
  214. // loader itself.
  215. //
  216. ProgramDescriptor = NULL;
  217. while ((ProgramDescriptor = ArcGetMemoryDescriptor(ProgramDescriptor)) != NULL) {
  218. if (ProgramDescriptor->MemoryType == MemoryLoadedProgram) {
  219. break;
  220. }
  221. }
  222. //
  223. // If a loaded program memory descriptor was found, then it must be
  224. // for the OS loader since that is the only program that can be loaded.
  225. // If a loaded program memory descriptor was not found, then firmware
  226. // is not functioning properly and an unsuccessful status is returned.
  227. //
  228. if (ProgramDescriptor == NULL) {
  229. DBGTRACE( TEXT("Couldn't find ProgramDescriptor\r\n"));
  230. return ENOMEM;
  231. }
  232. //
  233. // Find the free memory descriptor that is just below the loaded
  234. // program in memory. There should be several megabytes of free
  235. // memory just preceeding the OS loader.
  236. //
  237. StackPages = BL_STACK_PAGES;
  238. HeapAndStackPages = BL_HEAP_PAGES + BL_STACK_PAGES;
  239. HeapDescriptor = NULL;
  240. while ((HeapDescriptor = ArcGetMemoryDescriptor(HeapDescriptor)) != NULL) {
  241. if (((HeapDescriptor->MemoryType == MemoryFree) ||
  242. (HeapDescriptor->MemoryType == MemoryFreeContiguous)) &&
  243. ((HeapDescriptor->BasePage + HeapDescriptor->PageCount) ==
  244. ProgramDescriptor->BasePage)) {
  245. break;
  246. }
  247. }
  248. #else
  249. StackPages = BL_STACK_PAGES;
  250. HeapAndStackPages = BL_HEAP_PAGES + BL_STACK_PAGES;
  251. HeapDescriptor = NULL;
  252. #endif
  253. //
  254. // If a free memory descriptor was not found that describes the free
  255. // memory just below the OS loader, or the memory descriptor is not
  256. // large enough for the OS loader stack and heap, then try and find
  257. // a suitable one.
  258. //
  259. if ((HeapDescriptor == NULL) ||
  260. (HeapDescriptor->PageCount < (BL_HEAP_PAGES + BL_STACK_PAGES))) {
  261. HeapDescriptor = NULL;
  262. while ((HeapDescriptor = ArcGetMemoryDescriptor(HeapDescriptor)) != NULL) {
  263. #if defined(_IA64_)
  264. //
  265. // We only have enough TR's to map the region between 16 MB
  266. // and 80 MB. So we ignore anything that's not in that range
  267. //
  268. if ((HeapDescriptor->BasePage < _48MB) &&
  269. (HeapDescriptor->BasePage >= _16MB)) {
  270. #endif
  271. if (((HeapDescriptor->MemoryType == MemoryFree) ||
  272. (HeapDescriptor->MemoryType == MemoryFreeContiguous)) &&
  273. (HeapDescriptor->PageCount >= (BL_HEAP_PAGES + BL_STACK_PAGES))) {
  274. break;
  275. }
  276. #if defined(_IA64_)
  277. }
  278. #endif
  279. }
  280. }
  281. //
  282. // A suitable descriptor could not be found, return an unsuccessful
  283. // status.
  284. //
  285. if (HeapDescriptor == NULL) {
  286. DBGTRACE( TEXT("Couldn't find HeapDescriptor\r\n"));
  287. return(ENOMEM);
  288. }
  289. StackBasePage = HeapDescriptor->BasePage + HeapDescriptor->PageCount - BL_STACK_PAGES;
  290. //
  291. // Compute the address of the loader heap, initialize the heap
  292. // allocation variables, and zero the heap memory.
  293. //
  294. EndPage = HeapDescriptor->BasePage + HeapDescriptor->PageCount;
  295. BlpTrackUsage (LoaderOsloaderHeap,HeapDescriptor->BasePage,HeapDescriptor->PageCount);
  296. BlHeapFree = KSEG0_BASE | ((EndPage - HeapAndStackPages) << PAGE_SHIFT);
  297. //
  298. // always reserve enough space in the heap for one more memory
  299. // descriptor, so we can go create more heap if we run out.
  300. //
  301. BlHeapLimit = (BlHeapFree + (BL_HEAP_PAGES << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
  302. RtlZeroMemory((PVOID)BlHeapFree, BL_HEAP_PAGES << PAGE_SHIFT);
  303. //
  304. // Allocate and initialize the loader parameter block.
  305. //
  306. BlLoaderBlock =
  307. (PLOADER_PARAMETER_BLOCK)BlAllocateHeap(sizeof(LOADER_PARAMETER_BLOCK));
  308. if (BlLoaderBlock == NULL) {
  309. DBGTRACE( TEXT("Couldn't initialize loader block\r\n"));
  310. return ENOMEM;
  311. }
  312. BlLoaderBlock->Extension =
  313. (PLOADER_PARAMETER_EXTENSION)
  314. BlAllocateHeap(sizeof(LOADER_PARAMETER_EXTENSION));
  315. if (BlLoaderBlock->Extension == NULL) {
  316. DBGTRACE( TEXT("Couldn't initialize loader block extension\r\n"));
  317. return ENOMEM;
  318. }
  319. BlLoaderBlock->Extension->Size = sizeof (LOADER_PARAMETER_EXTENSION);
  320. major = strcpy(versionBuffer, VER_PRODUCTVERSION_STR);
  321. minor = strchr(major, '.');
  322. *minor++ = '\0';
  323. BlLoaderBlock->Extension->MajorVersion = atoi(major);
  324. BlLoaderBlock->Extension->MinorVersion = atoi(minor);
  325. BlLoaderBlock->Extension->InfFileImage = NULL;
  326. BlLoaderBlock->Extension->InfFileSize = 0;
  327. InitializeListHead(&BlLoaderBlock->LoadOrderListHead);
  328. InitializeListHead(&BlLoaderBlock->MemoryDescriptorListHead);
  329. //
  330. // Copy the memory descriptor list from firmware into the local heap and
  331. // deallocate the loader heap and stack from the free memory descriptor.
  332. //
  333. MemoryDescriptor = NULL;
  334. while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) {
  335. AllocationDescriptor =
  336. (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
  337. sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
  338. if (AllocationDescriptor == NULL) {
  339. DBGTRACE( TEXT("Couldn't allocate heap for memory allocation descriptor\r\n"));
  340. return ENOMEM;
  341. }
  342. AllocationDescriptor->MemoryType =
  343. (TYPE_OF_MEMORY)MemoryDescriptor->MemoryType;
  344. if (MemoryDescriptor->MemoryType == MemoryFreeContiguous) {
  345. AllocationDescriptor->MemoryType = LoaderFree;
  346. } else if (MemoryDescriptor->MemoryType == MemorySpecialMemory) {
  347. AllocationDescriptor->MemoryType = LoaderSpecialMemory;
  348. }
  349. AllocationDescriptor->BasePage = MemoryDescriptor->BasePage;
  350. AllocationDescriptor->PageCount = MemoryDescriptor->PageCount;
  351. if (MemoryDescriptor == HeapDescriptor) {
  352. AllocationDescriptor->PageCount -= HeapAndStackPages;
  353. }
  354. //
  355. // [chuckl 11/19/2001, fixing a bug from 11/15/1993]
  356. //
  357. // In rare cases, the above subtraction of HeapAndStackPages from
  358. // PageCount can result in a PageCount of 0. MM doesn't like this,
  359. // so don't insert the descriptor if PageCount is 0. The side
  360. // effect of this is that we "lose" a descriptor, but that's just
  361. // a few bytes of heap lost.
  362. //
  363. if (AllocationDescriptor->PageCount != 0) {
  364. BlInsertDescriptor(AllocationDescriptor);
  365. }
  366. }
  367. //
  368. // Allocate a memory descriptor for the loader stack.
  369. //
  370. if (StackPages != 0) {
  371. AllocationDescriptor =
  372. (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
  373. sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
  374. if (AllocationDescriptor == NULL) {
  375. DBGTRACE( TEXT("Couldn't allocate heap for loader stack\r\n"));
  376. return ENOMEM;
  377. }
  378. AllocationDescriptor->MemoryType = LoaderOsloaderStack;
  379. AllocationDescriptor->BasePage = StackBasePage;
  380. AllocationDescriptor->PageCount = BL_STACK_PAGES;
  381. BlInsertDescriptor(AllocationDescriptor);
  382. }
  383. //
  384. // Allocate a memory descriptor for the loader heap.
  385. //
  386. AllocationDescriptor =
  387. (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
  388. sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
  389. if (AllocationDescriptor == NULL) {
  390. DBGTRACE( TEXT("Couldn't allocate heap for loader heap\r\n"));
  391. return ENOMEM;
  392. }
  393. AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
  394. AllocationDescriptor->BasePage = EndPage - HeapAndStackPages;
  395. AllocationDescriptor->PageCount = BL_HEAP_PAGES;
  396. BlInsertDescriptor(AllocationDescriptor);
  397. return ESUCCESS;
  398. }
  399. ARC_STATUS
  400. BlAllocateAlignedDescriptor (
  401. IN TYPE_OF_MEMORY MemoryType,
  402. IN ULONG BasePage,
  403. IN ULONG PageCount,
  404. IN ULONG Alignment,
  405. OUT PULONG ActualBase
  406. )
  407. /*++
  408. Routine Description:
  409. This routine allocates memory and generates one of more memory
  410. descriptors to describe the allocated region. The first attempt
  411. is to allocate the specified region of memory (at BasePage).
  412. If the memory is not free, then the smallest region of free
  413. memory that satisfies the request is allocated. The Alignment
  414. parameter can be used to force the block to be allocated at a
  415. particular alignment.
  416. Arguments:
  417. MemoryType - Supplies the memory type that is to be assigned to
  418. the generated descriptor.
  419. BasePage - Supplies the base page number of the desired region.
  420. If 0, no particular base page is required.
  421. PageCount - Supplies the number of pages required.
  422. Alignment - Supplies the required alignment, in pages. (E.g.,
  423. with 4K page size, 16K alignment requires Alignment == 4.)
  424. If 0, no particular alignment is required.
  425. N.B. If BasePage is not 0, and the specified BasePage is
  426. available, Alignment is ignored. It is up to the caller
  427. to specify a BasePage that meets the caller's alignment
  428. requirement.
  429. ActualBase - Supplies a pointer to a variable that receives the
  430. page number of the allocated region.
  431. Return Value:
  432. ESUCCESS is returned if an available block of free memory can be
  433. allocated. Otherwise, return a unsuccessful status.
  434. --*/
  435. {
  436. PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
  437. PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
  438. PLIST_ENTRY NextEntry;
  439. ARC_STATUS Status;
  440. ULONG AlignedBasePage, AlignedPageCount;
  441. ULONG FreeBasePage, FreePageCount;
  442. MEMORY_TYPE TypeToUse;
  443. ALLOCATION_POLICY OldPolicy = BlMemoryAllocationPolicy;
  444. BOOLEAN retryalloc=FALSE;
  445. //
  446. // Simplify the alignment checks by changing 0 to 1.
  447. //
  448. if (Alignment == 0) {
  449. Alignment = 1;
  450. }
  451. //
  452. // If the allocation is for zero pages, make it one, because allocation of zero
  453. // breaks the internal algorithms for merging, etc.
  454. //
  455. if (PageCount == 0) {
  456. PageCount = 1;
  457. }
  458. //
  459. // Attempt to find a free memory descriptor that encompasses the
  460. // specified region or a free memory descriptor that is large
  461. // enough to satisfy the request.
  462. //
  463. retry:
  464. TypeToUse=BlpDetermineAllocationPolicy (MemoryType,BasePage,PageCount,retryalloc);
  465. //
  466. // If a base page was specified, find the containing descriptor and try and use
  467. // that directly.
  468. //
  469. if (BasePage &&
  470. (BasePage >= BlUsableBase) &&
  471. (BasePage + PageCount <= BlUsableLimit)) {
  472. FreeDescriptor = BlFindMemoryDescriptor(BasePage);
  473. if ((FreeDescriptor) &&
  474. (FreeDescriptor->MemoryType == TypeToUse) &&
  475. (FreeDescriptor->BasePage + FreeDescriptor->PageCount >= BasePage + PageCount)) {
  476. Status = BlGenerateDescriptor(FreeDescriptor,
  477. MemoryType,
  478. BasePage,
  479. PageCount);
  480. *ActualBase = BasePage;
  481. BlpTrackUsage (TypeToUse,*ActualBase,PageCount);
  482. if (BlpCheckMapping (BasePage,PageCount+1) != ESUCCESS) {
  483. BlMemoryAllocationPolicy=OldPolicy;
  484. return (ENOMEM);
  485. }
  486. BlMemoryAllocationPolicy=OldPolicy;
  487. return Status;
  488. }
  489. }
  490. FreeDescriptor = NULL;
  491. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  492. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  493. NextDescriptor = CONTAINING_RECORD(NextEntry,
  494. MEMORY_ALLOCATION_DESCRIPTOR,
  495. ListEntry);
  496. AlignedBasePage = (NextDescriptor->BasePage + (Alignment - 1)) & ~(Alignment - 1);
  497. AlignedPageCount= NextDescriptor->PageCount - (AlignedBasePage - NextDescriptor->BasePage);
  498. if ((NextDescriptor->MemoryType == TypeToUse) &&
  499. (AlignedPageCount <= NextDescriptor->PageCount) &&
  500. (AlignedBasePage + AlignedPageCount > BlUsableBase) &&
  501. (AlignedBasePage <= BlUsableLimit)) {
  502. //
  503. // Adjust bounds to account for the usable limits
  504. //
  505. if (AlignedBasePage < BlUsableBase) {
  506. AlignedBasePage = (BlUsableBase + (Alignment - 1)) & ~(Alignment - 1);
  507. AlignedPageCount= NextDescriptor->PageCount - (AlignedBasePage - NextDescriptor->BasePage);
  508. }
  509. if (AlignedBasePage + AlignedPageCount > BlUsableLimit) {
  510. AlignedPageCount = BlUsableLimit - AlignedBasePage;
  511. }
  512. if (PageCount <= AlignedPageCount) {
  513. //
  514. // This block will work. If the allocation policy is
  515. // LowestFit, take this block (the memory list is sorted).
  516. // Otherwise, if this block best meets the allocation
  517. // policy, remember it and keep looking.
  518. //
  519. if (BlMemoryAllocationPolicy == BlAllocateLowestFit) {
  520. FreeDescriptor = NextDescriptor;
  521. FreeBasePage = AlignedBasePage;
  522. FreePageCount = AlignedPageCount;
  523. break;
  524. } else if ((FreeDescriptor == NULL) ||
  525. (BlMemoryAllocationPolicy == BlAllocateHighestFit) ||
  526. ((FreeDescriptor != NULL) &&
  527. (AlignedPageCount < FreePageCount))) {
  528. FreeDescriptor = NextDescriptor;
  529. FreeBasePage = AlignedBasePage;
  530. FreePageCount = AlignedPageCount;
  531. }
  532. }
  533. }
  534. NextEntry = NextEntry->Flink;
  535. }
  536. //
  537. // If a free region that satisfies the request was found, then allocate
  538. // the space from that descriptor. Otherwise, return an unsuccessful status.
  539. //
  540. // If allocating lowest-fit or best-fit, allocate from the start of the block,
  541. // rounding up to the required alignment. If allocating highest-fit, allocate
  542. // from the end of the block, rounding down to the required alignment.
  543. //
  544. if (FreeDescriptor != NULL) {
  545. #if defined(EFI)
  546. if (MemoryType == LoaderXIPRom) {
  547. FreeDescriptor->MemoryType = LoaderFirmwareTemporary;
  548. }
  549. #endif
  550. if (BlMemoryAllocationPolicy == BlAllocateHighestFit) {
  551. AlignedBasePage = (FreeBasePage + FreePageCount - PageCount) & ~(Alignment - 1);
  552. }
  553. *ActualBase = AlignedBasePage;
  554. BlpTrackUsage (TypeToUse,*ActualBase,PageCount);
  555. if (BlpCheckMapping (AlignedBasePage,PageCount+1) != ESUCCESS) {
  556. BlMemoryAllocationPolicy=OldPolicy;
  557. return (ENOMEM);
  558. }
  559. BlMemoryAllocationPolicy=OldPolicy;
  560. return BlGenerateDescriptor(FreeDescriptor,
  561. MemoryType,
  562. AlignedBasePage,
  563. PageCount);
  564. } else {
  565. //
  566. // Invade the MemoryLoaderReserve pool.
  567. //
  568. if (BlOldKernel || (retryalloc == TRUE)) {
  569. BlMemoryAllocationPolicy=OldPolicy;
  570. return ENOMEM;
  571. } else {
  572. retryalloc=TRUE;
  573. goto retry;
  574. }
  575. }
  576. }
  577. ARC_STATUS
  578. BlFreeDescriptor (
  579. IN ULONG BasePage
  580. )
  581. /*++
  582. Routine Description:
  583. This routine free the memory block starting at the specified base page.
  584. Arguments:
  585. BasePage - Supplies the base page number of the region to be freed.
  586. Return Value:
  587. ESUCCESS.
  588. --*/
  589. {
  590. PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
  591. PLIST_ENTRY NextEntry;
  592. //
  593. // Attempt to find a memory descriptor that starts at the
  594. // specified base page.
  595. //
  596. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  597. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  598. NextDescriptor = CONTAINING_RECORD(NextEntry,
  599. MEMORY_ALLOCATION_DESCRIPTOR,
  600. ListEntry);
  601. if (NextDescriptor->BasePage == BasePage) {
  602. if ((NextDescriptor->MemoryType != LoaderFree)) {
  603. NextDescriptor->MemoryType = LoaderFree;
  604. if ((NextDescriptor->BasePage+NextDescriptor->PageCount) == BlHighestPage) {
  605. //
  606. // Freeing the last descriptor. Set the highest page to 1 before us.
  607. // -- this doesn't work if the guy before is free too...but....
  608. //
  609. BlHighestPage = NextDescriptor->BasePage +1;
  610. } else if (NextDescriptor->BasePage == BlLowestPage) {
  611. BlLowestPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
  612. }
  613. BlRemoveDescriptor(NextDescriptor);
  614. BlInsertDescriptor(NextDescriptor);
  615. }
  616. return ESUCCESS;
  617. }
  618. NextEntry = NextEntry->Flink;
  619. }
  620. //
  621. // The caller is confused and should be ignored.
  622. //
  623. return ESUCCESS;
  624. }
  625. PVOID
  626. BlAllocateHeapAligned (
  627. IN ULONG Size
  628. )
  629. /*++
  630. Routine Description:
  631. This routine allocates memory from the OS loader heap. The memory
  632. will be allocated on a cache line boundary.
  633. Arguments:
  634. Size - Supplies the size of block required in bytes.
  635. Return Value:
  636. If a free block of memory of the specified size is available, then
  637. the address of the block is returned. Otherwise, NULL is returned.
  638. --*/
  639. {
  640. PVOID Buffer;
  641. Buffer = BlAllocateHeap(Size + BlDcacheFillSize - 1);
  642. if (Buffer != NULL) {
  643. //
  644. // round up to a cache line boundary
  645. //
  646. Buffer = ALIGN_BUFFER(Buffer);
  647. }
  648. return(Buffer);
  649. }
  650. PVOID
  651. BlAllocateHeap (
  652. IN ULONG Size
  653. )
  654. /*++
  655. Routine Description:
  656. This routine allocates memory from the OS loader heap.
  657. Arguments:
  658. Size - Supplies the size of block required in bytes.
  659. Return Value:
  660. If a free block of memory of the specified size is available, then
  661. the address of the block is returned. Otherwise, NULL is returned.
  662. --*/
  663. {
  664. PMEMORY_ALLOCATION_DESCRIPTOR AllocationDescriptor;
  665. PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
  666. PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
  667. PLIST_ENTRY NextEntry;
  668. ULONG NewHeapPages;
  669. ULONG LastAttempt;
  670. PVOID Block;
  671. //
  672. // Round size up to next allocation boundary and attempt to allocate
  673. // a block of the requested size.
  674. //
  675. Size = (Size + (BL_GRANULARITY - 1)) & (~(BL_GRANULARITY - 1));
  676. Block = (PVOID)BlHeapFree;
  677. if ((BlHeapFree + Size) <= BlHeapLimit) {
  678. BlHeapFree += Size;
  679. return Block;
  680. } else {
  681. #if DBG
  682. TotalHeapAbandoned += (BlHeapLimit - BlHeapFree);
  683. BlLog((LOG_ALL_W,"ABANDONING %d bytes of heap; total abandoned %d\n",
  684. (BlHeapLimit - BlHeapFree), TotalHeapAbandoned));
  685. #endif
  686. //
  687. // Our heap is full. BlHeapLimit always reserves enough space
  688. // for one more MEMORY_ALLOCATION_DESCRIPTOR, so use that to
  689. // go try and find more free memory we can use.
  690. //
  691. AllocationDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)BlHeapLimit;
  692. //
  693. // Attempt to find a free memory descriptor big enough to hold this
  694. // allocation or BL_HEAP_PAGES, whichever is bigger.
  695. //
  696. NewHeapPages = ((Size + sizeof(MEMORY_ALLOCATION_DESCRIPTOR) + (PAGE_SIZE-1)) >> PAGE_SHIFT);
  697. if (NewHeapPages < BL_HEAP_PAGES) {
  698. NewHeapPages = BL_HEAP_PAGES;
  699. }
  700. if (!BlOldKernel && BlVirtualBias) {
  701. BlHeapAllocationPolicy = BlAllocateHighestFit;
  702. }else {
  703. BlHeapAllocationPolicy = BlAllocateLowestFit;
  704. }
  705. do {
  706. FreeDescriptor = NULL;
  707. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  708. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  709. NextDescriptor = CONTAINING_RECORD(NextEntry,
  710. MEMORY_ALLOCATION_DESCRIPTOR,
  711. ListEntry);
  712. #if defined(_IA64_)
  713. //
  714. // We only have enough TR's to map the region between 16 MB
  715. // and 80 MB. So we ignore anything that's not in that range
  716. //
  717. if ((NextDescriptor->BasePage < _48MB) &&
  718. (NextDescriptor->BasePage >= _16MB)) {
  719. #endif
  720. if ((NextDescriptor->MemoryType == LoaderFree) &&
  721. (NextDescriptor->PageCount >= NewHeapPages)) {
  722. //
  723. // This block will work. If the allocation policy is
  724. // LowestFit, take this block (the memory list is sorted).
  725. // Otherwise, if this block best meets the allocation
  726. // policy, remember it and keep looking.
  727. //
  728. if (BlHeapAllocationPolicy == BlAllocateLowestFit) {
  729. FreeDescriptor = NextDescriptor;
  730. break;
  731. }
  732. if ((FreeDescriptor == NULL) ||
  733. (BlHeapAllocationPolicy == BlAllocateHighestFit) ||
  734. ((FreeDescriptor != NULL) &&
  735. (NextDescriptor->PageCount < FreeDescriptor->PageCount))) {
  736. FreeDescriptor = NextDescriptor;
  737. }
  738. }
  739. #if defined(_IA64_)
  740. }
  741. #endif
  742. NextEntry = NextEntry->Flink;
  743. }
  744. //
  745. // If we were unable to find a block of the desired size, memory
  746. // must be getting tight, so try again, this time looking just
  747. // enough to keep us going. (The first time through, we try to
  748. // allocate at least BL_HEAP_PAGES.)
  749. //
  750. if (FreeDescriptor != NULL) {
  751. break;
  752. }
  753. LastAttempt = NewHeapPages;
  754. NewHeapPages = ((Size + sizeof(MEMORY_ALLOCATION_DESCRIPTOR) + (PAGE_SIZE-1)) >> PAGE_SHIFT);
  755. if (NewHeapPages == LastAttempt) {
  756. break;
  757. }
  758. } while (TRUE);
  759. if (FreeDescriptor == NULL) {
  760. //
  761. // No free memory left.
  762. //
  763. return(NULL);
  764. }
  765. //
  766. // We've found a descriptor that's big enough. Just carve a
  767. // piece off the end and use that for our heap. If we're taking
  768. // all of the memory from the descriptor, remove it from the
  769. // memory list. (This wastes a descriptor, but that's life.)
  770. //
  771. FreeDescriptor->PageCount -= NewHeapPages;
  772. if (FreeDescriptor->PageCount == 0) {
  773. BlRemoveDescriptor(FreeDescriptor);
  774. }
  775. //
  776. // Initialize our new descriptor and add it to the list.
  777. //
  778. AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
  779. AllocationDescriptor->BasePage = FreeDescriptor->BasePage +
  780. FreeDescriptor->PageCount;
  781. AllocationDescriptor->PageCount = NewHeapPages;
  782. BlpTrackUsage (LoaderOsloaderHeap,AllocationDescriptor->BasePage,AllocationDescriptor->PageCount);
  783. BlInsertDescriptor(AllocationDescriptor);
  784. //
  785. // initialize new heap values and return pointer to newly
  786. // alloc'd memory.
  787. //
  788. BlHeapFree = KSEG0_BASE | (AllocationDescriptor->BasePage << PAGE_SHIFT);
  789. BlHeapLimit = (BlHeapFree + (NewHeapPages << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
  790. RtlZeroMemory((PVOID)BlHeapFree, NewHeapPages << PAGE_SHIFT);
  791. Block = (PVOID)BlHeapFree;
  792. if ((BlHeapFree + Size) < BlHeapLimit) {
  793. BlHeapFree += Size;
  794. return Block;
  795. } else {
  796. //
  797. // we should never get here
  798. //
  799. return(NULL);
  800. }
  801. }
  802. }
  803. VOID
  804. BlGenerateNewHeap (
  805. IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
  806. IN ULONG BasePage,
  807. IN ULONG PageCount
  808. )
  809. /*++
  810. Routine Description:
  811. This routine allocates a new heap block from the specified memory
  812. descriptor, avoiding the region specified by BasePage and PageCount.
  813. The caller must ensure that this region does not encompass the entire
  814. block.
  815. The allocated heap block may be as small as a single page.
  816. Arguments:
  817. MemoryDescriptor - Supplies a pointer to a free memory descriptor
  818. from which the heap block is to be allocated.
  819. BasePage - Supplies the base page number of the excluded region.
  820. PageCount - Supplies the number of pages in the excluded region.
  821. Return Value:
  822. None.
  823. --*/
  824. {
  825. PMEMORY_ALLOCATION_DESCRIPTOR AllocationDescriptor;
  826. ULONG NewHeapPages;
  827. ULONG AvailableAtFront;
  828. ULONG AvailableAtBack;
  829. //
  830. // BlHeapLimit always reserves enough space for one more
  831. // MEMORY_ALLOCATION_DESCRIPTOR, so use that to describe the
  832. // new heap block.
  833. //
  834. AllocationDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)BlHeapLimit;
  835. //
  836. // Allocate the new heap from either the front or the back of the
  837. // specified descriptor, whichever fits best. We'd like to allocate
  838. // BL_HEAP_PAGES pages, but we'll settle for less.
  839. //
  840. AvailableAtFront = BasePage - MemoryDescriptor->BasePage;
  841. AvailableAtBack = (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) -
  842. (BasePage + PageCount);
  843. if ((AvailableAtFront == 0) ||
  844. ((AvailableAtBack != 0) && (AvailableAtBack < AvailableAtFront))) {
  845. NewHeapPages = MIN(AvailableAtBack, BL_HEAP_PAGES);
  846. AllocationDescriptor->BasePage =
  847. MemoryDescriptor->BasePage + MemoryDescriptor->PageCount - NewHeapPages;
  848. } else {
  849. NewHeapPages = MIN(AvailableAtFront, BL_HEAP_PAGES);
  850. AllocationDescriptor->BasePage = MemoryDescriptor->BasePage;
  851. MemoryDescriptor->BasePage += NewHeapPages;
  852. }
  853. MemoryDescriptor->PageCount -= NewHeapPages;
  854. //
  855. // Initialize our new descriptor and add it to the list.
  856. //
  857. AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
  858. AllocationDescriptor->PageCount = NewHeapPages;
  859. BlInsertDescriptor(AllocationDescriptor);
  860. //
  861. // Initialize new heap values.
  862. //
  863. BlpTrackUsage (LoaderOsloaderHeap,AllocationDescriptor->BasePage,AllocationDescriptor->PageCount);
  864. BlHeapFree = KSEG0_BASE | (AllocationDescriptor->BasePage << PAGE_SHIFT);
  865. BlHeapLimit = (BlHeapFree + (NewHeapPages << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
  866. RtlZeroMemory((PVOID)BlHeapFree, NewHeapPages << PAGE_SHIFT);
  867. return;
  868. }
  869. ARC_STATUS
  870. BlGenerateDescriptor (
  871. IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
  872. IN MEMORY_TYPE MemoryType,
  873. IN ULONG BasePage,
  874. IN ULONG PageCount
  875. )
  876. /*++
  877. Routine Description:
  878. This routine allocates a new memory descriptor to describe the
  879. specified region of memory which is assumed to lie totally within
  880. the specified region which is free.
  881. Arguments:
  882. MemoryDescriptor - Supplies a pointer to a free memory descriptor
  883. from which the specified memory is to be allocated.
  884. MemoryType - Supplies the type that is assigned to the allocated
  885. memory.
  886. BasePage - Supplies the base page number.
  887. PageCount - Supplies the number of pages.
  888. Return Value:
  889. ESUCCESS is returned if a descriptor(s) is successfully generated.
  890. Otherwise, return an unsuccessful status.
  891. --*/
  892. {
  893. PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor1;
  894. PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor2;
  895. LONG Offset;
  896. TYPE_OF_MEMORY OldType;
  897. BOOLEAN SecondDescriptorNeeded;
  898. //
  899. // If the allocation is for zero pages, make it one, because allocation of zero
  900. // breaks the internal algorithms for merging, etc.
  901. //
  902. if (PageCount == 0) {
  903. PageCount = 1;
  904. }
  905. //
  906. // If the specified region totally consumes the free region, then no
  907. // additional descriptors need to be allocated. If the specified region
  908. // is at the start or end of the free region, then only one descriptor
  909. // needs to be allocated. Otherwise, two additional descriptors need to
  910. // be allocated.
  911. //
  912. Offset = BasePage - MemoryDescriptor->BasePage;
  913. if ((Offset == 0) && (PageCount == MemoryDescriptor->PageCount)) {
  914. //
  915. // The specified region totally consumes the free region.
  916. //
  917. MemoryDescriptor->MemoryType = MemoryType;
  918. } else {
  919. //
  920. // Mark the entire given memory descriptor as in use. If we are
  921. // out of heap, BlAllocateHeap will search for a new descriptor
  922. // to grow the heap and this prevents both routines from trying
  923. // to use the same descriptor.
  924. //
  925. OldType = MemoryDescriptor->MemoryType;
  926. MemoryDescriptor->MemoryType = LoaderSpecialMemory;
  927. //
  928. // A memory descriptor must be generated to describe the allocated
  929. // memory.
  930. //
  931. SecondDescriptorNeeded =
  932. (BOOLEAN)((BasePage != MemoryDescriptor->BasePage) &&
  933. ((ULONG)(Offset + PageCount) != MemoryDescriptor->PageCount));
  934. NewDescriptor1 = BlAllocateHeap( sizeof(MEMORY_ALLOCATION_DESCRIPTOR) );
  935. //
  936. // If allocation of the first additional memory descriptor failed,
  937. // then generate new heap using the block from which we are
  938. // allocating. This can only be done if the block is free.
  939. //
  940. // Note that BlGenerateNewHeap cannot fail, because we know there is
  941. // at least one more page in the block than we want to take from it.
  942. //
  943. // Note also that the allocation following BlGenerateNewHeap is
  944. // guaranteed to succeed.
  945. //
  946. if (NewDescriptor1 == NULL) {
  947. if (OldType != LoaderFree) {
  948. MemoryDescriptor->MemoryType = OldType;
  949. return ENOMEM;
  950. }
  951. BlGenerateNewHeap(MemoryDescriptor, BasePage, PageCount);
  952. NewDescriptor1 = BlAllocateHeap( sizeof(MEMORY_ALLOCATION_DESCRIPTOR) );
  953. //
  954. // Recompute offset, as the base page of the memory descriptor
  955. // has been changed by BlGenerateNewHeap
  956. //
  957. Offset = BasePage - MemoryDescriptor->BasePage;
  958. }
  959. //
  960. // If a second descriptor is needed, allocate it. As above, if the
  961. // allocation fails, generate new heap using our block.
  962. //
  963. // Note that if BlGenerateNewHeap was called above, the first call
  964. // to BlAllocateHeap below will not fail. (So we won't call
  965. // BlGenerateNewHeap twice.)
  966. //
  967. if (SecondDescriptorNeeded) {
  968. NewDescriptor2 = BlAllocateHeap( sizeof(MEMORY_ALLOCATION_DESCRIPTOR) );
  969. if (NewDescriptor2 == NULL) {
  970. if (OldType != LoaderFree) {
  971. MemoryDescriptor->MemoryType = OldType;
  972. return ENOMEM;
  973. }
  974. BlGenerateNewHeap(MemoryDescriptor, BasePage, PageCount);
  975. NewDescriptor2 = BlAllocateHeap( sizeof(MEMORY_ALLOCATION_DESCRIPTOR) );
  976. Offset = BasePage - MemoryDescriptor->BasePage;
  977. }
  978. }
  979. NewDescriptor1->MemoryType = MemoryType;
  980. NewDescriptor1->BasePage = BasePage;
  981. NewDescriptor1->PageCount = PageCount;
  982. if (BasePage == MemoryDescriptor->BasePage) {
  983. //
  984. // The specified region lies at the start of the free region.
  985. //
  986. MemoryDescriptor->BasePage += PageCount;
  987. MemoryDescriptor->PageCount -= PageCount;
  988. MemoryDescriptor->MemoryType = OldType;
  989. } else if ((ULONG)(Offset + PageCount) == MemoryDescriptor->PageCount) {
  990. //
  991. // The specified region lies at the end of the free region.
  992. //
  993. MemoryDescriptor->PageCount -= PageCount;
  994. MemoryDescriptor->MemoryType = OldType;
  995. } else {
  996. //
  997. // The specified region lies in the middle of the free region.
  998. //
  999. NewDescriptor2->MemoryType = OldType;
  1000. NewDescriptor2->BasePage = BasePage + PageCount;
  1001. NewDescriptor2->PageCount =
  1002. MemoryDescriptor->PageCount - (PageCount + Offset);
  1003. MemoryDescriptor->PageCount = Offset;
  1004. MemoryDescriptor->MemoryType = OldType;
  1005. BlInsertDescriptor(NewDescriptor2);
  1006. }
  1007. BlInsertDescriptor(NewDescriptor1);
  1008. }
  1009. BlpTrackUsage (MemoryType,BasePage,PageCount);
  1010. return ESUCCESS;
  1011. }
  1012. PMEMORY_ALLOCATION_DESCRIPTOR
  1013. BlFindMemoryDescriptor(
  1014. IN ULONG BasePage
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. Finds the memory allocation descriptor that contains the given page.
  1019. Arguments:
  1020. BasePage - Supplies the page whose allocation descriptor is to be found.
  1021. Return Value:
  1022. != NULL - Pointer to the requested memory allocation descriptor
  1023. == NULL - indicates no memory descriptor contains the given page
  1024. --*/
  1025. {
  1026. PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor=NULL;
  1027. PLIST_ENTRY NextEntry;
  1028. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  1029. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  1030. MemoryDescriptor = CONTAINING_RECORD(NextEntry,
  1031. MEMORY_ALLOCATION_DESCRIPTOR,
  1032. ListEntry);
  1033. if ((MemoryDescriptor->BasePage <= BasePage) &&
  1034. (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > BasePage)) {
  1035. //
  1036. // Found it.
  1037. //
  1038. break;
  1039. }
  1040. NextEntry = NextEntry->Flink;
  1041. }
  1042. if (NextEntry == &BlLoaderBlock->MemoryDescriptorListHead) {
  1043. return(NULL);
  1044. } else {
  1045. return(MemoryDescriptor);
  1046. }
  1047. }
  1048. #ifdef SETUP
  1049. PMEMORY_ALLOCATION_DESCRIPTOR
  1050. BlFindFreeMemoryBlock(
  1051. IN ULONG PageCount
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. Find a free memory block of at least a given size (using a best-fit
  1056. algorithm) or find the largest free memory block.
  1057. Arguments:
  1058. PageCount - supplies the size in pages of the block. If this is 0,
  1059. then find the largest free block.
  1060. Return Value:
  1061. Pointer to the memory allocation descriptor for the block or NULL if
  1062. no block could be found matching the search criteria.
  1063. --*/
  1064. {
  1065. PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
  1066. PMEMORY_ALLOCATION_DESCRIPTOR FoundMemoryDescriptor=NULL;
  1067. PLIST_ENTRY NextEntry;
  1068. ULONG LargestSize = 0;
  1069. ULONG SmallestLeftOver = (ULONG)(-1);
  1070. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  1071. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  1072. MemoryDescriptor = CONTAINING_RECORD(NextEntry,
  1073. MEMORY_ALLOCATION_DESCRIPTOR,
  1074. ListEntry);
  1075. if (MemoryDescriptor->MemoryType == LoaderFree) {
  1076. if(PageCount) {
  1077. //
  1078. // Looking for a block of a specific size.
  1079. //
  1080. if((MemoryDescriptor->PageCount >= PageCount)
  1081. && (MemoryDescriptor->PageCount - PageCount < SmallestLeftOver))
  1082. {
  1083. SmallestLeftOver = MemoryDescriptor->PageCount - PageCount;
  1084. FoundMemoryDescriptor = MemoryDescriptor;
  1085. }
  1086. } else {
  1087. //
  1088. // Looking for the largest free block.
  1089. //
  1090. if(MemoryDescriptor->PageCount > LargestSize) {
  1091. LargestSize = MemoryDescriptor->PageCount;
  1092. FoundMemoryDescriptor = MemoryDescriptor;
  1093. }
  1094. }
  1095. }
  1096. NextEntry = NextEntry->Flink;
  1097. }
  1098. return(FoundMemoryDescriptor);
  1099. }
  1100. ULONG
  1101. BlDetermineTotalMemory(
  1102. VOID
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. Determine the total amount of memory in the machine.
  1107. Arguments:
  1108. None.
  1109. Return Value:
  1110. Total amount of memory in the system, in bytes.
  1111. --*/
  1112. {
  1113. PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
  1114. PLIST_ENTRY NextEntry;
  1115. ULONG PageCount;
  1116. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  1117. PageCount = 0;
  1118. while(NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  1119. MemoryDescriptor = CONTAINING_RECORD(NextEntry,
  1120. MEMORY_ALLOCATION_DESCRIPTOR,
  1121. ListEntry);
  1122. PageCount += MemoryDescriptor->PageCount;
  1123. #if i386
  1124. //
  1125. // Note: on x86 machines, we never use the 40h pages below the 16
  1126. // meg line (bios shadow area). But we want to account for them here,
  1127. // so check for this case.
  1128. //
  1129. if(MemoryDescriptor->BasePage + MemoryDescriptor->PageCount == 0xfc0) {
  1130. PageCount += 0x40;
  1131. }
  1132. #endif
  1133. NextEntry = NextEntry->Flink;
  1134. }
  1135. return(PageCount << PAGE_SHIFT);
  1136. }
  1137. #endif // def SETUP
  1138. ULONG
  1139. HbPageDisposition (
  1140. IN PFN_NUMBER Page
  1141. )
  1142. {
  1143. static PLIST_ENTRY Entry;
  1144. PLIST_ENTRY Start;
  1145. PMEMORY_ALLOCATION_DESCRIPTOR MemDesc;
  1146. ULONG Disposition;
  1147. //
  1148. // Check to see if page is in the range of the last descritor looked at.
  1149. //
  1150. if (Entry) {
  1151. MemDesc = CONTAINING_RECORD(Entry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
  1152. if (Page >= MemDesc->BasePage && Page < MemDesc->BasePage + MemDesc->PageCount) {
  1153. goto Done;
  1154. }
  1155. }
  1156. //
  1157. // Find descriptor describing this page
  1158. //
  1159. if (!Entry) {
  1160. Entry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  1161. }
  1162. Start = Entry;
  1163. for (; ;) {
  1164. if (Entry != &BlLoaderBlock->MemoryDescriptorListHead) {
  1165. MemDesc = CONTAINING_RECORD(Entry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
  1166. if (Page >= MemDesc->BasePage && Page < MemDesc->BasePage + MemDesc->PageCount) {
  1167. goto Done;
  1168. }
  1169. }
  1170. Entry = Entry->Flink;
  1171. if (Entry == Start) {
  1172. //
  1173. // Descriptor for this page was not found
  1174. //
  1175. return HbPageInvalid;
  1176. }
  1177. }
  1178. Done:
  1179. //
  1180. // Convert memory type to the proper disposition
  1181. //
  1182. switch (MemDesc->MemoryType) {
  1183. case LoaderFree:
  1184. case LoaderReserve:
  1185. Disposition = HbPageNotInUse;
  1186. break;
  1187. case LoaderBad:
  1188. Disposition = HbPageInvalid;
  1189. break;
  1190. case LoaderFirmwareTemporary:
  1191. //
  1192. // On x86 systems memory above 16Mb is marked as firmware temporary
  1193. // by i386\memory.c to prevent the loader from typically trying to
  1194. // map it
  1195. //
  1196. Disposition = HbPageInUseByLoader;
  1197. #if i386
  1198. if (Page > ((ULONG)0x1000000 >> PAGE_SHIFT)) {
  1199. Disposition = HbPageNotInUse;
  1200. }
  1201. #endif
  1202. break;
  1203. default:
  1204. Disposition = HbPageInUseByLoader;
  1205. break;
  1206. }
  1207. return Disposition;
  1208. }
  1209. VOID
  1210. BlpTruncateDescriptors (
  1211. IN ULONG HighestPage
  1212. )
  1213. /*++
  1214. Routine Description:
  1215. This routine locates and truncates or removes any memory located in a
  1216. page above HighestPage from the memory descriptor list in the loader
  1217. block.
  1218. Arguments:
  1219. HighestPage - Supplies the physical page number above which we are to
  1220. remove all pages.
  1221. Return Value:
  1222. None.
  1223. --*/
  1224. {
  1225. PLIST_ENTRY listHead;
  1226. PLIST_ENTRY listEntry;
  1227. PMEMORY_ALLOCATION_DESCRIPTOR descriptor;
  1228. ULONG lastDescriptorPage;
  1229. listHead = &BlLoaderBlock->MemoryDescriptorListHead;
  1230. listEntry = listHead->Flink;
  1231. while (listEntry != listHead) {
  1232. descriptor = CONTAINING_RECORD( listEntry,
  1233. MEMORY_ALLOCATION_DESCRIPTOR,
  1234. ListEntry );
  1235. //
  1236. // Determine the page number of the last page in this descriptor
  1237. //
  1238. lastDescriptorPage = descriptor->BasePage +
  1239. descriptor->PageCount - 1;
  1240. if (lastDescriptorPage <= HighestPage) {
  1241. //
  1242. // None of the memory described by this descriptor is above
  1243. // HighestPage. Ignore this descriptor.
  1244. //
  1245. } else if (descriptor->BasePage > HighestPage) {
  1246. //
  1247. // All of this descriptor is above HighestPage. Remove it.
  1248. //
  1249. BlRemoveDescriptor( descriptor );
  1250. } else {
  1251. //
  1252. // Some but not all of the memory described by this descriptor lies
  1253. // above HighestPage. Truncate it.
  1254. //
  1255. descriptor->PageCount = HighestPage - descriptor->BasePage + 1;
  1256. }
  1257. listEntry = listEntry->Flink;
  1258. }
  1259. }
  1260. TYPE_OF_MEMORY
  1261. BlpDetermineAllocationPolicy (
  1262. TYPE_OF_MEMORY MemoryType,
  1263. ULONG BasePage,
  1264. ULONG PageCount,
  1265. BOOLEAN retry
  1266. )
  1267. {
  1268. TYPE_OF_MEMORY TypeToUse;
  1269. //
  1270. // Give the restore code buffers as low as possible to avoid double buffering
  1271. //
  1272. if (BlRestoring == TRUE) {
  1273. BlMemoryAllocationPolicy = BlAllocateLowestFit;
  1274. return (LoaderFree);
  1275. }
  1276. if (MemoryType == LoaderXIPRom) {
  1277. #ifndef EFI
  1278. if (PageCount <= (4*1024*1024 >> PAGE_SHIFT)) {
  1279. TypeToUse = (retry) ? LoaderReserve:LoaderFree;
  1280. BlMemoryAllocationPolicy = BlAllocateLowestFit;
  1281. } else {
  1282. TypeToUse = LoaderReserve;
  1283. BlMemoryAllocationPolicy = BlAllocateHighestFit;
  1284. }
  1285. #else
  1286. TypeToUse = LoaderReserve;
  1287. BlMemoryAllocationPolicy = BlAllocateHighestFit;
  1288. #endif
  1289. return TypeToUse;
  1290. }
  1291. #ifndef EFI
  1292. if (BlVirtualBias != 0) {
  1293. //
  1294. // Booted /3GB
  1295. //
  1296. // With a 5.0 or prior kernel, allocate from the bottom
  1297. // up (this loader will never run setup)
  1298. //
  1299. if (!BlOldKernel) {
  1300. if (IsTrackMem (MemoryType)){
  1301. // We care about this allocation.
  1302. // Allocations from reserve are done lowest fit (growing up from 16MB)
  1303. // Allocations from free are done highest fit (growing down from 16MB)
  1304. TypeToUse = (retry) ? LoaderReserve : LoaderFree;
  1305. BlMemoryAllocationPolicy = (retry) ? BlAllocateLowestFit : BlAllocateHighestFit;
  1306. } else {
  1307. TypeToUse = (retry) ? LoaderReserve : LoaderFree;
  1308. BlMemoryAllocationPolicy = BlAllocateLowestFit;
  1309. }
  1310. } else {
  1311. //
  1312. // Old kernel, load the kernel at the bottom
  1313. //
  1314. TypeToUse = LoaderFree;
  1315. if (IsTrackMem (MemoryType) || (MemoryType == LoaderOsloaderHeap)) {
  1316. // We care about this allocation.
  1317. BlMemoryAllocationPolicy = BlAllocateLowestFit;
  1318. } else {
  1319. BlMemoryAllocationPolicy = BlAllocateHighestFit;
  1320. }
  1321. }
  1322. } else
  1323. #endif
  1324. {
  1325. if (!IsTrackMem (MemoryType)) {
  1326. // We don't care about this allocation.
  1327. TypeToUse = (retry) ? LoaderFree:LoaderReserve;
  1328. BlMemoryAllocationPolicy = BlAllocateHighestFit;
  1329. } else {
  1330. BlMemoryAllocationPolicy = BlAllocateLowestFit;
  1331. TypeToUse = (retry) ? LoaderReserve : LoaderFree;
  1332. }
  1333. }
  1334. if (BlOldKernel) {
  1335. TypeToUse = LoaderFree;
  1336. }
  1337. return (TypeToUse);
  1338. }
  1339. void
  1340. BlpTrackUsage (
  1341. MEMORY_TYPE MemoryType,
  1342. ULONG ActualBase,
  1343. ULONG NumberPages
  1344. )
  1345. {
  1346. if (BlRestoring || !(IsTrackMem (MemoryType)) || BlOldKernel ||
  1347. !IsValidTrackingRange (ActualBase,NumberPages)) {
  1348. //
  1349. // Don't track
  1350. //
  1351. return;
  1352. }
  1353. if ((ActualBase+NumberPages) > BlHighestPage) {
  1354. BlHighestPage = ActualBase+NumberPages;
  1355. }
  1356. if ((BlLowestPage == 0) || (BlLowestPage < ActualBase) ) {
  1357. BlLowestPage = ActualBase;
  1358. }
  1359. }