~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to loader/i386/xnu.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2010-01-11 11:12:55 UTC
  • mfrom: (17.3.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100111111255-lr8ebkqw5x41gq6j
Tags: 1.98~20100101-1ubuntu1
* Resynchronise with Debian. Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Conflict with grub (<< 0.97-54) as well as grub-legacy.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu. Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed. If it is, show the
    menu, otherwise boot immediately. If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt. Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - If the environment variable "quiet" is set to something other than 0,
    suppress progress messages as the kernel and initrd load. Set this for
    non-recovery kernel menu entries.
  - Add GRUB_DEFAULT=saved, as well as grub-set-default and grub-reboot
    utilities. Provides functionality essentially equivalent to GRUB
    Legacy's savedefault.
  - Keep the loopback file open so that subsequent changes to the "root"
    environment variable don't affect it.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Handle RAID devices containing virtio components.
* Update savedefault patch from current Bazaar branch, fixing grub-reboot
  to have distinct behaviour from grub-set-default (LP: #497326).
* Fix grub-mkisofs compilation error with FORTIFY_SOURCE.
* Convert recordfail boilerplate in each menu entry to use a function.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <grub/loader.h>
26
26
#include <grub/autoefi.h>
27
27
#include <grub/i386/tsc.h>
 
28
#include <grub/efi/api.h>
28
29
#include <grub/i386/pit.h>
29
30
#include <grub/misc.h>
 
31
#include <grub/charset.h>
30
32
#include <grub/term.h>
 
33
#include <grub/command.h>
 
34
#include <grub/gzio.h>
31
35
 
32
36
char grub_xnu_cmdline[1024];
 
37
grub_uint32_t grub_xnu_heap_will_be_at;
 
38
grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack;
33
39
 
34
40
/* Aliases set for some tables. */
35
41
struct tbl_alias
44
50
    {GRUB_EFI_ACPI_TABLE_GUID, "ACPI"},
45
51
  };
46
52
 
47
 
/* The following function is used to be able to debug xnu loader
48
 
   with grub-emu. */
49
 
#ifdef GRUB_UTIL
50
 
static grub_err_t
51
 
grub_xnu_launch (void)
 
53
struct grub_xnu_devprop_device_descriptor
52
54
{
53
 
  grub_printf ("Fake launch %x:%p:%p", grub_xnu_entry_point, grub_xnu_arg1,
54
 
               grub_xnu_stack);
55
 
  grub_getkey ();
56
 
  return 0;
57
 
}
58
 
#else
59
 
static void (*grub_xnu_launch) (void) = 0;
60
 
#endif
 
55
  struct grub_xnu_devprop_device_descriptor *next;
 
56
  struct property_descriptor *properties;
 
57
  struct grub_efi_device_path *path;
 
58
  int pathlen;
 
59
};
61
60
 
62
61
static int
63
62
utf16_strlen (grub_uint16_t *in)
205
204
                        ((msrlow >> 7) & 0x3e) + ((msrlow >> 14) & 1), 0);
206
205
}
207
206
 
 
207
struct property_descriptor
 
208
{
 
209
  struct property_descriptor *next;
 
210
  grub_uint8_t *name;
 
211
  grub_uint16_t *name16;
 
212
  int name16len;
 
213
  int length;
 
214
  void *data;
 
215
};
 
216
 
 
217
struct grub_xnu_devprop_device_descriptor *devices = 0;
 
218
 
 
219
grub_err_t
 
220
grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor *dev,
 
221
                                  char *name)
 
222
{
 
223
  struct property_descriptor *prop;
 
224
  prop = grub_named_list_find (GRUB_AS_NAMED_LIST_P (&dev->properties), name);
 
225
  if (!prop)
 
226
    return GRUB_ERR_NONE;
 
227
 
 
228
  grub_free (prop->name);
 
229
  grub_free (prop->name16);
 
230
  grub_free (prop->data);
 
231
 
 
232
  grub_list_remove (GRUB_AS_LIST_P (&dev->properties), GRUB_AS_LIST (prop));
 
233
 
 
234
  return GRUB_ERR_NONE;
 
235
}
 
