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.

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