~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/efiemu/symbols.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Code for managing symbols and pointers in efiemu */
 
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/err.h>
 
21
#include <grub/mm.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/efiemu/efiemu.h>
 
24
#include <grub/efiemu/runtime.h>
 
25
 
 
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;
 
32
 
 
33
struct grub_efiemu_sym
 
34
{
 
35
  struct grub_efiemu_sym *next;
 
36
  char *name;
 
37
  int handle;
 
38
  grub_off_t off;
 
39
};
 
40
 
 
41
void
 
42
grub_efiemu_free_syms (void)
 
43
{
 
44
  struct grub_efiemu_sym *cur, *d;
 
45
  for (cur = efiemu_syms; cur;)
 
46
    {
 
47
      d = cur->next;
 
48
      grub_free (cur->name);
 
49
      grub_free (cur);
 
50
      cur = d;
 
51
    }
 
52
  efiemu_syms = 0;
 
53
  ptv_written = 0;
 
54
  ptv_alloc = 0;
 
55
  ptv_requested = 0;
 
56
  grub_efiemu_mm_return_request (ptv_handle);
 
57
  ptv_handle = 0;
 
58
  grub_efiemu_mm_return_request (relocated_handle);
 
59
  relocated_handle = 0;
 
60
}
 
61
 
 
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*/
 
65
grub_err_t
 
66
grub_efiemu_request_symbols (int num)
 
67
{
 
68
  if (ptv_alloc)
 
69
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
70
                       "symbols have already been allocated");
 
71
  if (num < 0)
 
72
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
73
                       "can't request negative symbols");
 
74
  ptv_requested += num;
 
75
  return GRUB_ERR_NONE;
 
76
}
 
77
 
 
78
/* Resolve the symbol name NAME and set HANDLE and OFF accordingly  */
 
79
grub_err_t
 
80
grub_efiemu_resolve_symbol (const char *name, int *handle, grub_off_t *off)
 
81
{
 
82
  struct grub_efiemu_sym *cur;
 
83
  for (cur = efiemu_syms; cur; cur = cur->next)
 
84
    if (!grub_strcmp (name, cur->name))
 
85
      {
 
86
        *handle = cur->handle;
 
87
        *off = cur->off;
 
88
        return GRUB_ERR_NONE;
 
89
      }
 
90
  grub_dprintf ("efiemu", "%s not found\n", name);
 
91
  return grub_error (GRUB_ERR_BAD_OS, "symbol %s isn't found", name);
 
92
}
 
93
 
 
94
/* Register symbol named NAME in memory handle HANDLE at offset OFF */
 
95
grub_err_t
 
96
grub_efiemu_register_symbol (const char *name, int handle, grub_off_t off)
 
97
{
 
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);
 
101
  if (!cur)
 
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;
 
106
  cur->off = off;
 
107
  efiemu_syms = cur;
 
108
 
 
109
  return 0;
 
110
}
 
111
 
 
112
/* Go from phase 1 to phase 2. Must be called before similar function in mm.c */
 
113
grub_err_t
 
114
grub_efiemu_alloc_syms (void)
 
115
{
 
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);
 
122
 
 
123
  grub_efiemu_register_symbol ("efiemu_ptv_relocated", relocated_handle, 0);
 
124
  grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0);
 
125
  return grub_errno;
 
126
}
 
127
 
 
128
grub_err_t
 
129
grub_efiemu_write_sym_markers (void)
 
130
{
 
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));
 
136
  *relocated = 0;
 
137
  return GRUB_ERR_NONE;
 
138
}
 
139
 
 
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
 
144
*/
 
145
grub_err_t
 
146
grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle,
 
147
                         int minus_handle, int ptv_needed, int size)
 
148
{
 
149
  /* Announce relocator to runtime */
 
150
  if (ptv_needed)
 
151
    {
 
152
      struct grub_efiemu_ptv_rel *ptv_rels
 
153
        = grub_efiemu_mm_obtain_request (ptv_handle);
 
154
 
 
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");
 
159
 
 
160
      if (minus_handle)
 
161
        ptv_rels[ptv_written].minustype
 
162
          = grub_efiemu_mm_get_type (minus_handle);
 
163
      else
 
164
        ptv_rels[ptv_written].minustype = 0;
 
165
 
 
166
      if (plus_handle)
 
167
        ptv_rels[ptv_written].plustype
 
168
          = grub_efiemu_mm_get_type (plus_handle);
 
169
      else
 
170
        ptv_rels[ptv_written].plustype = 0;
 
171
 
 
172
      ptv_rels[ptv_written].addr = PTR_TO_UINT64 (addr);
 
173
      ptv_rels[ptv_written].size = size;
 
174
      ptv_written++;
 
175
 
 
176
      /* memset next value to zero to mark the end */
 
177
      grub_memset (&ptv_rels[ptv_written], 0, sizeof (ptv_rels[ptv_written]));
 
178
    }
 
179
 
 
180
  /* Compute the value */
 
181
  if (minus_handle)
 
182
    value -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle));
 
183
 
 
184
  if (plus_handle)
 
185
    value += PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle));
 
186
 
 
187
  /* Write the value */
 
188
  switch (size)
 
189
    {
 
190
    case 8:
 
191
      *((grub_uint64_t *) addr) = value;
 
192
      break;
 
193
    case 4:
 
194
      *((grub_uint32_t *) addr) = value;
 
195
      break;
 
196
    case 2:
 
197
      *((grub_uint16_t *) addr) = value;
 
198
      break;
 
199
    case 1:
 
200
      *((grub_uint8_t *) addr) = value;
 
201
      break;
 
202
    default:
 
203
      return grub_error (GRUB_ERR_BAD_ARGUMENT, "wrong symbol size");
 
204
    }
 
205
 
 
206
  return GRUB_ERR_NONE;
 
207
}
 
208
 
 
209
grub_err_t
 
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)
 
215
{
 
216
  grub_uint8_t *ptv_relocated;
 
217
  struct grub_efiemu_ptv_rel *cur_relloc;
 
218
  struct grub_efiemu_ptv_rel *ptv_rels;
 
219
 
 
220
  ptv_relocated = grub_efiemu_mm_obtain_request (relocated_handle);
 
221
  ptv_rels = grub_efiemu_mm_obtain_request (ptv_handle);
 
222
 
 
223
  /* Ensure that we are called only once */
 
224
  if (*ptv_relocated)
 
225
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "EfiEmu is already relocated");
 
226
  *ptv_relocated = 1;
 
227
 
 
228
  /* Correct addresses using information supplied by grub */
 
229
  for (cur_relloc = ptv_rels; cur_relloc->size; cur_relloc++)
 
230
    {
 
231
      grub_int64_t corr = 0;
 
232
      grub_efi_memory_descriptor_t *descptr;
 
233
 
 
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))
 
240
        {
 
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;
 
245
        }
 
246
 
 
247
      /* Apply correction */
 
248
      switch (cur_relloc->size)
 
249
        {
 
250
        case 8:
 
251
          *((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
 
252
          break;
 
253
        case 4:
 
254
          *((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
 
255
          break;
 
256
        case 2:
 
257
          *((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
 
258
          break;
 
259
        case 1:
 
260
          *((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
 
261
          break;
 
262
        }
 
263
    }
 
264
 
 
265
  /* Recompute crc32 of system table and runtime services */
 
266
 
 
267
  if (grub_efiemu_sizeof_uintn_t () == 4)
 
268
    return grub_efiemu_crc32 ();
 
269
  else
 
270
    return grub_efiemu_crc64 ();
 
271
}