236
 
 
237
grub_err_t
 
238
grub_xnu_devprop_remove_device (struct grub_xnu_devprop_device_descriptor *dev)
 
239
{
 
240
  void *t;
 
241
  struct property_descriptor *prop;
 
242
 
 
243
  grub_list_remove (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (dev));
 
244
 
 
245
  for (prop = dev->properties; prop; )
 
246
    {
 
247
      grub_free (prop->name);
 
248
      grub_free (prop->name16);
 
249
      grub_free (prop->data);
 
250
      t = prop;
 
251
      prop = prop->next;
 
252
      grub_free (t);
 
253
    }
 
254
 
 
255
  grub_free (dev->path);
 
256
  grub_free (dev);
 
257
 
 
258
  return GRUB_ERR_NONE;
 
259
}
 
260
 
 
261
struct grub_xnu_devprop_device_descriptor *
 
262
grub_xnu_devprop_add_device (struct grub_efi_device_path *path, int length)
 
263
{
 
264
  struct grub_xnu_devprop_device_descriptor *ret;
 
265
 
 
266
  ret = grub_zalloc (sizeof (*ret));
 
267
  if (!ret)
 
268
    return 0;
 
269
 
 
270
  ret->path = grub_malloc (length);
 
271
  if (!ret->path)
 
272
    {
 
273
      grub_free (ret);
 
274
      return 0;
 
275
    }
 
276
  ret->pathlen = length;
 
277
  grub_memcpy (ret->path, path, length);
 
278
 
 
279
  grub_list_push (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (ret));
 
280
 
 
281
  return ret;
 
282
}
 
283
 
 
284
static grub_err_t
 
285
grub_xnu_devprop_add_property (struct grub_xnu_devprop_device_descriptor *dev,
 
286
                               grub_uint8_t *utf8, grub_uint16_t *utf16,
 
287
                               int utf16len, void *data, int datalen)
 
288
{
 
289
  struct property_descriptor *prop;
 
290
 
 
291
  prop = grub_malloc (sizeof (*prop));
 
292
  if (!prop)
 
293
    return grub_errno;
 
294
 
 
295
  prop->name = utf8;
 
296
  prop->name16 = utf16;
 
297
  prop->name16len = utf16len;
 
298
 
 
299
  prop->length = datalen;
 
300
  prop->data = grub_malloc (prop->length);
 
301
  if (!prop->data)
 
302
    {
 
303
      grub_free (prop);
 
304
      grub_free (prop->name);
 
305
      grub_free (prop->name16);
 
306
      return grub_errno;
 
307
    }
 
308
  grub_memcpy (prop->data, data, prop->length);
 
309
  grub_list_push (GRUB_AS_LIST_P (&dev->properties),
 
310
                  GRUB_AS_LIST (prop));
 
311
  return GRUB_ERR_NONE;
 
312
}
 
313
 
 
314
grub_err_t
 
315
grub_xnu_devprop_add_property_utf8 (struct grub_xnu_devprop_device_descriptor *dev,
 
316
                                    char *name, void *data, int datalen)
 
317
{
 
318
  grub_uint8_t *utf8;
 
319
  grub_uint16_t *utf16;
 
320
  int len, utf16len;
 
321
  grub_err_t err;
 
322
 
 
323
  utf8 = (grub_uint8_t *) grub_strdup (name);
 
324
  if (!utf8)
 
325
    return grub_errno;
 
326
 
 
327
  len = grub_strlen (name);
 
328
  utf16 = grub_malloc (sizeof (grub_uint16_t) * len);
 
329
  if (!utf16)
 
330
    {
 
331
      grub_free (utf8);
 
332
      return grub_errno;
 
333
    }
 
334
 
 
335
  utf16len = grub_utf8_to_utf16 (utf16, len, utf8, len, NULL);
 
336
  if (utf16len < 0)
 
337
    {
 
338
      grub_free (utf8);
 
339
      grub_free (utf16);
 
340
      return grub_errno;
 
341
    }
 
342
 
 
343
  err = grub_xnu_devprop_add_property (dev, utf8, utf16,
 
344
                                       utf16len, data, datalen);
 
345
  if (err)
 
346
    {
 
347
      grub_free (utf8);
 
348
      grub_free (utf16);
 
349
      return err;
 
350
    }
 
351
 
 
352
  return GRUB_ERR_NONE;
 
353
}
 
