~ubuntu-branches/debian/sid/grub2/sid-200907171840

« back to all changes in this revision

Viewing changes to mmap/efi/mmap.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Millan
  • Date: 2009-07-02 13:23:51 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702132351-tanpn0ryyijp93gu
Tags: 1.96+20090702-1
* New SVN snapshot.
* rules: Remove duplicated files in sparc64-ieee1275 port.
* rules: Comment out -DGRUB_ASSUME_LINUX_HAS_FB_SUPPORT=1 setting.  We'll
  re-evaluate using it when it's more mature.  (Closes: #535026).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Mmap management. */
 
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
#include <grub/machine/memory.h>
 
21
#include <grub/memory.h>
 
22
#include <grub/err.h>
 
23
#include <grub/efi/api.h>
 
24
#include <grub/efi/efi.h>
 
25
#include <grub/mm.h>
 
26
#include <grub/misc.h>
 
27
 
 
28
#define NEXT_MEMORY_DESCRIPTOR(desc, size)      \
 
29
  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
 
30
 
 
31
grub_err_t
 
32
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t,
 
33
                                                         grub_uint64_t,
 
34
                                                         grub_uint32_t))
 
35
{
 
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;
 
42
 
 
43
  if (grub_efi_get_memory_map (&mmap_size, map_buf,
 
44
                               &map_key, &desc_size,
 
45
                               &desc_version) < 0)
 
46
    return grub_errno;
 
47
 
 
48
  map_buf = grub_malloc (mmap_size);
 
49
  if (! map_buf)
 
50
    return grub_errno;
 
51
 
 
52
  if (grub_efi_get_memory_map (&mmap_size, map_buf,
 
53
                               &map_key, &desc_size,
 
54
                               &desc_version) <= 0)
 
55
    {
 
56
      grub_free (map_buf);
 
57
      return grub_errno;
 
58
    }
 
59
 
 
60
  for (desc = map_buf;
 
61
       desc < NEXT_MEMORY_DESCRIPTOR (map_buf, mmap_size);
 
62
       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
 
63
    {
 
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);
 
68
      switch (desc->type)
 
69
        {
 
70
        case GRUB_EFI_RUNTIME_SERVICES_CODE:
 
71
          hook (desc->physical_start, desc->num_pages * 4096,
 
72
                GRUB_MACHINE_MEMORY_CODE);
 
73
          break;
 
74
 
 
75
        default:
 
76
          grub_printf ("Unknown memory type %d, considering reserved\n",
 
77
                       desc->type);
 
78
 
 
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);
 
87
          break;
 
88
 
 
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);
 
96
          break;
 
97
 
 
98
        case GRUB_EFI_ACPI_RECLAIM_MEMORY:
 
99
          hook (desc->physical_start, desc->num_pages * 4096,
 
100
                GRUB_MACHINE_MEMORY_ACPI);
 
101
          break;
 
102
 
 
103
        case GRUB_EFI_ACPI_MEMORY_NVS:
 
104
          hook (desc->physical_start, desc->num_pages * 4096,
 
105
                GRUB_MACHINE_MEMORY_NVS);
 
106
          break;
 
107
        }
 
108
    }
 
109
 
 
110
  return GRUB_ERR_NONE;
 
111
}
 
112
 
 
113
static inline grub_efi_memory_type_t
 
114
make_efi_memtype (int type)
 
115
{
 
116
  switch (type)
 
117
    {
 
118
    case GRUB_MACHINE_MEMORY_CODE:
 
119
      return GRUB_EFI_RUNTIME_SERVICES_CODE;
 
120
 
 
121
      /* No way to remove a chunk of memory from EFI mmap.
 
122
         So mark it as unusable. */
 
123
    case GRUB_MACHINE_MEMORY_HOLE:
 
124
 
 
125
    default:
 
126
 
 
127
    case GRUB_MACHINE_MEMORY_RESERVED:
 
128
      return GRUB_EFI_UNUSABLE_MEMORY;
 
129
 
 
130
    case GRUB_MACHINE_MEMORY_AVAILABLE:
 
131
      return GRUB_EFI_CONVENTIONAL_MEMORY;
 
132
 
 
133
    case GRUB_MACHINE_MEMORY_ACPI:
 
134
      return GRUB_EFI_ACPI_RECLAIM_MEMORY;
 
135
 
 
136
    case GRUB_MACHINE_MEMORY_NVS:
 
137
      return GRUB_EFI_ACPI_RECLAIM_MEMORY;
 
138
 
 
139
    }
 
140
 
 
141
}
 
