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

« back to all changes in this revision

Viewing changes to grub-core/efiemu/runtime/efiemu.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
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2006,2007,2009  Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
/* This is an emulation of EFI runtime services.
 
20
   This allows a more uniform boot on i386 machines.
 
21
   As it emulates only runtime serviceit isn't able
 
22
   to chainload EFI bootloader on non-EFI system (TODO) */
 
23
 
 
24
#include <grub/symbol.h>
 
25
#include <grub/types.h>
 
26
#include <grub/efi/api.h>
 
27
#include <grub/efiemu/runtime.h>
 
28
 
 
29
grub_efi_status_t
 
30
efiemu_get_time (grub_efi_time_t *time,
 
31
                 grub_efi_time_capabilities_t *capabilities);
 
32
grub_efi_status_t
 
33
efiemu_set_time (grub_efi_time_t *time);
 
34
 
 
35
grub_efi_status_t
 
36
efiemu_get_wakeup_time (grub_efi_boolean_t *enabled,
 
37
                        grub_efi_boolean_t *pending,
 
38
                        grub_efi_time_t *time);
 
39
grub_efi_status_t
 
40
efiemu_set_wakeup_time (grub_efi_boolean_t enabled,
 
41
                        grub_efi_time_t *time);
 
42
 
 
43
#ifdef APPLE_CC
 
44
#define PHYSICAL_ATTRIBUTE __attribute__ ((section("_text-physical, _text-physical")));
 
45
#else
 
46
#define PHYSICAL_ATTRIBUTE __attribute__ ((section(".text-physical")));
 
47
#endif
 
48
 
 
49
grub_efi_status_t
 
50
efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
 
51
                                grub_efi_uintn_t descriptor_size,
 
52
                                grub_efi_uint32_t descriptor_version,
 
53
                                grub_efi_memory_descriptor_t *virtual_map)
 
54
  PHYSICAL_ATTRIBUTE;
 
55
 
 
56
grub_efi_status_t
 
57
efiemu_convert_pointer (grub_efi_uintn_t debug_disposition,
 
58
                        void **address)
 
59
  PHYSICAL_ATTRIBUTE;
 
60
 
 
61
grub_efi_status_t
 
62
efiemu_get_variable (grub_efi_char16_t *variable_name,
 
63
                     grub_efi_guid_t *vendor_guid,
 
64
                     grub_efi_uint32_t *attributes,
 
65
                     grub_efi_uintn_t *data_size,
 
66
                     void *data);
 
67
 
 
68
grub_efi_status_t
 
69
efiemu_get_next_variable_name (grub_efi_uintn_t *variable_name_size,
 
70
                               grub_efi_char16_t *variable_name,
 
71
                               grub_efi_guid_t *vendor_guid);
 
72
 
 
73
grub_efi_status_t
 
74
efiemu_set_variable (grub_efi_char16_t *variable_name,
 
75
                     grub_efi_guid_t *vendor_guid,
 
76
                     grub_efi_uint32_t attributes,
 
77
                     grub_efi_uintn_t data_size,
 
78
                     void *data);
 
79
grub_efi_status_t
 
80
efiemu_get_next_high_monotonic_count (grub_efi_uint32_t *high_count);
 
81
void
 
82
efiemu_reset_system (grub_efi_reset_type_t reset_type,
 
83
                     grub_efi_status_t reset_status,
 
84
                     grub_efi_uintn_t data_size,
 
85
                     grub_efi_char16_t *reset_data);
 
86
 
 
87
grub_efi_status_t
 
88
EFI_FUNC (efiemu_set_virtual_address_map) (grub_efi_uintn_t,
 
89
                                              grub_efi_uintn_t,
 
90
                                              grub_efi_uint32_t,
 
91
                                              grub_efi_memory_descriptor_t *)
 
92
     PHYSICAL_ATTRIBUTE;
 
93
grub_efi_status_t
 
94
EFI_FUNC (efiemu_convert_pointer) (grub_efi_uintn_t debug_disposition,
 
95
                                      void **address)
 
