mm.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /* Memory management for efiemu */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /*
  20. To keep efiemu runtime contiguous this mm is special.
  21. It uses deferred allocation.
  22. In the first stage you may request memory with grub_efiemu_request_memalign
  23. It will give you a handle with which in the second phase you can access your
  24. memory with grub_efiemu_mm_obtain_request (handle). It's guaranteed that
  25. subsequent calls with the same handle return the same result. You can't request any additional memory once you're in the second phase
  26. */
  27. #include <grub/err.h>
  28. #include <grub/normal.h>
  29. #include <grub/mm.h>
  30. #include <grub/misc.h>
  31. #include <grub/efiemu/efiemu.h>
  32. #include <grub/memory.h>
  33. struct grub_efiemu_memrequest
  34. {
  35. struct grub_efiemu_memrequest *next;
  36. grub_efi_memory_type_t type;
  37. grub_size_t size;
  38. grub_size_t align_overhead;
  39. int handle;
  40. void *val;
  41. };
  42. /* Linked list of requested memory. */
  43. static struct grub_efiemu_memrequest *memrequests = 0;
  44. /* Memory map. */
  45. static grub_efi_memory_descriptor_t *efiemu_mmap = 0;
  46. /* Pointer to allocated memory */
  47. static void *resident_memory = 0;
  48. /* Size of requested memory per type */
  49. static grub_size_t requested_memory[GRUB_EFI_MAX_MEMORY_TYPE];
  50. /* How many slots is allocated for memory_map and how many are already used */
  51. static int mmap_reserved_size = 0, mmap_num = 0;
  52. /* Add a memory region to map*/
  53. static grub_err_t
  54. grub_efiemu_add_to_mmap (grub_uint64_t start, grub_uint64_t size,
  55. grub_efi_memory_type_t type)
  56. {
  57. grub_uint64_t page_start, npages;
  58. /* Extend map if necessary*/
  59. if (mmap_num >= mmap_reserved_size)
  60. {
  61. void *old;
  62. mmap_reserved_size = 2 * (mmap_reserved_size + 1);
  63. old = efiemu_mmap;
  64. efiemu_mmap = (grub_efi_memory_descriptor_t *)
  65. grub_realloc (efiemu_mmap, mmap_reserved_size
  66. * sizeof (grub_efi_memory_descriptor_t));
  67. if (!efiemu_mmap)
  68. {
  69. grub_free (old);
  70. return grub_errno;
  71. }
  72. }
  73. /* Fill slot*/
  74. page_start = start - (start % GRUB_EFIEMU_PAGESIZE);
  75. npages = (size + (start % GRUB_EFIEMU_PAGESIZE) + GRUB_EFIEMU_PAGESIZE - 1)
  76. / GRUB_EFIEMU_PAGESIZE;
  77. efiemu_mmap[mmap_num].physical_start = page_start;
  78. efiemu_mmap[mmap_num].virtual_start = page_start;
  79. efiemu_mmap[mmap_num].num_pages = npages;
  80. efiemu_mmap[mmap_num].type = type;
  81. mmap_num++;
  82. return GRUB_ERR_NONE;
  83. }
  84. /* Request a resident memory of type TYPE of size SIZE aligned at ALIGN
  85. ALIGN must be a divisor of page size (if it's a divisor of 4096
  86. it should be ok on all platforms)
  87. */
  88. int
  89. grub_efiemu_request_memalign (grub_size_t align, grub_size_t size,
  90. grub_efi_memory_type_t type)
  91. {
  92. grub_size_t align_overhead;
  93. struct grub_efiemu_memrequest *ret, *cur, *prev;
  94. /* Check that the request is correct */
  95. if (type <= GRUB_EFI_LOADER_CODE || type == GRUB_EFI_PERSISTENT_MEMORY ||
  96. type >= GRUB_EFI_MAX_MEMORY_TYPE)
  97. return -2;
  98. /* Add new size to requested size */
  99. align_overhead = align - (requested_memory[type]%align);
  100. if (align_overhead == align)
  101. align_overhead = 0;
  102. requested_memory[type] += align_overhead + size;
  103. /* Remember the request */
  104. ret = grub_zalloc (sizeof (*ret));
  105. if (!ret)
  106. return -1;
  107. ret->type = type;
  108. ret->size = size;
  109. ret->align_overhead = align_overhead;
  110. prev = 0;
  111. /* Add request to the end of the chain.
  112. It should be at the end because otherwise alignment isn't guaranteed */
  113. for (cur = memrequests; cur; prev = cur, cur = cur->next);
  114. if (prev)
  115. {
  116. ret->handle = prev->handle + 1;
  117. prev->next = ret;
  118. }
  119. else
  120. {
  121. ret->handle = 1; /* Avoid 0 handle*/
  122. memrequests = ret;
  123. }
  124. return ret->handle;
  125. }
  126. /* Really allocate the memory */
  127. static grub_err_t
  128. efiemu_alloc_requests (void)
  129. {
  130. grub_size_t align_overhead = 0;
  131. grub_uint8_t *curptr, *typestart;
  132. struct grub_efiemu_memrequest *cur;
  133. grub_size_t total_alloc = 0;
  134. unsigned i;
  135. /* Order of memory regions */
  136. grub_efi_memory_type_t reqorder[] =
  137. {
  138. /* First come regions usable by OS*/
  139. GRUB_EFI_LOADER_CODE,
  140. GRUB_EFI_LOADER_DATA,
  141. GRUB_EFI_BOOT_SERVICES_CODE,
  142. GRUB_EFI_BOOT_SERVICES_DATA,
  143. GRUB_EFI_CONVENTIONAL_MEMORY,
  144. GRUB_EFI_ACPI_RECLAIM_MEMORY,
  145. /* Then memory used by runtime */
  146. /* This way all our regions are in a single block */
  147. GRUB_EFI_RUNTIME_SERVICES_CODE,
  148. GRUB_EFI_RUNTIME_SERVICES_DATA,
  149. GRUB_EFI_ACPI_MEMORY_NVS,
  150. /* And then unavailable memory types. This is more for a completeness.
  151. You should double think before allocating memory of any of these types
  152. */
  153. GRUB_EFI_UNUSABLE_MEMORY,
  154. GRUB_EFI_MEMORY_MAPPED_IO,
  155. GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE,
  156. GRUB_EFI_PAL_CODE
  157. /*
  158. * These are not allocatable:
  159. * GRUB_EFI_RESERVED_MEMORY_TYPE
  160. * GRUB_EFI_PERSISTENT_MEMORY
  161. * >= GRUB_EFI_MAX_MEMORY_TYPE
  162. */
  163. };
  164. /* Compute total memory needed */
  165. for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++)
  166. {
  167. align_overhead = GRUB_EFIEMU_PAGESIZE
  168. - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE);
  169. if (align_overhead == GRUB_EFIEMU_PAGESIZE)
  170. align_overhead = 0;
  171. total_alloc += requested_memory[reqorder[i]] + align_overhead;
  172. }
  173. /* Allocate the whole memory in one block */
  174. resident_memory = grub_memalign (GRUB_EFIEMU_PAGESIZE, total_alloc);
  175. if (!resident_memory)
  176. return grub_errno;
  177. /* Split the memory into blocks by type */
  178. curptr = resident_memory;
  179. for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++)
  180. {
  181. if (!requested_memory[reqorder[i]])
  182. continue;
  183. typestart = curptr;
  184. /* Write pointers to requests */
  185. for (cur = memrequests; cur; cur = cur->next)
  186. if (cur->type == reqorder[i])
  187. {
  188. curptr = ((grub_uint8_t *)curptr) + cur->align_overhead;
  189. cur->val = curptr;
  190. curptr = ((grub_uint8_t *)curptr) + cur->size;
  191. }
  192. /* Ensure that the regions are page-aligned */
  193. align_overhead = GRUB_EFIEMU_PAGESIZE
  194. - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE);
  195. if (align_overhead == GRUB_EFIEMU_PAGESIZE)
  196. align_overhead = 0;
  197. curptr = ((grub_uint8_t *) curptr) + align_overhead;
  198. /* Add the region to memory map */
  199. grub_efiemu_add_to_mmap ((grub_addr_t) typestart,
  200. curptr - typestart, reqorder[i]);
  201. }
  202. return GRUB_ERR_NONE;
  203. }
  204. /* Get a pointer to requested memory from handle */
  205. void *
  206. grub_efiemu_mm_obtain_request (int handle)
  207. {
  208. struct grub_efiemu_memrequest *cur;
  209. for (cur = memrequests; cur; cur = cur->next)
  210. if (cur->handle == handle)
  211. return cur->val;
  212. return 0;
  213. }
  214. /* Get type of requested memory by handle */
  215. grub_efi_memory_type_t
  216. grub_efiemu_mm_get_type (int handle)
  217. {
  218. struct grub_efiemu_memrequest *cur;
  219. for (cur = memrequests; cur; cur = cur->next)
  220. if (cur->handle == handle)
  221. return cur->type;
  222. return 0;
  223. }
  224. /* Free a request */
  225. void
  226. grub_efiemu_mm_return_request (int handle)
  227. {
  228. struct grub_efiemu_memrequest *cur, *prev;
  229. /* Remove head if necessary */
  230. while (memrequests && memrequests->handle == handle)
  231. {
  232. cur = memrequests->next;
  233. grub_free (memrequests);
  234. memrequests = cur;
  235. }
  236. if (!memrequests)
  237. return;
  238. /* Remove request from a middle of chain*/
  239. for (prev = memrequests, cur = prev->next; cur;)
  240. if (cur->handle == handle)
  241. {
  242. prev->next = cur->next;
  243. grub_free (cur);
  244. cur = prev->next;
  245. }
  246. else
  247. {
  248. prev = cur;
  249. cur = prev->next;
  250. }
  251. }
  252. /* Helper for grub_efiemu_mmap_init. */
  253. static int
  254. bounds_hook (grub_uint64_t addr __attribute__ ((unused)),
  255. grub_uint64_t size __attribute__ ((unused)),
  256. grub_memory_type_t type __attribute__ ((unused)),
  257. void *data __attribute__ ((unused)))
  258. {
  259. mmap_reserved_size++;
  260. return 0;
  261. }
  262. /* Reserve space for memory map */
  263. static grub_err_t
  264. grub_efiemu_mmap_init (void)
  265. {
  266. // the place for memory used by efiemu itself
  267. mmap_reserved_size = GRUB_EFI_MAX_MEMORY_TYPE + 1;
  268. #ifndef GRUB_MACHINE_EMU
  269. grub_machine_mmap_iterate (bounds_hook, NULL);
  270. #endif
  271. return GRUB_ERR_NONE;
  272. }
  273. /* This is a drop-in replacement of grub_efi_get_memory_map */
  274. /* Get the memory map as defined in the EFI spec. Return 1 if successful,
  275. return 0 if partial, or return -1 if an error occurs. */
  276. int
  277. grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size,
  278. grub_efi_memory_descriptor_t *memory_map,
  279. grub_efi_uintn_t *map_key,
  280. grub_efi_uintn_t *descriptor_size,
  281. grub_efi_uint32_t *descriptor_version)
  282. {
  283. if (!efiemu_mmap)
  284. {
  285. grub_error (GRUB_ERR_INVALID_COMMAND,
  286. "you need to first launch efiemu_prepare");
  287. return -1;
  288. }
  289. if (*memory_map_size < mmap_num * sizeof (grub_efi_memory_descriptor_t))
  290. {
  291. *memory_map_size = mmap_num * sizeof (grub_efi_memory_descriptor_t);
  292. return 0;
  293. }
  294. *memory_map_size = mmap_num * sizeof (grub_efi_memory_descriptor_t);
  295. grub_memcpy (memory_map, efiemu_mmap, *memory_map_size);
  296. if (descriptor_size)
  297. *descriptor_size = sizeof (grub_efi_memory_descriptor_t);
  298. if (descriptor_version)
  299. *descriptor_version = 1;
  300. if (map_key)
  301. *map_key = 0;
  302. return 1;
  303. }
  304. grub_err_t
  305. grub_efiemu_finish_boot_services (grub_efi_uintn_t *memory_map_size,
  306. grub_efi_memory_descriptor_t *memory_map,
  307. grub_efi_uintn_t *map_key,
  308. grub_efi_uintn_t *descriptor_size,
  309. grub_efi_uint32_t *descriptor_version)
  310. {
  311. int val = grub_efiemu_get_memory_map (memory_map_size,
  312. memory_map, map_key,
  313. descriptor_size,
  314. descriptor_version);
  315. if (val == 1)
  316. return GRUB_ERR_NONE;
  317. if (val == -1)
  318. return grub_errno;
  319. return grub_error (GRUB_ERR_IO, "memory map buffer is too small");
  320. }
  321. /* Free everything */
  322. grub_err_t
  323. grub_efiemu_mm_unload (void)
  324. {
  325. struct grub_efiemu_memrequest *cur, *d;
  326. for (cur = memrequests; cur;)
  327. {
  328. d = cur->next;
  329. grub_free (cur);
  330. cur = d;
  331. }
  332. memrequests = 0;
  333. grub_memset (&requested_memory, 0, sizeof (requested_memory));
  334. grub_free (resident_memory);
  335. resident_memory = 0;
  336. grub_free (efiemu_mmap);
  337. efiemu_mmap = 0;
  338. mmap_reserved_size = mmap_num = 0;
  339. return GRUB_ERR_NONE;
  340. }
  341. /* This function should be called before doing any requests */
  342. grub_err_t
  343. grub_efiemu_mm_init (void)
  344. {
  345. grub_err_t err;
  346. err = grub_efiemu_mm_unload ();
  347. if (err)
  348. return err;
  349. grub_efiemu_mmap_init ();
  350. return GRUB_ERR_NONE;
  351. }
  352. /* Helper for grub_efiemu_mmap_fill. */
  353. static int
  354. fill_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
  355. void *data __attribute__ ((unused)))
  356. {
  357. switch (type)
  358. {
  359. case GRUB_MEMORY_AVAILABLE:
  360. return grub_efiemu_add_to_mmap (addr, size,
  361. GRUB_EFI_CONVENTIONAL_MEMORY);
  362. case GRUB_MEMORY_ACPI:
  363. return grub_efiemu_add_to_mmap (addr, size,
  364. GRUB_EFI_ACPI_RECLAIM_MEMORY);
  365. case GRUB_MEMORY_NVS:
  366. return grub_efiemu_add_to_mmap (addr, size,
  367. GRUB_EFI_ACPI_MEMORY_NVS);
  368. case GRUB_MEMORY_PERSISTENT:
  369. case GRUB_MEMORY_PERSISTENT_LEGACY:
  370. return grub_efiemu_add_to_mmap (addr, size,
  371. GRUB_EFI_PERSISTENT_MEMORY);
  372. default:
  373. grub_dprintf ("efiemu",
  374. "Unknown memory type %d. Assuming unusable\n", type);
  375. /* FALLTHROUGH */
  376. case GRUB_MEMORY_RESERVED:
  377. return grub_efiemu_add_to_mmap (addr, size,
  378. GRUB_EFI_UNUSABLE_MEMORY);
  379. }
  380. }
  381. /* Copy host memory map */
  382. static grub_err_t
  383. grub_efiemu_mmap_fill (void)
  384. {
  385. #ifndef GRUB_MACHINE_EMU
  386. grub_machine_mmap_iterate (fill_hook, NULL);
  387. #endif
  388. return GRUB_ERR_NONE;
  389. }
  390. grub_err_t
  391. grub_efiemu_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
  392. {
  393. unsigned i;
  394. for (i = 0; i < (unsigned) mmap_num; i++)
  395. switch (efiemu_mmap[i].type)
  396. {
  397. case GRUB_EFI_RUNTIME_SERVICES_CODE:
  398. hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096,
  399. GRUB_MEMORY_CODE, hook_data);
  400. break;
  401. case GRUB_EFI_UNUSABLE_MEMORY:
  402. hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096,
  403. GRUB_MEMORY_BADRAM, hook_data);
  404. break;
  405. case GRUB_EFI_RESERVED_MEMORY_TYPE:
  406. case GRUB_EFI_RUNTIME_SERVICES_DATA:
  407. case GRUB_EFI_MEMORY_MAPPED_IO:
  408. case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE:
  409. case GRUB_EFI_PAL_CODE:
  410. default:
  411. hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096,
  412. GRUB_MEMORY_RESERVED, hook_data);
  413. break;
  414. case GRUB_EFI_LOADER_CODE:
  415. case GRUB_EFI_LOADER_DATA:
  416. case GRUB_EFI_BOOT_SERVICES_CODE:
  417. case GRUB_EFI_BOOT_SERVICES_DATA:
  418. case GRUB_EFI_CONVENTIONAL_MEMORY:
  419. hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096,
  420. GRUB_MEMORY_AVAILABLE, hook_data);
  421. break;
  422. case GRUB_EFI_ACPI_RECLAIM_MEMORY:
  423. hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096,
  424. GRUB_MEMORY_ACPI, hook_data);
  425. break;
  426. case GRUB_EFI_ACPI_MEMORY_NVS:
  427. hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096,
  428. GRUB_MEMORY_NVS, hook_data);
  429. break;
  430. case GRUB_EFI_PERSISTENT_MEMORY:
  431. hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096,
  432. GRUB_MEMORY_PERSISTENT, hook_data);
  433. break;
  434. }
  435. return 0;
  436. }
  437. /* This function resolves overlapping regions and sorts the memory map
  438. It uses scanline (sweeping) algorithm
  439. */
  440. static grub_err_t
  441. grub_efiemu_mmap_sort_and_uniq (void)
  442. {
  443. /* If same page is used by multiple types it's resolved
  444. according to priority
  445. 0 - free memory
  446. 1 - memory immediately usable after ExitBootServices
  447. 2 - memory usable after loading ACPI tables
  448. 3 - efiemu memory
  449. 4 - unusable memory
  450. */
  451. int priority[GRUB_EFI_MAX_MEMORY_TYPE] =
  452. {
  453. [GRUB_EFI_RESERVED_MEMORY_TYPE] = 4,
  454. [GRUB_EFI_LOADER_CODE] = 1,
  455. [GRUB_EFI_LOADER_DATA] = 1,
  456. [GRUB_EFI_BOOT_SERVICES_CODE] = 1,
  457. [GRUB_EFI_BOOT_SERVICES_DATA] = 1,
  458. [GRUB_EFI_RUNTIME_SERVICES_CODE] = 3,
  459. [GRUB_EFI_RUNTIME_SERVICES_DATA] = 3,
  460. [GRUB_EFI_CONVENTIONAL_MEMORY] = 0,
  461. [GRUB_EFI_UNUSABLE_MEMORY] = 4,
  462. [GRUB_EFI_ACPI_RECLAIM_MEMORY] = 2,
  463. [GRUB_EFI_ACPI_MEMORY_NVS] = 3,
  464. [GRUB_EFI_MEMORY_MAPPED_IO] = 4,
  465. [GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE] = 4,
  466. [GRUB_EFI_PAL_CODE] = 4,
  467. [GRUB_EFI_PERSISTENT_MEMORY] = 4
  468. };
  469. int i, j, k, done;
  470. /* Scanline events */
  471. struct grub_efiemu_mmap_scan
  472. {
  473. /* At which memory address*/
  474. grub_uint64_t pos;
  475. /* 0 = region starts, 1 = region ends */
  476. int type;
  477. /* Which type of memory region */
  478. grub_efi_memory_type_t memtype;
  479. };
  480. struct grub_efiemu_mmap_scan *scanline_events;
  481. struct grub_efiemu_mmap_scan t;
  482. /* Previous scanline event */
  483. grub_uint64_t lastaddr;
  484. int lasttype;
  485. /* Current scanline event */
  486. int curtype;
  487. /* how many regions of given type overlap at current location */
  488. int present[GRUB_EFI_MAX_MEMORY_TYPE];
  489. /* Here is stored the resulting memory map*/
  490. grub_efi_memory_descriptor_t *result;
  491. /* Initialize variables*/
  492. grub_memset (present, 0, sizeof (int) * GRUB_EFI_MAX_MEMORY_TYPE);
  493. scanline_events = (struct grub_efiemu_mmap_scan *)
  494. grub_calloc (mmap_num, sizeof (struct grub_efiemu_mmap_scan) * 2);
  495. /* Number of chunks can't increase more than by factor of 2 */
  496. result = (grub_efi_memory_descriptor_t *)
  497. grub_calloc (mmap_num, sizeof (grub_efi_memory_descriptor_t) * 2);
  498. if (!result || !scanline_events)
  499. {
  500. grub_free (result);
  501. grub_free (scanline_events);
  502. return grub_errno;
  503. }
  504. /* Register scanline events */
  505. for (i = 0; i < mmap_num; i++)
  506. {
  507. scanline_events[2 * i].pos = efiemu_mmap[i].physical_start;
  508. scanline_events[2 * i].type = 0;
  509. scanline_events[2 * i].memtype = efiemu_mmap[i].type;
  510. scanline_events[2 * i + 1].pos = efiemu_mmap[i].physical_start
  511. + efiemu_mmap[i].num_pages * GRUB_EFIEMU_PAGESIZE;
  512. scanline_events[2 * i + 1].type = 1;
  513. scanline_events[2 * i + 1].memtype = efiemu_mmap[i].type;
  514. }
  515. /* Primitive bubble sort. It has complexity O(n^2) but since we're
  516. unlikely to have more than 100 chunks it's probably one of the
  517. fastest for one purpose */
  518. done = 1;
  519. while (done)
  520. {
  521. done = 0;
  522. for (i = 0; i < 2 * mmap_num - 1; i++)
  523. if (scanline_events[i + 1].pos < scanline_events[i].pos)
  524. {
  525. t = scanline_events[i + 1];
  526. scanline_events[i + 1] = scanline_events[i];
  527. scanline_events[i] = t;
  528. done = 1;
  529. }
  530. }
  531. /* Pointer in resulting memory map */
  532. j = 0;
  533. lastaddr = scanline_events[0].pos;
  534. lasttype = scanline_events[0].memtype;
  535. for (i = 0; i < 2 * mmap_num; i++)
  536. {
  537. /* Process event */
  538. if (scanline_events[i].type)
  539. present[scanline_events[i].memtype]--;
  540. else
  541. present[scanline_events[i].memtype]++;
  542. /* Determine current region type */
  543. curtype = -1;
  544. for (k = 0; k < GRUB_EFI_MAX_MEMORY_TYPE; k++)
  545. if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
  546. curtype = k;
  547. /* Add memory region to resulting map if necessary */
  548. if ((curtype == -1 || curtype != lasttype)
  549. && lastaddr != scanline_events[i].pos
  550. && lasttype != -1)
  551. {
  552. result[j].virtual_start = result[j].physical_start = lastaddr;
  553. result[j].num_pages = (scanline_events[i].pos - lastaddr)
  554. / GRUB_EFIEMU_PAGESIZE;
  555. result[j].type = lasttype;
  556. /* We set runtime attribute on pages we need to be mapped */
  557. result[j].attribute
  558. = (lasttype == GRUB_EFI_RUNTIME_SERVICES_CODE
  559. || lasttype == GRUB_EFI_RUNTIME_SERVICES_DATA)
  560. ? GRUB_EFI_MEMORY_RUNTIME : 0;
  561. grub_dprintf ("efiemu",
  562. "mmap entry: type %d start 0x%llx 0x%llx pages\n",
  563. result[j].type,
  564. result[j].physical_start, result[j].num_pages);
  565. j++;
  566. }
  567. /* Update last values if necessary */
  568. if (curtype == -1 || curtype != lasttype)
  569. {
  570. lasttype = curtype;
  571. lastaddr = scanline_events[i].pos;
  572. }
  573. }
  574. grub_free (scanline_events);
  575. /* Shrink resulting memory map to really used size and replace efiemu_mmap
  576. by new value */
  577. grub_free (efiemu_mmap);
  578. efiemu_mmap = grub_realloc (result, j * sizeof (*result));
  579. return GRUB_ERR_NONE;
  580. }
  581. /* This function is called to switch from first to second phase */
  582. grub_err_t
  583. grub_efiemu_mm_do_alloc (void)
  584. {
  585. grub_err_t err;
  586. /* Preallocate mmap */
  587. efiemu_mmap = (grub_efi_memory_descriptor_t *)
  588. grub_calloc (mmap_reserved_size, sizeof (grub_efi_memory_descriptor_t));
  589. if (!efiemu_mmap)
  590. {
  591. grub_efiemu_unload ();
  592. return grub_errno;
  593. }
  594. err = efiemu_alloc_requests ();
  595. if (err)
  596. return err;
  597. err = grub_efiemu_mmap_fill ();
  598. if (err)
  599. return err;
  600. return grub_efiemu_mmap_sort_and_uniq ();
  601. }