1
/* Code for managing symbols and pointers in efiemu */
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/>.
22
#include <grub/misc.h>
23
#include <grub/efiemu/efiemu.h>
24
#include <grub/efiemu/runtime.h>
26
static int ptv_written = 0;
27
static int ptv_alloc = 0;
28
static int ptv_handle = 0;
29
static int relocated_handle = 0;
30
static int ptv_requested = 0;
31
static struct grub_efiemu_sym *efiemu_syms = 0;
33
struct grub_efiemu_sym
35
struct grub_efiemu_sym *next;
42
grub_efiemu_free_syms (void)
44
struct grub_efiemu_sym *cur, *d;
45
for (cur = efiemu_syms; cur;)
48
grub_free (cur->name);
56
grub_efiemu_mm_return_request (ptv_handle);
58
grub_efiemu_mm_return_request (relocated_handle);
62
/* Announce that the module will need NUM allocators */
63
/* Because of deferred memory allocation all the relocators have to be
64
announced during phase 1*/
66
grub_efiemu_request_symbols (int num)
69
return grub_error (GRUB_ERR_BAD_ARGUMENT,
70
"symbols have already been allocated");
72
return grub_error (GRUB_ERR_BAD_ARGUMENT,
73
"can't request negative symbols");
78
/* Resolve the symbol name NAME and set HANDLE and OFF accordingly */
80
grub_efiemu_resolve_symbol (const char *name, int *handle, grub_off_t *off)
82
struct grub_efiemu_sym *cur;
83
for (cur = efiemu_syms; cur; cur = cur->next)
84
if (!grub_strcmp (name, cur->name))
86
*handle = cur->handle;
90
grub_dprintf ("efiemu", "%s not found\n", name);
91
return grub_error (GRUB_ERR_BAD_OS, "symbol %s isn't found", name);
94
/* Register symbol named NAME in memory handle HANDLE at offset OFF */
96
grub_efiemu_register_symbol (const char *name, int handle, grub_off_t off)
98
struct grub_efiemu_sym *cur;
99
cur = (struct grub_efiemu_sym *) grub_malloc (sizeof (*cur));
100
grub_dprintf ("efiemu", "registering symbol '%s'\n", name);
102
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't register symbol");
103
cur->name = grub_strdup (name);
104
cur->next = efiemu_syms;
105
cur->handle = handle;
112
/* Go from phase 1 to phase 2. Must be called before similar function in mm.c */
114
grub_efiemu_alloc_syms (void)
116
ptv_alloc = ptv_requested;
117
ptv_handle = grub_efiemu_request_memalign
118
(1, (ptv_requested + 1) * sizeof (struct grub_efiemu_ptv_rel),
119
GRUB_EFI_RUNTIME_SERVICES_DATA);
120
relocated_handle = grub_efiemu_request_memalign
121
(1, sizeof (grub_uint8_t), GRUB_EFI_RUNTIME_SERVICES_DATA);
123
grub_efiemu_register_symbol ("efiemu_ptv_relocated", relocated_handle, 0);
124
grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0);
129
grub_efiemu_write_sym_markers (void)
131
struct grub_efiemu_ptv_rel *ptv_rels
132
= grub_efiemu_mm_obtain_request (ptv_handle);
133
grub_uint8_t *relocated = grub_efiemu_mm_obtain_request (relocated_handle);
134
grub_memset (ptv_rels, 0, (ptv_requested + 1)
135
* sizeof (struct grub_efiemu_ptv_rel));
137
return GRUB_ERR_NONE;
140
/* Write value (pointer to memory PLUS_HANDLE)
141
- (pointer to memory MINUS_HANDLE) + VALUE to ADDR assuming that the
142
size SIZE bytes. If PTV_NEEDED is 1 then announce it to runtime that this
143
value needs to be recomputed before going to virtual mode
146
grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle,
147
int minus_handle, int ptv_needed, int size)
149
/* Announce relocator to runtime */
152
struct grub_efiemu_ptv_rel *ptv_rels
153
= grub_efiemu_mm_obtain_request (ptv_handle);
155
if (ptv_needed && ptv_written >= ptv_alloc)
156
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
157
"your module didn't declare efiemu "
158
" relocators correctly");
161
ptv_rels[ptv_written].minustype
162
= grub_efiemu_mm_get_type (minus_handle);
164
ptv_rels[ptv_written].minustype = 0;
167
ptv_rels[ptv_written].plustype
168
= grub_efiemu_mm_get_type (plus_handle);
170
ptv_rels[ptv_written].plustype = 0;
172
ptv_rels[ptv_written].addr = PTR_TO_UINT64 (addr);
173
ptv_rels[ptv_written].size = size;
176
/* memset next value to zero to mark the end */
177
grub_memset (&ptv_rels[ptv_written], 0, sizeof (ptv_rels[ptv_written]));
180
/* Compute the value */
182
value -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle));
185
value += PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle));
187
/* Write the value */
191
*((grub_uint64_t *) addr) = value;
194
*((grub_uint32_t *) addr) = value;
197
*((grub_uint16_t *) addr) = value;
200
*((grub_uint8_t *) addr) = value;
203
return grub_error (GRUB_ERR_BAD_ARGUMENT, "wrong symbol size");
206
return GRUB_ERR_NONE;
210
grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
211
grub_efi_uintn_t descriptor_size,
212
grub_efi_uint32_t descriptor_version
213
__attribute__ ((unused)),
214
grub_efi_memory_descriptor_t *virtual_map)
216
grub_uint8_t *ptv_relocated;
217
struct grub_efiemu_ptv_rel *cur_relloc;
218
struct grub_efiemu_ptv_rel *ptv_rels;
220
ptv_relocated = grub_efiemu_mm_obtain_request (relocated_handle);
221
ptv_rels = grub_efiemu_mm_obtain_request (ptv_handle);
223
/* Ensure that we are called only once */
225
return grub_error (GRUB_ERR_BAD_ARGUMENT, "EfiEmu is already relocated");
228
/* Correct addresses using information supplied by grub */
229
for (cur_relloc = ptv_rels; cur_relloc->size; cur_relloc++)
231
grub_int64_t corr = 0;
232
grub_efi_memory_descriptor_t *descptr;
234
/* Compute correction */
235
for (descptr = virtual_map;
236
(grub_size_t) ((grub_uint8_t *) descptr
237
- (grub_uint8_t *) virtual_map) < memory_map_size;
238
descptr = (grub_efi_memory_descriptor_t *)
239
((grub_uint8_t *) descptr + descriptor_size))
241
if (descptr->type == cur_relloc->plustype)
242
corr += descptr->virtual_start - descptr->physical_start;
243
if (descptr->type == cur_relloc->minustype)
244
corr -= descptr->virtual_start - descptr->physical_start;
247
/* Apply correction */
248
switch (cur_relloc->size)
251
*((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
254
*((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
257
*((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
260
*((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
265
/* Recompute crc32 of system table and runtime services */
267
if (grub_efiemu_sizeof_uintn_t () == 4)
268
return grub_efiemu_crc32 ();
270
return grub_efiemu_crc64 ();