96
     PHYSICAL_ATTRIBUTE;
 
97
static grub_uint32_t
 
98
efiemu_getcrc32 (grub_uint32_t crc, void *buf, int size)
 
99
     PHYSICAL_ATTRIBUTE;
 
100
static void
 
101
init_crc32_table (void)
 
102
     PHYSICAL_ATTRIBUTE;
 
103
static grub_uint32_t
 
104
reflect (grub_uint32_t ref, int len)
 
105
     PHYSICAL_ATTRIBUTE;
 
106
 
 
107
/*
 
108
  The log. It's used when examining memory dump
 
109
*/
 
110
static grub_uint8_t loge[1000] = "EFIEMULOG";
 
111
static int logn = 9;
 
112
#define LOG(x)   { if (logn<900) loge[logn++]=x; }
 
113
 
 
114
/* Interface with grub */
 
115
extern grub_uint8_t efiemu_ptv_relocated;
 
116
struct grub_efi_runtime_services efiemu_runtime_services;
 
117
struct grub_efi_system_table efiemu_system_table;
 
118
extern struct grub_efiemu_ptv_rel efiemu_ptv_relloc[];
 
119
extern grub_uint8_t efiemu_variables[];
 
120
extern grub_uint32_t efiemu_varsize;
 
121
extern grub_uint32_t efiemu_high_monotonic_count;
 
122
extern grub_int16_t efiemu_time_zone;
 
123
extern grub_uint8_t efiemu_time_daylight;
 
124
extern grub_uint32_t efiemu_time_accuracy;
 
125
 
 
126
/* Some standard functions because we need to be standalone */
 
127
static void
 
128
efiemu_memcpy (void *to, void *from, int count)
 
129
{
 
130
  int i;
 
131
  for (i = 0; i < count; i++)
 
132
    ((grub_uint8_t *) to)[i] = ((grub_uint8_t *) from)[i];
 
133
}
 
134
 
 
135
static int
 
136
efiemu_str16equal (grub_uint16_t *a, grub_uint16_t *b)
 
137
{
 
138
  grub_uint16_t *ptr1, *ptr2;
 
139
  for (ptr1=a,ptr2=b; *ptr1 && *ptr2 == *ptr1; ptr1++, ptr2++);
 
140
  return *ptr2 == *ptr1;
 
141
}
 
142
 
 
143
static grub_size_t
 
144
efiemu_str16len (grub_uint16_t *a)
 
145
{
 
146
  grub_uint16_t *ptr1;
 
147
  for (ptr1 = a; *ptr1; ptr1++);
 
148
  return ptr1 - a;
 
149
}
 
150
 
 
151
static int
 
152
efiemu_memequal (void *a, void *b, grub_size_t n)
 
153
{
 
154
  grub_uint8_t *ptr1, *ptr2;
 
155
  for (ptr1 = (grub_uint8_t *) a, ptr2 = (grub_uint8_t *)b;
 
156
       ptr1 < (grub_uint8_t *)a + n && *ptr2 == *ptr1; ptr1++, ptr2++);
 
157
  return ptr1 == a + n;
 
158
}
 
159
 
 
160
static void
 
161
efiemu_memset (grub_uint8_t *a, grub_uint8_t b, grub_size_t n)
 
162
{
 
163
  grub_uint8_t *ptr1;
 
164
  for (ptr1=a; ptr1 < a + n; ptr1++)
 
165
    *ptr1 = b;
 
166
}
 
167
 
 
168
static inline void
 
169
write_cmos (grub_uint8_t addr, grub_uint8_t val)
 
170
{
 
171
  __asm__ __volatile__ ("outb %%al,$0x70\n"
 
172
                        "mov %%cl, %%al\n"
 
173
                        "outb %%al,$0x71": :"a" (addr), "c" (val));
 
174
}
 
175
 
 
176
static inline grub_uint8_t
 
177
read_cmos (grub_uint8_t addr)
 
178
{
 
179
  grub_uint8_t ret;
 
180
  __asm__ __volatile__ ("outb %%al, $0x70\n"
 
181
                        "inb $0x71, %%al": "=a"(ret) :"a" (addr));
 
182
  return ret;
 
183
}
 