354
 
 
355
grub_err_t
 
356
grub_xnu_devprop_add_property_utf16 (struct grub_xnu_devprop_device_descriptor *dev,
 
357
                                     grub_uint16_t *name, int namelen,
 
358
                                     void *data, int datalen)
 
359
{
 
360
  grub_uint8_t *utf8;
 
361
  grub_uint16_t *utf16;
 
362
  grub_err_t err;
 
363
 
 
364
  utf16 = grub_malloc (sizeof (grub_uint16_t) * namelen);
 
365
  if (!utf16)
 
366
    return grub_errno;
 
367
  grub_memcpy (utf16, name, sizeof (grub_uint16_t) * namelen);
 
368
 
 
369
  utf8 = grub_malloc (namelen * 4 + 1);
 
370
  if (!utf8)
 
371
    {
 
372
      grub_free (utf8);
 
373
      return grub_errno;
 
374
    }
 
375
 
 
376
  *grub_utf16_to_utf8 ((grub_uint8_t *) utf8, name, namelen) = '\0';
 
377
 
 
378
  err = grub_xnu_devprop_add_property (dev, utf8, utf16,
 
379
                                       namelen, data, datalen);
 
380
  if (err)
 
381
    {
 
382
      grub_free (utf8);
 
383
      grub_free (utf16);
 
384
      return err;
 
385
    }
 
386
 
 
387
  return GRUB_ERR_NONE;
 
388
}
 
389
 
 
390
static inline int
 
391
hextoval (char c)
 
392
{
 
393
  if (c >= '0' && c <= '9')
 
394
    return c - '0';
 
395
  if (c >= 'a' && c <= 'z')
 
396
    return c - 'a' + 10;
 
397
  if (c >= 'A' && c <= 'Z')
 
398
    return c - 'A' + 10;
 
399
  return 0;
 
400
}
 
401
 
 
402
void
 
403
grub_cpu_xnu_unload (void)
 
404
{
 
405
  struct grub_xnu_devprop_device_descriptor *dev1, *dev2;
 
406
 
 
407
  for (dev1 = devices; dev1; )
 
408
    {
 
409
      dev2 = dev1->next;
 
410
      grub_xnu_devprop_remove_device (dev1);
 
411
      dev1 = dev2;
 
412
    }
 
413
}
 
414
 
 
415
static grub_err_t
 
416
grub_cpu_xnu_fill_devprop (void)
 