142
 
 
143
struct overlay
 
144
{
 
145
  struct overlay *next;
 
146
  grub_efi_physical_address_t address;
 
147
  grub_efi_uintn_t pages;
 
148
  int handle;
 
149
};
 
150
 
 
151
static struct overlay *overlays = 0;
 
152
static int curhandle = 1;
 
153
 
 
154
int
 
155
grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
 
156
{
 
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;
 
163
 
 
164
  curover = (struct overlay *) grub_malloc (sizeof (struct overlay));
 
165
  if (! curover)
 
166
    return 0;
 
167
 
 
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)
 
173
    {
 
174
      grub_free (curover);
 
175
      return 0;
 
176
    }
 
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)
 
180
    {
 
181
      grub_free (curover);
 
182
      return 0;
 
183
    }
 
184
  curover->next = overlays;
 
185
  curover->handle = curhandle++;
 
186
  curover->address = address;
 
187
  curover->pages = pages;
 
188
  overlays = curover;
 
189
 
 
190
  return curover->handle;
 
191
}
 
192
 
 
193
grub_err_t
 
194
grub_mmap_unregister (int handle)
 
195
{
 
196
  struct overlay *curover, *prevover;
 
197
  grub_efi_boot_services_t *b;
 
198
  grub_efi_status_t status;
 
199
 
 
200
  b = grub_efi_system_table->boot_services;
 
201
 
 
202
 
 
203
  for (curover = overlays, prevover = 0; curover;
 
204
       prevover = curover, curover = curover->next)
 
205
    {
 
206
      if (curover->handle == handle)
 
207
        {
 
208
          status = efi_call_2 (b->free_pages, curover->address, curover->pages);
 
209
          if (prevover != 0)
 
210
            prevover->next = curover->next;
 
211
          else
 
212
            overlays = curover->next;
 
213
          grub_free (curover);
 
214
          return GRUB_ERR_NONE;
 
215
        }
 
216
    }
 
217
  return grub_error (GRUB_ERR_BAD_ARGUMENT, "handle %d not found", handle);
 
218
}
 
219
 
 
220
/* Result is always page-aligned. */
 
221
void *
 
222
grub_mmap_malign_and_register (grub_uint64_t align __attribute__ ((unused)),
 
223
                               grub_uint64_t size,
 
224
                               int *handle, int type,
 
225
                               int flags __attribute__ ((unused)))
 
226
{
 
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;
 
233
 
 
234
  curover = (struct overlay *) grub_malloc (sizeof (struct overlay));
 
235
  if (! curover)
 
236
    return 0;
 
237
 
 
238
  b = grub_efi_system_table->boot_services;
 
239
 
 
240
  address = 0xffffffff;
 
241
 
 
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;
 
245
#else
 
246
  atype = GRUB_EFI_ALLOCATE_ANY_PAGES;
 
247
#endif
 
248
 
 
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)
 
253
    {
 
254
      grub_free (curover);
 
255
      return 0;
 
256
    }
 
257
 
 
258
  if (address == 0)
 
259
    {
 
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)
 
267
        return 0;
 
268
    }
 
269
 
 
270
  curover->next = overlays;
 
271
  curover->handle = curhandle++;
 
272
  curover->address = address;
 
273
  curover->pages = pages;
 
274
  overlays = curover;
 
275
  *handle = curover->handle;
 
276
 
 
277
  return UINT_TO_PTR (curover->address);
 
278
}
 
279
 
 
280
void
 
281
grub_mmap_free_and_unregister (int handle)
 
282
{
 
283
  grub_mmap_unregister (handle);
 
284
}