184
 
 
185
/* Needed by some gcc versions */
 
186
int __stack_chk_fail ()
 
187
{
 
188
  return 0;
 
189
}
 
190
 
 
191
/* The function that implement runtime services as specified in
 
192
   EFI specification */
 
193
static inline grub_uint8_t
 
194
bcd_to_hex (grub_uint8_t in)
 
195
{
 
196
  return 10 * ((in & 0xf0) >> 4) + (in & 0x0f);
 
197
}
 
198
 
 
199
grub_efi_status_t
 
200
EFI_FUNC (efiemu_get_time) (grub_efi_time_t *time,
 
201
                               grub_efi_time_capabilities_t *capabilities)
 
202
{
 
203
  LOG ('a');
 
204
  grub_uint8_t state;
 
205
  state = read_cmos (0xb);
 
206
  if (!(state & (1 << 2)))
 
207
    {
 
208
      time->year = 2000 + bcd_to_hex (read_cmos (0x9));
 
209
      time->month = bcd_to_hex (read_cmos (0x8));
 
210
      time->day = bcd_to_hex (read_cmos (0x7));
 
211
      time->hour = bcd_to_hex (read_cmos (0x4));
 
212
      if (time->hour >= 81)
 
213
        time->hour -= 80 - 12;
 
214
      if (time->hour == 24)
 
215
        time->hour = 0;
 
216
      time->minute = bcd_to_hex (read_cmos (0x2));
 
217
      time->second = bcd_to_hex (read_cmos (0x0));
 
218
    }
 
219
  else
 
220
    {
 
221
      time->year = 2000 + read_cmos (0x9);
 
222
      time->month = read_cmos (0x8);
 
223
      time->day = read_cmos (0x7);
 
224
      time->hour = read_cmos (0x4);
 
225
      if (time->hour >= 0x81)
 
226
        time->hour -= 0x80 - 12;
 
227
      if (time->hour == 24)
 
228
        time->hour = 0;
 
229
      time->minute = read_cmos (0x2);
 
230
      time->second = read_cmos (0x0);
 
231
    }
 
232
  time->nanosecond = 0;
 
233
  time->pad1 = 0;
 
234
  time->pad2 = 0;
 
235
  time->time_zone = efiemu_time_zone;
 
236
  time->daylight = efiemu_time_daylight;
 
237
  capabilities->resolution = 1;
 
238
  capabilities->accuracy = efiemu_time_accuracy;
 
239
  capabilities->sets_to_zero = 0;
 
240
  return GRUB_EFI_SUCCESS;
 
241
}
 
242
 
 
243
grub_efi_status_t
 
244
EFI_FUNC (efiemu_set_time) (grub_efi_time_t *time)
 
245
{
 
246
  LOG ('b');
 
247
  grub_uint8_t state;
 
248
  state = read_cmos (0xb);
 
249
  write_cmos (0xb, state | 0x6);
 
250
  write_cmos (0x9, time->year - 2000);
 
251
  write_cmos (0x8, time->month);
 
252
  write_cmos (0x7, time->day);
 
253
  write_cmos (0x4, time->hour);
 
254
  write_cmos (0x2, time->minute);
 
255
  write_cmos (0x0, time->second);
 
256
  efiemu_time_zone = time->time_zone;
 
257
  efiemu_time_daylight = time->daylight;
 
258
  return GRUB_EFI_SUCCESS;
 
259
}
 
260
 
 
261
/* Following 2 functions are vendor specific. So announce it as unsupported */
 
262
grub_efi_status_t
 
263
EFI_FUNC (efiemu_get_wakeup_time) (grub_efi_boolean_t *enabled,
 
264
                                      grub_efi_boolean_t *pending,
 
265
                                      grub_efi_time_t *time)
 
266
{
 
267
  LOG ('c');
 
268
  return GRUB_EFI_UNSUPPORTED;
 
269
}
 
270
 
 
271
grub_efi_status_t
 
