1 /* mm.c - generic EFI memory management */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/misc.h>
22 #include <grub/efi/api.h>
23 #include <grub/efi/efi.h>
24 #include <grub/cpu/efi/memory.h>
26 #if defined (__i386__) || defined (__x86_64__)
30 #define NEXT_MEMORY_DESCRIPTOR(desc, size) \
31 ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
33 #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12)
34 #define BYTES_TO_PAGES_DOWN(bytes) ((bytes) >> 12)
35 #define PAGES_TO_BYTES(pages) ((pages) << 12)
37 /* The size of a memory map obtained from the firmware. This must be
38 a multiplier of 4KB. */
39 #define MEMORY_MAP_SIZE 0x3000
41 /* The minimum and maximum heap size for GRUB itself. */
42 #define MIN_HEAP_SIZE 0x100000
43 #define MAX_HEAP_SIZE (1600 * 0x100000)
45 static void *finish_mmap_buf
= 0;
46 static grub_efi_uintn_t finish_mmap_size
= 0;
47 static grub_efi_uintn_t finish_key
= 0;
48 static grub_efi_uintn_t finish_desc_size
;
49 static grub_efi_uint32_t finish_desc_version
;
50 int grub_efi_is_finished
= 0;
52 static grub_efi_uint64_t g_total_pages
;
53 static grub_efi_uint64_t g_required_pages
;
56 * We need to roll back EFI allocations on exit. Remember allocations that
59 struct efi_allocation
;
60 struct efi_allocation
{
61 grub_efi_physical_address_t address
;
62 grub_efi_uint64_t pages
;
63 struct efi_allocation
*next
;
65 static struct efi_allocation
*efi_allocated_memory
;
68 grub_efi_store_alloc (grub_efi_physical_address_t address
,
69 grub_efi_uintn_t pages
)
71 grub_efi_boot_services_t
*b
;
72 struct efi_allocation
*alloc
;
73 grub_efi_status_t status
;
75 b
= grub_efi_system_table
->boot_services
;
76 status
= efi_call_3 (b
->allocate_pool
, GRUB_EFI_LOADER_DATA
,
77 sizeof(*alloc
), (void**)&alloc
);
79 if (status
== GRUB_EFI_SUCCESS
)
81 alloc
->next
= efi_allocated_memory
;
82 alloc
->address
= address
;
84 efi_allocated_memory
= alloc
;
87 grub_printf ("Could not malloc memory to remember EFI allocation. "
88 "Exiting GRUB won't free all memory.\n");
92 grub_efi_drop_alloc (grub_efi_physical_address_t address
,
93 grub_efi_uintn_t pages
)
95 struct efi_allocation
*ea
, *eap
;
96 grub_efi_boot_services_t
*b
;
98 b
= grub_efi_system_table
->boot_services
;
100 for (eap
= NULL
, ea
= efi_allocated_memory
; ea
; eap
= ea
, ea
= ea
->next
)
102 if (ea
->address
!= address
|| ea
->pages
!= pages
)
105 /* Remove the current entry from the list. */
107 eap
->next
= ea
->next
;
109 efi_allocated_memory
= ea
->next
;
111 /* Then free the memory backing it. */
112 efi_call_1 (b
->free_pool
, ea
);
114 /* And leave, we're done. */
119 /* Allocate pages. Return the pointer to the first of allocated pages. */
121 grub_efi_allocate_pages_real (grub_efi_physical_address_t address
,
122 grub_efi_uintn_t pages
,
123 grub_efi_allocate_type_t alloctype
,
124 grub_efi_memory_type_t memtype
)
126 grub_efi_status_t status
;
127 grub_efi_boot_services_t
*b
;
129 /* Limit the memory access to less than 4GB for 32-bit platforms. */
130 if (address
> GRUB_EFI_MAX_USABLE_ADDRESS
)
133 b
= grub_efi_system_table
->boot_services
;
134 status
= efi_call_4 (b
->allocate_pages
, alloctype
, memtype
, pages
, &address
);
135 if (status
!= GRUB_EFI_SUCCESS
)
140 /* Uggh, the address 0 was allocated... This is too annoying,
141 so reallocate another one. */
142 address
= GRUB_EFI_MAX_USABLE_ADDRESS
;
143 status
= efi_call_4 (b
->allocate_pages
, alloctype
, memtype
, pages
, &address
);
144 grub_efi_free_pages (0, pages
);
145 if (status
!= GRUB_EFI_SUCCESS
)
149 grub_efi_store_alloc (address
, pages
);
151 return (void *) ((grub_addr_t
) address
);
155 grub_efi_allocate_any_pages (grub_efi_uintn_t pages
)
157 return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS
,
158 pages
, GRUB_EFI_ALLOCATE_MAX_ADDRESS
,
159 GRUB_EFI_LOADER_DATA
);
163 grub_efi_allocate_fixed (grub_efi_physical_address_t address
,
164 grub_efi_uintn_t pages
)
166 return grub_efi_allocate_pages_real (address
, pages
,
167 GRUB_EFI_ALLOCATE_ADDRESS
,
168 GRUB_EFI_LOADER_DATA
);
171 /* Free pages starting from ADDRESS. */
173 grub_efi_free_pages (grub_efi_physical_address_t address
,
174 grub_efi_uintn_t pages
)
176 grub_efi_boot_services_t
*b
;
178 b
= grub_efi_system_table
->boot_services
;
179 efi_call_2 (b
->free_pages
, address
, pages
);
181 grub_efi_drop_alloc (address
, pages
);
184 #if defined (__i386__) || defined (__x86_64__)
186 /* Helper for stop_broadcom. */
188 find_card (grub_pci_device_t dev
, grub_pci_id_t pciid
,
189 void *data
__attribute__ ((unused
)))
191 grub_pci_address_t addr
;
193 grub_uint16_t pm_state
;
195 if ((pciid
& 0xffff) != GRUB_PCI_VENDOR_BROADCOM
)
198 addr
= grub_pci_make_address (dev
, GRUB_PCI_REG_CLASS
);
199 if (grub_pci_read (addr
) >> 24 != GRUB_PCI_CLASS_NETWORK
)
201 cap
= grub_pci_find_capability (dev
, GRUB_PCI_CAP_POWER_MANAGEMENT
);
204 addr
= grub_pci_make_address (dev
, cap
+ 4);
205 pm_state
= grub_pci_read_word (addr
);
206 pm_state
= pm_state
| 0x03;
207 grub_pci_write_word (addr
, pm_state
);
208 grub_pci_read_word (addr
);
215 grub_pci_iterate (find_card
, NULL
);
221 grub_efi_finish_boot_services (grub_efi_uintn_t
*outbuf_size
, void *outbuf
,
222 grub_efi_uintn_t
*map_key
,
223 grub_efi_uintn_t
*efi_desc_size
,
224 grub_efi_uint32_t
*efi_desc_version
)
226 grub_efi_boot_services_t
*b
;
227 grub_efi_status_t status
;
229 #if defined (__i386__) || defined (__x86_64__)
230 const grub_uint16_t apple
[] = { 'A', 'p', 'p', 'l', 'e' };
233 is_apple
= (grub_memcmp (grub_efi_system_table
->firmware_vendor
,
234 apple
, sizeof (apple
)) == 0);
239 if (grub_efi_get_memory_map (&finish_mmap_size
, finish_mmap_buf
, &finish_key
,
240 &finish_desc_size
, &finish_desc_version
) < 0)
241 return grub_error (GRUB_ERR_IO
, "couldn't retrieve memory map");
243 if (outbuf
&& *outbuf_size
< finish_mmap_size
)
244 return grub_error (GRUB_ERR_IO
, "memory map buffer is too small");
246 finish_mmap_buf
= grub_malloc (finish_mmap_size
);
247 if (!finish_mmap_buf
)
250 if (grub_efi_get_memory_map (&finish_mmap_size
, finish_mmap_buf
, &finish_key
,
251 &finish_desc_size
, &finish_desc_version
) <= 0)
253 grub_free (finish_mmap_buf
);
254 return grub_error (GRUB_ERR_IO
, "couldn't retrieve memory map");
257 b
= grub_efi_system_table
->boot_services
;
258 status
= efi_call_2 (b
->exit_boot_services
, grub_efi_image_handle
,
260 if (status
== GRUB_EFI_SUCCESS
)
263 if (status
!= GRUB_EFI_INVALID_PARAMETER
)
265 grub_free (finish_mmap_buf
);
266 return grub_error (GRUB_ERR_IO
, "couldn't terminate EFI services");
269 grub_free (finish_mmap_buf
);
270 grub_printf ("Trying to terminate EFI services again\n");
272 grub_efi_is_finished
= 1;
274 *outbuf_size
= finish_mmap_size
;
276 grub_memcpy (outbuf
, finish_mmap_buf
, finish_mmap_size
);
278 *map_key
= finish_key
;
280 *efi_desc_size
= finish_desc_size
;
281 if (efi_desc_version
)
282 *efi_desc_version
= finish_desc_version
;
284 #if defined (__i386__) || defined (__x86_64__)
289 return GRUB_ERR_NONE
;
293 * To obtain the UEFI memory map, we must pass a buffer of sufficient size
294 * to hold the entire map. This function returns a sane start value for
298 grub_efi_find_mmap_size (void)
300 grub_efi_uintn_t mmap_size
= 0;
301 grub_efi_uintn_t desc_size
;
303 if (grub_efi_get_memory_map (&mmap_size
, NULL
, NULL
, &desc_size
, 0) < 0)
305 grub_error (GRUB_ERR_IO
, "cannot get EFI memory map size");
310 * Add an extra page, since UEFI can alter the memory map itself on
311 * callbacks or explicit calls, including console output.
313 return ALIGN_UP (mmap_size
+ GRUB_EFI_PAGE_SIZE
, GRUB_EFI_PAGE_SIZE
);
316 /* Get the memory map as defined in the EFI spec. Return 1 if successful,
317 return 0 if partial, or return -1 if an error occurs. */
319 grub_efi_get_memory_map (grub_efi_uintn_t
*memory_map_size
,
320 grub_efi_memory_descriptor_t
*memory_map
,
321 grub_efi_uintn_t
*map_key
,
322 grub_efi_uintn_t
*descriptor_size
,
323 grub_efi_uint32_t
*descriptor_version
)
325 grub_efi_status_t status
;
326 grub_efi_boot_services_t
*b
;
327 grub_efi_uintn_t key
;
328 grub_efi_uint32_t version
;
329 grub_efi_uintn_t size
;
331 if (grub_efi_is_finished
)
334 if (*memory_map_size
< finish_mmap_size
)
336 grub_memcpy (memory_map
, finish_mmap_buf
, *memory_map_size
);
341 grub_memcpy (memory_map
, finish_mmap_buf
, finish_mmap_size
);
344 *memory_map_size
= finish_mmap_size
;
346 *map_key
= finish_key
;
348 *descriptor_size
= finish_desc_size
;
349 if (descriptor_version
)
350 *descriptor_version
= finish_desc_version
;
354 /* Allow some parameters to be missing. */
357 if (! descriptor_version
)
358 descriptor_version
= &version
;
359 if (! descriptor_size
)
360 descriptor_size
= &size
;
362 b
= grub_efi_system_table
->boot_services
;
363 status
= efi_call_5 (b
->get_memory_map
, memory_map_size
, memory_map
, map_key
,
364 descriptor_size
, descriptor_version
);
365 if (*descriptor_size
== 0)
366 *descriptor_size
= sizeof (grub_efi_memory_descriptor_t
);
367 if (status
== GRUB_EFI_SUCCESS
)
369 else if (status
== GRUB_EFI_BUFFER_TOO_SMALL
)
375 /* Sort the memory map in place. */
377 sort_memory_map (grub_efi_memory_descriptor_t
*memory_map
,
378 grub_efi_uintn_t desc_size
,
379 grub_efi_memory_descriptor_t
*memory_map_end
)
381 grub_efi_memory_descriptor_t
*d1
;
382 grub_efi_memory_descriptor_t
*d2
;
384 for (d1
= memory_map
;
386 d1
= NEXT_MEMORY_DESCRIPTOR (d1
, desc_size
))
388 grub_efi_memory_descriptor_t
*max_desc
= d1
;
390 for (d2
= NEXT_MEMORY_DESCRIPTOR (d1
, desc_size
);
392 d2
= NEXT_MEMORY_DESCRIPTOR (d2
, desc_size
))
394 if (max_desc
->num_pages
< d2
->num_pages
)
400 grub_efi_memory_descriptor_t tmp
;
409 /* Filter the descriptors. GRUB needs only available memory. */
410 static grub_efi_memory_descriptor_t
*
411 filter_memory_map (grub_efi_memory_descriptor_t
*memory_map
,
412 grub_efi_memory_descriptor_t
*filtered_memory_map
,
413 grub_efi_uintn_t desc_size
,
414 grub_efi_memory_descriptor_t
*memory_map_end
)
416 grub_efi_memory_descriptor_t
*desc
;
417 grub_efi_memory_descriptor_t
*filtered_desc
;
419 for (desc
= memory_map
, filtered_desc
= filtered_memory_map
;
420 desc
< memory_map_end
;
421 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
423 if (desc
->type
== GRUB_EFI_CONVENTIONAL_MEMORY
425 && desc
->physical_start
<= GRUB_EFI_MAX_USABLE_ADDRESS
427 && desc
->physical_start
+ PAGES_TO_BYTES (desc
->num_pages
) > 0x100000
428 && desc
->num_pages
!= 0)
430 grub_memcpy (filtered_desc
, desc
, desc_size
);
432 /* Avoid less than 1MB, because some loaders seem to be confused. */
433 if (desc
->physical_start
< 0x100000)
435 desc
->num_pages
-= BYTES_TO_PAGES (0x100000
436 - desc
->physical_start
);
437 desc
->physical_start
= 0x100000;
441 if (BYTES_TO_PAGES (filtered_desc
->physical_start
)
442 + filtered_desc
->num_pages
443 > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS
))
444 filtered_desc
->num_pages
445 = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS
)
446 - BYTES_TO_PAGES (filtered_desc
->physical_start
));
449 if (filtered_desc
->num_pages
== 0)
452 filtered_desc
= NEXT_MEMORY_DESCRIPTOR (filtered_desc
, desc_size
);
456 return filtered_desc
;
459 /* Return the total number of pages. */
460 static grub_efi_uint64_t
461 get_total_pages (grub_efi_memory_descriptor_t
*memory_map
,
462 grub_efi_uintn_t desc_size
,
463 grub_efi_memory_descriptor_t
*memory_map_end
)
465 grub_efi_memory_descriptor_t
*desc
;
466 grub_efi_uint64_t total
= 0;
468 for (desc
= memory_map
;
469 desc
< memory_map_end
;
470 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
471 total
+= desc
->num_pages
;
476 /* Add memory regions. */
478 add_memory_regions (grub_efi_memory_descriptor_t
*memory_map
,
479 grub_efi_uintn_t desc_size
,
480 grub_efi_memory_descriptor_t
*memory_map_end
,
481 grub_efi_uint64_t required_pages
)
483 grub_efi_memory_descriptor_t
*desc
;
485 for (desc
= memory_map
;
486 desc
< memory_map_end
;
487 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
489 grub_efi_uint64_t pages
;
490 grub_efi_physical_address_t start
;
493 start
= desc
->physical_start
;
494 pages
= desc
->num_pages
;
495 if (pages
> required_pages
)
497 start
+= PAGES_TO_BYTES (pages
- required_pages
);
498 pages
= required_pages
;
501 addr
= grub_efi_allocate_pages_real (start
, pages
,
502 GRUB_EFI_ALLOCATE_ADDRESS
,
503 GRUB_EFI_LOADER_CODE
);
505 grub_fatal ("cannot allocate conventional memory %p with %u pages",
506 (void *) ((grub_addr_t
) start
),
509 grub_mm_init_region (addr
, PAGES_TO_BYTES (pages
));
511 required_pages
-= pages
;
512 if (required_pages
== 0)
516 if (required_pages
> 0)
517 grub_fatal ("too little memory");
521 grub_efi_memory_fini (void)
524 * Free all stale allocations. grub_efi_free_pages() will remove
525 * the found entry from the list and it will always find the first
526 * list entry (efi_allocated_memory is the list start). Hence we
527 * remove all entries from the list until none is left altogether.
529 while (efi_allocated_memory
)
530 grub_efi_free_pages (efi_allocated_memory
->address
,
531 efi_allocated_memory
->pages
);
535 /* Print the memory map. */
537 print_memory_map (grub_efi_memory_descriptor_t
*memory_map
,
538 grub_efi_uintn_t desc_size
,
539 grub_efi_memory_descriptor_t
*memory_map_end
)
541 grub_efi_memory_descriptor_t
*desc
;
544 for (desc
= memory_map
, i
= 0;
545 desc
< memory_map_end
;
546 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
), i
++)
548 grub_printf ("MD: t=%x, p=%llx, v=%llx, n=%llx, a=%llx\n",
549 desc
->type
, desc
->physical_start
, desc
->virtual_start
,
550 desc
->num_pages
, desc
->attribute
);
556 grub_efi_mm_init (void)
558 grub_efi_memory_descriptor_t
*memory_map
;
559 grub_efi_memory_descriptor_t
*memory_map_end
;
560 grub_efi_memory_descriptor_t
*filtered_memory_map
;
561 grub_efi_memory_descriptor_t
*filtered_memory_map_end
;
562 grub_efi_uintn_t map_size
;
563 grub_efi_uintn_t desc_size
;
564 grub_efi_uint64_t total_pages
;
565 grub_efi_uint64_t required_pages
;
568 /* Prepare a memory region to store two memory maps. */
569 memory_map
= grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE
));
571 grub_fatal ("cannot allocate memory");
573 /* Obtain descriptors for available memory. */
574 map_size
= MEMORY_MAP_SIZE
;
576 mm_status
= grub_efi_get_memory_map (&map_size
, memory_map
, 0, &desc_size
, 0);
581 ((grub_efi_physical_address_t
) ((grub_addr_t
) memory_map
),
582 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE
));
584 /* Freeing/allocating operations may increase memory map size. */
585 map_size
+= desc_size
* 32;
587 memory_map
= grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size
));
589 grub_fatal ("cannot allocate memory");
591 mm_status
= grub_efi_get_memory_map (&map_size
, memory_map
, 0,
596 grub_fatal ("cannot get memory map");
598 memory_map_end
= NEXT_MEMORY_DESCRIPTOR (memory_map
, map_size
);
600 filtered_memory_map
= memory_map_end
;
602 filtered_memory_map_end
= filter_memory_map (memory_map
, filtered_memory_map
,
603 desc_size
, memory_map_end
);
605 /* By default, request a quarter of the available memory. */
606 total_pages
= get_total_pages (filtered_memory_map
, desc_size
,
607 filtered_memory_map_end
);
609 #if defined (__mips__) && (_MIPS_SIM == _ABI64)
610 required_pages
= (total_pages
> 4096) ? (total_pages
- 4096) : (total_pages
>> 1);
612 required_pages
= (total_pages
>> 2);
615 if (required_pages
< BYTES_TO_PAGES (MIN_HEAP_SIZE
))
616 required_pages
= BYTES_TO_PAGES (MIN_HEAP_SIZE
);
617 else if (required_pages
> BYTES_TO_PAGES (MAX_HEAP_SIZE
))
618 required_pages
= BYTES_TO_PAGES (MAX_HEAP_SIZE
);
620 g_total_pages
= total_pages
;
621 g_required_pages
= required_pages
;
623 /* Sort the filtered descriptors, so that GRUB can allocate pages
624 from smaller regions. */
625 sort_memory_map (filtered_memory_map
, desc_size
, filtered_memory_map_end
);
627 /* Allocate memory regions for GRUB's memory management. */
628 add_memory_regions (filtered_memory_map
, desc_size
,
629 filtered_memory_map_end
, required_pages
);
633 map_size
= MEMORY_MAP_SIZE
;
635 if (grub_efi_get_memory_map (&map_size
, memory_map
, 0, &desc_size
, 0) < 0)
636 grub_fatal ("cannot get memory map");
638 grub_printf ("printing memory map\n");
639 print_memory_map (memory_map
, desc_size
,
640 NEXT_MEMORY_DESCRIPTOR (memory_map
, map_size
));
641 grub_fatal ("Debug. ");
644 /* Release the memory maps. */
645 grub_efi_free_pages ((grub_addr_t
) memory_map
,
646 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE
));
649 #if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
651 grub_efi_get_ram_base(grub_addr_t
*base_addr
)
653 grub_efi_memory_descriptor_t
*memory_map
, *desc
;
654 grub_efi_uintn_t memory_map_size
, desc_size
;
657 memory_map_size
= grub_efi_find_mmap_size();
659 memory_map
= grub_malloc (memory_map_size
);
661 return GRUB_ERR_OUT_OF_MEMORY
;
662 ret
= grub_efi_get_memory_map (&memory_map_size
, memory_map
, NULL
,
668 for (desc
= memory_map
, *base_addr
= GRUB_EFI_MAX_USABLE_ADDRESS
;
669 (grub_addr_t
) desc
< ((grub_addr_t
) memory_map
+ memory_map_size
);
670 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
671 if (desc
->attribute
& GRUB_EFI_MEMORY_WB
)
672 *base_addr
= grub_min (*base_addr
, desc
->physical_start
);
674 grub_free(memory_map
);
676 return GRUB_ERR_NONE
;
680 void grub_efi_get_reserved_page_num(grub_uint64_t
*total
, grub_uint64_t
*required
)
682 *total
= g_total_pages
;
683 *required
= g_required_pages
;