source: grub-pc/trunk/fuentes/grub-core/loader/i386/xnu.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 28.9 KB
Line 
1/*
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 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#include <grub/env.h>
20#include <grub/file.h>
21#include <grub/disk.h>
22#include <grub/xnu.h>
23#include <grub/cpu/xnu.h>
24#include <grub/mm.h>
25#include <grub/loader.h>
26#include <grub/autoefi.h>
27#include <grub/i386/tsc.h>
28#include <grub/i386/cpuid.h>
29#include <grub/efi/api.h>
30#include <grub/i386/pit.h>
31#include <grub/misc.h>
32#include <grub/charset.h>
33#include <grub/term.h>
34#include <grub/command.h>
35#include <grub/i18n.h>
36#include <grub/bitmap_scale.h>
37#include <grub/cpu/io.h>
38
39#define min(a,b) (((a) < (b)) ? (a) : (b))
40#define max(a,b) (((a) > (b)) ? (a) : (b))
41
42#define DEFAULT_VIDEO_MODE "auto"
43
44char grub_xnu_cmdline[1024];
45grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack;
46
47/* Aliases set for some tables. */
48struct tbl_alias
49{
50  grub_efi_guid_t guid;
51  const char *name;
52};
53
54static struct tbl_alias table_aliases[] =
55  {
56    {GRUB_EFI_ACPI_20_TABLE_GUID, "ACPI_20"},
57    {GRUB_EFI_ACPI_TABLE_GUID, "ACPI"},
58  };
59
60struct grub_xnu_devprop_device_descriptor
61{
62  struct grub_xnu_devprop_device_descriptor *next;
63  struct grub_xnu_devprop_device_descriptor **prev;
64  struct property_descriptor *properties;
65  struct grub_efi_device_path *path;
66  int pathlen;
67};
68
69static int
70utf16_strlen (grub_uint16_t *in)
71{
72  int i;
73  for (i = 0; in[i]; i++);
74  return i;
75}
76
77/* Read frequency from a string in MHz and return it in Hz. */
78static grub_uint64_t
79readfrequency (const char *str)
80{
81  grub_uint64_t num = 0;
82  int mul = 1000000;
83  int found = 0;
84
85  while (*str)
86    {
87      unsigned long digit;
88
89      digit = grub_tolower (*str) - '0';
90      if (digit > 9)
91        break;
92
93      found = 1;
94
95      num = num * 10 + digit;
96      str++;
97    }
98  num *= 1000000;
99  if (*str == '.')
100    {
101      str++;
102      while (*str)
103        {
104          unsigned long digit;
105
106          digit = grub_tolower (*str) - '0';
107          if (digit > 9)
108            break;
109
110          found = 1;
111
112          mul /= 10;
113          num = num + mul * digit;
114          str++;
115        }
116    }
117  if (! found)
118    return 0;
119
120  return num;
121}
122
123/* Thanks to Kabyl for precious information about Intel architecture. */
124static grub_uint64_t
125guessfsb (void)
126{
127  const grub_uint64_t sane_value = 100000000;
128  grub_uint32_t manufacturer[3], max_cpuid, capabilities, msrlow;
129  grub_uint32_t a, b, d;
130
131  if (! grub_cpu_is_cpuid_supported ())
132    return sane_value;
133
134  grub_cpuid (0, max_cpuid, manufacturer[0], manufacturer[2], manufacturer[1]);
135
136  /* Only Intel for now is done. */
137  if (grub_memcmp (manufacturer, "GenuineIntel", 12) != 0)
138    return sane_value;
139
140  /* Check Speedstep. */
141  if (max_cpuid < 1)
142    return sane_value;
143
144  grub_cpuid (1, a, b, capabilities, d);
145
146  if (! (capabilities & (1 << 7)))
147    return sane_value;
148
149  /* Read the multiplier. */
150  asm volatile ("movl $0x198, %%ecx\n"
151                "rdmsr"
152                : "=d" (msrlow)
153                :
154                : "%ecx", "%eax");
155
156  grub_uint64_t v;
157  grub_uint32_t r;
158
159  /* (2000ULL << 32) / grub_tsc_rate  */
160  /* Assumption: TSC frequency is over 2 MHz.  */
161  v = 0xffffffff / grub_tsc_rate;
162  v *= 2000;
163  /* v is at most 2000 off from (2000ULL << 32) / grub_tsc_rate.
164     Since grub_tsc_rate < 2^32/2^11=2^21, so no overflow.
165   */
166  r = (2000ULL << 32) - v * grub_tsc_rate;
167  v += r / grub_tsc_rate;
168
169  return grub_divmod64 (v, ((msrlow >> 7) & 0x3e) | ((msrlow >> 14) & 1),
170                         0);
171}
172
173struct property_descriptor
174{
175  struct property_descriptor *next;
176  struct property_descriptor **prev;
177  grub_uint8_t *name;
178  grub_uint16_t *name16;
179  int name16len;
180  int length;
181  void *data;
182};
183
184static struct grub_xnu_devprop_device_descriptor *devices = 0;
185
186grub_err_t
187grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor *dev,
188                                  char *name)
189{
190  struct property_descriptor *prop;
191  prop = grub_named_list_find (GRUB_AS_NAMED_LIST (dev->properties), name);
192  if (!prop)
193    return GRUB_ERR_NONE;
194
195  grub_free (prop->name);
196  grub_free (prop->name16);
197  grub_free (prop->data);
198
199  grub_list_remove (GRUB_AS_LIST (prop));
200
201  return GRUB_ERR_NONE;
202}
203
204grub_err_t
205grub_xnu_devprop_remove_device (struct grub_xnu_devprop_device_descriptor *dev)
206{
207  void *t;
208  struct property_descriptor *prop;
209
210  grub_list_remove (GRUB_AS_LIST (dev));
211
212  for (prop = dev->properties; prop; )
213    {
214      grub_free (prop->name);
215      grub_free (prop->name16);
216      grub_free (prop->data);
217      t = prop;
218      prop = prop->next;
219      grub_free (t);
220    }
221
222  grub_free (dev->path);
223  grub_free (dev);
224
225  return GRUB_ERR_NONE;
226}
227
228struct grub_xnu_devprop_device_descriptor *
229grub_xnu_devprop_add_device (struct grub_efi_device_path *path, int length)
230{
231  struct grub_xnu_devprop_device_descriptor *ret;
232
233  ret = grub_zalloc (sizeof (*ret));
234  if (!ret)
235    return 0;
236
237  ret->path = grub_malloc (length);
238  if (!ret->path)
239    {
240      grub_free (ret);
241      return 0;
242    }
243  ret->pathlen = length;
244  grub_memcpy (ret->path, path, length);
245
246  grub_list_push (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (ret));
247
248  return ret;
249}
250
251static grub_err_t
252grub_xnu_devprop_add_property (struct grub_xnu_devprop_device_descriptor *dev,
253                               grub_uint8_t *utf8, grub_uint16_t *utf16,
254                               int utf16len, void *data, int datalen)
255{
256  struct property_descriptor *prop;
257
258  prop = grub_malloc (sizeof (*prop));
259  if (!prop)
260    return grub_errno;
261
262  prop->name = utf8;
263  prop->name16 = utf16;
264  prop->name16len = utf16len;
265
266  prop->length = datalen;
267  prop->data = grub_malloc (prop->length);
268  if (!prop->data)
269    {
270      grub_free (prop);
271      grub_free (prop->name);
272      grub_free (prop->name16);
273      return grub_errno;
274    }
275  grub_memcpy (prop->data, data, prop->length);
276  grub_list_push (GRUB_AS_LIST_P (&dev->properties),
277                  GRUB_AS_LIST (prop));
278  return GRUB_ERR_NONE;
279}
280
281grub_err_t
282grub_xnu_devprop_add_property_utf8 (struct grub_xnu_devprop_device_descriptor *dev,
283                                    char *name, void *data, int datalen)
284{
285  grub_uint8_t *utf8;
286  grub_uint16_t *utf16;
287  int len, utf16len;
288  grub_err_t err;
289
290  utf8 = (grub_uint8_t *) grub_strdup (name);
291  if (!utf8)
292    return grub_errno;
293
294  len = grub_strlen (name);
295  utf16 = grub_malloc (sizeof (grub_uint16_t) * len);
296  if (!utf16)
297    {
298      grub_free (utf8);
299      return grub_errno;
300    }
301
302  utf16len = grub_utf8_to_utf16 (utf16, len, utf8, len, NULL);
303  if (utf16len < 0)
304    {
305      grub_free (utf8);
306      grub_free (utf16);
307      return grub_errno;
308    }
309
310  err = grub_xnu_devprop_add_property (dev, utf8, utf16,
311                                       utf16len, data, datalen);
312  if (err)
313    {
314      grub_free (utf8);
315      grub_free (utf16);
316      return err;
317    }
318
319  return GRUB_ERR_NONE;
320}
321
322grub_err_t
323grub_xnu_devprop_add_property_utf16 (struct grub_xnu_devprop_device_descriptor *dev,
324                                     grub_uint16_t *name, int namelen,
325                                     void *data, int datalen)
326{
327  grub_uint8_t *utf8;
328  grub_uint16_t *utf16;
329  grub_err_t err;
330
331  utf16 = grub_malloc (sizeof (grub_uint16_t) * namelen);
332  if (!utf16)
333    return grub_errno;
334  grub_memcpy (utf16, name, sizeof (grub_uint16_t) * namelen);
335
336  utf8 = grub_malloc (namelen * 4 + 1);
337  if (!utf8)
338    {
339      grub_free (utf8);
340      return grub_errno;
341    }
342
343  *grub_utf16_to_utf8 ((grub_uint8_t *) utf8, name, namelen) = '\0';
344
345  err = grub_xnu_devprop_add_property (dev, utf8, utf16,
346                                       namelen, data, datalen);
347  if (err)
348    {
349      grub_free (utf8);
350      grub_free (utf16);
351      return err;
352    }
353
354  return GRUB_ERR_NONE;
355}
356
357void
358grub_cpu_xnu_unload (void)
359{
360  struct grub_xnu_devprop_device_descriptor *dev1, *dev2;
361
362  for (dev1 = devices; dev1; )
363    {
364      dev2 = dev1->next;
365      grub_xnu_devprop_remove_device (dev1);
366      dev1 = dev2;
367    }
368}
369
370static grub_err_t
371grub_cpu_xnu_fill_devprop (void)
372{
373  struct grub_xnu_devtree_key *efikey;
374  int total_length = sizeof (struct grub_xnu_devprop_header);
375  struct grub_xnu_devtree_key *devprop;
376  struct grub_xnu_devprop_device_descriptor *device;
377  void *ptr;
378  struct grub_xnu_devprop_header *head;
379  void *t;
380  int numdevs = 0;
381
382  /* The key "efi". */
383  efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi");
384  if (! efikey)
385    return grub_errno;
386
387  for (device = devices; device; device = device->next)
388    {
389      struct property_descriptor *propdesc;
390      total_length += sizeof (struct grub_xnu_devprop_device_header);
391      total_length += device->pathlen;
392
393      for (propdesc = device->properties; propdesc; propdesc = propdesc->next)
394        {
395          total_length += sizeof (grub_uint32_t);
396          total_length += sizeof (grub_uint16_t)
397            * (propdesc->name16len + 1);
398          total_length += sizeof (grub_uint32_t);
399          total_length += propdesc->length;
400        }
401      numdevs++;
402    }
403
404  devprop = grub_xnu_create_value (&(efikey->first_child), "device-properties");
405  if (!devprop)
406    return grub_errno;
407
408  devprop->data = grub_malloc (total_length);
409  devprop->datasize = total_length;
410
411  ptr = devprop->data;
412  head = ptr;
413  ptr = head + 1;
414  head->length = total_length;
415  head->alwaysone = 1;
416  head->num_devices = numdevs;
417  for (device = devices; device; )
418    {
419      struct grub_xnu_devprop_device_header *devhead;
420      struct property_descriptor *propdesc;
421      devhead = ptr;
422      devhead->num_values = 0;
423      ptr = devhead + 1;
424
425      grub_memcpy (ptr, device->path, device->pathlen);
426      ptr = (char *) ptr + device->pathlen;
427
428      for (propdesc = device->properties; propdesc; )
429        {
430          grub_uint32_t *len;
431          grub_uint16_t *name;
432          void *data;
433
434          len = ptr;
435          *len = 2 * propdesc->name16len + sizeof (grub_uint16_t)
436            + sizeof (grub_uint32_t);
437          ptr = len + 1;
438
439          name = ptr;
440          grub_memcpy (name, propdesc->name16, 2 * propdesc->name16len);
441          name += propdesc->name16len;
442
443          /* NUL terminator.  */
444          *name = 0;
445          ptr = name + 1;
446
447          len = ptr;
448          *len = propdesc->length + sizeof (grub_uint32_t);
449          data = len + 1;
450          ptr = data;
451          grub_memcpy (ptr, propdesc->data, propdesc->length);
452          ptr = (char *) ptr + propdesc->length;
453
454          grub_free (propdesc->name);
455          grub_free (propdesc->name16);
456          grub_free (propdesc->data);
457          t = propdesc;
458          propdesc = propdesc->next;
459          grub_free (t);
460          devhead->num_values++;
461        }
462
463      devhead->length = (char *) ptr - (char *) devhead;
464      t = device;
465      device = device->next;
466      grub_free (t);
467    }
468
469  devices = 0;
470
471  return GRUB_ERR_NONE;
472}
473
474static grub_err_t
475grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)),
476                       int argc, char *args[])
477{
478  grub_file_t file;
479  void *buf, *bufstart, *bufend;
480  struct grub_xnu_devprop_header *head;
481  grub_size_t size;
482  unsigned i, j;
483
484  if (argc != 1)
485    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
486
487  file = grub_file_open (args[0]);
488  if (! file)
489    return grub_errno;
490  size = grub_file_size (file);
491  buf = grub_malloc (size);
492  if (!buf)
493    {
494      grub_file_close (file);
495      return grub_errno;
496    }
497  if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
498    {
499      grub_file_close (file);
500      return grub_errno;
501    }
502  grub_file_close (file);
503
504  bufstart = buf;
505  bufend = (char *) buf + size;
506  head = buf;
507  buf = head + 1;
508  for (i = 0; i < grub_le_to_cpu32 (head->num_devices) && buf < bufend; i++)
509    {
510      struct grub_efi_device_path *dp, *dpstart;
511      struct grub_xnu_devprop_device_descriptor *dev;
512      struct grub_xnu_devprop_device_header *devhead;
513
514      devhead = buf;
515      buf = devhead + 1;
516      dpstart = buf;
517
518      do
519        {
520          dp = buf;
521          buf = (char *) buf + GRUB_EFI_DEVICE_PATH_LENGTH (dp);
522        }
523      while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp) && buf < bufend);
524
525      dev = grub_xnu_devprop_add_device (dpstart, (char *) buf
526                                         - (char *) dpstart);
527
528      for (j = 0; j < grub_le_to_cpu32 (devhead->num_values) && buf < bufend;
529           j++)
530        {
531          grub_uint32_t *namelen;
532          grub_uint32_t *datalen;
533          grub_uint16_t *utf16;
534          void *data;
535          grub_err_t err;
536
537          namelen = buf;
538          buf = namelen + 1;
539          if (buf >= bufend)
540            break;
541
542          utf16 = buf;
543          buf = (char *) buf + *namelen - sizeof (grub_uint32_t);
544          if (buf >= bufend)
545            break;
546
547          datalen = buf;
548          buf = datalen + 1;
549          if (buf >= bufend)
550            break;
551
552          data = buf;
553          buf = (char *) buf + *datalen - sizeof (grub_uint32_t);
554          if (buf >= bufend)
555            break;
556          err = grub_xnu_devprop_add_property_utf16
557            (dev, utf16, (*namelen - sizeof (grub_uint32_t)
558                          - sizeof (grub_uint16_t)) / sizeof (grub_uint16_t),
559             data, *datalen - sizeof (grub_uint32_t));
560          if (err)
561            {
562              grub_free (bufstart);
563              return err;
564            }
565        }
566    }
567
568  grub_free (bufstart);
569  return GRUB_ERR_NONE;
570}
571
572/* Fill device tree. */
573/* FIXME: some entries may be platform-agnostic. Move them to loader/xnu.c. */
574static grub_err_t
575grub_cpu_xnu_fill_devicetree (grub_uint64_t *fsbfreq_out)
576{
577  struct grub_xnu_devtree_key *efikey;
578  struct grub_xnu_devtree_key *cfgtablekey;
579  struct grub_xnu_devtree_key *curval;
580  struct grub_xnu_devtree_key *runtimesrvkey;
581  struct grub_xnu_devtree_key *platformkey;
582  unsigned i, j;
583
584  /* The value "model". */
585  /* FIXME: may this value be sometimes different? */
586  curval = grub_xnu_create_value (&grub_xnu_devtree_root, "model");
587  if (! curval)
588    return grub_errno;
589  curval->datasize = sizeof ("ACPI");
590  curval->data = grub_strdup ("ACPI");
591  curval = grub_xnu_create_value (&grub_xnu_devtree_root, "compatible");
592  if (! curval)
593    return grub_errno;
594  curval->datasize = sizeof ("ACPI");
595  curval->data = grub_strdup ("ACPI");
596
597  /* The key "efi". */
598  efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi");
599  if (! efikey)
600    return grub_errno;
601
602  /* Information about firmware. */
603  curval = grub_xnu_create_value (&(efikey->first_child), "firmware-revision");
604  if (! curval)
605    return grub_errno;
606  curval->datasize = (SYSTEM_TABLE_SIZEOF (firmware_revision));
607  curval->data = grub_malloc (curval->datasize);
608  if (! curval->data)
609    return grub_errno;
610  grub_memcpy (curval->data, (SYSTEM_TABLE_VAR(firmware_revision)),
611               curval->datasize);
612
613  curval = grub_xnu_create_value (&(efikey->first_child), "firmware-vendor");
614  if (! curval)
615    return grub_errno;
616  curval->datasize =
617    2 * (utf16_strlen (SYSTEM_TABLE_PTR (firmware_vendor)) + 1);
618  curval->data = grub_malloc (curval->datasize);
619  if (! curval->data)
620    return grub_errno;
621  grub_memcpy (curval->data, SYSTEM_TABLE_PTR (firmware_vendor),
622               curval->datasize);
623
624  curval = grub_xnu_create_value (&(efikey->first_child), "firmware-abi");
625  if (! curval)
626    return grub_errno;
627  curval->datasize = sizeof ("EFI32");
628  curval->data = grub_malloc (curval->datasize);
629  if (! curval->data)
630    return grub_errno;
631  if (SIZEOF_OF_UINTN == 4)
632    grub_memcpy (curval->data, "EFI32", curval->datasize);
633  else
634    grub_memcpy (curval->data, "EFI64", curval->datasize);
635
636  /* The key "platform". */
637  platformkey = grub_xnu_create_key (&(efikey->first_child),
638                                     "platform");
639  if (! platformkey)
640    return grub_errno;
641
642  /* Pass FSB frequency to the kernel. */
643  curval = grub_xnu_create_value (&(platformkey->first_child), "FSBFrequency");
644  if (! curval)
645    return grub_errno;
646  curval->datasize = sizeof (grub_uint64_t);
647  curval->data = grub_malloc (curval->datasize);
648  if (!curval->data)
649    return grub_errno;
650
651  /* First see if user supplies the value. */
652  const char *fsbvar = grub_env_get ("fsb");
653  grub_uint64_t fsbfreq = 0;
654  if (fsbvar)
655    fsbfreq = readfrequency (fsbvar);
656  /* Try autodetect. */
657  if (! fsbfreq)
658    fsbfreq = guessfsb ();
659  *((grub_uint64_t *) curval->data) = fsbfreq;
660  *fsbfreq_out = fsbfreq;
661  grub_dprintf ("xnu", "fsb autodetected as %llu\n",
662                (unsigned long long) *((grub_uint64_t *) curval->data));
663
664  cfgtablekey = grub_xnu_create_key (&(efikey->first_child),
665                                     "configuration-table");
666  if (!cfgtablekey)
667    return grub_errno;
668
669  /* Fill "configuration-table" key. */
670  for (i = 0; i < SYSTEM_TABLE (num_table_entries); i++)
671    {
672      void *ptr;
673      struct grub_xnu_devtree_key *curkey;
674      grub_efi_packed_guid_t guid;
675      char guidbuf[64];
676
677      /* Retrieve current key. */
678#ifdef GRUB_MACHINE_EFI
679      {
680        ptr = (void *)
681          grub_efi_system_table->configuration_table[i].vendor_table;
682        guid = grub_efi_system_table->configuration_table[i].vendor_guid;
683      }
684#else
685      if (SIZEOF_OF_UINTN == 4)
686        {
687          ptr = (void *) (grub_addr_t) ((grub_efiemu_configuration_table32_t *)
688                                        SYSTEM_TABLE_PTR (configuration_table))[i]
689            .vendor_table;
690          guid =
691            ((grub_efiemu_configuration_table32_t *)
692             SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid;
693        }
694      else
695        {
696          ptr = (void *) (grub_addr_t) ((grub_efiemu_configuration_table64_t *)
697                                        SYSTEM_TABLE_PTR (configuration_table))[i]
698            .vendor_table;
699          guid =
700            ((grub_efiemu_configuration_table64_t *)
701             SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid;
702        }
703#endif
704
705      /* The name of key for new table. */
706      grub_snprintf (guidbuf, sizeof (guidbuf), "%08x-%04x-%04x-%02x%02x-",
707                     guid.data1, guid.data2, guid.data3, guid.data4[0],
708                     guid.data4[1]);
709      for (j = 2; j < 8; j++)
710        grub_snprintf (guidbuf + grub_strlen (guidbuf),
711                       sizeof (guidbuf) - grub_strlen (guidbuf),
712                       "%02x", guid.data4[j]);
713      /* For some reason GUID has to be in uppercase. */
714      for (j = 0; guidbuf[j] ; j++)
715        if (guidbuf[j] >= 'a' && guidbuf[j] <= 'f')
716          guidbuf[j] += 'A' - 'a';
717      curkey = grub_xnu_create_key (&(cfgtablekey->first_child), guidbuf);
718      if (! curkey)
719        return grub_errno;
720
721      curval = grub_xnu_create_value (&(curkey->first_child), "guid");
722      if (! curval)
723        return grub_errno;
724      curval->datasize = sizeof (guid);
725      curval->data = grub_malloc (curval->datasize);
726      if (! curval->data)
727        return grub_errno;
728      grub_memcpy (curval->data, &guid, curval->datasize);
729
730      /* The value "table". */
731      curval = grub_xnu_create_value (&(curkey->first_child), "table");
732      if (! curval)
733        return grub_errno;
734      curval->datasize = SIZEOF_OF_UINTN;
735      curval->data = grub_malloc (curval->datasize);
736      if (! curval->data)
737        return grub_errno;
738      if (SIZEOF_OF_UINTN == 4)
739        *((grub_uint32_t *) curval->data) = (grub_addr_t) ptr;
740      else
741        *((grub_uint64_t *) curval->data) = (grub_addr_t) ptr;
742
743      /* Create alias. */
744      for (j = 0; j < sizeof (table_aliases) / sizeof (table_aliases[0]); j++)
745        if (grub_memcmp (&table_aliases[j].guid, &guid, sizeof (guid)) == 0)
746          break;
747      if (j != sizeof (table_aliases) / sizeof (table_aliases[0]))
748        {
749          curval = grub_xnu_create_value (&(curkey->first_child), "alias");
750          if (!curval)
751            return grub_errno;
752          curval->datasize = grub_strlen (table_aliases[j].name) + 1;
753          curval->data = grub_malloc (curval->datasize);
754          if (!curval->data)
755            return grub_errno;
756          grub_memcpy (curval->data, table_aliases[j].name, curval->datasize);
757        }
758    }
759
760  /* Create and fill "runtime-services" key. */
761  runtimesrvkey = grub_xnu_create_key (&(efikey->first_child),
762                                       "runtime-services");
763  if (! runtimesrvkey)
764    return grub_errno;
765  curval = grub_xnu_create_value (&(runtimesrvkey->first_child), "table");
766  if (! curval)
767    return grub_errno;
768  curval->datasize = SIZEOF_OF_UINTN;
769  curval->data = grub_malloc (curval->datasize);
770  if (! curval->data)
771    return grub_errno;
772  if (SIZEOF_OF_UINTN == 4)
773    *((grub_uint32_t *) curval->data)
774      = (grub_addr_t) SYSTEM_TABLE_PTR (runtime_services);
775  else
776    *((grub_uint64_t *) curval->data)
777      = (grub_addr_t) SYSTEM_TABLE_PTR (runtime_services);
778
779  return GRUB_ERR_NONE;
780}
781
782grub_err_t
783grub_xnu_boot_resume (void)
784{
785  struct grub_relocator32_state state;
786
787  state.esp = grub_xnu_stack;
788  state.ebp = grub_xnu_stack;
789  state.eip = grub_xnu_entry_point;
790  state.eax = grub_xnu_arg1;
791
792  return grub_relocator32_boot (grub_xnu_relocator, state, 0); 
793}
794
795/* Setup video for xnu. */
796static grub_err_t
797grub_xnu_set_video (struct grub_xnu_boot_params_common *params)
798{
799  struct grub_video_mode_info mode_info;
800  char *tmp;
801  const char *modevar;
802  void *framebuffer;
803  grub_err_t err;
804  struct grub_video_bitmap *bitmap = NULL;
805
806  modevar = grub_env_get ("gfxpayload");
807  /* Consider only graphical 32-bit deep modes.  */
808  if (! modevar || *modevar == 0)
809    err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
810                               GRUB_VIDEO_MODE_TYPE_PURE_TEXT
811                               | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
812                               32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
813  else
814    {
815      tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
816      if (! tmp)
817        return grub_errno;
818      err = grub_video_set_mode (tmp,
819                                 GRUB_VIDEO_MODE_TYPE_PURE_TEXT
820                                 | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
821                                 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
822      grub_free (tmp);
823    }
824
825  if (err)
826    return err;
827
828  err = grub_video_get_info (&mode_info);
829  if (err)
830    return err;
831
832  if (grub_xnu_bitmap)
833     {
834       if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH)
835         err = grub_video_bitmap_create_scaled (&bitmap,
836                                                mode_info.width,
837                                                mode_info.height,
838                                                grub_xnu_bitmap,
839                                                GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
840       else
841         bitmap = grub_xnu_bitmap;
842     }
843
844  if (bitmap)
845    {
846      if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH)
847        err = grub_video_bitmap_create_scaled (&bitmap,
848                                               mode_info.width,
849                                               mode_info.height,
850                                               grub_xnu_bitmap,
851                                               GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
852      else
853        bitmap = grub_xnu_bitmap;
854    }
855
856  if (bitmap)
857    {
858      int x, y;
859
860      x = mode_info.width - bitmap->mode_info.width;
861      x /= 2;
862      y = mode_info.height - bitmap->mode_info.height;
863      y /= 2;
864      err = grub_video_blit_bitmap (bitmap,
865                                    GRUB_VIDEO_BLIT_REPLACE,
866                                    x > 0 ? x : 0,
867                                    y > 0 ? y : 0,
868                                    x < 0 ? -x : 0,
869                                    y < 0 ? -y : 0,
870                                    min (bitmap->mode_info.width,
871                                         mode_info.width),
872                                    min (bitmap->mode_info.height,
873                                         mode_info.height));
874    }
875  if (err)
876    {
877      grub_print_error ();
878      grub_errno = GRUB_ERR_NONE;
879      bitmap = 0;
880    }
881
882  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
883  if (err)
884    return err;
885
886  params->lfb_width = mode_info.width;
887  params->lfb_height = mode_info.height;
888  params->lfb_depth = mode_info.bpp;
889  params->lfb_line_len = mode_info.pitch;
890
891  params->lfb_base = (grub_addr_t) framebuffer;
892  params->lfb_mode = bitmap ? GRUB_XNU_VIDEO_SPLASH 
893    : GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
894
895  return GRUB_ERR_NONE;
896}
897
898/* Boot xnu. */
899grub_err_t
900grub_xnu_boot (void)
901{
902  union grub_xnu_boot_params_any *bootparams;
903  struct grub_xnu_boot_params_common *bootparams_common;
904  void *bp_in;
905  grub_addr_t bootparams_target;
906  grub_err_t err;
907  grub_efi_uintn_t memory_map_size = 0;
908  void *memory_map;
909  grub_addr_t memory_map_target;
910  grub_efi_uintn_t map_key = 0;
911  grub_efi_uintn_t descriptor_size = 0;
912  grub_efi_uint32_t descriptor_version = 0;
913  grub_uint64_t firstruntimepage, lastruntimepage;
914  grub_uint64_t curruntimepage;
915  grub_addr_t devtree_target;
916  grub_size_t devtreelen;
917  int i;
918  struct grub_relocator32_state state;
919  grub_uint64_t fsbfreq = 100000000;
920  int v2 = (grub_xnu_darwin_version >= 11);
921  grub_uint32_t efi_system_table = 0;
922
923  err = grub_autoefi_prepare ();
924  if (err)
925    return err;
926
927  err = grub_cpu_xnu_fill_devprop ();
928  if (err)
929    return err;
930
931  err = grub_cpu_xnu_fill_devicetree (&fsbfreq);
932  if (err)
933    return err;
934
935  err = grub_xnu_fill_devicetree ();
936  if (err)
937    return err;
938
939  /* Page-align to avoid following parts to be inadvertently freed. */
940  err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
941  if (err)
942    return err;
943
944  /* Pass memory map to kernel. */
945  memory_map_size = 0;
946  memory_map = 0;
947  map_key = 0;
948  descriptor_size = 0;
949  descriptor_version = 0;
950
951  grub_dprintf ("xnu", "eip=%x, efi=%p\n", grub_xnu_entry_point,
952                grub_autoefi_system_table);
953
954  const char *debug = grub_env_get ("debug");
955
956  if (debug && (grub_strword (debug, "all") || grub_strword (debug, "xnu")))
957    {
958      grub_puts_ (N_("Press any key to launch xnu"));
959      grub_getkey ();
960    }
961
962  /* Relocate the boot parameters to heap. */
963  err = grub_xnu_heap_malloc (sizeof (*bootparams),
964                              &bp_in, &bootparams_target);
965  if (err)
966    return err;
967  bootparams = bp_in;
968
969  grub_memset (bootparams, 0, sizeof (*bootparams));
970  if (v2)
971    {
972      bootparams_common = &bootparams->v2.common;
973      bootparams->v2.fsbfreq = fsbfreq;
974    }
975  else
976    bootparams_common = &bootparams->v1.common;
977
978  /* Set video. */
979  err = grub_xnu_set_video (bootparams_common);
980  if (err != GRUB_ERR_NONE)
981    {
982      grub_print_error ();
983      grub_errno = GRUB_ERR_NONE;
984      grub_puts_ (N_("Booting in blind mode"));
985
986      bootparams_common->lfb_mode = 0;
987      bootparams_common->lfb_width = 0;
988      bootparams_common->lfb_height = 0;
989      bootparams_common->lfb_depth = 0;
990      bootparams_common->lfb_line_len = 0;
991      bootparams_common->lfb_base = 0;
992    }
993
994  if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
995                                   &map_key, &descriptor_size,
996                                   &descriptor_version) < 0)
997    return grub_errno;
998
999  /* We will do few allocations later. Reserve some space for possible
1000     memory map growth.  */
1001  memory_map_size += 20 * descriptor_size;
1002  err = grub_xnu_heap_malloc (memory_map_size,
1003                              &memory_map, &memory_map_target);
1004  if (err)
1005    return err;
1006
1007  err = grub_xnu_writetree_toheap (&devtree_target, &devtreelen);
1008  if (err)
1009    return err;
1010
1011  grub_memcpy (bootparams_common->cmdline, grub_xnu_cmdline,
1012               sizeof (bootparams_common->cmdline));
1013
1014  bootparams_common->devtree = devtree_target;
1015  bootparams_common->devtreelen = devtreelen;
1016
1017  err = grub_autoefi_finish_boot_services (&memory_map_size, memory_map,
1018                                           &map_key, &descriptor_size,
1019                                           &descriptor_version);
1020  if (err)
1021    return err;
1022
1023  if (v2)
1024    bootparams->v2.efi_system_table = (grub_addr_t) grub_autoefi_system_table;
1025  else
1026    bootparams->v1.efi_system_table = (grub_addr_t) grub_autoefi_system_table; 
1027
1028  firstruntimepage = (((grub_addr_t) grub_xnu_heap_target_start
1029                       + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1)
1030                      / GRUB_XNU_PAGESIZE) + 20;
1031  curruntimepage = firstruntimepage;
1032
1033  for (i = 0; (unsigned) i < memory_map_size / descriptor_size; i++)
1034    {
1035      grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *)
1036        ((char *) memory_map + descriptor_size * i);
1037
1038      curdesc->virtual_start = curdesc->physical_start;
1039
1040      if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA
1041          || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE)
1042        {
1043          curdesc->virtual_start = curruntimepage << 12;
1044          curruntimepage += curdesc->num_pages;
1045          if (curdesc->physical_start
1046              <= (grub_addr_t) grub_autoefi_system_table
1047              && curdesc->physical_start + (curdesc->num_pages << 12)
1048              > (grub_addr_t) grub_autoefi_system_table)
1049            efi_system_table
1050              = (grub_addr_t) grub_autoefi_system_table
1051              - curdesc->physical_start + curdesc->virtual_start;
1052          if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit)
1053            curdesc->virtual_start |= 0xffffff8000000000ULL;
1054        }
1055    }
1056
1057  lastruntimepage = curruntimepage;
1058
1059  if (v2)
1060    {
1061      bootparams->v2.efi_uintnbits = SIZEOF_OF_UINTN * 8;
1062      bootparams->v2.verminor = GRUB_XNU_BOOTARGSV2_VERMINOR;
1063      bootparams->v2.vermajor = GRUB_XNU_BOOTARGSV2_VERMAJOR;
1064      bootparams->v2.efi_system_table = efi_system_table;
1065    }
1066  else
1067    {
1068      bootparams->v1.efi_uintnbits = SIZEOF_OF_UINTN * 8;
1069      bootparams->v1.verminor = GRUB_XNU_BOOTARGSV1_VERMINOR;
1070      bootparams->v1.vermajor = GRUB_XNU_BOOTARGSV1_VERMAJOR;
1071      bootparams->v1.efi_system_table = efi_system_table;
1072    }
1073
1074  bootparams_common->efi_runtime_first_page = firstruntimepage;
1075  bootparams_common->efi_runtime_npages = lastruntimepage - firstruntimepage;
1076  bootparams_common->efi_mem_desc_size = descriptor_size;
1077  bootparams_common->efi_mem_desc_version = descriptor_version;
1078  bootparams_common->efi_mmap = memory_map_target;
1079  bootparams_common->efi_mmap_size = memory_map_size;
1080  bootparams_common->heap_start = grub_xnu_heap_target_start;
1081  bootparams_common->heap_size = grub_xnu_heap_size;
1082
1083  /* Parameters for asm helper. */
1084  grub_xnu_stack = bootparams_common->heap_start
1085    + bootparams_common->heap_size + GRUB_XNU_PAGESIZE;
1086  grub_xnu_arg1 = bootparams_target;
1087
1088  grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
1089                                        descriptor_version, memory_map);
1090
1091  state.eip = grub_xnu_entry_point;
1092  state.eax = grub_xnu_arg1;
1093  state.esp = grub_xnu_stack;
1094  state.ebp = grub_xnu_stack;
1095
1096  /* XNU uses only APIC. Disable PIC.  */
1097  grub_outb (0xff, 0x21);
1098  grub_outb (0xff, 0xa1);
1099
1100  return grub_relocator32_boot (grub_xnu_relocator, state, 0);
1101}
1102
1103static grub_command_t cmd_devprop_load;
1104
1105void
1106grub_cpu_xnu_init (void)
1107{
1108  cmd_devprop_load = grub_register_command ("xnu_devprop_load",
1109                                            grub_cmd_devprop_load,
1110                                            /* TRANSLATORS: `device-properties'
1111                                               is a variable name,
1112                                               not a program.  */
1113                                            0, N_("Load `device-properties' dump."));
1114}
1115
1116void
1117grub_cpu_xnu_fini (void)
1118{
1119  grub_unregister_command (cmd_devprop_load);
1120}
Note: See TracBrowser for help on using the repository browser.