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.

1253 lines
43 KiB

  1. #include "bldr.h"
  2. #include "sal.h"
  3. #include "efi.h"
  4. #include "efip.h"
  5. #include "bootia64.h"
  6. #include "smbios.h"
  7. #include "extern.h"
  8. extern EFI_SYSTEM_TABLE *EfiST;
  9. extern EFI_BOOT_SERVICES *EfiBS;
  10. extern EFI_HANDLE EfiImageHandle;
  11. extern TR_INFO Sal;
  12. extern TR_INFO SalGP;
  13. extern TR_INFO Pal;
  14. extern ULONGLONG PalProcPhysical;
  15. extern ULONGLONG PalPhysicalBase;
  16. extern ULONGLONG PalTrPs;
  17. extern ULONGLONG IoPortPhysicalBase;
  18. extern ULONGLONG IoPortTrPs;
  19. #if DBG
  20. #define DBG_TRACE(_X) EfiPrint(_X)
  21. #else
  22. #define DBG_TRACE(_X)
  23. #endif
  24. // M E M O R Y D E S C R I P T O R
  25. //
  26. // Memory Descriptor - each contiguous block of physical memory is
  27. // described by a Memory Descriptor. The descriptors are a table, with
  28. // the last entry having a BlockBase and BlockSize of zero. A pointer
  29. // to the beginning of this table is passed as part of the BootContext
  30. // Record to the OS Loader.
  31. //
  32. //
  33. // define the number of Efi Pages in an OS page
  34. //
  35. #define EFI_PAGES_PER_OS_PAGE ((EFI_PAGE_SHIFT < PAGE_SHIFT) ? (1 << (PAGE_SHIFT - EFI_PAGE_SHIFT)) : 1)
  36. //
  37. // global values associated with global Efi memory descriptor array
  38. //
  39. ULONGLONG MemoryMapKey;
  40. ULONG BlPlatformPropertiesEfiFlags = 0;
  41. //
  42. // values to make sure we only get sal,pal,salgp,ioport info once
  43. //
  44. BOOLEAN SalFound = FALSE;
  45. BOOLEAN PalFound = FALSE;
  46. BOOLEAN SalGpFound = FALSE;
  47. BOOLEAN IoPortFound = FALSE;
  48. //
  49. // prototypes for local routines
  50. //
  51. BOOLEAN
  52. pDescriptorContainsAddress(
  53. EFI_MEMORY_DESCRIPTOR *EfiMd,
  54. ULONGLONG PhysicalAddress
  55. );
  56. BOOLEAN
  57. pCoalesceDescriptor(
  58. MEMORY_DESCRIPTOR *PrevEntry,
  59. MEMORY_DESCRIPTOR *CurrentEntry
  60. );
  61. //
  62. // function definitions for routines exported outside
  63. // this file
  64. //
  65. MEMORY_TYPE
  66. EfiToArcType (
  67. UINT32 Type
  68. )
  69. /*++
  70. Routine Description:
  71. Maps an EFI memory type to an Arc memory type. We only care about a few
  72. kinds of memory, so this list is incomplete.
  73. Arguments:
  74. Type - an EFI memory type
  75. Returns:
  76. A MEMORY_TYPE enumerated type.
  77. --*/
  78. {
  79. MEMORY_TYPE typeRet=MemoryFirmwarePermanent;
  80. switch (Type) {
  81. case EfiLoaderCode:
  82. {
  83. typeRet=MemoryLoadedProgram; // This gets claimed later
  84. break;
  85. }
  86. case EfiLoaderData:
  87. case EfiBootServicesCode:
  88. case EfiBootServicesData:
  89. {
  90. typeRet=MemoryFirmwareTemporary;
  91. break;
  92. }
  93. case EfiConventionalMemory:
  94. {
  95. typeRet=MemoryFree;
  96. break;
  97. }
  98. case EfiUnusableMemory:
  99. {
  100. typeRet=MemoryBad;
  101. break;
  102. }
  103. default:
  104. //
  105. // all others are memoryfirmwarepermanent
  106. //
  107. break;
  108. }
  109. return typeRet;
  110. }
  111. VOID
  112. ConstructArcMemoryDescriptorsWithAllocation(
  113. ULONGLONG LowBoundary,
  114. ULONGLONG HighBoundary
  115. )
  116. /*++
  117. Routine Description:
  118. Builds up memory descriptors for the OS loader. This routine queries EFI
  119. for it's memory map (a variable sized array of EFI_MEMORY_DESCRIPTOR's).
  120. It then allocates sufficient space for the MDArray global (a variable sized
  121. array of ARC-based MEMORY_DESCRIPTOR's.) The routine then maps the EFI
  122. memory map to the ARC memory map, carving out all of the conventional
  123. memory space for the EFI loader to help keep the memory map intact. We
  124. must leave behind some amount of memory for the EFI boot services to use,
  125. which we allocate as conventional memory in our map.
  126. This routine will allocate the memory (using EFI) for the
  127. EfiMemoryDescriptors
  128. Arguments:
  129. LowBoundary - The entire Efi Memory descriptor list does not need be
  130. HigBoundary - translated to Arc descriptors. Low/High Boundary map
  131. the desired region to be mapped. Their values are
  132. addresses (not pages)
  133. Returns:
  134. NOTHING: If this routine encounters an error, it is treated as fatal
  135. and the program exits.
  136. --*/
  137. {
  138. EFI_STATUS Status;
  139. ULONG i;
  140. EFI_MEMORY_DESCRIPTOR *MDEfi = NULL;
  141. ULONGLONG MemoryMapSize = 0;
  142. ULONGLONG DescriptorSize;
  143. UINT32 DescriptorVersion;
  144. //
  145. // Get memory map info from EFI firmware
  146. //
  147. // To do this, we first find out how much space we need by calling
  148. // with an empty buffer.
  149. //
  150. Status = EfiBS->GetMemoryMap (
  151. &MemoryMapSize,
  152. NULL,
  153. &MemoryMapKey,
  154. &DescriptorSize,
  155. &DescriptorVersion
  156. );
  157. if (Status != EFI_BUFFER_TOO_SMALL) {
  158. EfiPrint(L"ConstructArcMemoryDescriptors: GetMemoryMap failed\n");
  159. EfiBS->Exit(EfiImageHandle, Status, 0, 0);
  160. }
  161. //
  162. // We are going to make a few extra allocations before we call GetMemoryMap
  163. // again, so add some extra space.
  164. //
  165. // 1. EfiMD (a descriptor for us, if we can't fit)
  166. // 2. MDarray (a descriptor for the MDArray, if not already allocated)
  167. // 3. Split out memory above and below the desired boundaries
  168. // and add a few more so we hopefully don't have to reallocate memory
  169. // for the descriptor
  170. //
  171. MemoryMapSize += 3*DescriptorSize;
  172. #if DBG_MEMORY
  173. wsprintf(DebugBuffer,
  174. L"ConstructArcMemoryDescriptor: Allocated 0x%x bytes for MDEfi\r\n",
  175. (ULONG)MemoryMapSize
  176. );
  177. EfiPrint(DebugBuffer);
  178. #endif
  179. //
  180. // now allocate space for the EFI-based memory map and assign it to the loader
  181. //
  182. Status = EfiAllocateAndZeroMemory(EfiLoaderData,
  183. (ULONG) MemoryMapSize,
  184. &MDEfi);
  185. if (EFI_ERROR(Status)) {
  186. DBG_TRACE( L"ConstructArcMemoryDescriptors: AllocatePool failed\r\n");
  187. EfiBS->Exit(EfiImageHandle, Status, 0, 0);
  188. }
  189. //
  190. // now Allocate and zero the MDArray, which is the native loader memory
  191. // map which we need to map the EFI memory map to.
  192. //
  193. // The MDArray has one entry for each EFI_MEMORY_DESCRIPTOR, and each entry
  194. // is MEMORY_DESCRIPTOR large.
  195. //
  196. if (MDArray == NULL) {
  197. i=((ULONG)(MemoryMapSize / DescriptorSize)+1)*sizeof (MEMORY_DESCRIPTOR);
  198. #if DBG_MEMORY
  199. wsprintf(DebugBuffer,
  200. L"ConstructArcMemoryDescriptor: Allocated 0x%x bytes for MDArray\r\n",
  201. i
  202. );
  203. EfiPrint(DebugBuffer);
  204. #endif
  205. Status = EfiAllocateAndZeroMemory(EfiLoaderData,i,&MDArray);
  206. if (EFI_ERROR(Status)) {
  207. DBG_TRACE (L"ConstructArcMemoryDescriptors: AllocatePool failed\r\n");
  208. EfiBS->Exit(EfiImageHandle, Status, 0, 0);
  209. }
  210. }
  211. //
  212. // we have all of the memory allocated at this point, so retreive the
  213. // memory map again, which should succeed the second time.
  214. //
  215. Status = EfiBS->GetMemoryMap (
  216. &MemoryMapSize,
  217. MDEfi,
  218. &MemoryMapKey,
  219. &DescriptorSize,
  220. &DescriptorVersion
  221. );
  222. if (EFI_ERROR(Status)) {
  223. DBG_TRACE(L"ConstructArcMemoryDescriptors: GetMemoryMap failed\r\n");
  224. EfiBS->Exit(EfiImageHandle, Status, 0, 0);
  225. }
  226. //
  227. // initialize global variables
  228. //
  229. MaxDescriptors = (ULONG)((MemoryMapSize / DescriptorSize)+1); // zero-based
  230. //
  231. // construct the arc memory descriptors for the
  232. // efi descriptors
  233. //
  234. ConstructArcMemoryDescriptors(MDEfi,
  235. MDArray,
  236. MemoryMapSize,
  237. DescriptorSize,
  238. LowBoundary,
  239. HighBoundary);
  240. #if DBG_MEMORY
  241. PrintArcMemoryDescriptorList(MDArray,
  242. NumberDescriptors
  243. );
  244. #endif
  245. }
  246. #define MASK_16MB (ULONGLONG) 0xffffffffff000000I64
  247. #define MASK_16KB (ULONGLONG) 0xffffffffffffc000I64
  248. #define SIZE_IN_BYTES_16KB 16384
  249. VOID
  250. ConstructArcMemoryDescriptors(
  251. EFI_MEMORY_DESCRIPTOR *EfiMd,
  252. MEMORY_DESCRIPTOR *ArcMd,
  253. ULONGLONG MemoryMapSize,
  254. ULONGLONG EfiDescriptorSize,
  255. ULONGLONG LowBoundary,
  256. ULONGLONG HighBoundary
  257. )
  258. /*++
  259. Routine Description:
  260. Builds up memory descriptors for the OS loader. The routine maps the EFI
  261. memory map to the ARC memory map, carving out all of the conventional
  262. memory space for the EFI loader to help keep the memory map intact. We
  263. must leave behind some amount of memory for the EFI boot services to use,
  264. which we allocate as conventional memory in our map.
  265. If consecutive calls are made into ConstructArcMemoryDescriptors,
  266. the efi routine GetMemoryMap must be called before each instance,
  267. since we may allocate new pages inside of this routine. therefore
  268. a new efi memory map may be required to illustrate these changes.
  269. Arguments:
  270. EfiMd - a pointer to the efi memory descriptor list that we will be
  271. constructing arc memory descriptors for.
  272. ArcMd - (must be allocated). This will be populated with ARC-based memory
  273. descriptors corresponding to the EFI Memory Descriptors
  274. MemoryMapSize - Size of the Efi Memory Map
  275. EfiDescriptorSize - size of Efi Memory Descriptor
  276. LowBoundary - The entire Efi Memory descriptor list does not need be
  277. HigBoundary - translated to Arc descriptors. Low/High Boundary map
  278. the desired region to be mapped. Their values are
  279. addresses (not pages)
  280. Returns:
  281. Nothing. Fills in the MDArray global variable. If this routine encounters
  282. an error, it is treated as fatal and the program exits.
  283. --*/
  284. {
  285. EFI_STATUS Status;
  286. ULONG i;
  287. ULONGLONG IoPortSize;
  288. ULONGLONG MdPhysicalStart;
  289. ULONGLONG MdPhysicalEnd;
  290. ULONGLONG MdPhysicalSize;
  291. MEMORY_DESCRIPTOR *OldMDArray = NULL; // initialize for w4 compiler
  292. ULONG OldNumberDescriptors = 0; // initialize for w4 compiler
  293. ULONG OldMaxDescriptors = 0; // initialize for w4 compiler
  294. BOOLEAN ReplaceMDArray = FALSE;
  295. ULONG efiMemMapIOWriteCombining = 0;
  296. ULONG efiMemMapIO = 0;
  297. ULONG efiMainMemoryWC = 0;
  298. ULONG efiMainMemoryUC = 0;
  299. //
  300. // check to make sure ArcMd is allocated
  301. //
  302. if (ArcMd == NULL) {
  303. EfiPrint(L"ConstructArcMemoryDescriptors: Invalid parameter\r\n");
  304. EfiBS->Exit(EfiImageHandle, 0, 0, 0);
  305. return;
  306. }
  307. //
  308. // this is a bit hacky, but instead of changing the functionality of
  309. // all the other functions (insertdescriptor, adjustarcmemorydescriptor, etc)
  310. // just have MDArray point to the new ArcMd (if we want to write a new descriptor
  311. // list. when we are done, switch it back
  312. //
  313. if (MDArray != ArcMd) {
  314. ReplaceMDArray = TRUE;
  315. OldMDArray = MDArray;
  316. OldNumberDescriptors = NumberDescriptors;
  317. OldMaxDescriptors = MaxDescriptors;
  318. MDArray = ArcMd;
  319. #if DBG_MEMORY
  320. EfiPrint(L"ConstructArcMemoryDescriptors: Using alternate Memory Descriptor List\r\n");
  321. #endif
  322. //
  323. // perhaps change this functionality.
  324. // right now a descriptor list besides the global
  325. // one will always expect to create a whole new list
  326. // each time
  327. //
  328. NumberDescriptors = 0;
  329. MaxDescriptors = (ULONG)((MemoryMapSize / EfiDescriptorSize)+1); // zero-based
  330. RtlZeroMemory(MDArray, MemoryMapSize);
  331. }
  332. #if DBG_MEMORY
  333. wsprintf( DebugBuffer,
  334. L"unaligned (LowBoundary, HighBoundary) = (0x%x, 0x%x)\r\n",
  335. LowBoundary, HighBoundary
  336. );
  337. EfiPrint( DebugBuffer );
  338. #endif
  339. //
  340. // align boundaries (with OS page size)
  341. // having this be os page size makes alignment issues easier later
  342. //
  343. LowBoundary = (LowBoundary >> PAGE_SHIFT) << PAGE_SHIFT; // this should alway round down
  344. if (HighBoundary % PAGE_SIZE) {
  345. // this should round up
  346. HighBoundary = ((HighBoundary + PAGE_SIZE) >> PAGE_SHIFT << PAGE_SHIFT);
  347. }
  348. // make sure that we did not wrap around ...
  349. if (HighBoundary == 0) {
  350. HighBoundary = (ULONGLONG)-1;
  351. }
  352. #if DBG_MEMORY
  353. wsprintf( DebugBuffer,
  354. L"aligned (LowBoundary, HighBoundary) = (0x%x, 0x%x)\r\n",
  355. LowBoundary, HighBoundary
  356. );
  357. EfiPrint( DebugBuffer );
  358. #endif
  359. //
  360. // now walk the EFI_MEMORY_DESCRIPTOR array, mapping each
  361. // entry to an arc-based MEMORY_DESCRIPTOR.
  362. //
  363. // MemoryMapSize contains actual size of the memory descriptor array.
  364. //
  365. for (i = 0; MemoryMapSize > 0; i++) {
  366. #if DBG_MEMORY
  367. wsprintf( DebugBuffer,
  368. L"PageStart (%x), Size (%x), Type (%x)\r\n",
  369. (EfiMd->PhysicalStart >> EFI_PAGE_SHIFT),
  370. EfiMd->NumberOfPages,
  371. EfiMd->Type);
  372. EfiPrint(DebugBuffer);
  373. //DBG_EFI_PAUSE();
  374. #endif
  375. if (EfiMd->NumberOfPages > 0) {
  376. MdPhysicalStart = EfiMd->PhysicalStart;
  377. MdPhysicalEnd = EfiMd->PhysicalStart + (EfiMd->NumberOfPages << EFI_PAGE_SHIFT);
  378. MdPhysicalSize = MdPhysicalEnd - MdPhysicalStart;
  379. #if DBG_MEMORY
  380. wsprintf( DebugBuffer,
  381. L"PageStart %x (%x), PageEnd %x (%x), Type (%x)\r\n",
  382. MdPhysicalStart, (EfiMd->PhysicalStart >> EFI_PAGE_SHIFT),
  383. MdPhysicalEnd, (EfiMd->PhysicalStart >>EFI_PAGE_SHIFT) + EfiMd->NumberOfPages,
  384. EfiMd->Type);
  385. EfiPrint(DebugBuffer);
  386. //DBG_EFI_PAUSE();
  387. #endif
  388. //
  389. // only create arc memory descriptors for the desired region.
  390. // but always look for efi memory mapped io space. this is not
  391. // included in the arc descripter list, but is needed for the
  392. // tr's to enable virtual mode.
  393. // also save off any pal information for later.
  394. //
  395. if (EfiMd->Type == EfiMemoryMappedIOPortSpace) {
  396. if (!IoPortFound) {
  397. //
  398. // save off the Io stuff for later
  399. //
  400. IoPortPhysicalBase = EfiMd->PhysicalStart;
  401. IoPortSize = EfiMd->NumberOfPages << EFI_PAGE_SHIFT;
  402. MEM_SIZE_TO_PS(IoPortSize, IoPortTrPs);
  403. IoPortFound = TRUE;
  404. }
  405. #if DBG_MEMORY
  406. else {
  407. EfiPrint(L"Ignoring IoPort.\r\n");
  408. }
  409. #endif
  410. }
  411. else if (EfiMd->Type == EfiPalCode) {
  412. if (!PalFound) {
  413. BOOLEAN LargerThan16Mb;
  414. ULONGLONG PalTrMask;
  415. ULONGLONG PalTrSize;
  416. ULONGLONG PalSize;
  417. //
  418. // save off the Pal stuff for later
  419. //
  420. PalPhysicalBase = Pal.PhysicalAddressMemoryDescriptor = EfiMd->PhysicalStart;
  421. PalSize = EfiMd->NumberOfPages << EFI_PAGE_SHIFT;
  422. Pal.PageSizeMemoryDescriptor = (ULONG)EfiMd->NumberOfPages;
  423. MEM_SIZE_TO_PS(PalSize, PalTrPs);
  424. Pal.PageSize = (ULONG)PalTrPs;
  425. //
  426. // Copied from Halia64\ia64\i64efi.c
  427. //
  428. PalTrSize = SIZE_IN_BYTES_16KB;
  429. PalTrMask = MASK_16KB;
  430. LargerThan16Mb = TRUE;
  431. while (PalTrMask >= MASK_16MB) {
  432. if ( (Pal.PhysicalAddressMemoryDescriptor + PalSize) <=
  433. ((Pal.PhysicalAddressMemoryDescriptor & PalTrMask) + PalTrSize)) {
  434. LargerThan16Mb = FALSE;
  435. break;
  436. }
  437. PalTrMask <<= 2;
  438. PalTrSize <<= 2;
  439. }
  440. //
  441. // This is the virtual base adddress of the PAL
  442. //
  443. Pal.VirtualAddress = VIRTUAL_PAL_BASE + (Pal.PhysicalAddressMemoryDescriptor & ~PalTrMask);
  444. //
  445. // We've done this already. Remember that
  446. //
  447. PalFound = TRUE;
  448. }
  449. #if DBG_MEMORY
  450. else {
  451. EfiPrint(L"Ignoring Pal.\r\n");
  452. }
  453. #endif
  454. }
  455. else if (EfiMd->Type == EfiMemoryMappedIO) {
  456. //
  457. // In terms of arc descriptor entry, just ignore this type since
  458. // it's not real memory -- the system can use ACPI tables to get
  459. // at this later on.
  460. //
  461. efiMemMapIO++;
  462. //
  463. // Simply check the attribute for the PlatformProperties global.
  464. //
  465. if ( EfiMd->Attribute & EFI_MEMORY_WC ) {
  466. efiMemMapIOWriteCombining++;
  467. }
  468. }
  469. //
  470. // don't insert all memory into the arc descriptor table
  471. // just the descriptors between the Low/High Boundaries
  472. // so before we even continue, make sure that some part
  473. // of the descriptor is in the desired boundary.
  474. // there are three cases for crossing a boundary
  475. // 1. the start page (not the end page) is in the boundary
  476. // 2. the end page (not the start page) is in the boundary
  477. // 3. the range covers the entire boundary (neither start/end page) in boundary
  478. //
  479. // these can be written more simply as:
  480. // A descriptor is NOT within a region if the entire
  481. // descriptor is LESS than the region ( MdStart <= MdEnd <= LowBoundary )
  482. // OR is GREATER than the region ( HighBoundary <= MdStart <= MdEnd )
  483. // Therefore we simplify this futher to say
  484. // Start < HighBoundary && LowBoundary < MdEnd
  485. else if ( (MdPhysicalStart < HighBoundary) && (LowBoundary < MdPhysicalEnd) ) {
  486. //
  487. // Insert conventional memory descriptors with WB flag set
  488. // into NT loader memory descriptor list.
  489. //
  490. if ( (EfiMd->Type == EfiConventionalMemory) &&
  491. ((EfiMd->Attribute & EFI_MEMORY_WB) == EFI_MEMORY_WB) ) {
  492. ULONGLONG AmountOfMemory;
  493. ULONGLONG NumberOfEfiPages;
  494. BOOLEAN BrokeRange = FALSE;
  495. EFI_PHYSICAL_ADDRESS AllocationAddress = 0;
  496. //
  497. // adjust the descriptor if not completely in
  498. // desired boundary (we know that if we are here at least
  499. // part of descriptor is in boundary
  500. //
  501. if (MdPhysicalStart < LowBoundary) {
  502. #if DBG_MEMORY
  503. wsprintf(DebugBuffer,
  504. L"Broke Low (start=0x%x) LowBoundary=0x%x\r\n",
  505. MdPhysicalStart,
  506. LowBoundary);
  507. EfiPrint(DebugBuffer);
  508. #endif
  509. MdPhysicalStart = LowBoundary;
  510. BrokeRange = TRUE;
  511. }
  512. if (HighBoundary < MdPhysicalEnd) {
  513. #if DBG_MEMORY
  514. wsprintf(DebugBuffer,
  515. L"Broke High (end=0x%x) HighBoundary=0x%x\r\n",
  516. MdPhysicalEnd,
  517. HighBoundary);
  518. EfiPrint(DebugBuffer);
  519. #endif
  520. MdPhysicalEnd = HighBoundary;
  521. BrokeRange = TRUE;
  522. }
  523. //
  524. // determine the memory range for this descriptor
  525. //
  526. AmountOfMemory = MdPhysicalEnd - MdPhysicalStart;
  527. NumberOfEfiPages = AmountOfMemory >> EFI_PAGE_SHIFT;
  528. if (BrokeRange) {
  529. //
  530. // allocate pages for the new region
  531. //
  532. // note: we have 1 descriptor describing up to 3 new regions.
  533. // we can change the descriptor but still may have to allocate 2
  534. // new regions. but if we allocate with the same type, they will just
  535. // coellesce.
  536. // one way to get around this is to allocate the middle page (in this
  537. // boundary region) of a different efi memory type (this will cause
  538. // efi to break the descriptor into three. then we can keep
  539. // a better record of it in our arc descriptor list
  540. //
  541. // the possible regions are
  542. // start address - low boundary
  543. // low boundar - high boundary
  544. // high boundary - end address
  545. //
  546. // have the current descriptor modified for this boundary
  547. // region, allocating pages for that below and above us
  548. //
  549. AllocationAddress = MdPhysicalStart;
  550. Status = EfiBS->AllocatePages ( AllocateAddress,
  551. EfiLoaderData,
  552. NumberOfEfiPages,
  553. &AllocationAddress );
  554. #if DBG_MEMORY
  555. wsprintf( DebugBuffer,
  556. L"allocate pages @ %x size = %x\r\n",
  557. (MdPhysicalStart >> EFI_PAGE_SHIFT),
  558. NumberOfEfiPages );
  559. EfiPrint(DebugBuffer);
  560. //DBG_EFI_PAUSE();
  561. #endif
  562. if (EFI_ERROR(Status)) {
  563. EfiPrint(L"SuMain: AllocPages failed\n");
  564. EfiBS->Exit(EfiImageHandle, Status, 0, 0);
  565. }
  566. }
  567. //
  568. // now we can finally insert this (possibly modified) descriptor
  569. //
  570. InsertDescriptor( (ULONG)(MdPhysicalStart >> EFI_PAGE_SHIFT),
  571. (ULONG)((ULONGLONG)AmountOfMemory >> EFI_PAGE_SHIFT),
  572. EfiToArcType(EfiMd->Type)
  573. );
  574. }
  575. else {
  576. //
  577. // some other type -- just insert it without any changes
  578. //
  579. InsertDescriptor( (ULONG)(MdPhysicalStart >> EFI_PAGE_SHIFT),
  580. (ULONG)(MdPhysicalSize >> EFI_PAGE_SHIFT),
  581. EfiToArcType(EfiMd->Type));
  582. }
  583. }
  584. //
  585. // try to get the size of the sal.
  586. //
  587. if (pDescriptorContainsAddress(EfiMd,Sal.PhysicalAddress)) {
  588. if (!SalFound) {
  589. Sal.PhysicalAddressMemoryDescriptor = EfiMd->PhysicalStart;
  590. Sal.PageSizeMemoryDescriptor = (ULONG)EfiMd->NumberOfPages;
  591. SalFound = TRUE;
  592. }
  593. #if DBG_MEMORY
  594. else {
  595. EfiPrint(L"Ignoring Sal.\r\n");
  596. }
  597. #endif
  598. }
  599. //
  600. // try to get the size of the sal gp.
  601. //
  602. if (pDescriptorContainsAddress(EfiMd,SalGP.PhysicalAddress)) {
  603. if (!SalGpFound) {
  604. SalGP.PhysicalAddressMemoryDescriptor = EfiMd->PhysicalStart;
  605. SalGP.PageSizeMemoryDescriptor = (ULONG)EfiMd->NumberOfPages;
  606. SalGpFound = TRUE;
  607. }
  608. #if DBG_MEMORY
  609. else {
  610. EfiPrint(L"Ignoring SalGP.\r\n");
  611. }
  612. #endif
  613. }
  614. //
  615. // try to get the cacheability attribute of ACPI Tables. Remember
  616. // that the ACPI tables must be cached in the exceptional case where
  617. // the firmware doesn't map the acpi tables non-cached.
  618. //
  619. if ( AcpiTable && pDescriptorContainsAddress(EfiMd,(ULONG_PTR)AcpiTable)) {
  620. if ( (EfiMd->Attribute & EFI_MEMORY_WB) && !(EfiMd->Attribute & EFI_MEMORY_UC) ) {
  621. BlPlatformPropertiesEfiFlags |= HAL_PLATFORM_ACPI_TABLES_CACHED;
  622. }
  623. }
  624. //
  625. // if none of EFI MD Main Memory does present Uncacheable or WriteCombining,
  626. // it's assumed this platform doesn't support Uncacheable or Write Combining
  627. // in Main Memory.
  628. //
  629. if ( EfiMd->Type == EfiConventionalMemory ) {
  630. if ( EfiMd->Attribute & EFI_MEMORY_WC ) {
  631. efiMainMemoryWC++;
  632. }
  633. if (EfiMd->Attribute & EFI_MEMORY_UC ) {
  634. efiMainMemoryUC++;
  635. }
  636. }
  637. }
  638. EfiMd = (EFI_MEMORY_DESCRIPTOR *) ( (PUCHAR) EfiMd + EfiDescriptorSize );
  639. MemoryMapSize -= EfiDescriptorSize;
  640. }
  641. //
  642. // If this platform supports at least 1 MMIO Write Combining EFI MD or if there are
  643. // no memory mapped I/O entries, then indicate the platform can support write
  644. // combined accesses to the I/O space.
  645. //
  646. if ( efiMemMapIOWriteCombining || (efiMemMapIO == 0)) {
  647. BlPlatformPropertiesEfiFlags |= HAL_PLATFORM_ENABLE_WRITE_COMBINING_MMIO;
  648. }
  649. //
  650. // If this platform doesn't support Main Memory Uncacheable or Write Combining
  651. // from a point of view of EFI MDs, let's flag the PlatformProperties global.
  652. //
  653. if ( !efiMainMemoryUC ) {
  654. BlPlatformPropertiesEfiFlags |= HAL_PLATFORM_DISABLE_UC_MAIN_MEMORY;
  655. }
  656. if ( !efiMainMemoryWC ) {
  657. BlPlatformPropertiesEfiFlags |= HAL_PLATFORM_DISABLE_WRITE_COMBINING;
  658. }
  659. //
  660. // reset globals
  661. //
  662. if (ReplaceMDArray) {
  663. MDArray = OldMDArray;
  664. NumberDescriptors = OldNumberDescriptors;
  665. MaxDescriptors = OldMaxDescriptors;
  666. }
  667. }
  668. VOID
  669. InsertDescriptor (
  670. ULONG BasePage,
  671. ULONG NumberOfPages,
  672. MEMORY_TYPE MemoryType
  673. )
  674. /*++
  675. Routine Description:
  676. This routine inserts a descriptor into the correct place in the
  677. memory descriptor list.
  678. The descriptors come in in EFI_PAGE_SIZE pages and must be
  679. converted to PAGE_SIZE pages. This significantly complicates things,
  680. as we must page align the start of descriptors and hte lengths of the
  681. descriptors.
  682. pCoalesceDescriptor does the necessary work for coalescing descriptors
  683. plus converting from EF_PAGE_SIZE to PAGE_SIZE.
  684. Arguments:
  685. BasePage - Base page that the memory starts at.
  686. NumberOfPages - The number of pages starting at memory block to be inserted.
  687. MemoryType - An arc memory type describing the memory.
  688. Return Value:
  689. None. Updates MDArray global memory array.
  690. --*/
  691. {
  692. MEMORY_DESCRIPTOR *CurrentEntry, *PriorEntry;
  693. //
  694. // grab the pointers for CurrentEntry and PriorEntry.
  695. // fill in the efi values for CurrentEntry
  696. //
  697. PriorEntry = (NumberDescriptors == 0) ? NULL : (MEMORY_DESCRIPTOR *)&MDArray[NumberDescriptors-1];
  698. CurrentEntry = (MEMORY_DESCRIPTOR *)&MDArray[NumberDescriptors];
  699. //
  700. // The last entry had better be empty or the descriptor list is
  701. // somehow corrupted.
  702. //
  703. if (CurrentEntry->PageCount != 0) {
  704. wsprintf(DebugBuffer,
  705. L"InsertDescriptor: Inconsistent Descriptor count(0x%x) (PageCount=0x%x)\r\n",
  706. NumberDescriptors,
  707. CurrentEntry->PageCount
  708. );
  709. EfiPrint(DebugBuffer);
  710. EfiBS->Exit(EfiImageHandle, 0, 0, 0);
  711. }
  712. //
  713. // fill in values for this entry
  714. //
  715. CurrentEntry->BasePage = BasePage;
  716. CurrentEntry->PageCount = NumberOfPages;
  717. CurrentEntry->MemoryType = MemoryType;
  718. //
  719. // call pCoalesceDescriptor. this will do all the basepage/pagecount manipulation
  720. // for EFI_PAGES -> OS_PAGES.
  721. // the return value is TRUE if the current entry merged with the previous entry,
  722. // otherwise the descriptor should be added.
  723. //
  724. if (pCoalesceDescriptor(PriorEntry, CurrentEntry) == FALSE) {
  725. NumberDescriptors++;
  726. }
  727. else {
  728. CurrentEntry->BasePage = CurrentEntry->PageCount = CurrentEntry->MemoryType = 0;
  729. }
  730. #if DBG_MEMORY
  731. wsprintf( DebugBuffer,
  732. L"insert new descriptor #%x of %x, BasePage %x, NumberOfPages %x, Type (%x)\r\n",
  733. NumberDescriptors,
  734. MaxDescriptors,
  735. CurrentEntry->BasePage,
  736. CurrentEntry->PageCount,
  737. CurrentEntry->MemoryType);
  738. EfiPrint(DebugBuffer);
  739. //DBG_EFI_PAUSE();
  740. #endif
  741. return;
  742. }
  743. #ifdef DBG
  744. VOID
  745. PrintArcMemoryDescriptorList(
  746. MEMORY_DESCRIPTOR *ArcMd,
  747. ULONG MaxDesc
  748. )
  749. {
  750. ULONG i;
  751. for (i = 0; i < MaxDesc; i++) {
  752. //
  753. // print to console BasePage, EndPage, PageCount, MemoryType
  754. //
  755. wsprintf( DebugBuffer,
  756. L"#%x BasePage:0x%x EndPage:0x%x PageCount:0x%x MemoryType:0x%x\r\n",
  757. i,
  758. ArcMd[i].BasePage,
  759. ArcMd[i].BasePage + ArcMd[i].PageCount,
  760. ArcMd[i].PageCount,
  761. ArcMd[i].MemoryType
  762. );
  763. EfiPrint(DebugBuffer);
  764. }
  765. }
  766. #endif
  767. //
  768. // private function definitions
  769. //
  770. BOOLEAN
  771. pDescriptorContainsAddress(
  772. EFI_MEMORY_DESCRIPTOR *EfiMd,
  773. ULONGLONG PhysicalAddress
  774. )
  775. {
  776. ULONGLONG MdPhysicalStart, MdPhysicalEnd;
  777. MdPhysicalStart = (ULONGLONG)EfiMd->PhysicalStart;
  778. MdPhysicalEnd = MdPhysicalStart + ((ULONGLONG)EfiMd->NumberOfPages << EFI_PAGE_SHIFT);
  779. if ((PhysicalAddress >= MdPhysicalStart) &&
  780. (PhysicalAddress < MdPhysicalEnd)) {
  781. #if DBG_MEMORY
  782. EfiPrint(L"DescriptorContainsAddress: returning TRUE\r\n");
  783. #endif
  784. return(TRUE);
  785. }
  786. return(FALSE);
  787. }
  788. BOOLEAN
  789. pCoalesceDescriptor(
  790. MEMORY_DESCRIPTOR *PrevEntry,
  791. MEMORY_DESCRIPTOR *CurrentEntry
  792. )
  793. /*++
  794. Routine Description:
  795. This routine attempts to coalesce a memory descriptor with the
  796. previous descriptor. Note: the arc memory descriptor table
  797. keeps track of everything in OS pages, and we are getting information
  798. from the EFI memory descriptor table which is in EFI pages.
  799. So conversions will be made for PriorEntry since this
  800. will be in OS pages.
  801. there are two options, either shrink the previous entry (from the end)
  802. or shrink the current entry from the begining. this will be determined
  803. by each's memory type.
  804. This routine will align all blocks (they need to be aligned at the end)
  805. Note: the memory descriptor's memory types need to be in ARC type
  806. Arguments:
  807. PriorEntry - Previous memory descriptor in MDArray (in OS pages)
  808. CurrentEntry - Entry we are working on to place in MDArray (in EFI pages)
  809. Return Value:
  810. BOOLEAN value indicating if coalescing occurred (merged with previous
  811. entry. TRUE if so, FALSE otherwise. Therefore, if TRUE
  812. is returned, do not add to the descriptor table
  813. --*/
  814. {
  815. ULONG NumPagesToShrink;
  816. ULONG NumPagesToExtend;
  817. BOOLEAN RetVal = FALSE;
  818. MEMORY_DESCRIPTOR PriorEntry;
  819. MEMORY_DESCRIPTOR *MemoryDescriptor;
  820. BOOLEAN ShrinkPrior = FALSE;
  821. //
  822. // convert prev entry's page information to be in efi pages
  823. //
  824. if (PrevEntry != NULL) {
  825. #if DBG_MEMORY
  826. wsprintf(DebugBuffer,
  827. L"PriorEntry(OsPages): BasePage=0x%x PageCount=0x%x MemoryType=0x%x\r\n",
  828. PrevEntry->BasePage,
  829. PrevEntry->PageCount,
  830. PrevEntry->MemoryType
  831. );
  832. EfiPrint(DebugBuffer);
  833. #endif
  834. PriorEntry.BasePage = (ULONG)(((ULONGLONG)PrevEntry->BasePage << PAGE_SHIFT) >> EFI_PAGE_SHIFT);
  835. PriorEntry.PageCount = (ULONG)(((ULONGLONG)PrevEntry->PageCount << PAGE_SHIFT) >> EFI_PAGE_SHIFT);
  836. PriorEntry.MemoryType = PrevEntry->MemoryType;
  837. }
  838. else {
  839. //
  840. // initialize for w4 compiler... even though the below if statement
  841. // will already be true by the time we look at PriorEntry
  842. //
  843. PriorEntry.BasePage = PriorEntry.PageCount = PriorEntry.MemoryType = 0;
  844. }
  845. #if DBG_MEMORY
  846. wsprintf(DebugBuffer,
  847. L"PriorEntry(EfiPages): BasePage=0x%x PageCount=0x%x MemoryType=0x%x\r\n",
  848. PriorEntry.BasePage,
  849. PriorEntry.PageCount,
  850. PriorEntry.MemoryType
  851. );
  852. EfiPrint(DebugBuffer);
  853. wsprintf(DebugBuffer,
  854. L"CurrentEntry(EfiPages): BasePage=0x%x PageCount=0x%x MemoryType=0x%x\r\n",
  855. CurrentEntry->BasePage,
  856. CurrentEntry->PageCount,
  857. CurrentEntry->MemoryType
  858. );
  859. EfiPrint(DebugBuffer);
  860. #endif
  861. //
  862. // calculate the number of pages we have to move to be on an OS page
  863. // boundary
  864. //
  865. NumPagesToShrink = CurrentEntry->BasePage % EFI_PAGES_PER_OS_PAGE;
  866. NumPagesToExtend = (NumPagesToShrink != 0) ? (EFI_PAGES_PER_OS_PAGE - NumPagesToShrink) : 0;
  867. #if DBG_MEMORY
  868. wsprintf(DebugBuffer,
  869. L"NumPagesToShrink=0x%x, NumPagesToExtend=0x%x\r\n",
  870. NumPagesToShrink,
  871. NumPagesToExtend
  872. );
  873. EfiPrint(DebugBuffer);
  874. #endif
  875. //
  876. // do the simple cases where coealescing is easy or non-existent
  877. // case 1: No pages to Shrink
  878. // case 2: this is the first memory descriptor
  879. // case 3: previous page does not extend to new page
  880. // case 4: previous descriptor extends past current page... something is messed up
  881. // or list is not ordered. assume we are suppose to just insert this entry
  882. //
  883. if ( (PrevEntry == NULL) ||
  884. (NumPagesToShrink == 0 && (PriorEntry.MemoryType != CurrentEntry->MemoryType)) ||
  885. (PriorEntry.BasePage + PriorEntry.PageCount < CurrentEntry->BasePage - NumPagesToShrink) ||
  886. (PriorEntry.BasePage + PriorEntry.PageCount > CurrentEntry->BasePage + NumPagesToExtend)
  887. ) {
  888. CurrentEntry->BasePage -= NumPagesToShrink;
  889. CurrentEntry->PageCount += NumPagesToShrink;
  890. }
  891. //
  892. // if none of the previous cases were met, we are going to have to try
  893. // to coellesce with the previous entry
  894. //
  895. else {
  896. #if DBG_MEMORY
  897. wsprintf(
  898. DebugBuffer,
  899. L"must coellesce because the BasePage isn't module PAGE_SIZE (%x mod %x = %x).\r\n",
  900. CurrentEntry->BasePage,
  901. EFI_PAGES_PER_OS_PAGE,
  902. NumPagesToShrink );
  903. EfiPrint(DebugBuffer);
  904. #endif
  905. if (CurrentEntry->MemoryType == PriorEntry.MemoryType) {
  906. //
  907. // same memory type... coalesce the entire region
  908. //
  909. // we are only changing the base page, so we can reuse the code below
  910. // that converts efi pages to os pages
  911. //
  912. RetVal = TRUE;
  913. PrevEntry->PageCount = CurrentEntry->BasePage + CurrentEntry->PageCount - PriorEntry.BasePage;
  914. PrevEntry->BasePage = (ULONG)(((ULONGLONG)PrevEntry->BasePage << PAGE_SHIFT) >> EFI_PAGE_SHIFT);
  915. #if DBG_MEMORY
  916. wsprintf(DebugBuffer,
  917. L"Merge with previous entry (basepage=0x%x, pagecount= 0x%x, memorytype=0x%x\r\n",
  918. PrevEntry->BasePage,
  919. PrevEntry->PageCount,
  920. PrevEntry->MemoryType
  921. );
  922. EfiPrint(DebugBuffer);
  923. #endif
  924. }
  925. else {
  926. //
  927. // determine which end we will shrink
  928. //
  929. switch( CurrentEntry->MemoryType ) {
  930. case MemoryFirmwarePermanent:
  931. //
  932. // if the current type is permanent, we must steal from the prior entry
  933. //
  934. ShrinkPrior = TRUE;
  935. break;
  936. case MemoryLoadedProgram:
  937. if (PriorEntry.MemoryType == MemoryFirmwarePermanent) {
  938. ShrinkPrior = FALSE;
  939. } else {
  940. ShrinkPrior = TRUE;
  941. }
  942. break;
  943. case MemoryFirmwareTemporary:
  944. if (PriorEntry.MemoryType == MemoryFirmwarePermanent ||
  945. PriorEntry.MemoryType == MemoryLoadedProgram) {
  946. ShrinkPrior = FALSE;
  947. } else {
  948. ShrinkPrior = TRUE;
  949. }
  950. break;
  951. case MemoryFree:
  952. ShrinkPrior = FALSE;
  953. break;
  954. case MemoryBad:
  955. ShrinkPrior = TRUE;
  956. break;
  957. default:
  958. EfiPrint(L"SuMain: bad memory type in InsertDescriptor\r\n");
  959. EfiBS->Exit(EfiImageHandle, 0, 0, 0);
  960. }
  961. if (ShrinkPrior) {
  962. //
  963. // shrink the previous descriptor (from the end)
  964. //
  965. // we can just subtrace 1 OS page from the previous entry,
  966. // since we can never Shrink more than one OS page.
  967. //
  968. PrevEntry->PageCount--;
  969. CurrentEntry->BasePage -= NumPagesToShrink;
  970. CurrentEntry->PageCount += NumPagesToShrink;
  971. //
  972. // if we shrunk this to nothing, get rid of it
  973. //
  974. if (PrevEntry->PageCount == 0) {
  975. PrevEntry->BasePage = CurrentEntry->BasePage;
  976. PrevEntry->PageCount = CurrentEntry->PageCount;
  977. PrevEntry->MemoryType = CurrentEntry->MemoryType;
  978. CurrentEntry->BasePage = CurrentEntry->PageCount = CurrentEntry->MemoryType = 0;
  979. RetVal = TRUE;
  980. }
  981. #if DBG_MEMORY
  982. wsprintf(DebugBuffer,
  983. L"Shrink previous descriptor by 0x%x EFI pages\r\n",
  984. NumPagesToShrink
  985. );
  986. EfiPrint(DebugBuffer);
  987. #endif
  988. }
  989. else {
  990. //
  991. // shrink the current descriptor (from the start)
  992. //
  993. // don't have to touch the previous entry, just
  994. // shift the current entry to the next os page
  995. // boundary
  996. CurrentEntry->BasePage += NumPagesToExtend;
  997. CurrentEntry->PageCount -= NumPagesToExtend;
  998. //
  999. // if we shrunk this to nothing, get rid of it
  1000. //
  1001. if (CurrentEntry->PageCount == 0) {
  1002. //
  1003. // need to convert previous entry back to efi pages, so checks work
  1004. // at the bottome
  1005. //
  1006. PrevEntry->BasePage = (ULONG)(((ULONGLONG)PrevEntry->BasePage << PAGE_SHIFT) >> EFI_PAGE_SHIFT);
  1007. PrevEntry->PageCount = (ULONG)(((ULONGLONG)PrevEntry->PageCount << PAGE_SHIFT) >> EFI_PAGE_SHIFT);
  1008. CurrentEntry->BasePage = CurrentEntry->PageCount = CurrentEntry->MemoryType = 0;
  1009. RetVal = TRUE;
  1010. }
  1011. #if DBG_MEMORY
  1012. wsprintf(DebugBuffer,
  1013. L"Shrink this descriptor by 0x%x EFI pages\r\n",
  1014. NumPagesToExtend
  1015. );
  1016. EfiPrint(DebugBuffer);
  1017. #endif
  1018. }
  1019. }
  1020. }
  1021. //
  1022. // set one variable to the entry we modified. that way we can use the same
  1023. // code to convert efi pages to os pages + extend the page count
  1024. //
  1025. MemoryDescriptor = (RetVal == TRUE) ? PrevEntry : CurrentEntry;
  1026. #if DBG_MEMORY
  1027. wsprintf(DebugBuffer,
  1028. L"MemoryDescriptor: BasePage=0x%x PageCount=0x%x MemoryType=0x%x\r\n",
  1029. MemoryDescriptor->BasePage,
  1030. MemoryDescriptor->PageCount,
  1031. MemoryDescriptor->MemoryType
  1032. );
  1033. EfiPrint(DebugBuffer);
  1034. #endif
  1035. //
  1036. // we think we are done coalescing, and have done so successfully
  1037. // make sure this is indeed the case
  1038. //
  1039. ASSERT( MemoryDescriptor->BasePage % EFI_PAGES_PER_OS_PAGE == 0 );
  1040. if ( MemoryDescriptor->BasePage % EFI_PAGES_PER_OS_PAGE != 0 ) {
  1041. EfiPrint(L"CoalesceDescriptor: BasePage not on OS page boundary\r\n");
  1042. EfiBS->Exit(EfiImageHandle, 0, 0, 0);
  1043. }
  1044. //
  1045. // great... we did this right.
  1046. // now extend then end of a region to an os page boundary, and
  1047. // set the values to os pages (instead of efi pages)
  1048. //
  1049. NumPagesToExtend = EFI_PAGES_PER_OS_PAGE - (MemoryDescriptor->PageCount % EFI_PAGES_PER_OS_PAGE);
  1050. MemoryDescriptor->PageCount += (NumPagesToExtend == EFI_PAGES_PER_OS_PAGE) ? 0 : NumPagesToExtend;
  1051. ASSERT( MemoryDescriptor->PageCount % EFI_PAGES_PER_OS_PAGE == 0 );
  1052. if ( MemoryDescriptor->PageCount % EFI_PAGES_PER_OS_PAGE != 0 ) {
  1053. EfiPrint(L"CoalesceDescriptor: PageCount not on OS page boundary\r\n");
  1054. EfiBS->Exit(EfiImageHandle, 0, 0, 0);
  1055. }
  1056. //
  1057. // convert to os pages
  1058. //
  1059. MemoryDescriptor->PageCount = (ULONG)(((ULONGLONG)MemoryDescriptor->PageCount << EFI_PAGE_SHIFT) >> PAGE_SHIFT);
  1060. MemoryDescriptor->BasePage = (ULONG)(((ULONGLONG)MemoryDescriptor->BasePage << EFI_PAGE_SHIFT) >> PAGE_SHIFT);
  1061. #if DBG_MEMORY
  1062. wsprintf( DebugBuffer,
  1063. L"descriptor value #%x of %x, BasePage %x, NumberOfPages %x, Type (%x)\r\n",
  1064. NumberDescriptors, MaxDescriptors, MemoryDescriptor->BasePage,
  1065. MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType);
  1066. EfiPrint(DebugBuffer);
  1067. #endif
  1068. return RetVal;
  1069. }