417
{
 
418
  struct grub_xnu_devtree_key *efikey;
 
419
  int total_length = sizeof (struct grub_xnu_devprop_header);
 
420
  struct grub_xnu_devtree_key *devprop;
 
421
  struct grub_xnu_devprop_device_descriptor *device;
 
422
  void *ptr;
 
423
  struct grub_xnu_devprop_header *head;
 
424
  void *t;
 
425
  int numdevs = 0;
 
426
 
 
427
  /* The key "efi". */
 
428
  efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi");
 
429
  if (! efikey)
 
430
    return grub_errno;
 
431
 
 
432
  for (device = devices; device; device = device->next)
 
433
    {
 
434
      struct property_descriptor *propdesc;
 
435
      total_length += sizeof (struct grub_xnu_devprop_device_header);
 
436
      total_length += device->pathlen;
 
437
 
 
438
      for (propdesc = device->properties; propdesc; propdesc = propdesc->next)
 
439
        {
 
440
          total_length += sizeof (grub_uint32_t);
 
441
          total_length += sizeof (grub_uint16_t)
 
442
            * (propdesc->name16len + 1);
 
443
          total_length += sizeof (grub_uint32_t);
 
444
          total_length += propdesc->length;
 
445
        }
 
446
      numdevs++;
 
447
    }
 
448
 
 
449
  devprop = grub_xnu_create_value (&(efikey->first_child), "device-properties");
 
450
  if (devprop)
 
451
    {
 
452
      devprop->data = grub_malloc (total_length);
 
453
      devprop->datasize = total_length;
 
454
    }
 
455
 
 
456
  ptr = devprop->data;
 
457
  head = ptr;
 
458
  ptr = head + 1;
 
459
  head->length = total_length;
 
460
  head->alwaysone = 1;
 
461
  head->num_devices = numdevs;
 
462
  for (device = devices; device; )
 
463
    {
 
464
      struct grub_xnu_devprop_device_header *devhead;
 
465
      struct property_descriptor *propdesc;
 
466
      devhead = ptr;
 
467
      devhead->num_values = 0;
 
468
      ptr = devhead + 1;
 
469
 
 
470
      grub_memcpy (ptr, device->path, device->pathlen);
 
471
      ptr = (char *) ptr + device->pathlen;
 
472
 
 
473
      for (propdesc = device->properties; propdesc; )
 
474
        {
 
475
          grub_uint32_t *len;
 
476
          grub_uint16_t *name;
 
477
          void *data;
 
478
 
 
479
          len = ptr;
 
480
          *len = 2 * propdesc->name16len + sizeof (grub_uint16_t)
 
481
            + sizeof (grub_uint32_t);
 
482
          ptr = len + 1;
 
483
 
 
484
          name = ptr;
 
485
          grub_memcpy (name, propdesc->name16, 2 * propdesc->name16len);
 
486
          name += propdesc->name16len;
 
487
 
 
488
          /* NUL terminator.  */
 
489
          *name = 0;
 
490
          ptr = name + 1;
 
491
 
 
492
          len = ptr;
 
493
          *len = propdesc->length + sizeof (grub_uint32_t);
 
494
          data = len + 1;
 
495
          ptr = data;
 
496
          grub_memcpy (ptr, propdesc->data, propdesc->length);
 
497
          ptr = (char *) ptr + propdesc->length;
 
498
 
 
499
          grub_free (propdesc->name);
 
500
          grub_free (propdesc->name16);
 
501
          grub_free (propdesc->data);
 
502
          t = propdesc;
 
503
          propdesc = propdesc->next;
 
504
          grub_free (t);
 
505
          devhead->num_values++;
 
506
        }
 
507
 
 
508
      devhead->length = (char *) ptr - (char *) devhead;
 
509
      t = device;
 
510
      device = device->next;
 
511
      grub_free (t);
 
512
    }
 
513
 
 
514
  devices = 0;
 
515
 
 
516
  return GRUB_ERR_NONE;
 
517
}
 
518
 
 
519
static grub_err_t
 
520
grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)),
 
521
                       int argc, char *args[])
 
522
{
 
523
  grub_file_t file;
 
524
  void *buf, *bufstart, *bufend;
 
525
  struct grub_xnu_devprop_header *head;
 
526
  grub_size_t size;
 
527
  unsigned i, j;
 
528
 
 
529
  if (argc != 1)
 
530
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
 
531
 
 
532
  file = grub_gzfile_open (args[0], 1);
 
533
  if (! file)
 
534
    return grub_error (GRUB_ERR_FILE_NOT_FOUND,
 
535
                       "couldn't load device-propertie dump");
 
536
  size = grub_file_size (file);
 
537
  buf = grub_malloc (size);
 
538
  if (!buf)
 
539
    {
 
540
      grub_file_close (file);
 
541
      return grub_errno;
 
542
    }
 
543
  if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
 
544
    {
 
545
      grub_file_close (file);
 
546
      return grub_errno;
 
547
    }
 
548
  grub_file_close (file);
 
549
 
 
550
  bufstart = buf;
 
551
  bufend = (char *) buf + size;
 
552
  head = buf;
 
553
  buf = head + 1;
 
554
  for (i = 0; i < grub_le_to_cpu32 (head->num_devices) && buf < bufend; i++)
 
555
    {
 
556
      struct grub_efi_device_path *dp, *dpstart;
 
557
      struct grub_xnu_devprop_device_descriptor *dev;
 
558
      struct grub_xnu_devprop_device_header *devhead;
 
559
 
 
560
      devhead = buf;
 
561
      buf = devhead + 1;
 
562
      dpstart = buf;
 
563
 
 
564
      do
 
565
        {
 
566
          dp = buf;
 
567
          buf = (char *) buf + GRUB_EFI_DEVICE_PATH_LENGTH (dp);
 
568
        }
 
569
      while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp) && buf < bufend);
 
