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_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t,
36
grub_efi_uintn_t mmap_size = 0;
37
grub_efi_memory_descriptor_t *map_buf = 0;
38
grub_efi_uintn_t map_key = 0;
39
grub_efi_uintn_t desc_size = 0;
40
grub_efi_uint32_t desc_version = 0;
41
grub_efi_memory_descriptor_t *desc;
43
if (grub_efi_get_memory_map (&mmap_size, map_buf,
48
map_buf = grub_malloc (mmap_size);
52
if (grub_efi_get_memory_map (&mmap_size, map_buf,
61
desc < NEXT_MEMORY_DESCRIPTOR (map_buf, mmap_size);
62
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
64
grub_dprintf ("mmap", "EFI memory region 0x%llx-0x%llx: %d\n",
65
(unsigned long long) desc->physical_start,
66
(unsigned long long) desc->physical_start
67
+ desc->num_pages * 4096, desc->type);
70
case GRUB_EFI_RUNTIME_SERVICES_CODE:
71
hook (desc->physical_start, desc->num_pages * 4096,
72
GRUB_MACHINE_MEMORY_CODE);
76
grub_printf ("Unknown memory type %d, considering reserved\n",
79
case GRUB_EFI_RESERVED_MEMORY_TYPE:
80
case GRUB_EFI_RUNTIME_SERVICES_DATA:
81
case GRUB_EFI_UNUSABLE_MEMORY:
82
case GRUB_EFI_MEMORY_MAPPED_IO:
83
case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE:
84
case GRUB_EFI_PAL_CODE:
85
hook (desc->physical_start, desc->num_pages * 4096,
86
GRUB_MACHINE_MEMORY_RESERVED);
89
case GRUB_EFI_LOADER_CODE:
90
case GRUB_EFI_LOADER_DATA:
91
case GRUB_EFI_BOOT_SERVICES_CODE:
92
case GRUB_EFI_BOOT_SERVICES_DATA:
93
case GRUB_EFI_CONVENTIONAL_MEMORY:
94
hook (desc->physical_start, desc->num_pages * 4096,
95
GRUB_MACHINE_MEMORY_AVAILABLE);
98
case GRUB_EFI_ACPI_RECLAIM_MEMORY:
99
hook (desc->physical_start, desc->num_pages * 4096,
100
GRUB_MACHINE_MEMORY_ACPI);
103
case GRUB_EFI_ACPI_MEMORY_NVS:
104
hook (desc->physical_start, desc->num_pages * 4096,
105
GRUB_MACHINE_MEMORY_NVS);
110
return GRUB_ERR_NONE;
113
static inline grub_efi_memory_type_t
114
make_efi_memtype (int type)
118
case GRUB_MACHINE_MEMORY_CODE:
119
return GRUB_EFI_RUNTIME_SERVICES_CODE;
121
/* No way to remove a chunk of memory from EFI mmap.
122
So mark it as unusable. */
123
case GRUB_MACHINE_MEMORY_HOLE:
127
case GRUB_MACHINE_MEMORY_RESERVED:
128
return GRUB_EFI_UNUSABLE_MEMORY;
130
case GRUB_MACHINE_MEMORY_AVAILABLE:
131
return GRUB_EFI_CONVENTIONAL_MEMORY;
133
case GRUB_MACHINE_MEMORY_ACPI:
134
return GRUB_EFI_ACPI_RECLAIM_MEMORY;
136
case GRUB_MACHINE_MEMORY_NVS:
137
return GRUB_EFI_ACPI_RECLAIM_MEMORY;
145
struct overlay *next;
146
grub_efi_physical_address_t address;
147
grub_efi_uintn_t pages;
151
static struct overlay *overlays = 0;
152
static int curhandle = 1;
155
grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
157
grub_uint64_t end = start + size;
158
grub_efi_physical_address_t address;
159
grub_efi_boot_services_t *b;
160
grub_efi_uintn_t pages;
161
grub_efi_status_t status;
162
struct overlay *curover;
164
curover = (struct overlay *) grub_malloc (sizeof (struct overlay));
168
b = grub_efi_system_table->boot_services;
169
address = start & (~0x3ffULL);
170
pages = (end - address + 0x3ff) >> 12;
171
status = efi_call_2 (b->free_pages, address, pages);
172
if (status != GRUB_EFI_SUCCESS && status != GRUB_EFI_NOT_FOUND)
177
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ADDRESS,
178
make_efi_memtype (type), pages, &address);
179
if (status != GRUB_EFI_SUCCESS)
184
curover->next = overlays;
185
curover->handle = curhandle++;
186
curover->address = address;
187
curover->pages = pages;
190
return curover->handle;
194
grub_mmap_unregister (int handle)
196
struct overlay *curover, *prevover;
197
grub_efi_boot_services_t *b;
198
grub_efi_status_t status;
200
b = grub_efi_system_table->boot_services;
203
for (curover = overlays, prevover = 0; curover;
204
prevover = curover, curover = curover->next)
206
if (curover->handle == handle)
208
status = efi_call_2 (b->free_pages, curover->address, curover->pages);
210
prevover->next = curover->next;
212
overlays = curover->next;
214
return GRUB_ERR_NONE;
217
return grub_error (GRUB_ERR_BAD_ARGUMENT, "handle %d not found", handle);
220
/* Result is always page-aligned. */
222
grub_mmap_malign_and_register (grub_uint64_t align __attribute__ ((unused)),
224
int *handle, int type,
225
int flags __attribute__ ((unused)))
227
grub_efi_physical_address_t address;
228
grub_efi_boot_services_t *b;
229
grub_efi_uintn_t pages;
230
grub_efi_status_t status;
231
struct overlay *curover;
232
grub_efi_allocate_type_t atype;
234
curover = (struct overlay *) grub_malloc (sizeof (struct overlay));
238
b = grub_efi_system_table->boot_services;
240
address = 0xffffffff;
242
#if GRUB_TARGET_SIZEOF_VOID_P < 8
243
/* Limit the memory access to less than 4GB for 32-bit platforms. */
244
atype = GRUB_EFI_ALLOCATE_MAX_ADDRESS;
246
atype = GRUB_EFI_ALLOCATE_ANY_PAGES;
249
pages = (size + 0x3ff) >> 12;
250
status = efi_call_4 (b->allocate_pages, atype,
251
make_efi_memtype (type), pages, &address);
252
if (status != GRUB_EFI_SUCCESS)
260
/* Uggh, the address 0 was allocated... This is too annoying,
261
so reallocate another one. */
262
address = 0xffffffff;
263
status = efi_call_4 (b->allocate_pages, atype,
264
make_efi_memtype (type), pages, &address);
265
grub_efi_free_pages (0, pages);
266
if (status != GRUB_EFI_SUCCESS)
270
curover->next = overlays;
271
curover->handle = curhandle++;
272
curover->address = address;
273
curover->pages = pages;
275
*handle = curover->handle;
277
return UINT_TO_PTR (curover->address);
281
grub_mmap_free_and_unregister (int handle)
283
grub_mmap_unregister (handle);