272
EFI_FUNC (efiemu_set_wakeup_time) (grub_efi_boolean_t enabled,
 
273
                                      grub_efi_time_t *time)
 
274
{
 
275
  LOG ('d');
 
276
  return GRUB_EFI_UNSUPPORTED;
 
277
}
 
278
 
 
279
static grub_uint32_t crc32_table [256];
 
280
 
 
281
static grub_uint32_t
 
282
reflect (grub_uint32_t ref, int len)
 
283
{
 
284
  grub_uint32_t result = 0;
 
285
  int i;
 
286
 
 
287
  for (i = 1; i <= len; i++)
 
288
    {
 
289
      if (ref & 1)
 
290
        result |= 1 << (len - i);
 
291
      ref >>= 1;
 
292
    }
 
293
 
 
294
  return result;
 
295
}
 
296
 
 
297
static void
 
298
init_crc32_table (void)
 
299
{
 
300
  grub_uint32_t polynomial = 0x04c11db7;
 
301
  int i, j;
 
302
 
 
303
  for(i = 0; i < 256; i++)
 
304
    {
 
305
      crc32_table[i] = reflect(i, 8) << 24;
 
306
      for (j = 0; j < 8; j++)
 
307
        crc32_table[i] = (crc32_table[i] << 1) ^
 
308
            (crc32_table[i] & (1 << 31) ? polynomial : 0);
 
309
      crc32_table[i] = reflect(crc32_table[i], 32);
 
310
    }
 
311
}
 
312
 
 
313
static grub_uint32_t
 
314
efiemu_getcrc32 (grub_uint32_t crc, void *buf, int size)
 
315
{
 
316
  int i;
 
317
  grub_uint8_t *data = buf;
 
318
 
 
319
  if (! crc32_table[1])
 
320
    init_crc32_table ();
 
321
 
 
322
  crc^= 0xffffffff;
 
323
 
 
324
  for (i = 0; i < size; i++)
 
325
    {
 
326
      crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *data];
 
327
      data++;
 
328
    }
 
329
 
 
330
  return crc ^ 0xffffffff;
 
331
}
 
332
 
 
333
 
 
334
grub_efi_status_t EFI_FUNC
 
335
(efiemu_set_virtual_address_map) (grub_efi_uintn_t memory_map_size,
 
336
                                  grub_efi_uintn_t descriptor_size,
 
337
                                  grub_efi_uint32_t descriptor_version,
 
338
                                  grub_efi_memory_descriptor_t *virtual_map)
 