570
 
 
571
      dev = grub_xnu_devprop_add_device (dpstart, (char *) buf
 
572
                                         - (char *) dpstart);
 
573
 
 
574
      for (j = 0; j < grub_le_to_cpu32 (devhead->num_values) && buf < bufend;
 
575
           j++)
 
576
        {
 
577
          grub_uint32_t *namelen;
 
578
          grub_uint32_t *datalen;
 
579
          grub_uint16_t *utf16;
 
580
          void *data;
 
581
          grub_err_t err;
 
582
 
 
583
          namelen = buf;
 
584
          buf = namelen + 1;
 
585
          if (buf >= bufend)
 
586
            break;
 
587
 
 
588
          utf16 = buf;
 
589
          buf = (char *) buf + *namelen - sizeof (grub_uint32_t);
 
590
          if (buf >= bufend)
 
591
            break;
 
592
 
 
593
          datalen = buf;
 
594
          buf = datalen + 1;
 
595
          if (buf >= bufend)
 
596
            break;
 
597
 
 
598
          data = buf;
 
599
          buf = (char *) buf + *datalen - sizeof (grub_uint32_t);
 
600
          if (buf >= bufend)
 
601
            break;
 
602
          err = grub_xnu_devprop_add_property_utf16
 
603
            (dev, utf16, (*namelen - sizeof (grub_uint32_t)
 
604
                          - sizeof (grub_uint16_t)) / sizeof (grub_uint16_t),
 
605
             data, *datalen - sizeof (grub_uint32_t));
 
606
          if (err)
 
607
            {
 
608
              grub_free (bufstart);
 
609
              return err;
 
610
            }
 
611
        }
 
612
    }
 
613
 
 
614
  grub_free (bufstart);
 
615
  return GRUB_ERR_NONE;
 
616
}
 
617
 
208
618
/* Fill device tree. */
209
619
/* FIXME: some entries may be platform-agnostic. Move them to loader/xnu.c. */
210
620
grub_err_t
216
626
  struct grub_xnu_devtree_key *runtimesrvkey;
217
627
  struct grub_xnu_devtree_key *platformkey;
218
628
  unsigned i, j;
219
 
  grub_err_t err;
220
 
 
221
 
  err = grub_autoefi_prepare ();
222
 
  if (err)
223
 
    return err;
224
629
 
225
630
  /* The value "model". */
226
631
  /* FIXME: may this value be sometimes different? */
417
822
  return GRUB_ERR_NONE;
418
823
}
419
824
 
 
825
grub_err_t
 
826
grub_xnu_boot_resume (void)
 
827
{
 
828
  struct grub_relocator32_state state;
 
829
 
 
830
  state.esp = grub_xnu_stack;
 
831
  state.eip = grub_xnu_entry_point;
 
832
  state.eax = grub_xnu_arg1;
 
833
 
 
834
  return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at,
 
835
                                state); 
 
836
}
 
837
 
420
838
/* Boot xnu. */
421
839
grub_err_t
422
840
grub_xnu_boot (void)
430
848
  grub_efi_uintn_t map_key = 0;
431
849
  grub_efi_uintn_t descriptor_size = 0;
432
850
  grub_efi_uint32_t descriptor_version = 0;
433
 
  grub_uint64_t firstruntimeaddr, lastruntimeaddr;
 
851
  grub_uint64_t firstruntimepage, lastruntimepage;
 
852
  grub_uint64_t curruntimepage;
434
853
  void *devtree;
435
854
  grub_size_t devtreelen;
436
855
  int i;
 
856
  struct grub_relocator32_state state;
 
857
 
 
858
  err = grub_autoefi_prepare ();
 
859
  if (err)
 
860
    return err;
 
