~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to efiemu/runtime/efiemu.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2011-02-08 11:39:26 UTC
  • mfrom: (17.6.26 experimental)
  • mto: (17.6.27 experimental)
  • mto: This revision was merged to the branch mainline in revision 104.
  • Revision ID: james.westby@ubuntu.com-20110208113926-clfs90haboyk9zip
Tags: 1.99~rc1-2
* Merge 1.98+20100804-13 and 1.98+20100804-14, updating translations:
  - Kazakh (Baurzhan Muftakhidinov / Timur Birsh).
* mkconfig_skip_dmcrypt.patch: Refer to GRUB_PRELOAD_MODULES rather than
  suggesting people write a /etc/grub.d/01_modules script (thanks, Jordan
  Uggla).
* Handle empty dir passed to grub_find_root_device_from_mountinfo; fixes
  grub-mkrelpath on btrfs subvolumes (LP: #712029).
* Add rootflags=subvol=<name> if / is on a btrfs subvolume (LP: #712029).
* Upload to unstable.

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