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;
53 * We need to roll back EFI allocations on exit. Remember allocations that
56 struct efi_allocation
;
57 struct efi_allocation
{
58 grub_efi_physical_address_t address
;
59 grub_efi_uint64_t pages
;
60 struct efi_allocation
*next
;
62 static struct efi_allocation
*efi_allocated_memory
;
65 grub_efi_store_alloc (grub_efi_physical_address_t address
,
66 grub_efi_uintn_t pages
)
68 grub_efi_boot_services_t
*b
;
69 struct efi_allocation
*alloc
;
70 grub_efi_status_t status
;
72 b
= grub_efi_system_table
->boot_services
;
73 status
= efi_call_3 (b
->allocate_pool
, GRUB_EFI_LOADER_DATA
,
74 sizeof(*alloc
), (void**)&alloc
);
76 if (status
== GRUB_EFI_SUCCESS
)
78 alloc
->next
= efi_allocated_memory
;
79 alloc
->address
= address
;
81 efi_allocated_memory
= alloc
;
84 grub_printf ("Could not malloc memory to remember EFI allocation. "
85 "Exiting GRUB won't free all memory.\n");
89 grub_efi_drop_alloc (grub_efi_physical_address_t address
,
90 grub_efi_uintn_t pages
)
92 struct efi_allocation
*ea
, *eap
;
93 grub_efi_boot_services_t
*b
;
95 b
= grub_efi_system_table
->boot_services
;
97 for (eap
= NULL
, ea
= efi_allocated_memory
; ea
; eap
= ea
, ea
= ea
->next
)
99 if (ea
->address
!= address
|| ea
->pages
!= pages
)
102 /* Remove the current entry from the list. */
104 eap
->next
= ea
->next
;
106 efi_allocated_memory
= ea
->next
;
108 /* Then free the memory backing it. */
109 efi_call_1 (b
->free_pool
, ea
);
111 /* And leave, we're done. */
116 /* Allocate pages. Return the pointer to the first of allocated pages. */
118 grub_efi_allocate_pages_real (grub_efi_physical_address_t address
,
119 grub_efi_uintn_t pages
,
120 grub_efi_allocate_type_t alloctype
,
121 grub_efi_memory_type_t memtype
)
123 grub_efi_status_t status
;
124 grub_efi_boot_services_t
*b
;
126 /* Limit the memory access to less than 4GB for 32-bit platforms. */
127 if (address
> GRUB_EFI_MAX_USABLE_ADDRESS
)
130 b
= grub_efi_system_table
->boot_services
;
131 status
= efi_call_4 (b
->allocate_pages
, alloctype
, memtype
, pages
, &address
);
132 if (status
!= GRUB_EFI_SUCCESS
)
137 /* Uggh, the address 0 was allocated... This is too annoying,
138 so reallocate another one. */
139 address
= GRUB_EFI_MAX_USABLE_ADDRESS
;
140 status
= efi_call_4 (b
->allocate_pages
, alloctype
, memtype
, pages
, &address
);
141 grub_efi_free_pages (0, pages
);
142 if (status
!= GRUB_EFI_SUCCESS
)
146 grub_efi_store_alloc (address
, pages
);
148 return (void *) ((grub_addr_t
) address
);
152 grub_efi_allocate_any_pages (grub_efi_uintn_t pages
)
154 return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS
,
155 pages
, GRUB_EFI_ALLOCATE_MAX_ADDRESS
,
156 GRUB_EFI_LOADER_DATA
);
160 grub_efi_allocate_fixed (grub_efi_physical_address_t address
,
161 grub_efi_uintn_t pages
)
163 return grub_efi_allocate_pages_real (address
, pages
,
164 GRUB_EFI_ALLOCATE_ADDRESS
,
165 GRUB_EFI_LOADER_DATA
);
168 /* Free pages starting from ADDRESS. */
170 grub_efi_free_pages (grub_efi_physical_address_t address
,
171 grub_efi_uintn_t pages
)
173 grub_efi_boot_services_t
*b
;
175 b
= grub_efi_system_table
->boot_services
;
176 efi_call_2 (b
->free_pages
, address
, pages
);
178 grub_efi_drop_alloc (address
, pages
);
181 #if defined (__i386__) || defined (__x86_64__)
183 /* Helper for stop_broadcom. */
185 find_card (grub_pci_device_t dev
, grub_pci_id_t pciid
,
186 void *data
__attribute__ ((unused
)))
188 grub_pci_address_t addr
;
190 grub_uint16_t pm_state
;
192 if ((pciid
& 0xffff) != GRUB_PCI_VENDOR_BROADCOM
)
195 addr
= grub_pci_make_address (dev
, GRUB_PCI_REG_CLASS
);
196 if (grub_pci_read (addr
) >> 24 != GRUB_PCI_CLASS_NETWORK
)
198 cap
= grub_pci_find_capability (dev
, GRUB_PCI_CAP_POWER_MANAGEMENT
);
201 addr
= grub_pci_make_address (dev
, cap
+ 4);
202 pm_state
= grub_pci_read_word (addr
);
203 pm_state
= pm_state
| 0x03;
204 grub_pci_write_word (addr
, pm_state
);
205 grub_pci_read_word (addr
);
212 grub_pci_iterate (find_card
, NULL
);
218 grub_efi_finish_boot_services (grub_efi_uintn_t
*outbuf_size
, void *outbuf
,
219 grub_efi_uintn_t
*map_key
,
220 grub_efi_uintn_t
*efi_desc_size
,
221 grub_efi_uint32_t
*efi_desc_version
)
223 grub_efi_boot_services_t
*b
;
224 grub_efi_status_t status
;
226 #if defined (__i386__) || defined (__x86_64__)
227 const grub_uint16_t apple
[] = { 'A', 'p', 'p', 'l', 'e' };
230 is_apple
= (grub_memcmp (grub_efi_system_table
->firmware_vendor
,
231 apple
, sizeof (apple
)) == 0);
236 if (grub_efi_get_memory_map (&finish_mmap_size
, finish_mmap_buf
, &finish_key
,
237 &finish_desc_size
, &finish_desc_version
) < 0)
238 return grub_error (GRUB_ERR_IO
, "couldn't retrieve memory map");
240 if (outbuf
&& *outbuf_size
< finish_mmap_size
)
241 return grub_error (GRUB_ERR_IO
, "memory map buffer is too small");
243 finish_mmap_buf
= grub_malloc (finish_mmap_size
);
244 if (!finish_mmap_buf
)
247 if (grub_efi_get_memory_map (&finish_mmap_size
, finish_mmap_buf
, &finish_key
,
248 &finish_desc_size
, &finish_desc_version
) <= 0)
250 grub_free (finish_mmap_buf
);
251 return grub_error (GRUB_ERR_IO
, "couldn't retrieve memory map");
254 b
= grub_efi_system_table
->boot_services
;
255 status
= efi_call_2 (b
->exit_boot_services
, grub_efi_image_handle
,
257 if (status
== GRUB_EFI_SUCCESS
)
260 if (status
!= GRUB_EFI_INVALID_PARAMETER
)
262 grub_free (finish_mmap_buf
);
263 return grub_error (GRUB_ERR_IO
, "couldn't terminate EFI services");
266 grub_free (finish_mmap_buf
);
267 grub_printf ("Trying to terminate EFI services again\n");
269 grub_efi_is_finished
= 1;
271 *outbuf_size
= finish_mmap_size
;
273 grub_memcpy (outbuf
, finish_mmap_buf
, finish_mmap_size
);
275 *map_key
= finish_key
;
277 *efi_desc_size
= finish_desc_size
;
278 if (efi_desc_version
)
279 *efi_desc_version
= finish_desc_version
;
281 #if defined (__i386__) || defined (__x86_64__)
286 return GRUB_ERR_NONE
;
290 * To obtain the UEFI memory map, we must pass a buffer of sufficient size
291 * to hold the entire map. This function returns a sane start value for
295 grub_efi_find_mmap_size (void)
297 grub_efi_uintn_t mmap_size
= 0;
298 grub_efi_uintn_t desc_size
;
300 if (grub_efi_get_memory_map (&mmap_size
, NULL
, NULL
, &desc_size
, 0) < 0)
302 grub_error (GRUB_ERR_IO
, "cannot get EFI memory map size");
307 * Add an extra page, since UEFI can alter the memory map itself on
308 * callbacks or explicit calls, including console output.
310 return ALIGN_UP (mmap_size
+ GRUB_EFI_PAGE_SIZE
, GRUB_EFI_PAGE_SIZE
);
313 /* Get the memory map as defined in the EFI spec. Return 1 if successful,
314 return 0 if partial, or return -1 if an error occurs. */
316 grub_efi_get_memory_map (grub_efi_uintn_t
*memory_map_size
,
317 grub_efi_memory_descriptor_t
*memory_map
,
318 grub_efi_uintn_t
*map_key
,
319 grub_efi_uintn_t
*descriptor_size
,
320 grub_efi_uint32_t
*descriptor_version
)
322 grub_efi_status_t status
;
323 grub_efi_boot_services_t
*b
;
324 grub_efi_uintn_t key
;
325 grub_efi_uint32_t version
;
326 grub_efi_uintn_t size
;
328 if (grub_efi_is_finished
)
331 if (*memory_map_size
< finish_mmap_size
)
333 grub_memcpy (memory_map
, finish_mmap_buf
, *memory_map_size
);
338 grub_memcpy (memory_map
, finish_mmap_buf
, finish_mmap_size
);
341 *memory_map_size
= finish_mmap_size
;
343 *map_key
= finish_key
;
345 *descriptor_size
= finish_desc_size
;
346 if (descriptor_version
)
347 *descriptor_version
= finish_desc_version
;
351 /* Allow some parameters to be missing. */
354 if (! descriptor_version
)
355 descriptor_version
= &version
;
356 if (! descriptor_size
)
357 descriptor_size
= &size
;
359 b
= grub_efi_system_table
->boot_services
;
360 status
= efi_call_5 (b
->get_memory_map
, memory_map_size
, memory_map
, map_key
,
361 descriptor_size
, descriptor_version
);
362 if (*descriptor_size
== 0)
363 *descriptor_size
= sizeof (grub_efi_memory_descriptor_t
);
364 if (status
== GRUB_EFI_SUCCESS
)
366 else if (status
== GRUB_EFI_BUFFER_TOO_SMALL
)
372 /* Sort the memory map in place. */
374 sort_memory_map (grub_efi_memory_descriptor_t
*memory_map
,
375 grub_efi_uintn_t desc_size
,
376 grub_efi_memory_descriptor_t
*memory_map_end
)
378 grub_efi_memory_descriptor_t
*d1
;
379 grub_efi_memory_descriptor_t
*d2
;
381 for (d1
= memory_map
;
383 d1
= NEXT_MEMORY_DESCRIPTOR (d1
, desc_size
))
385 grub_efi_memory_descriptor_t
*max_desc
= d1
;
387 for (d2
= NEXT_MEMORY_DESCRIPTOR (d1
, desc_size
);
389 d2
= NEXT_MEMORY_DESCRIPTOR (d2
, desc_size
))
391 if (max_desc
->num_pages
< d2
->num_pages
)
397 grub_efi_memory_descriptor_t tmp
;
406 /* Filter the descriptors. GRUB needs only available memory. */
407 static grub_efi_memory_descriptor_t
*
408 filter_memory_map (grub_efi_memory_descriptor_t
*memory_map
,
409 grub_efi_memory_descriptor_t
*filtered_memory_map
,
410 grub_efi_uintn_t desc_size
,
411 grub_efi_memory_descriptor_t
*memory_map_end
)
413 grub_efi_memory_descriptor_t
*desc
;
414 grub_efi_memory_descriptor_t
*filtered_desc
;
416 for (desc
= memory_map
, filtered_desc
= filtered_memory_map
;
417 desc
< memory_map_end
;
418 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
420 if (desc
->type
== GRUB_EFI_CONVENTIONAL_MEMORY
422 && desc
->physical_start
<= GRUB_EFI_MAX_USABLE_ADDRESS
424 && desc
->physical_start
+ PAGES_TO_BYTES (desc
->num_pages
) > 0x100000
425 && desc
->num_pages
!= 0)
427 grub_memcpy (filtered_desc
, desc
, desc_size
);
429 /* Avoid less than 1MB, because some loaders seem to be confused. */
430 if (desc
->physical_start
< 0x100000)
432 desc
->num_pages
-= BYTES_TO_PAGES (0x100000
433 - desc
->physical_start
);
434 desc
->physical_start
= 0x100000;
438 if (BYTES_TO_PAGES (filtered_desc
->physical_start
)
439 + filtered_desc
->num_pages
440 > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS
))
441 filtered_desc
->num_pages
442 = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS
)
443 - BYTES_TO_PAGES (filtered_desc
->physical_start
));
446 if (filtered_desc
->num_pages
== 0)
449 filtered_desc
= NEXT_MEMORY_DESCRIPTOR (filtered_desc
, desc_size
);
453 return filtered_desc
;
456 /* Return the total number of pages. */
457 static grub_efi_uint64_t
458 get_total_pages (grub_efi_memory_descriptor_t
*memory_map
,
459 grub_efi_uintn_t desc_size
,
460 grub_efi_memory_descriptor_t
*memory_map_end
)
462 grub_efi_memory_descriptor_t
*desc
;
463 grub_efi_uint64_t total
= 0;
465 for (desc
= memory_map
;
466 desc
< memory_map_end
;
467 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
468 total
+= desc
->num_pages
;
473 /* Add memory regions. */
475 add_memory_regions (grub_efi_memory_descriptor_t
*memory_map
,
476 grub_efi_uintn_t desc_size
,
477 grub_efi_memory_descriptor_t
*memory_map_end
,
478 grub_efi_uint64_t required_pages
)
480 grub_efi_memory_descriptor_t
*desc
;
482 for (desc
= memory_map
;
483 desc
< memory_map_end
;
484 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
486 grub_efi_uint64_t pages
;
487 grub_efi_physical_address_t start
;
490 start
= desc
->physical_start
;
491 pages
= desc
->num_pages
;
492 if (pages
> required_pages
)
494 start
+= PAGES_TO_BYTES (pages
- required_pages
);
495 pages
= required_pages
;
498 addr
= grub_efi_allocate_pages_real (start
, pages
,
499 GRUB_EFI_ALLOCATE_ADDRESS
,
500 GRUB_EFI_LOADER_CODE
);
502 grub_fatal ("cannot allocate conventional memory %p with %u pages",
503 (void *) ((grub_addr_t
) start
),
506 grub_mm_init_region (addr
, PAGES_TO_BYTES (pages
));
508 required_pages
-= pages
;
509 if (required_pages
== 0)
513 if (required_pages
> 0)
514 grub_fatal ("too little memory");
518 grub_efi_memory_fini (void)
521 * Free all stale allocations. grub_efi_free_pages() will remove
522 * the found entry from the list and it will always find the first
523 * list entry (efi_allocated_memory is the list start). Hence we
524 * remove all entries from the list until none is left altogether.
526 while (efi_allocated_memory
)
527 grub_efi_free_pages (efi_allocated_memory
->address
,
528 efi_allocated_memory
->pages
);
532 /* Print the memory map. */
534 print_memory_map (grub_efi_memory_descriptor_t
*memory_map
,
535 grub_efi_uintn_t desc_size
,
536 grub_efi_memory_descriptor_t
*memory_map_end
)
538 grub_efi_memory_descriptor_t
*desc
;
541 for (desc
= memory_map
, i
= 0;
542 desc
< memory_map_end
;
543 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
), i
++)
545 grub_printf ("MD: t=%x, p=%llx, v=%llx, n=%llx, a=%llx\n",
546 desc
->type
, desc
->physical_start
, desc
->virtual_start
,
547 desc
->num_pages
, desc
->attribute
);
553 grub_efi_mm_init (void)
555 grub_efi_memory_descriptor_t
*memory_map
;
556 grub_efi_memory_descriptor_t
*memory_map_end
;
557 grub_efi_memory_descriptor_t
*filtered_memory_map
;
558 grub_efi_memory_descriptor_t
*filtered_memory_map_end
;
559 grub_efi_uintn_t map_size
;
560 grub_efi_uintn_t desc_size
;
561 grub_efi_uint64_t total_pages
;
562 grub_efi_uint64_t required_pages
;
565 /* Prepare a memory region to store two memory maps. */
566 memory_map
= grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE
));
568 grub_fatal ("cannot allocate memory");
570 /* Obtain descriptors for available memory. */
571 map_size
= MEMORY_MAP_SIZE
;
573 mm_status
= grub_efi_get_memory_map (&map_size
, memory_map
, 0, &desc_size
, 0);
578 ((grub_efi_physical_address_t
) ((grub_addr_t
) memory_map
),
579 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE
));
581 /* Freeing/allocating operations may increase memory map size. */
582 map_size
+= desc_size
* 32;
584 memory_map
= grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size
));
586 grub_fatal ("cannot allocate memory");
588 mm_status
= grub_efi_get_memory_map (&map_size
, memory_map
, 0,
593 grub_fatal ("cannot get memory map");
595 memory_map_end
= NEXT_MEMORY_DESCRIPTOR (memory_map
, map_size
);
597 filtered_memory_map
= memory_map_end
;
599 filtered_memory_map_end
= filter_memory_map (memory_map
, filtered_memory_map
,
600 desc_size
, memory_map_end
);
602 /* By default, request a quarter of the available memory. */
603 total_pages
= get_total_pages (filtered_memory_map
, desc_size
,
604 filtered_memory_map_end
);
606 #if defined (__mips__) && (_MIPS_SIM == _ABI64)
607 required_pages
= (total_pages
> 4096) ? (total_pages
- 4096) : (total_pages
>> 1);
609 required_pages
= (total_pages
>> 2);
612 if (required_pages
< BYTES_TO_PAGES (MIN_HEAP_SIZE
))
613 required_pages
= BYTES_TO_PAGES (MIN_HEAP_SIZE
);
614 else if (required_pages
> BYTES_TO_PAGES (MAX_HEAP_SIZE
))
615 required_pages
= BYTES_TO_PAGES (MAX_HEAP_SIZE
);
617 /* Sort the filtered descriptors, so that GRUB can allocate pages
618 from smaller regions. */
619 sort_memory_map (filtered_memory_map
, desc_size
, filtered_memory_map_end
);
621 /* Allocate memory regions for GRUB's memory management. */
622 add_memory_regions (filtered_memory_map
, desc_size
,
623 filtered_memory_map_end
, required_pages
);
627 map_size
= MEMORY_MAP_SIZE
;
629 if (grub_efi_get_memory_map (&map_size
, memory_map
, 0, &desc_size
, 0) < 0)
630 grub_fatal ("cannot get memory map");
632 grub_printf ("printing memory map\n");
633 print_memory_map (memory_map
, desc_size
,
634 NEXT_MEMORY_DESCRIPTOR (memory_map
, map_size
));
635 grub_fatal ("Debug. ");
638 /* Release the memory maps. */
639 grub_efi_free_pages ((grub_addr_t
) memory_map
,
640 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE
));
643 #if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
645 grub_efi_get_ram_base(grub_addr_t
*base_addr
)
647 grub_efi_memory_descriptor_t
*memory_map
, *desc
;
648 grub_efi_uintn_t memory_map_size
, desc_size
;
651 memory_map_size
= grub_efi_find_mmap_size();
653 memory_map
= grub_malloc (memory_map_size
);
655 return GRUB_ERR_OUT_OF_MEMORY
;
656 ret
= grub_efi_get_memory_map (&memory_map_size
, memory_map
, NULL
,
662 for (desc
= memory_map
, *base_addr
= GRUB_EFI_MAX_USABLE_ADDRESS
;
663 (grub_addr_t
) desc
< ((grub_addr_t
) memory_map
+ memory_map_size
);
664 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
665 if (desc
->attribute
& GRUB_EFI_MEMORY_WB
)
666 *base_addr
= grub_min (*base_addr
, desc
->physical_start
);
668 grub_free(memory_map
);
670 return GRUB_ERR_NONE
;