861
 
 
862
  err = grub_cpu_xnu_fill_devprop ();
 
863
  if (err)
 
864
    return err;
 
865
 
 
866
  err = grub_cpu_xnu_fill_devicetree ();
 
867
  if (err)
 
868
    return err;
 
869
 
 
870
  err = grub_xnu_fill_devicetree ();
 
871
  if (err)
 
872
    return err;
437
873
 
438
874
  /* Page-align to avoid following parts to be inadvertently freed. */
439
875
  err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
447
883
  descriptor_size = 0;
448
884
  descriptor_version = 0;
449
885
 
 
886
  grub_dprintf ("xnu", "eip=%x\n", grub_xnu_entry_point);
 
887
 
 
888
  const char *debug = grub_env_get ("debug");
 
889
 
 
890
  if (debug && (grub_strword (debug, "all") || grub_strword (debug, "xnu")))
 
891
    {
 
892
      grub_printf ("Press any key to launch xnu\n");
 
893
      grub_getkey ();
 
894
    }
 
895
 
 
896
  /* Relocate the boot parameters to heap. */
 
897
  bootparams_relloc = grub_xnu_heap_malloc (sizeof (*bootparams_relloc));
 
898
  if (! bootparams_relloc)
 
899
    return grub_errno;
 
900
  bootparams_relloc_off = (grub_uint8_t *) bootparams_relloc
 
901
    - (grub_uint8_t *) grub_xnu_heap_start;
 
902
 
 
903
  /* Set video. */
 
904
  err = grub_xnu_set_video (bootparams_relloc);
 
905
  if (err != GRUB_ERR_NONE)
 
906
    {
 
907
      grub_print_error ();
 
908
      grub_errno = GRUB_ERR_NONE;
 
909
      grub_printf ("Booting in blind mode\n");
 
910
 
 
911
      bootparams_relloc->lfb_mode = 0;
 
912
      bootparams_relloc->lfb_width = 0;
 
913
      bootparams_relloc->lfb_height = 0;
 
914
      bootparams_relloc->lfb_depth = 0;
 
915
      bootparams_relloc->lfb_line_len = 0;
 
916
      bootparams_relloc->lfb_base = 0;
 
917
    }
 
918
 
450
919
  if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
451
920
                                   &map_key, &descriptor_size,
452
921
                                   &descriptor_version) < 0)
453
922
    return grub_errno;
454
923
 
 
924
  /* We will do few allocations later. Reserve some space for possible
 
925
     memory map growth.  */
 
926
  memory_map_size += 20 * descriptor_size;
455
927
  memory_map = grub_xnu_heap_malloc (memory_map_size);
456
928
  if (! memory_map)
457
929
    return grub_errno;
458
 
 
459
 
  if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
460
 
                                   &map_key, &descriptor_size,
461
 
                                   &descriptor_version) <= 0)
462
 
    return grub_errno;
463
930
  mmap_relloc_off = (grub_uint8_t *) memory_map
464
931
    - (grub_uint8_t *) grub_xnu_heap_start;
465
932
 
466
 
  firstruntimeaddr = (grub_uint64_t) (-1);
467
 
  lastruntimeaddr = 0;
468
 
  for (i = 0; (unsigned) i < memory_map_size / descriptor_size; i++)
469
 
    {
470
 
      grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *)
471
 
        ((char *) memory_map + descriptor_size * i);
472
 
 
473
 
      /* Some EFI implementations set physical_start to 0 which
474
 
         causes XNU crash. */
475
 
      curdesc->virtual_start = curdesc->physical_start;
476
 
 
477
 
      if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA
478
 
          || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE)
479
 
        {
480
 
          if (firstruntimeaddr > curdesc->physical_start)
481
 
            firstruntimeaddr = curdesc->physical_start;
482
 
          if (lastruntimeaddr < curdesc->physical_start
483
 
              + curdesc->num_pages * 4096)
484
 
            lastruntimeaddr = curdesc->physical_start
485
 
              + curdesc->num_pages * 4096;
486
 
        }
487
 
    }
488
 
 
489
 
  /* Relocate the boot parameters to heap. */
