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.

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