3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 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/machine/memory.h>
21 #include <grub/memory.h>
23 #include <grub/efi/api.h>
24 #include <grub/efi/efi.h>
26 #include <grub/misc.h>
28 #define NEXT_MEMORY_DESCRIPTOR(desc, size) \
29 ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
32 grub_efi_mmap_iterate (grub_memory_hook_t hook
, int avoid_efi_boot_services
)
34 grub_efi_uintn_t mmap_size
= 0;
35 grub_efi_memory_descriptor_t
*map_buf
= 0;
36 grub_efi_uintn_t map_key
= 0;
37 grub_efi_uintn_t desc_size
= 0;
38 grub_efi_uint32_t desc_version
= 0;
39 grub_efi_memory_descriptor_t
*desc
;
41 if (grub_efi_get_memory_map (&mmap_size
, map_buf
,
46 map_buf
= grub_malloc (mmap_size
);
50 if (grub_efi_get_memory_map (&mmap_size
, map_buf
,
59 desc
< NEXT_MEMORY_DESCRIPTOR (map_buf
, mmap_size
);
60 desc
= NEXT_MEMORY_DESCRIPTOR (desc
, desc_size
))
62 grub_dprintf ("mmap", "EFI memory region 0x%llx-0x%llx: %d\n",
63 (unsigned long long) desc
->physical_start
,
64 (unsigned long long) desc
->physical_start
65 + desc
->num_pages
* 4096, desc
->type
);
68 case GRUB_EFI_BOOT_SERVICES_CODE
:
69 if (!avoid_efi_boot_services
)
71 hook (desc
->physical_start
, desc
->num_pages
* 4096,
72 GRUB_MEMORY_AVAILABLE
);
75 case GRUB_EFI_RUNTIME_SERVICES_CODE
:
76 hook (desc
->physical_start
, desc
->num_pages
* 4096,
80 case GRUB_EFI_UNUSABLE_MEMORY
:
81 hook (desc
->physical_start
, desc
->num_pages
* 4096,
86 grub_printf ("Unknown memory type %d, considering reserved\n",
89 case GRUB_EFI_BOOT_SERVICES_DATA
:
90 if (!avoid_efi_boot_services
)
92 hook (desc
->physical_start
, desc
->num_pages
* 4096,
93 GRUB_MEMORY_AVAILABLE
);
96 case GRUB_EFI_RESERVED_MEMORY_TYPE
:
97 case GRUB_EFI_RUNTIME_SERVICES_DATA
:
98 case GRUB_EFI_MEMORY_MAPPED_IO
:
99 case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE
:
100 case GRUB_EFI_PAL_CODE
:
101 hook (desc
->physical_start
, desc
->num_pages
* 4096,
102 GRUB_MEMORY_RESERVED
);
105 case GRUB_EFI_LOADER_CODE
:
106 case GRUB_EFI_LOADER_DATA
:
107 case GRUB_EFI_CONVENTIONAL_MEMORY
:
108 hook (desc
->physical_start
, desc
->num_pages
* 4096,
109 GRUB_MEMORY_AVAILABLE
);
112 case GRUB_EFI_ACPI_RECLAIM_MEMORY
:
113 hook (desc
->physical_start
, desc
->num_pages
* 4096,
117 case GRUB_EFI_ACPI_MEMORY_NVS
:
118 hook (desc
->physical_start
, desc
->num_pages
* 4096,
124 return GRUB_ERR_NONE
;
128 grub_machine_mmap_iterate (grub_memory_hook_t hook
)
130 return grub_efi_mmap_iterate (hook
, 0);
133 static inline grub_efi_memory_type_t
134 make_efi_memtype (int type
)
138 case GRUB_MEMORY_CODE
:
139 return GRUB_EFI_RUNTIME_SERVICES_CODE
;
141 /* No way to remove a chunk of memory from EFI mmap.
142 So mark it as unusable. */
143 case GRUB_MEMORY_HOLE
:
144 case GRUB_MEMORY_RESERVED
:
145 return GRUB_EFI_UNUSABLE_MEMORY
;
147 case GRUB_MEMORY_AVAILABLE
:
148 return GRUB_EFI_CONVENTIONAL_MEMORY
;
150 case GRUB_MEMORY_ACPI
:
151 return GRUB_EFI_ACPI_RECLAIM_MEMORY
;
153 case GRUB_MEMORY_NVS
:
154 return GRUB_EFI_ACPI_MEMORY_NVS
;
157 return GRUB_EFI_UNUSABLE_MEMORY
;
162 struct overlay
*next
;
163 grub_efi_physical_address_t address
;
164 grub_efi_uintn_t pages
;
168 static struct overlay
*overlays
= 0;
169 static int curhandle
= 1;
172 grub_mmap_register (grub_uint64_t start
, grub_uint64_t size
, int type
)
174 grub_uint64_t end
= start
+ size
;
175 grub_efi_physical_address_t address
;
176 grub_efi_boot_services_t
*b
;
177 grub_efi_uintn_t pages
;
178 grub_efi_status_t status
;
179 struct overlay
*curover
;
181 curover
= (struct overlay
*) grub_malloc (sizeof (struct overlay
));
185 b
= grub_efi_system_table
->boot_services
;
186 address
= start
& (~0x3ffULL
);
187 pages
= (end
- address
+ 0x3ff) >> 12;
188 status
= efi_call_2 (b
->free_pages
, address
, pages
);
189 if (status
!= GRUB_EFI_SUCCESS
&& status
!= GRUB_EFI_NOT_FOUND
)
194 status
= efi_call_4 (b
->allocate_pages
, GRUB_EFI_ALLOCATE_ADDRESS
,
195 make_efi_memtype (type
), pages
, &address
);
196 if (status
!= GRUB_EFI_SUCCESS
)
201 curover
->next
= overlays
;
202 curover
->handle
= curhandle
++;
203 curover
->address
= address
;
204 curover
->pages
= pages
;
207 return curover
->handle
;
211 grub_mmap_unregister (int handle
)
213 struct overlay
*curover
, *prevover
;
214 grub_efi_boot_services_t
*b
;
216 b
= grub_efi_system_table
->boot_services
;
219 for (curover
= overlays
, prevover
= 0; curover
;
220 prevover
= curover
, curover
= curover
->next
)
222 if (curover
->handle
== handle
)
224 efi_call_2 (b
->free_pages
, curover
->address
, curover
->pages
);
226 prevover
->next
= curover
->next
;
228 overlays
= curover
->next
;
230 return GRUB_ERR_NONE
;
233 return grub_error (GRUB_ERR_BUG
, "handle %d not found", handle
);
236 /* Result is always page-aligned. */
238 grub_mmap_malign_and_register (grub_uint64_t align
__attribute__ ((unused
)),
240 int *handle
, int type
,
241 int flags
__attribute__ ((unused
)))
243 grub_efi_physical_address_t address
;
244 grub_efi_boot_services_t
*b
;
245 grub_efi_uintn_t pages
;
246 grub_efi_status_t status
;
247 struct overlay
*curover
;
248 grub_efi_allocate_type_t atype
;
250 curover
= (struct overlay
*) grub_malloc (sizeof (struct overlay
));
254 b
= grub_efi_system_table
->boot_services
;
256 address
= 0xffffffff;
258 #if GRUB_TARGET_SIZEOF_VOID_P < 8
259 /* Limit the memory access to less than 4GB for 32-bit platforms. */
260 atype
= GRUB_EFI_ALLOCATE_MAX_ADDRESS
;
262 atype
= GRUB_EFI_ALLOCATE_ANY_PAGES
;
265 pages
= (size
+ 0x3ff) >> 12;
266 status
= efi_call_4 (b
->allocate_pages
, atype
,
267 make_efi_memtype (type
), pages
, &address
);
268 if (status
!= GRUB_EFI_SUCCESS
)
276 /* Uggh, the address 0 was allocated... This is too annoying,
277 so reallocate another one. */
278 address
= 0xffffffff;
279 status
= efi_call_4 (b
->allocate_pages
, atype
,
280 make_efi_memtype (type
), pages
, &address
);
281 grub_efi_free_pages (0, pages
);
282 if (status
!= GRUB_EFI_SUCCESS
)
286 curover
->next
= overlays
;
287 curover
->handle
= curhandle
++;
288 curover
->address
= address
;
289 curover
->pages
= pages
;
291 *handle
= curover
->handle
;
293 return (void *) (grub_addr_t
) curover
->address
;
297 grub_mmap_free_and_unregister (int handle
)
299 grub_mmap_unregister (handle
);