490
 
  bootparams_relloc = grub_xnu_heap_malloc (sizeof (*bootparams_relloc));
491
 
  if (! bootparams_relloc)
492
 
    return grub_errno;
493
 
  bootparams_relloc_off = (grub_uint8_t *) bootparams_relloc
494
 
    - (grub_uint8_t *) grub_xnu_heap_start;
495
933
  err = grub_xnu_writetree_toheap (&devtree, &devtreelen);
496
934
  if (err)
497
935
    return err;
501
939
  grub_memcpy (bootparams_relloc->cmdline, grub_xnu_cmdline,
502
940
               sizeof (bootparams_relloc->cmdline));
503
941
 
504
 
  bootparams_relloc->devtree = ((char *) devtree - grub_xnu_heap_start)
 
942
  bootparams_relloc->devtree
 
943
    = ((grub_uint8_t *) devtree - (grub_uint8_t *) grub_xnu_heap_start)
505
944
    + grub_xnu_heap_will_be_at;
506
945
  bootparams_relloc->devtreelen = devtreelen;
507
946
 
508
 
  bootparams_relloc->heap_start = grub_xnu_heap_will_be_at;
509
 
  bootparams_relloc->heap_size = grub_xnu_heap_size;
 
947
  memory_map = (grub_efi_memory_descriptor_t *)
 
948
    ((grub_uint8_t *) grub_xnu_heap_start + mmap_relloc_off);
 
949
 
 
950
  if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
 
951
                                   &map_key, &descriptor_size,
 
952
                                   &descriptor_version) <= 0)
 
953
    return grub_errno;
 
954
 
 
955
  bootparams_relloc->efi_system_table
 
956
    = PTR_TO_UINT32 (grub_autoefi_system_table);
 
957
 
 
958
  firstruntimepage = (((grub_addr_t) grub_xnu_heap_will_be_at
 
959
                       + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1)
 
960
                      / GRUB_XNU_PAGESIZE) + 20;
 
961
  curruntimepage = firstruntimepage;
 
962
 
 
963
  for (i = 0; (unsigned) i < memory_map_size / descriptor_size; i++)
 
964
    {
 
965
      grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *)
 
966
        ((char *) memory_map + descriptor_size * i);
 
967
 
 
968
      curdesc->virtual_start = curdesc->physical_start;
 
969
 
 
970
      if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA
 
971
          || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE)
 
972
        {
 
973
          curdesc->virtual_start = curruntimepage << 12;
 
974
          curruntimepage += curdesc->num_pages;
 
975
          if (curdesc->physical_start
 
976
              <= PTR_TO_UINT64 (grub_autoefi_system_table)
 
977
              && curdesc->physical_start + (curdesc->num_pages << 12)
 
978
              > PTR_TO_UINT64 (grub_autoefi_system_table))
 
979
            bootparams_relloc->efi_system_table
 
980
              = PTR_TO_UINT64 (grub_autoefi_system_table)
 
981
              - curdesc->physical_start + curdesc->virtual_start;
 
982
          if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit)
 
983
            curdesc->virtual_start |= 0xffffff8000000000ULL;
 
984
        }
 
985
    }
 
986
 
 
987
  lastruntimepage = curruntimepage;
510
988
 
511
989
  bootparams_relloc->efi_mmap = grub_xnu_heap_will_be_at + mmap_relloc_off;
512
990
  bootparams_relloc->efi_mmap_size = memory_map_size;
513
991
  bootparams_relloc->efi_mem_desc_size = descriptor_size;
514
992
  bootparams_relloc->efi_mem_desc_version = descriptor_version;
515
993
 
516
 
  bootparams_relloc->efi_runtime_first_page = firstruntimeaddr
517
 
    / GRUB_XNU_PAGESIZE;
518
 
  bootparams_relloc->efi_runtime_npages
519
 
    = ((lastruntimeaddr + GRUB_XNU_PAGESIZE - 1) / GRUB_XNU_PAGESIZE)
520
 
    - (firstruntimeaddr / GRUB_XNU_PAGESIZE);
 
