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.

1115 lines
30 KiB

  1. /*++
  2. Copyright (c) 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. memory.c
  5. Abstract:
  6. This module sets up the memory subsystem so that virtual addresses map 1:1
  7. with physical addresses. It also tweaks the EFI-supplied memory map for
  8. use by the loader. This mapping occurs as follows:
  9. Memory Map used by NTLDR:
  10. 0 - 1MB Legacy BIOS area, marked as unusable
  11. 32 MB - 48 MB used for diamond decompression engine
  12. 48 MB - 64 MB used for loading kernel and hal (the kernel must be loaded on a 16 MB boundary)
  13. 64 MB - 128 MB used for loading drivers
  14. There are not enough TRs to map all memory, so any other memory has a
  15. straight 1-1 translation. Since we use KSEG for our addresses, this
  16. means that these ranges are effectively unaddressable.
  17. Author:
  18. John Vert (jvert) 18-Jun-1991
  19. Environment:
  20. Kernel Mode
  21. Revision History:
  22. Andrew Ritz (andrewr) 15-Dec-2000 - added comments and major cleanup for
  23. running under EFI
  24. --*/
  25. #include "arccodes.h"
  26. #include "bootia64.h"
  27. #include "efi.h"
  28. extern EFI_SYSTEM_TABLE *EfiST;
  29. WCHAR DebugBuffer[512];
  30. //
  31. // Current heap start pointers (physical addresses)
  32. // Note that 0x50000 to 0x5ffff is reserved for detection configuration memory
  33. //
  34. #if FW_HEAP
  35. ULONG_PTR FwPermanentHeap = PERMANENT_HEAP_START * PAGE_SIZE;
  36. ULONG_PTR FwTemporaryHeap = (TEMPORARY_HEAP_START * PAGE_SIZE) - 0x10000;
  37. //
  38. // Current pool pointers. This is different than the temporary/permanent
  39. // heaps, because it is not required to be under 1MB. It is used by the
  40. // SCSI miniports for allocating their extensions and for the dbcs font image.
  41. //
  42. #define FW_POOL_SIZE (0x40000/PAGE_SIZE)
  43. ULONG_PTR FwPoolStart;
  44. ULONG_PTR FwPoolEnd;
  45. //
  46. // This gets set to FALSE right before we call into the osloader, so we
  47. // know that the fw memory descriptors can no longer be changed at will.
  48. //
  49. BOOLEAN FwDescriptorsValid = TRUE;
  50. #endif
  51. //
  52. // External function prototypes
  53. //
  54. extern
  55. ARC_STATUS
  56. MempGoVirtual (
  57. VOID
  58. );
  59. //
  60. // Private function prototypes
  61. //
  62. ARC_STATUS
  63. MempAllocDescriptor(
  64. IN ULONG StartPage,
  65. IN ULONG EndPage,
  66. IN TYPE_OF_MEMORY MemoryType
  67. );
  68. ARC_STATUS
  69. MempSetDescriptorRegion (
  70. IN ULONG StartPage,
  71. IN ULONG EndPage,
  72. IN TYPE_OF_MEMORY MemoryType
  73. );
  74. //
  75. // Global - memory management variables.
  76. //
  77. PHARDWARE_PTE PDE;
  78. PHARDWARE_PTE HalPT;
  79. //
  80. // Global memory array that is used by the loader to construct the
  81. // MemoryDescriptorList which is passed into the OS.
  82. //
  83. PMEMORY_DESCRIPTOR MDArray;
  84. //
  85. // These help us keep track of the memory descriptor array and are used
  86. // in the allocation and insertion routines
  87. //
  88. ULONG NumberDescriptors=0;
  89. ULONG MaxDescriptors=0;
  90. extern GoneVirtual;
  91. ARC_STATUS
  92. InitializeMemorySubsystem(
  93. PBOOT_CONTEXT BootContext
  94. )
  95. /*++
  96. Routine Description:
  97. The initial heap is mapped and allocated. Pointers to the
  98. Page directory and page tables are initialized.
  99. Arguments:
  100. BootContext - Supplies basic information provided by SU module.
  101. Returns:
  102. ESUCCESS - Memory succesfully initialized.
  103. --*/
  104. {
  105. ARC_STATUS Status = ESUCCESS;
  106. PMEMORY_DESCRIPTOR SuMemory;
  107. ULONG PageStart;
  108. ULONG PageEnd;
  109. extern BOOLEAN isOSCHOICE;
  110. //
  111. // We already have memory descriptors that describe the physical memory
  112. // layout on the system. We must walk this list and do some tweaking
  113. // to describe our memory layout.
  114. //
  115. SuMemory = MDArray;
  116. while (SuMemory->PageCount != 0) {
  117. PageStart = SuMemory->BasePage;
  118. PageEnd = SuMemory->BasePage+SuMemory->PageCount;
  119. #if DBG_MEMORY
  120. wsprintf( DebugBuffer, L"PageStart (%x), PageEnd (%x), Type (%x)\r\n", PageStart, PageEnd, SuMemory->MemoryType);
  121. EfiPrint(DebugBuffer);
  122. DBG_EFI_PAUSE();
  123. #endif
  124. //
  125. // we have no TRs for memory under 32MB so we can't use it in
  126. // the loader -- mark it as off limits
  127. //
  128. // Note: PageStart could be 0, so don't check for (PageStart >= _1MB) at this point.
  129. //
  130. if ((PageStart < _32MB) &&
  131. (SuMemory->MemoryType == MemoryFree)) {
  132. ULONG TmpPageEnd = (PageEnd > _32MB) ? _32MB : PageEnd;
  133. Status = MempAllocDescriptor( PageStart, TmpPageEnd,
  134. MemoryFirmwareTemporary );
  135. if (Status != ESUCCESS) {
  136. break;
  137. }
  138. PageStart = TmpPageEnd;
  139. if (PageStart != PageEnd ) {
  140. SuMemory->PageCount -= (PageStart - SuMemory->BasePage);
  141. SuMemory->BasePage = PageStart;
  142. }
  143. }
  144. //
  145. // Move to the next memory descriptor
  146. //
  147. ++SuMemory;
  148. }
  149. if (Status != ESUCCESS) {
  150. #if DBG
  151. wsprintf( DebugBuffer, TEXT("MempSetDescriptorRegion failed %lx\n"),Status);
  152. EfiPrint(DebugBuffer);
  153. #endif
  154. return(Status);
  155. }
  156. //
  157. // Describe the BIOS area. We are essentially burning the 1st Meg so the OS
  158. // can do legacy INT emulation.
  159. //
  160. // Note: EFI marks the 1st Meg as "boot services data" so that it won't
  161. // touch it. Once we get into the OS, we need to preserve this same
  162. // hack (for video card frame buffer, etc). We only really need to preserve
  163. // 640K - 1MB, but there is a dependency in the x86 emulation code in the
  164. // Hal upon this region being zero-based. So we burn 640K, and that's life.
  165. //
  166. #if DBG_MEMORY
  167. wsprintf( DebugBuffer, L"Mark 'BIOS' region %x - %x as firmware permanent\r\n", 0, ROM_END_PAGE );
  168. EfiPrint(DebugBuffer);
  169. #endif
  170. MempSetDescriptorRegion(0, ROM_END_PAGE, MemoryFirmwarePermanent);
  171. if ((BootContext->MediaType == BootMediaTcpip) &&
  172. (isOSCHOICE == FALSE)) {
  173. //
  174. // We RIS-booted setupldr, so make sure 32-128MB is clear.
  175. // when running oschooser, this memory was used for
  176. // the loader's heap, etc. therefore, it is probably
  177. // marked with the memory type firmware temporary.
  178. // reclaim it, marking it as free.
  179. //
  180. Status = MempSetDescriptorRegion(_32MB,
  181. _128MB,
  182. MemoryFree);
  183. if( Status != ESUCCESS ) {
  184. EfiPrint(TEXT("Failed to reclaim 32MB to 128MB!!!"));
  185. }
  186. }
  187. //
  188. // Make 48mb - 64mb reserved for kernel and 64mb - 128mb reserved for
  189. // driver loading
  190. //
  191. // THIS IS A HACK - the code in blmemory.c:BlMemoryInitialize that
  192. // allocates a region for the heap requires the descriptor the heap will
  193. // be carved from to be completely contained in the region the heap must
  194. // be allocated in. We require the heap to reside in the driver region.
  195. // The high boundary for this region was preserved from the call in sumain
  196. // to memdesc.c:ConstructArcMemoryDescriptorsWithAllocation. To ensure the
  197. // the lower boundary, allocate 1 page of FirmwareTemporary memory.
  198. //
  199. #if DBG_MEMORY
  200. wsprintf( DebugBuffer, L"Mark region %x - %x for systemblock\r\n", _48MB, _80MB );
  201. EfiPrint(DebugBuffer);
  202. #endif
  203. Status = MempAllocDescriptor(BL_DRIVER_RANGE_LOW - 1,
  204. BL_DRIVER_RANGE_LOW,
  205. MemoryFirmwareTemporary);
  206. if (Status != ESUCCESS) {
  207. #if DBG
  208. wsprintf( DebugBuffer, L"Mark systemblock region failed %x\r\n", Status );
  209. EfiPrint(DebugBuffer);
  210. #endif
  211. return(Status);
  212. }
  213. #if 0
  214. #if DBG_MEMORY
  215. SuMemory = MDArray;
  216. while (SuMemory->PageCount != 0) {
  217. PageStart = SuMemory->BasePage;
  218. PageEnd = SuMemory->BasePage+SuMemory->PageCount;
  219. wsprintf( DebugBuffer, L"dumpmem: PageStart (%x), PageEnd (%x), Type (%x)\r\n", PageStart, PageEnd, SuMemory->MemoryType);
  220. EfiPrint(DebugBuffer);
  221. DBG_EFI_PAUSE();
  222. ++SuMemory;
  223. }
  224. #endif
  225. #endif
  226. #if DBG
  227. EfiPrint(TEXT("About to Go Virtual\r\n") );
  228. #endif
  229. //
  230. // Setup TR's used by the NT loader and go into virtual addressing mode.
  231. //
  232. if ((BootContext->MediaType != BootMediaTcpip) ||
  233. (isOSCHOICE == TRUE)) {
  234. #if DBG
  235. EfiPrint(TEXT("Really going virtual\r\n") );
  236. #endif
  237. Status = MempGoVirtual();
  238. }
  239. else {
  240. //
  241. // always leave this function in virtual mode
  242. // for consistency
  243. //
  244. FlipToVirtual();
  245. }
  246. GoneVirtual = TRUE;
  247. if (Status != ESUCCESS) {
  248. return(Status);
  249. }
  250. return(Status);
  251. }
  252. ARC_STATUS
  253. MempSetDescriptorRegion (
  254. IN ULONG StartPage,
  255. IN ULONG EndPage,
  256. IN TYPE_OF_MEMORY MemoryType
  257. )
  258. /*++
  259. Routine Description:
  260. This function sets a range to the corresponding memory type.
  261. Descriptors will be removed, modified, inserted as needed to
  262. set the specified range.
  263. Arguments:
  264. StartPage - Supplies the beginning page of the new memory descriptor
  265. EndPage - Supplies the ending page of the new memory descriptor
  266. MemoryType - Supplies the type of memory of the new memory descriptor
  267. Return Value:
  268. ESUCCESS - Memory descriptor succesfully added to MDL array
  269. ENOMEM - MDArray is full.
  270. --*/
  271. {
  272. ULONG i;
  273. ULONG sp, ep;
  274. TYPE_OF_MEMORY mt;
  275. BOOLEAN RegionAdded;
  276. if (EndPage <= StartPage) {
  277. //
  278. // This is a completely bogus memory descriptor. Ignore it.
  279. //
  280. #ifdef LOADER_DEBUG
  281. wsprintf( DebugBuffer, TEXT("Attempt to create invalid memory descriptor %lx - %lx\n"),
  282. StartPage,EndPage);
  283. EfiPrint(DebugBuffer);
  284. #endif
  285. return(ESUCCESS);
  286. }
  287. RegionAdded = FALSE;
  288. //
  289. // Clip, remove, any descriptors in target area
  290. //
  291. for (i=0; i < NumberDescriptors; i++) {
  292. sp = MDArray[i].BasePage;
  293. ep = MDArray[i].BasePage + MDArray[i].PageCount;
  294. mt = MDArray[i].MemoryType;
  295. if (sp < StartPage) {
  296. if (ep > StartPage && ep <= EndPage) {
  297. // truncate this descriptor
  298. ep = StartPage;
  299. }
  300. if (ep > EndPage) {
  301. //
  302. // Target area is contained totally within this
  303. // descriptor. Split the descriptor into two ranges
  304. //
  305. if (NumberDescriptors == MaxDescriptors) {
  306. #if DBG
  307. wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
  308. EfiPrint(DebugBuffer);
  309. #endif
  310. return(ENOMEM);
  311. }
  312. //
  313. // Add descriptor for EndPage - ep
  314. //
  315. MDArray[NumberDescriptors].MemoryType = mt;
  316. MDArray[NumberDescriptors].BasePage = EndPage;
  317. MDArray[NumberDescriptors].PageCount = ep - EndPage;
  318. NumberDescriptors += 1;
  319. //
  320. // Adjust current descriptor for sp - StartPage
  321. //
  322. ep = StartPage;
  323. }
  324. } else {
  325. // sp >= StartPage
  326. if (sp < EndPage) {
  327. if (ep < EndPage) {
  328. //
  329. // This descriptor is totally within the target area -
  330. // remove it
  331. //
  332. ep = sp;
  333. } else {
  334. // bump begining page of this descriptor
  335. sp = EndPage;
  336. }
  337. }
  338. }
  339. //
  340. // Check if the new range can be appended or prepended to
  341. // this descriptor
  342. //
  343. if (mt == MemoryType && !RegionAdded) {
  344. if (sp == EndPage) {
  345. // prepend region being set
  346. sp = StartPage;
  347. RegionAdded = TRUE;
  348. } else if (ep == StartPage) {
  349. // append region being set
  350. ep = EndPage;
  351. RegionAdded = TRUE;
  352. }
  353. }
  354. if (MDArray[i].BasePage == sp && MDArray[i].PageCount == ep-sp) {
  355. //
  356. // Descriptor was not editted
  357. //
  358. continue;
  359. }
  360. //
  361. // Reset this descriptor
  362. //
  363. MDArray[i].BasePage = sp;
  364. MDArray[i].PageCount = ep - sp;
  365. if (ep == sp) {
  366. //
  367. // Descriptor vanished - remove it
  368. //
  369. NumberDescriptors -= 1;
  370. if (i < NumberDescriptors) {
  371. //
  372. // move the last descriptor to this position
  373. //
  374. MDArray[i] = MDArray[NumberDescriptors];
  375. }
  376. //
  377. // and reset the last spot, since it is no longer valid
  378. //
  379. RtlZeroMemory(&MDArray[NumberDescriptors], sizeof(MEMORY_DESCRIPTOR));
  380. i--; // backup & recheck current position
  381. }
  382. }
  383. //
  384. // If region wasn't already added to a neighboring region, then
  385. // create a new descriptor now
  386. //
  387. if (!RegionAdded && MemoryType < LoaderMaximum) {
  388. if (NumberDescriptors == MaxDescriptors) {
  389. #if DBG
  390. wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
  391. EfiPrint(DebugBuffer);
  392. #endif
  393. return(ENOMEM);
  394. }
  395. #ifdef LOADER_DEBUG
  396. wsprintf( DebugBuffer, TEXT("Adding '%lx - %lx, type %x' to descriptor list\n"),
  397. StartPage << PAGE_SHIFT,
  398. EndPage << PAGE_SHIFT,
  399. (USHORT) MemoryType
  400. );
  401. EfiPrint(DebugBuffer);
  402. #endif
  403. MDArray[NumberDescriptors].MemoryType = MemoryType;
  404. MDArray[NumberDescriptors].BasePage = StartPage;
  405. MDArray[NumberDescriptors].PageCount = EndPage - StartPage;
  406. NumberDescriptors += 1;
  407. }
  408. return (ESUCCESS);
  409. }
  410. ARC_STATUS
  411. MempAllocDescriptor(
  412. IN ULONG StartPage,
  413. IN ULONG EndPage,
  414. IN TYPE_OF_MEMORY MemoryType
  415. )
  416. /*++
  417. Routine Description:
  418. This routine carves out a specific memory descriptor from the
  419. memory descriptors that have already been created. The MD array
  420. is updated to reflect the new state of memory.
  421. The new memory descriptor must be completely contained within an
  422. already existing memory descriptor. (i.e. memory that does not
  423. exist should never be marked as a certain type)
  424. Arguments:
  425. StartPage - Supplies the beginning page of the new memory descriptor
  426. EndPage - Supplies the ending page of the new memory descriptor
  427. MemoryType - Supplies the type of memory of the new memory descriptor
  428. Return Value:
  429. ESUCCESS - Memory descriptor succesfully added to MDL array
  430. ENOMEM - MDArray is full.
  431. --*/
  432. {
  433. ULONG i;
  434. //
  435. // Walk through the memory descriptors until we find one that
  436. // contains the start of the descriptor.
  437. //
  438. for (i=0; i<NumberDescriptors; i++) {
  439. if ((MDArray[i].MemoryType == MemoryFree) &&
  440. (MDArray[i].BasePage <= StartPage ) &&
  441. (MDArray[i].BasePage+MDArray[i].PageCount > StartPage) &&
  442. (MDArray[i].BasePage+MDArray[i].PageCount >= EndPage)) {
  443. break;
  444. }
  445. }
  446. if (i==MaxDescriptors) {
  447. #if DBG
  448. wsprintf( DebugBuffer, TEXT("NumDescriptors filled (%x) ENOMEM returned %S %d\r\n"), MaxDescriptors, __FILE__, __LINE__ );
  449. EfiPrint(DebugBuffer);
  450. #endif
  451. return(ENOMEM);
  452. }
  453. if (MDArray[i].BasePage == StartPage) {
  454. if (MDArray[i].BasePage+MDArray[i].PageCount == EndPage) {
  455. //
  456. // The new descriptor is identical to the existing descriptor.
  457. // Simply change the memory type of the existing descriptor in
  458. // place.
  459. //
  460. #if DBG_MEMORY
  461. wsprintf( DebugBuffer, TEXT("descriptor (%x) matched -- change type from %x to %x\r\n"), MDArray[i].BasePage, MDArray[i].MemoryType, MemoryType );
  462. EfiPrint(DebugBuffer);
  463. #endif
  464. MDArray[i].MemoryType = MemoryType;
  465. } else {
  466. //
  467. // The new descriptor starts on the same page, but is smaller
  468. // than the existing descriptor. Shrink the existing descriptor
  469. // by moving its start page up, and create a new descriptor.
  470. //
  471. if (NumberDescriptors == MaxDescriptors) {
  472. #if DBG_MEMORY
  473. wsprintf( DebugBuffer, TEXT("out of descriptors trying to grow (%x) (%x total)\r\n"), MDArray[i].BasePage,NumberDescriptors );
  474. EfiPrint(DebugBuffer);
  475. #endif
  476. #if DBG
  477. wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
  478. EfiPrint(DebugBuffer);
  479. #endif
  480. return(ENOMEM);
  481. }
  482. #if DBG_MEMORY
  483. wsprintf(
  484. DebugBuffer,
  485. TEXT("split descriptor starting at %x into two (%x pagecount into %x (size %x) and %x size %x)\r\n"),
  486. StartPage,
  487. MDArray[i].PageCount,
  488. EndPage,
  489. MDArray[i].PageCount - (EndPage-StartPage),
  490. StartPage,
  491. EndPage-StartPage );
  492. EfiPrint(DebugBuffer);
  493. #endif
  494. MDArray[i].BasePage = EndPage;
  495. MDArray[i].PageCount -= (EndPage-StartPage);
  496. MDArray[NumberDescriptors].BasePage = StartPage;
  497. MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
  498. MDArray[NumberDescriptors].MemoryType = MemoryType;
  499. ++NumberDescriptors;
  500. }
  501. } else if (MDArray[i].BasePage+MDArray[i].PageCount == EndPage) {
  502. //
  503. // The new descriptor ends on the same page. Shrink the existing
  504. // by decreasing its page count, and create a new descriptor.
  505. //
  506. if (NumberDescriptors == MaxDescriptors) {
  507. #if DBG_MEMORY
  508. wsprintf( DebugBuffer, TEXT("out of descriptors trying to shrink (%x) (%x total)\r\n"), MDArray[i].BasePage,NumberDescriptors );
  509. EfiPrint(DebugBuffer);
  510. #endif
  511. #if DBG
  512. wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
  513. EfiPrint(DebugBuffer);
  514. #endif
  515. return(ENOMEM);
  516. }
  517. #if DBG_MEMORY
  518. wsprintf(
  519. DebugBuffer,
  520. TEXT("shrink descriptor starting at %x into two (%x pagecount into %x (size %x) and %x size %x, type %x)\r\n"),
  521. MDArray[i].BasePage,
  522. MDArray[i].PageCount,
  523. MDArray[i].BasePage,
  524. StartPage - MDArray[i].BasePage,
  525. StartPage,
  526. EndPage-StartPage,
  527. MemoryType );
  528. EfiPrint(DebugBuffer);
  529. #endif
  530. MDArray[i].PageCount = StartPage - MDArray[i].BasePage;
  531. MDArray[NumberDescriptors].BasePage = StartPage;
  532. MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
  533. MDArray[NumberDescriptors].MemoryType = MemoryType;
  534. ++NumberDescriptors;
  535. } else {
  536. //
  537. // The new descriptor is in the middle of the existing descriptor.
  538. // Shrink the existing descriptor by decreasing its page count, and
  539. // create two new descriptors.
  540. //
  541. if (NumberDescriptors+1 >= MaxDescriptors) {
  542. #if DBG_MEMORY
  543. wsprintf( DebugBuffer, TEXT("out of descriptors trying to shrink (%x) (%x total)\r\n"), MDArray[i].BasePage,NumberDescriptors );
  544. EfiPrint(DebugBuffer);
  545. #endif
  546. #if DBG
  547. wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
  548. EfiPrint(DebugBuffer);
  549. #endif
  550. return(ENOMEM);
  551. }
  552. #if DBG_MEMORY
  553. wsprintf(
  554. DebugBuffer,
  555. TEXT("split descriptor starting at %x into 3 (%x pagecount into %x (size %x), %x size %x (memory free), %x size %x, type %x)\r\n"),
  556. MDArray[i].BasePage,
  557. MDArray[i].PageCount,
  558. MDArray[i].BasePage,
  559. StartPage-MDArray[i].BasePage,
  560. EndPage,
  561. MDArray[i].PageCount - (EndPage-MDArray[i].BasePage),
  562. StartPage,
  563. EndPage-StartPage,
  564. MemoryType );
  565. EfiPrint(DebugBuffer);
  566. #endif
  567. MDArray[NumberDescriptors].BasePage = EndPage;
  568. MDArray[NumberDescriptors].PageCount = MDArray[i].PageCount -
  569. (EndPage-MDArray[i].BasePage);
  570. MDArray[NumberDescriptors].MemoryType = MemoryFree;
  571. ++NumberDescriptors;
  572. MDArray[i].PageCount = StartPage - MDArray[i].BasePage;
  573. MDArray[NumberDescriptors].BasePage = StartPage;
  574. MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
  575. MDArray[NumberDescriptors].MemoryType = MemoryType;
  576. ++NumberDescriptors;
  577. }
  578. return(ESUCCESS);
  579. }
  580. #if FW_HEAP
  581. PVOID
  582. FwAllocateHeapPermanent(
  583. IN ULONG NumberPages
  584. )
  585. /*++
  586. Routine Description:
  587. This allocates pages from the private heap. The memory descriptor for
  588. the LoaderMemoryData area is grown to include the returned pages, while
  589. the memory descriptor for the temporary heap is shrunk by the same amount.
  590. N.B. DO NOT call this routine after we have passed control to
  591. BlOsLoader! Once BlOsLoader calls BlMemoryInitialize, the
  592. firmware memory descriptors are pulled into the OS Loader heap
  593. and those are the descriptors passed to the kernel. So any
  594. changes in the firmware private heap will be irrelevant.
  595. If you need to allocate permanent memory after the OS Loader
  596. has initialized, use BlAllocateDescriptor.
  597. Arguments:
  598. NumberPages - size of memory to allocate (in pages)
  599. Return Value:
  600. Pointer to block of memory, if successful.
  601. NULL, if unsuccessful.
  602. --*/
  603. {
  604. PVOID MemoryPointer;
  605. PMEMORY_DESCRIPTOR Descriptor;
  606. if (FwPermanentHeap + (NumberPages << PAGE_SHIFT) > FwTemporaryHeap) {
  607. //
  608. // Our heaps collide, so we are out of memory
  609. //
  610. wsprintf( DebugBuffer, TEXT("Out of permanent heap!\n"));
  611. EfiPrint(DebugBuffer);
  612. while (1) {
  613. }
  614. return(NULL);
  615. }
  616. //
  617. // Find the memory descriptor which describes the LoaderMemoryData area,
  618. // so we can grow it to include the just-allocated pages.
  619. //
  620. Descriptor = MDArray;
  621. while (Descriptor->MemoryType != LoaderMemoryData) {
  622. ++Descriptor;
  623. if (Descriptor > MDArray+MaxDescriptors) {
  624. wsprintf( DebugBuffer, TEXT("ERROR - FwAllocateHeapPermanent couldn't find the LoaderMemoryData descriptor!\r\n"));
  625. EfiPrint(DebugBuffer);
  626. return(NULL);
  627. }
  628. }
  629. Descriptor->PageCount += NumberPages;
  630. //
  631. // We know that the memory descriptor after this one is the firmware
  632. // temporary heap descriptor. Since it is physically contiguous with our
  633. // LoaderMemoryData block, we remove the pages from its descriptor.
  634. //
  635. ++Descriptor;
  636. Descriptor->PageCount -= NumberPages;
  637. Descriptor->BasePage += NumberPages;
  638. MemoryPointer = (PVOID)FwPermanentHeap;
  639. FwPermanentHeap += NumberPages << PAGE_SHIFT;
  640. return(MemoryPointer);
  641. }
  642. PVOID
  643. FwAllocateHeap(
  644. IN ULONG Size
  645. )
  646. /*++
  647. Routine Description:
  648. Allocates memory from the "firmware" temporary heap.
  649. Arguments:
  650. Size - Supplies size of block to allocate
  651. Return Value:
  652. PVOID - Pointer to the beginning of the block
  653. NULL - Out of memory
  654. --*/
  655. {
  656. ULONG i;
  657. ULONG SizeInPages;
  658. ULONG StartPage;
  659. ARC_STATUS Status;
  660. if (((FwTemporaryHeap - FwPermanentHeap) < Size) && (FwDescriptorsValid)) {
  661. //
  662. // Large allocations get their own descriptor so miniports that
  663. // have huge device extensions don't pull up all of the heap.
  664. //
  665. // Note that we can only do this while running in "firmware" mode.
  666. // Once we call into the osloader, it pulls all the memory descriptors
  667. // out of the "firmware" and changes to this list will not show
  668. // up there.
  669. //
  670. // We are looking for a descriptor that is MemoryFree and <16Mb.
  671. //
  672. SizeInPages = (Size+PAGE_SIZE-1) >> PAGE_SHIFT;
  673. for (i=0; i<NumberDescriptors; i++) {
  674. if ((MDArray[i].MemoryType == MemoryFree) &&
  675. (MDArray[i].PageCount >= SizeInPages)) {
  676. break;
  677. }
  678. }
  679. if (i < NumberDescriptors) {
  680. StartPage = MDArray[i].BasePage+MDArray[i].PageCount-SizeInPages;
  681. Status = MempAllocDescriptor(StartPage,
  682. StartPage+SizeInPages,
  683. MemoryFirmwareTemporary);
  684. if (Status==ESUCCESS) {
  685. return((PVOID)(ULONG_PTR)(StartPage << PAGE_SHIFT));
  686. }
  687. }
  688. }
  689. FwTemporaryHeap -= Size;
  690. //
  691. // Round down to 16-byte boundary
  692. //
  693. FwTemporaryHeap &= ~((ULONG)0xf);
  694. if (FwTemporaryHeap < FwPermanentHeap) {
  695. #if DBG
  696. wsprintf( DebugBuffer, TEXT("Out of temporary heap!\n"));
  697. EfiPrint(DebugBuffer);
  698. #endif
  699. return(NULL);
  700. }
  701. return((PVOID)FwTemporaryHeap);
  702. }
  703. #endif // FW_HEAP
  704. #if FW_HEAP
  705. PVOID
  706. FwAllocatePool(
  707. IN ULONG Size
  708. )
  709. /*++
  710. Routine Description:
  711. This routine allocates memory from the firmware pool. Note that
  712. this memory is NOT under the 1MB line, so it cannot be used for
  713. anything that must be accessed from real mode. It is currently used
  714. only by the SCSI miniport drivers and dbcs font loader.
  715. Arguments:
  716. Size - Supplies size of block to allocate.
  717. Return Value:
  718. PVOID - pointer to the beginning of the block
  719. NULL - out of memory
  720. --*/
  721. {
  722. PVOID Buffer;
  723. ULONG NewSize;
  724. //
  725. // round size up to 16 byte boundary
  726. //
  727. NewSize = (Size + 15) & ~0xf;
  728. if ((FwPoolStart + NewSize) <= FwPoolEnd) {
  729. Buffer = (PVOID)FwPoolStart;
  730. FwPoolStart += NewSize;
  731. return(Buffer);
  732. } else {
  733. //
  734. // we've used up all our pool, try to allocate from the heap.
  735. //
  736. return(BlAllocateHeap(Size));
  737. }
  738. }
  739. PVOID
  740. FwAllocateHeapAligned(
  741. IN ULONG Size
  742. )
  743. /*++
  744. Routine Description:
  745. Allocates memory from the "firmware" temporary heap. This memory is
  746. always allocated on a page boundary, so it can readily be used for
  747. temporary page tables
  748. Arguments:
  749. Size - Supplies size of block to allocate
  750. Return Value:
  751. PVOID - Pointer to the beginning of the block
  752. NULL - Out of memory
  753. --*/
  754. {
  755. FwTemporaryHeap -= Size;
  756. //
  757. // Round down to a page boundary
  758. //
  759. FwTemporaryHeap &= ~(PAGE_SIZE-1);
  760. if (FwTemporaryHeap < FwPermanentHeap) {
  761. wsprintf( DebugBuffer, TEXT("Out of temporary heap!\n")s);
  762. EfiPrint(DebugBuffer);
  763. return(NULL);
  764. }
  765. RtlZeroMemory((PVOID)FwTemporaryHeap,Size);
  766. return((PVOID)FwTemporaryHeap);
  767. }
  768. #endif
  769. #if !defined(NO_LEGACY_DRIVERS)
  770. //
  771. // This isn't used under EFI -- the HalPT is only setup immediately
  772. // before calling ExitBootServices(), and this routine is really
  773. // only present if ntbootdd.sys must be used.
  774. //
  775. PVOID
  776. MmMapIoSpace (
  777. IN PHYSICAL_ADDRESS PhysicalAddress,
  778. IN SIZE_T NumberOfBytes,
  779. IN MEMORY_CACHING_TYPE CacheType
  780. )
  781. /*++
  782. Routine Description:
  783. This function returns the corresponding virtual address for a
  784. known physical address.
  785. Arguments:
  786. PhysicalAddress - Supplies the phiscal address.
  787. NumberOfBytes - Unused.
  788. CacheType - Unused.
  789. Return Value:
  790. Returns the corresponding virtual address.
  791. Environment:
  792. Kernel mode. Any IRQL level.
  793. --*/
  794. {
  795. ULONG i;
  796. ULONG j;
  797. ULONG NumberPages;
  798. NumberPages = (ULONG)((NumberOfBytes+PAGE_SIZE-1) >> PAGE_SHIFT);
  799. //
  800. // We use the HAL's PDE for mapping memory buffers.
  801. // Find enough free PTEs.
  802. //
  803. for (i=0; i<=1024-NumberPages; i++) {
  804. for (j=0; j < NumberPages; j++) {
  805. if ((((PULONG)HalPT))[i+j]) {
  806. break;
  807. }
  808. }
  809. if (j == NumberPages) {
  810. for (j=0; j<NumberPages; j++) {
  811. HalPT[i+j].PageFrameNumber =
  812. (PhysicalAddress.LowPart >> PAGE_SHIFT)+j;
  813. HalPT[i+j].Valid = 1;
  814. HalPT[i+j].Write = 1;
  815. }
  816. return((PVOID)((ULONG_PTR)(0xffc00000 | (i<<12) | (PhysicalAddress.LowPart & 0xfff))));
  817. }
  818. //
  819. // page 'i + j' is used. walk past it
  820. //
  821. i += j;
  822. }
  823. return(NULL);
  824. }
  825. VOID
  826. MmUnmapIoSpace (
  827. IN PVOID BaseAddress,
  828. IN SIZE_T NumberOfBytes
  829. )
  830. /*++
  831. Routine Description:
  832. This function unmaps a range of physical address which were previously
  833. mapped via an MmMapIoSpace function call.
  834. Arguments:
  835. BaseAddress - Supplies the base virtual address where the physical
  836. address was previously mapped.
  837. NumberOfBytes - Supplies the number of bytes which were mapped.
  838. Return Value:
  839. None.
  840. Environment:
  841. Kernel mode, IRQL of DISPATCH_LEVEL or below.
  842. --*/
  843. {
  844. return;
  845. }
  846. #endif