339
{
 
340
  struct grub_efiemu_ptv_rel *cur_relloc;
 
341
 
 
342
  LOG ('e');
 
343
 
 
344
  /* Ensure that we are called only once */
 
345
  if (efiemu_ptv_relocated)
 
346
    return GRUB_EFI_UNSUPPORTED;
 
347
  efiemu_ptv_relocated = 1;
 
348
 
 
349
  /* Correct addresses using information supplied by grub */
 
350
  for (cur_relloc = efiemu_ptv_relloc; cur_relloc->size;cur_relloc++)
 
351
    {
 
352
      grub_int64_t corr = 0;
 
353
      grub_efi_memory_descriptor_t *descptr;
 
354
 
 
355
      /* Compute correction */
 
356
      for (descptr = virtual_map;
 
357
           ((grub_uint8_t *) descptr - (grub_uint8_t *) virtual_map)
 
358
             < memory_map_size;
 
359
           descptr = (grub_efi_memory_descriptor_t *)
 
360
             ((grub_uint8_t *) descptr + descriptor_size))
 
361
        {
 
362
          if (descptr->type == cur_relloc->plustype)
 
363
            corr += descptr->virtual_start - descptr->physical_start;
 
364
          if (descptr->type == cur_relloc->minustype)
 
365
            corr -= descptr->virtual_start - descptr->physical_start;
 
366
        }
 
367
 
 
368
      /* Apply correction */
 
369
      switch (cur_relloc->size)
 
370
        {
 
371
        case 8:
 
372
          *((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
 
373
          break;
 
374
        case 4:
 
375
          *((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
 
376
          break;
 
377
        case 2:
 
378
          *((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
 
379
          break;
 
380
        case 1:
 
381
          *((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
 
382
          break;
 
383
        }
 
384
    }
 
385
 
 
386
  /* Recompute crc32 of system table and runtime services */
 
387
  efiemu_system_table.hdr.crc32 = 0;
 
388
  efiemu_system_table.hdr.crc32 = efiemu_getcrc32
 
389
    (0, &efiemu_system_table, sizeof (efiemu_system_table));
 
390
 
 
391
  efiemu_runtime_services.hdr.crc32 = 0;
 
392
  efiemu_runtime_services.hdr.crc32 = efiemu_getcrc32
 
393
    (0, &efiemu_runtime_services, sizeof (efiemu_runtime_services));
 
394
 
 
395
  return GRUB_EFI_SUCCESS;
 
396
}
 
397
 
 
398
/* since efiemu_set_virtual_address_map corrects all the pointers
 
399
   we don't need efiemu_convert_pointer */
 
400
grub_efi_status_t
 
401
EFI_FUNC (efiemu_convert_pointer) (grub_efi_uintn_t debug_disposition,
 
402
                                      void **address)
 
403
{
 
404
  LOG ('f');
 
405
  return GRUB_EFI_UNSUPPORTED;
 
406
}
 
407
 
 
408
/* Next comes variable services. Because we have no vendor-independent
 
409
   way to store these variables we have no non-volatility */
 
410
 
 
411
/* Find variable by name and GUID. */
 
412
static struct efi_variable *
 
413
find_variable (grub_efi_guid_t *vendor_guid,
 
414
               grub_efi_char16_t *variable_name)
 
415
{
 
416
  grub_uint8_t *ptr;
 
417
  struct efi_variable *efivar;
 
418
 
 
419
  for (ptr = efiemu_variables; ptr < efiemu_variables + efiemu_varsize; )
 
420
    {
 
421
      efivar = (struct efi_variable *) ptr;
 
422
      if (!efivar->namelen)
 
423
        return 0;
 
424
      if (efiemu_str16equal((grub_efi_char16_t *)(efivar + 1), variable_name)
 
425
          && efiemu_memequal (&(efivar->guid), vendor_guid,
 
426
                              sizeof (efivar->guid)))
 
427
        return efivar;
 
428
      ptr += efivar->namelen + efivar->size + sizeof (*efivar);
 
429
    }
 
430
  return 0;
 
431
}
 
432
 
 
433
grub_efi_status_t
 
434
EFI_FUNC (efiemu_get_variable) (grub_efi_char16_t *variable_name,
 
435
                                   grub_efi_guid_t *vendor_guid,
 
436
                                   grub_efi_uint32_t *attributes,
 
437
                                   grub_efi_uintn_t *data_size,
 
438
                                   void *data)
 
439
{
 
440
  struct efi_variable *efivar;
 
441
  LOG ('g');
 
442
  efivar = find_variable (vendor_guid, variable_name);
 
443
  if (!efivar)
 
444
    return GRUB_EFI_NOT_FOUND;
 
445
  if (*data_size < efivar->size)
 
446
    {
 
447
      *data_size = efivar->size;
 
448
      return GRUB_EFI_BUFFER_TOO_SMALL;
 
449
    }
 
450
  *data_size = efivar->size;
 
451
  efiemu_memcpy (data, (grub_uint8_t *)(efivar + 1) + efivar->namelen,
 
452
                 efivar->size);
 
453
  *attributes = efivar->attributes;
 
454
 
 
455
  return GRUB_EFI_SUCCESS;
 
456
}
 
457
 
 
458
grub_efi_status_t EFI_FUNC
 
459
(efiemu_get_next_variable_name) (grub_efi_uintn_t *variable_name_size,
 
460
                                 grub_efi_char16_t *variable_name,
 
461
                                 grub_efi_guid_t *vendor_guid)
 
462
{
 
463
  struct efi_variable *efivar;
 
464
  LOG ('l');
 
465
 
 
466
  if (!variable_name_size || !variable_name || !vendor_guid)
 
467
    return GRUB_EFI_INVALID_PARAMETER;
 
468
  if (variable_name[0])
 
469
    {
 
470
      efivar = find_variable (vendor_guid, variable_name);
 
471
      if (!efivar)
 
472
        return GRUB_EFI_NOT_FOUND;
 
473
      efivar = (struct efi_variable *)((grub_uint8_t *)efivar
 
474
                                       + efivar->namelen
 
475
                                       + efivar->size + sizeof (*efivar));
 
476
    }
 
477
  else
 
478
    efivar = (struct efi_variable *) (efiemu_variables);
 
479
 
 
480
  LOG ('m');
 
481
  if ((grub_uint8_t *)efivar >= efiemu_variables + efiemu_varsize
 
482
      || !efivar->namelen)
 
483
    return GRUB_EFI_NOT_FOUND;
 
484
  if (*variable_name_size < efivar->namelen)
 
485
    {
 
486
      *variable_name_size = efivar->namelen;
 
487
      return GRUB_EFI_BUFFER_TOO_SMALL;
 
488
    }
 
489
 
 
490
  efiemu_memcpy (variable_name, efivar + 1, efivar->namelen);
 
491
  efiemu_memcpy (vendor_guid, &(efivar->guid),
 
492
                 sizeof (efivar->guid));
 
493
 
 
494
  LOG('h');
 
495
  return GRUB_EFI_SUCCESS;
 
496
}
 
497
 
 
498
grub_efi_status_t
 
499
EFI_FUNC (efiemu_set_variable) (grub_efi_char16_t *variable_name,
 
500
                                   grub_efi_guid_t *vendor_guid,
 
501
                                   grub_efi_uint32_t attributes,
 
502
                                   grub_efi_uintn_t data_size,
 
503
                                   void *data)
 
504
{
 
505
  struct efi_variable *efivar;
 
506
  grub_uint8_t *ptr;
 
507
  LOG('i');
 
508
  if (!variable_name[0])
 
509
    return GRUB_EFI_INVALID_PARAMETER;
 
510
  efivar = find_variable (vendor_guid, variable_name);
 
511
 
 
512
  /* Delete variable if any */
 
513
  if (efivar)
 
514
    {
 
515
      efiemu_memcpy (efivar, (grub_uint8_t *)(efivar + 1)
 
516
                     + efivar->namelen + efivar->size,
 
517
                     (efiemu_variables + efiemu_varsize)
 
518
                     - ((grub_uint8_t *)(efivar + 1)
 
519
                        + efivar->namelen + efivar->size));
 
520
      efiemu_memset (efiemu_variables + efiemu_varsize
 
521
                     - (sizeof (*efivar) + efivar->namelen + efivar->size),
 
522
                     0, (sizeof (*efivar) + efivar->namelen + efivar->size));
 
523
    }
 
524
 
 
525
  if (!data_size)
 
526
    return GRUB_EFI_SUCCESS;
 
527
 
 
528
  for (ptr = efiemu_variables; ptr < efiemu_variables + efiemu_varsize; )
 
529
    {
 
530
      efivar = (struct efi_variable *) ptr;
 
531
      ptr += efivar->namelen + efivar->size + sizeof (*efivar);
 
532
      if (!efivar->namelen)
 
533
        break;
 
534
    }
 
535
  if ((grub_uint8_t *)(efivar + 1) + data_size
 
536
      + 2 * (efiemu_str16len (variable_name) + 1)
 
537
      >= efiemu_variables + efiemu_varsize)
 
538
    return GRUB_EFI_OUT_OF_RESOURCES;
 
539
 
 
540
  efiemu_memcpy (&(efivar->guid), vendor_guid, sizeof (efivar->guid));
 
541
  efivar->namelen = 2 * (efiemu_str16len (variable_name) + 1);
 
542
  efivar->size = data_size;
 
543
  efivar->attributes = attributes;
 
544
  efiemu_memcpy (efivar + 1, variable_name,
 
545
                 2 * (efiemu_str16len (variable_name) + 1));
 
546
  efiemu_memcpy ((grub_uint8_t *)(efivar + 1)
 
547
                 + 2 * (efiemu_str16len (variable_name) + 1),
 
548
                 data, data_size);
 
549
 
 
550
  return GRUB_EFI_SUCCESS;
 
551
}
 
552
 
 
553
grub_efi_status_t EFI_FUNC
 
554
(efiemu_get_next_high_monotonic_count) (grub_efi_uint32_t *high_count)
 
555
{
 
556
  LOG ('j');
 
557
  if (!high_count)
 
558
    return GRUB_EFI_INVALID_PARAMETER;
 
559
  *high_count = ++efiemu_high_monotonic_count;
 
560
  return GRUB_EFI_SUCCESS;
 
561
}
 
562
 
 
563
/* To implement it with APM we need to go to real mode. It's too much hassle
 
564
   Besides EFI specification says that this function shouldn't be used
 
565
   on systems supporting ACPI
 
566
 */
 
567
void
 
568
EFI_FUNC (efiemu_reset_system) (grub_efi_reset_type_t reset_type,
 
569
                                   grub_efi_status_t reset_status,
 
570
                                   grub_efi_uintn_t data_size,
 
571
                                   grub_efi_char16_t *reset_data)
 
572
{
 
573
  LOG ('k');
 
574
}
 
575
 
 
576
struct grub_efi_runtime_services efiemu_runtime_services =
 
577
{
 
578
  .hdr =
 
579
  {
 
580
    .signature = GRUB_EFIEMU_RUNTIME_SERVICES_SIGNATURE,
 
581
    .revision = 0x0001000a,
 
582
    .header_size = sizeof (struct grub_efi_runtime_services),
 
583
    .crc32 = 0, /* filled later*/
 
584
    .reserved = 0
 
585
  },
 
586
  .get_time = efiemu_get_time,
 
587
  .set_time = efiemu_set_time,
 
588
  .get_wakeup_time = efiemu_get_wakeup_time,
 
589
  .set_wakeup_time = efiemu_set_wakeup_time,
 
590
 
 
591
  .set_virtual_address_map = efiemu_set_virtual_address_map,
 
592
  .convert_pointer = efiemu_convert_pointer,
 
593
 
 
594
  .get_variable = efiemu_get_variable,
 
595
  .get_next_variable_name = efiemu_get_next_variable_name,
 
596
  .set_variable = efiemu_set_variable,
 
597
  .get_next_high_monotonic_count = efiemu_get_next_high_monotonic_count,
 
598
 
 
599
  .reset_system = efiemu_reset_system
 
600
};
 
601
 
 
602
 
 
603
static grub_uint16_t efiemu_vendor[] =
 
604
  {'G', 'R', 'U', 'B', ' ', 'E', 'F', 'I', ' ',
 
605
   'R', 'U', 'N', 'T', 'I', 'M', 'E', 0};
 
606
 
 
607
struct grub_efi_system_table efiemu_system_table =
 
608
{
 
609
  .hdr =
 
610
  {
 
611
    .signature = GRUB_EFIEMU_SYSTEM_TABLE_SIGNATURE,
 
612
    .revision = 0x0001000a,
 
613
    .header_size = sizeof (struct grub_efi_system_table),
 
614
    .crc32 = 0, /* filled later*/
 
615
    .reserved = 0
 
616
  },
 
617
  .firmware_vendor = efiemu_vendor,
 
618
  .firmware_revision = 0x0001000a,
 
619
  .console_in_handler = 0,
 
620
  .con_in = 0,
 
621
  .console_out_handler = 0,
 
622
  .con_out = 0,
 
623
  .standard_error_handle = 0,
 
624
  .std_err = 0,
 
625
  .runtime_services = &efiemu_runtime_services,
 
626
  .boot_services = 0,
 
627
  .num_table_entries = 0,
 
628
  .configuration_table = 0
 
629
};
 
630