994
  bootparams_relloc->heap_start = grub_xnu_heap_will_be_at;
 
995
  bootparams_relloc->heap_size = grub_xnu_heap_size;
 
996
  bootparams_relloc->efi_runtime_first_page = firstruntimepage;
 
997
 
 
998
  bootparams_relloc->efi_runtime_npages = lastruntimepage - firstruntimepage;
521
999
  bootparams_relloc->efi_uintnbits = SIZEOF_OF_UINTN * 8;
522
 
  bootparams_relloc->efi_system_table
523
 
    = PTR_TO_UINT32 (grub_autoefi_system_table);
524
1000
 
525
1001
  bootparams_relloc->verminor = GRUB_XNU_BOOTARGS_VERMINOR;
526
1002
  bootparams_relloc->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR;
529
1005
  grub_xnu_stack = bootparams_relloc->heap_start
530
1006
    + bootparams_relloc->heap_size + GRUB_XNU_PAGESIZE;
531
1007
  grub_xnu_arg1 = bootparams_relloc_off + grub_xnu_heap_will_be_at;
532
 
#ifndef GRUB_UTIL
533
 
  grub_xnu_launch = (void (*) (void))
534
 
    (grub_xnu_heap_start + grub_xnu_heap_size);
535
 
#endif
536
 
  grub_dprintf ("xnu", "eip=%x\n", grub_xnu_entry_point);
537
 
  grub_dprintf ("xnu", "launch=%p\n", grub_xnu_launch);
538
 
 
539
 
  const char *debug = grub_env_get ("debug");
540
 
 
541
 
  if (debug && (grub_strword (debug, "all") || grub_strword (debug, "xnu")))
542
 
    {
543
 
      grub_printf ("Press any key to launch xnu\n");
544
 
      grub_getkey ();
545
 
    }
546
 
 
547
 
  /* Set video. */
548
 
  err = grub_xnu_set_video (bootparams_relloc);
549
 
  if (err != GRUB_ERR_NONE)
550
 
    {
551
 
      grub_print_error ();
552
 
      grub_errno = GRUB_ERR_NONE;
553
 
      grub_printf ("Booting in blind mode\n");
554
 
 
555
 
      bootparams_relloc->lfb_mode = 0;
556
 
      bootparams_relloc->lfb_width = 0;
557
 
      bootparams_relloc->lfb_height = 0;
558
 
      bootparams_relloc->lfb_depth = 0;
559
 
      bootparams_relloc->lfb_line_len = 0;
560
 
      bootparams_relloc->lfb_base = 0;
561
 
    }
562
 
 
563
 
  grub_memcpy (grub_xnu_heap_start + grub_xnu_heap_size,
564
 
               grub_xnu_launcher_start,
565
 
               grub_xnu_launcher_end - grub_xnu_launcher_start);
566
 
 
567
 
 
568
 
  if (! grub_autoefi_finish_boot_services ())
 
1008
 
 
1009
  if (! grub_autoefi_exit_boot_services (map_key))
569
1010
    return grub_error (GRUB_ERR_IO, "can't exit boot services");
570
1011
 
571
 
  grub_xnu_launch ();
572
 
 
573
 
  /* Never reaches here. */
574
 
  return 0;
 
1012
  grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
 
1013
                                        descriptor_version,memory_map);
 
1014
 
 
1015
  state.eip = grub_xnu_entry_point;
 
1016
  state.eax = grub_xnu_arg1;
 
1017
  state.esp = grub_xnu_stack;
 
1018
  return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at,
 
1019
                                state);
 
1020
}
 
1021
 
 
1022
static grub_command_t cmd_devprop_load;
 
1023
 
 
1024
void
 
1025
grub_cpu_xnu_init (void)
 
1026
{
 
1027
  cmd_devprop_load = grub_register_command ("xnu_devprop_load",
 
1028
                                            grub_cmd_devprop_load,
 
1029
                                            0, "Load device-properties dump.");
 
1030
}
 
1031
 
 
1032
void
 
1033
grub_cpu_xnu_fini (void)
 
1034
{
 
1035
  grub_unregister_command (cmd_devprop_load);
575
1036
}