memmap.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. memmap.c
  5. Abstract:
  6. This module implements support for returning the initial memory map from
  7. the PC/AT BIOS.
  8. Author:
  9. Evan Green 27-Feb-2014
  10. Environment:
  11. Firmware
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <uefifw.h>
  17. #include "biosfw.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. #define BIOS_MEMORY_DESCRIPTOR_COUNT 128
  22. #define E820_MAGIC 0x534D4150 // 'SMAP'
  23. //
  24. // ------------------------------------------------------ Data Type Definitions
  25. //
  26. typedef enum _E820_MEMORY_TYPE {
  27. E820TypeInvalid,
  28. E820TypeUsableMemory,
  29. E820TypeReserved,
  30. E820TypeAcpiReclaimable,
  31. E820TypeAcpiReserved,
  32. E820TypeBadMemory
  33. } E820_MEMORY_TYPE, *PE820_MEMORY_TYPE;
  34. typedef struct _E820_DESCRIPTOR {
  35. UINT32 BaseAddressLow;
  36. UINT32 BaseAddressHigh;
  37. UINT32 LengthLow;
  38. UINT32 LengthHigh;
  39. UINT32 Type;
  40. } E820_DESCRIPTOR, *PE820_DESCRIPTOR;
  41. //
  42. // ----------------------------------------------- Internal Function Prototypes
  43. //
  44. EFI_STATUS
  45. EfipGetE820MemoryMap (
  46. EFI_MEMORY_DESCRIPTOR *Map,
  47. UINTN *MapSize
  48. );
  49. EFI_STATUS
  50. EfipAddBiosMemoryDescriptor (
  51. EFI_MEMORY_DESCRIPTOR *Map,
  52. EFI_MEMORY_DESCRIPTOR *Descriptor,
  53. UINTN *MapSize,
  54. UINTN MapCapacity,
  55. BOOLEAN ForceAdd
  56. );
  57. EFI_STATUS
  58. EfipInsertDescriptorAtIndex (
  59. EFI_MEMORY_DESCRIPTOR *Map,
  60. EFI_MEMORY_DESCRIPTOR *Descriptor,
  61. UINTN Index,
  62. UINTN *MapSize,
  63. UINTN MapCapacity
  64. );
  65. //
  66. // -------------------------------------------------------------------- Globals
  67. //
  68. EFI_MEMORY_DESCRIPTOR EfiBiosMemoryMap[BIOS_MEMORY_DESCRIPTOR_COUNT];
  69. //
  70. // ------------------------------------------------------------------ Functions
  71. //
  72. EFI_STATUS
  73. EfiPlatformGetInitialMemoryMap (
  74. EFI_MEMORY_DESCRIPTOR **Map,
  75. UINTN *MapSize
  76. )
  77. /*++
  78. Routine Description:
  79. This routine returns the initial platform memory map to the EFI core. The
  80. core maintains this memory map. The memory map returned does not need to
  81. take into account the firmware image itself or stack, the EFI core will
  82. reserve those regions automatically.
  83. Arguments:
  84. Map - Supplies a pointer where the array of memory descriptors constituting
  85. the initial memory map is returned on success. The EFI core will make
  86. a copy of these descriptors, so they can be in read-only or
  87. temporary memory.
  88. MapSize - Supplies a pointer where the number of elements in the initial
  89. memory map will be returned on success.
  90. Return Value:
  91. EFI status code.
  92. --*/
  93. {
  94. UINTN Size;
  95. EFI_STATUS Status;
  96. Size = BIOS_MEMORY_DESCRIPTOR_COUNT;
  97. Status = EfipGetE820MemoryMap(EfiBiosMemoryMap, &Size);
  98. if (EFI_ERROR(Status)) {
  99. return Status;
  100. }
  101. *Map = EfiBiosMemoryMap;
  102. *MapSize = Size;
  103. return EFI_SUCCESS;
  104. }
  105. //
  106. // --------------------------------------------------------- Internal Functions
  107. //
  108. EFI_STATUS
  109. EfipGetE820MemoryMap (
  110. EFI_MEMORY_DESCRIPTOR *Map,
  111. UINTN *MapSize
  112. )
  113. /*++
  114. Routine Description:
  115. This routine gets the firmware memory map from the BIOS using int 15 E820
  116. calls.
  117. Arguments:
  118. Map - Supplies a pointer where the map will be returned on success.
  119. MapSize - Supplies a pointer that on input contains the maximum number of
  120. descriptors in the given array. On output, the number of descriptors
  121. reported will be returned.
  122. Return Value:
  123. EFI status code.
  124. --*/
  125. {
  126. EFI_PHYSICAL_ADDRESS BaseAddress;
  127. EFI_MEMORY_DESCRIPTOR Descriptor;
  128. UINTN DescriptorCount;
  129. EFI_MEMORY_TYPE DescriptorType;
  130. PE820_DESCRIPTOR E820Descriptor;
  131. E820_MEMORY_TYPE E820Type;
  132. BOOLEAN FirstCall;
  133. UINT64 Length;
  134. UINTN MaxDescriptors;
  135. UINTN MoveIndex;
  136. BIOS_CALL_CONTEXT RealModeContext;
  137. EFI_MEMORY_DESCRIPTOR *Search;
  138. UINTN SearchIndex;
  139. EFI_STATUS Status;
  140. DescriptorCount = 0;
  141. FirstCall = TRUE;
  142. MaxDescriptors = *MapSize;
  143. Status = EfipCreateBiosCallContext(&RealModeContext, 0x15);
  144. if (EFI_ERROR(Status)) {
  145. goto GetMemoryMapEnd;
  146. }
  147. E820Descriptor = (PE820_DESCRIPTOR)RealModeContext.DataPage;
  148. RealModeContext.Ebx = 0;
  149. do {
  150. //
  151. // Watch for overflow conditions or buggy firmware.
  152. //
  153. if (DescriptorCount >= MaxDescriptors) {
  154. break;
  155. }
  156. //
  157. // Set up the firmware call.
  158. //
  159. E820Descriptor->Type = E820TypeInvalid;
  160. RealModeContext.Es =
  161. ADDRESS_TO_SEGMENT((UINTN)RealModeContext.DataPage);
  162. RealModeContext.Edi = (UINTN)RealModeContext.DataPage & 0xF;
  163. RealModeContext.Edx = E820_MAGIC;
  164. RealModeContext.Eax = 0xE820;
  165. RealModeContext.Ecx = 24;
  166. //
  167. // Execute the firmware call.
  168. //
  169. EfipExecuteBiosCall(&RealModeContext);
  170. //
  171. // If eax is not set to the magic number (on the first call only), or
  172. // the carry clag is clear, then the call failed.
  173. //
  174. if ((FirstCall != FALSE) && (RealModeContext.Eax != E820_MAGIC)) {
  175. break;
  176. }
  177. FirstCall = FALSE;
  178. if ((RealModeContext.Eflags & IA32_EFLAG_CF) != 0) {
  179. break;
  180. }
  181. //
  182. // Get the descriptor information.
  183. //
  184. BaseAddress =
  185. ((EFI_PHYSICAL_ADDRESS)E820Descriptor->BaseAddressHigh << 32) |
  186. (E820Descriptor->BaseAddressLow);
  187. Length = ((EFI_PHYSICAL_ADDRESS)E820Descriptor->LengthHigh << 32) |
  188. (E820Descriptor->LengthLow);
  189. E820Type = E820Descriptor->Type;
  190. switch (E820Type) {
  191. case E820TypeUsableMemory:
  192. DescriptorType = EfiConventionalMemory;
  193. break;
  194. case E820TypeReserved:
  195. DescriptorType = EfiRuntimeServicesData;
  196. break;
  197. case E820TypeAcpiReclaimable:
  198. DescriptorType = EfiACPIReclaimMemory;
  199. break;
  200. case E820TypeAcpiReserved:
  201. DescriptorType = EfiACPIMemoryNVS;
  202. break;
  203. case E820TypeBadMemory:
  204. DescriptorType = EfiUnusableMemory;
  205. break;
  206. //
  207. // Unknown memory type. Skip this descriptor.
  208. //
  209. default:
  210. continue;
  211. }
  212. Descriptor.Type = DescriptorType;
  213. Descriptor.Padding = 0;
  214. Descriptor.PhysicalStart = BaseAddress;
  215. Descriptor.VirtualStart = 0;
  216. Descriptor.NumberOfPages = EFI_SIZE_TO_PAGES(Length);
  217. Descriptor.Attribute = 0;
  218. //
  219. // Add the descriptor to the memory map.
  220. //
  221. Status = EfipAddBiosMemoryDescriptor(Map,
  222. &Descriptor,
  223. &DescriptorCount,
  224. MaxDescriptors,
  225. FALSE);
  226. if (EFI_ERROR(Status)) {
  227. goto GetMemoryMapEnd;
  228. }
  229. } while ((RealModeContext.Ebx != 0) &&
  230. ((RealModeContext.Eflags & IA32_EFLAG_CF) == 0));
  231. //
  232. // Simply reserve the entire first megabyte.
  233. //
  234. Descriptor.Type = EfiUnusableMemory;
  235. Descriptor.Padding = 0;
  236. Descriptor.PhysicalStart = 0;
  237. Descriptor.NumberOfPages = (1024 * 1024) >> EFI_PAGE_SHIFT;
  238. Status = EfipAddBiosMemoryDescriptor(Map,
  239. &Descriptor,
  240. &DescriptorCount,
  241. MaxDescriptors,
  242. TRUE);
  243. if (EFI_ERROR(Status)) {
  244. goto GetMemoryMapEnd;
  245. }
  246. //
  247. // Mark a portion of that first megabyte usable between 0x1000 and 0x9F000.
  248. //
  249. Descriptor.Type = EfiConventionalMemory;
  250. Descriptor.Padding = 0;
  251. Descriptor.PhysicalStart = 0x1000;
  252. Descriptor.NumberOfPages = 0x9E;
  253. Status = EfipAddBiosMemoryDescriptor(Map,
  254. &Descriptor,
  255. &DescriptorCount,
  256. MaxDescriptors,
  257. TRUE);
  258. if (EFI_ERROR(Status)) {
  259. goto GetMemoryMapEnd;
  260. }
  261. //
  262. // Remove any empty regions.
  263. //
  264. SearchIndex = 0;
  265. while (SearchIndex < DescriptorCount) {
  266. Search = &(Map[SearchIndex]);
  267. if (Search->NumberOfPages == 0) {
  268. for (MoveIndex = SearchIndex;
  269. MoveIndex < DescriptorCount - 1;
  270. MoveIndex += 1) {
  271. Map[MoveIndex] = Map[MoveIndex + 1];
  272. }
  273. DescriptorCount -= 1;
  274. continue;
  275. }
  276. SearchIndex += 1;
  277. }
  278. Status = EFI_SUCCESS;
  279. GetMemoryMapEnd:
  280. *MapSize = DescriptorCount;
  281. EfipDestroyBiosCallContext(&RealModeContext);
  282. return Status;
  283. }
  284. EFI_STATUS
  285. EfipAddBiosMemoryDescriptor (
  286. EFI_MEMORY_DESCRIPTOR *Map,
  287. EFI_MEMORY_DESCRIPTOR *Descriptor,
  288. UINTN *MapSize,
  289. UINTN MapCapacity,
  290. BOOLEAN ForceAdd
  291. )
  292. /*++
  293. Routine Description:
  294. This routine adds a BIOS memory descriptor to the EFI memory map.
  295. Arguments:
  296. Map - Supplies a pointer to the current memory map.
  297. Descriptor - Supplies a pointer to the descriptor to add.
  298. MapSize - Supplies a pointer that on input contains the current size of the
  299. memory map. On output, this will be updated to reflect the added
  300. descriptor (or multiple).
  301. MapCapacity - Supplies the total capacity of the map.
  302. ForceAdd - Supplies a boolean indicating if this descriptor should trump
  303. existing descriptors for the same region. If FALSE, then automatic
  304. rules are used to determine which descriptor wins a conflict.
  305. Return Value:
  306. EFI status code.
  307. --*/
  308. {
  309. EFI_PHYSICAL_ADDRESS Base;
  310. EFI_PHYSICAL_ADDRESS End;
  311. EFI_MEMORY_DESCRIPTOR *Existing;
  312. EFI_PHYSICAL_ADDRESS ExistingEnd;
  313. BOOLEAN NewWins;
  314. EFI_MEMORY_DESCRIPTOR Remainder;
  315. UINTN SearchIndex;
  316. EFI_STATUS Status;
  317. EFI_MEMORY_TYPE Type;
  318. Base = Descriptor->PhysicalStart;
  319. End = Descriptor->PhysicalStart +
  320. (Descriptor->NumberOfPages << EFI_PAGE_SHIFT);
  321. Type = Descriptor->Type;
  322. //
  323. // Skip zero-length descriptors.
  324. //
  325. if (Descriptor->NumberOfPages == 0) {
  326. return EFI_SUCCESS;
  327. }
  328. //
  329. // Loop looking for the right place to put this descriptor in.
  330. //
  331. for (SearchIndex = 0; SearchIndex < *MapSize; SearchIndex += 1) {
  332. Existing = &(Map[SearchIndex]);
  333. ExistingEnd = Existing->PhysicalStart +
  334. (Existing->NumberOfPages << EFI_PAGE_SHIFT);
  335. //
  336. // Skip empty descriptors.
  337. //
  338. if (Existing->NumberOfPages == 0) {
  339. continue;
  340. }
  341. //
  342. // If this descriptor is entirely before the new one, keep looking.
  343. //
  344. if (ExistingEnd <= Base) {
  345. continue;
  346. }
  347. //
  348. // If the start of this descriptor is after the end of the new one,
  349. // then just insert the new one before this one.
  350. //
  351. if (Existing->PhysicalStart >= End) {
  352. Status = EfipInsertDescriptorAtIndex(Map,
  353. Descriptor,
  354. SearchIndex,
  355. MapSize,
  356. MapCapacity);
  357. goto AddBiosMemoryDescriptorEnd;
  358. }
  359. //
  360. // The existing descriptor overlaps in some way. Who wins depends on
  361. // the type. Take the new descriptor if the existing one is "free", or
  362. // if the new one is a "firmware permanent" type of memory.
  363. //
  364. NewWins = FALSE;
  365. if (ForceAdd != FALSE) {
  366. NewWins = TRUE;
  367. } else if (Existing->Type == EfiConventionalMemory) {
  368. NewWins = TRUE;
  369. } else if ((Type == EfiUnusableMemory) ||
  370. (Type == EfiRuntimeServicesCode) ||
  371. (Type == EfiRuntimeServicesData) ||
  372. (Type == EfiACPIMemoryNVS) ||
  373. (Type == EfiMemoryMappedIO) ||
  374. (Type == EfiMemoryMappedIOPortSpace) ||
  375. (Type == EfiPalCode)) {
  376. NewWins = TRUE;
  377. }
  378. //
  379. // Shrink the existing descriptor if the new one should win.
  380. //
  381. if (NewWins != FALSE) {
  382. //
  383. // If the new descriptor splits the existing one, add a remainder
  384. // descriptor.
  385. //
  386. if ((Existing->PhysicalStart < Base) &&
  387. (ExistingEnd > End)) {
  388. Remainder = *Existing;
  389. Remainder.NumberOfPages = (ExistingEnd - End) >> EFI_PAGE_SHIFT;
  390. Remainder.PhysicalStart = End;
  391. Status = EfipInsertDescriptorAtIndex(Map,
  392. &Remainder,
  393. SearchIndex + 1,
  394. MapSize,
  395. MapCapacity);
  396. if (EFI_ERROR(Status)) {
  397. goto AddBiosMemoryDescriptorEnd;
  398. }
  399. }
  400. //
  401. // Bump up the start if that's what overlaps with the new one.
  402. //
  403. if (Existing->PhysicalStart > Base) {
  404. if (ExistingEnd <= End) {
  405. Existing->NumberOfPages = 0;
  406. } else {
  407. Existing->NumberOfPages =
  408. (ExistingEnd - End) >> EFI_PAGE_SHIFT;
  409. Existing->PhysicalStart = End;
  410. }
  411. }
  412. //
  413. // Clip down the end if that's what overlaps with the new one.
  414. //
  415. if (ExistingEnd > Base) {
  416. if (Existing->PhysicalStart >= Base) {
  417. Existing->NumberOfPages = 0;
  418. } else {
  419. Existing->NumberOfPages =
  420. (Base - Existing->PhysicalStart) >> EFI_PAGE_SHIFT;
  421. }
  422. }
  423. //
  424. // The existing descriptor wins. Shrink the new descriptor.
  425. //
  426. } else {
  427. //
  428. // If the existing descriptor is completely contained within the
  429. // new descriptor, then it cuts it in two. Add the bottom portion
  430. // before this descriptor.
  431. //
  432. if ((Base < Existing->PhysicalStart) &&
  433. (End > Existing->PhysicalStart)) {
  434. Remainder = *Descriptor;
  435. Remainder.NumberOfPages =
  436. (Existing->PhysicalStart - Base) >> EFI_PAGE_SHIFT;
  437. Status = EfipInsertDescriptorAtIndex(Map,
  438. &Remainder,
  439. SearchIndex,
  440. MapSize,
  441. MapCapacity);
  442. if (EFI_ERROR(Status)) {
  443. goto AddBiosMemoryDescriptorEnd;
  444. }
  445. SearchIndex += 1;
  446. Existing = &(Map[SearchIndex]);
  447. } else {
  448. //
  449. // Bump up the start if that's what overlaps with the existing
  450. // one.
  451. //
  452. if (Base > Existing->PhysicalStart) {
  453. if (End <= ExistingEnd) {
  454. Status = EFI_SUCCESS;
  455. goto AddBiosMemoryDescriptorEnd;
  456. }
  457. Descriptor->NumberOfPages =
  458. (End - ExistingEnd) >> EFI_PAGE_SHIFT;
  459. Base = ExistingEnd;
  460. Descriptor->PhysicalStart = Base;
  461. }
  462. //
  463. // Clip down the end if that's what overlaps with the existing
  464. // one.
  465. //
  466. if (End > Existing->PhysicalStart) {
  467. if (Base >= Existing->PhysicalStart) {
  468. Status = EFI_SUCCESS;
  469. goto AddBiosMemoryDescriptorEnd;
  470. }
  471. Descriptor->NumberOfPages =
  472. (Existing->PhysicalStart - Base) >> EFI_PAGE_SHIFT;
  473. End = Descriptor->PhysicalStart +
  474. (Descriptor->NumberOfPages << EFI_PAGE_SHIFT);
  475. }
  476. }
  477. }
  478. //
  479. // If the existing descriptor is still there and is greater than the
  480. // new descriptor, insert the new descriptor here.
  481. //
  482. if ((Existing->NumberOfPages != 0) &&
  483. (Existing->PhysicalStart > Base)) {
  484. Status = EfipInsertDescriptorAtIndex(Map,
  485. Descriptor,
  486. SearchIndex,
  487. MapSize,
  488. MapCapacity);
  489. goto AddBiosMemoryDescriptorEnd;
  490. }
  491. }
  492. //
  493. // After going through the loop the descriptor still hasn't been added. So
  494. // add it here on the end.
  495. //
  496. Status = EfipInsertDescriptorAtIndex(Map,
  497. Descriptor,
  498. SearchIndex,
  499. MapSize,
  500. MapCapacity);
  501. AddBiosMemoryDescriptorEnd:
  502. return Status;
  503. }
  504. EFI_STATUS
  505. EfipInsertDescriptorAtIndex (
  506. EFI_MEMORY_DESCRIPTOR *Map,
  507. EFI_MEMORY_DESCRIPTOR *Descriptor,
  508. UINTN Index,
  509. UINTN *MapSize,
  510. UINTN MapCapacity
  511. )
  512. /*++
  513. Routine Description:
  514. This routine inserts a descriptor into the given memory map at a specific
  515. index.
  516. Arguments:
  517. Map - Supplies a pointer to the current memory map.
  518. Descriptor - Supplies a pointer to the descriptor to add.
  519. Index - Supplies the index to add the descriptor at.
  520. MapSize - Supplies a pointer that on input contains the current size of the
  521. memory map. On output, this will be updated to reflect the added
  522. descriptor (or multiple).
  523. MapCapacity - Supplies the total capacity of the map.
  524. Return Value:
  525. EFI status code.
  526. --*/
  527. {
  528. UINTN MoveIndex;
  529. if (*MapSize == MapCapacity) {
  530. return EFI_BUFFER_TOO_SMALL;
  531. }
  532. //
  533. // Scoot everything over by one.
  534. //
  535. for (MoveIndex = *MapSize; MoveIndex > Index; MoveIndex -= 1) {
  536. Map[MoveIndex] = Map[MoveIndex - 1];
  537. }
  538. Map[Index] = *Descriptor;
  539. *MapSize += 1;
  540. return EFI_SUCCESS;
  541. }