GRUB-1.98 changes
[grub2/jjazz.git] / loader / i386 / xnu.c
blob8000579d00f8d01d6c8643dabace404bcd057d5d
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
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.
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.
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/>.
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/efi/api.h>
29 #include <grub/i386/pit.h>
30 #include <grub/misc.h>
31 #include <grub/charset.h>
32 #include <grub/term.h>
33 #include <grub/command.h>
34 #include <grub/gzio.h>
35 #include <grub/i18n.h>
37 char grub_xnu_cmdline[1024];
38 grub_uint32_t grub_xnu_heap_will_be_at;
39 grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack;
41 /* Aliases set for some tables. */
42 struct tbl_alias
44 grub_efi_guid_t guid;
45 char *name;
48 struct tbl_alias table_aliases[] =
50 {GRUB_EFI_ACPI_20_TABLE_GUID, "ACPI_20"},
51 {GRUB_EFI_ACPI_TABLE_GUID, "ACPI"},
54 struct grub_xnu_devprop_device_descriptor
56 struct grub_xnu_devprop_device_descriptor *next;
57 struct property_descriptor *properties;
58 struct grub_efi_device_path *path;
59 int pathlen;
62 static int
63 utf16_strlen (grub_uint16_t *in)
65 int i;
66 for (i = 0; in[i]; i++);
67 return i;
70 /* Read frequency from a string in MHz and return it in Hz. */
71 static grub_uint64_t
72 readfrequency (const char *str)
74 grub_uint64_t num = 0;
75 int mul = 1000000;
76 int found = 0;
78 while (*str)
80 unsigned long digit;
82 digit = grub_tolower (*str) - '0';
83 if (digit > 9)
84 break;
86 found = 1;
88 num = num * 10 + digit;
89 str++;
91 num *= 1000000;
92 if (*str == '.')
94 str++;
95 while (*str)
97 unsigned long digit;
99 digit = grub_tolower (*str) - '0';
100 if (digit > 9)
101 break;
103 found = 1;
105 mul /= 10;
106 num = num + mul * digit;
107 str++;
110 if (! found)
111 return 0;
113 return num;
116 /* Thanks to Kabyl for precious information about Intel architecture. */
117 static grub_uint64_t
118 guessfsb (void)
120 const grub_uint64_t sane_value = 100000000;
121 grub_uint32_t manufacturer[3], max_cpuid, capabilities, msrlow;
122 grub_uint64_t start_tsc;
123 grub_uint64_t end_tsc;
124 grub_uint64_t tsc_ticks_per_ms;
126 if (! grub_cpu_is_cpuid_supported ())
127 return sane_value;
129 #ifdef APPLE_CC
130 asm volatile ("movl $0, %%eax\n"
131 #ifdef __x86_64__
132 "push %%rbx\n"
133 #else
134 "push %%ebx\n"
135 #endif
136 "cpuid\n"
137 #ifdef __x86_64__
138 "pop %%rbx\n"
139 #else
140 "pop %%ebx\n"
141 #endif
142 : "=a" (max_cpuid),
143 "=d" (manufacturer[1]), "=c" (manufacturer[2]));
145 /* Only Intel for now is done. */
146 if (grub_memcmp (manufacturer + 1, "ineIntel", 12) != 0)
147 return sane_value;
149 #else
150 asm volatile ("movl $0, %%eax\n"
151 "cpuid"
152 : "=a" (max_cpuid), "=b" (manufacturer[0]),
153 "=d" (manufacturer[1]), "=c" (manufacturer[2]));
155 /* Only Intel for now is done. */
156 if (grub_memcmp (manufacturer, "GenuineIntel", 12) != 0)
157 return sane_value;
158 #endif
160 /* Check Speedstep. */
161 if (max_cpuid < 1)
162 return sane_value;
164 #ifdef APPLE_CC
165 asm volatile ("movl $1, %%eax\n"
166 #ifdef __x86_64__
167 "push %%rbx\n"
168 #else
169 "push %%ebx\n"
170 #endif
171 "cpuid\n"
172 #ifdef __x86_64__
173 "pop %%rbx\n"
174 #else
175 "pop %%ebx\n"
176 #endif
177 : "=c" (capabilities):
178 : "%rax", "%rdx");
179 #else
180 asm volatile ("movl $1, %%eax\n"
181 "cpuid"
182 : "=c" (capabilities):
183 : "%rax", "%rbx", "%rdx");
184 #endif
186 if (! (capabilities & (1 << 7)))
187 return sane_value;
189 /* Calibrate the TSC rate. */
191 start_tsc = grub_get_tsc ();
192 grub_pit_wait (0xffff);
193 end_tsc = grub_get_tsc ();
195 tsc_ticks_per_ms = grub_divmod64 (end_tsc - start_tsc, 55, 0);
197 /* Read the multiplier. */
198 asm volatile ("movl $0x198, %%ecx\n"
199 "rdmsr"
200 : "=d" (msrlow)
202 : "%ecx", "%eax");
204 return grub_divmod64 (2000 * tsc_ticks_per_ms,
205 ((msrlow >> 7) & 0x3e) + ((msrlow >> 14) & 1), 0);
208 struct property_descriptor
210 struct property_descriptor *next;
211 grub_uint8_t *name;
212 grub_uint16_t *name16;
213 int name16len;
214 int length;
215 void *data;
218 struct grub_xnu_devprop_device_descriptor *devices = 0;
220 grub_err_t
221 grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor *dev,
222 char *name)
224 struct property_descriptor *prop;
225 prop = grub_named_list_find (GRUB_AS_NAMED_LIST_P (&dev->properties), name);
226 if (!prop)
227 return GRUB_ERR_NONE;
229 grub_free (prop->name);
230 grub_free (prop->name16);
231 grub_free (prop->data);
233 grub_list_remove (GRUB_AS_LIST_P (&dev->properties), GRUB_AS_LIST (prop));
235 return GRUB_ERR_NONE;
238 grub_err_t
239 grub_xnu_devprop_remove_device (struct grub_xnu_devprop_device_descriptor *dev)
241 void *t;
242 struct property_descriptor *prop;
244 grub_list_remove (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (dev));
246 for (prop = dev->properties; prop; )
248 grub_free (prop->name);
249 grub_free (prop->name16);
250 grub_free (prop->data);
251 t = prop;
252 prop = prop->next;
253 grub_free (t);
256 grub_free (dev->path);
257 grub_free (dev);
259 return GRUB_ERR_NONE;
262 struct grub_xnu_devprop_device_descriptor *
263 grub_xnu_devprop_add_device (struct grub_efi_device_path *path, int length)
265 struct grub_xnu_devprop_device_descriptor *ret;
267 ret = grub_zalloc (sizeof (*ret));
268 if (!ret)
269 return 0;
271 ret->path = grub_malloc (length);
272 if (!ret->path)
274 grub_free (ret);
275 return 0;
277 ret->pathlen = length;
278 grub_memcpy (ret->path, path, length);
280 grub_list_push (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (ret));
282 return ret;
285 static grub_err_t
286 grub_xnu_devprop_add_property (struct grub_xnu_devprop_device_descriptor *dev,
287 grub_uint8_t *utf8, grub_uint16_t *utf16,
288 int utf16len, void *data, int datalen)
290 struct property_descriptor *prop;
292 prop = grub_malloc (sizeof (*prop));
293 if (!prop)
294 return grub_errno;
296 prop->name = utf8;
297 prop->name16 = utf16;
298 prop->name16len = utf16len;
300 prop->length = datalen;
301 prop->data = grub_malloc (prop->length);
302 if (!prop->data)
304 grub_free (prop);
305 grub_free (prop->name);
306 grub_free (prop->name16);
307 return grub_errno;
309 grub_memcpy (prop->data, data, prop->length);
310 grub_list_push (GRUB_AS_LIST_P (&dev->properties),
311 GRUB_AS_LIST (prop));
312 return GRUB_ERR_NONE;
315 grub_err_t
316 grub_xnu_devprop_add_property_utf8 (struct grub_xnu_devprop_device_descriptor *dev,
317 char *name, void *data, int datalen)
319 grub_uint8_t *utf8;
320 grub_uint16_t *utf16;
321 int len, utf16len;
322 grub_err_t err;
324 utf8 = (grub_uint8_t *) grub_strdup (name);
325 if (!utf8)
326 return grub_errno;
328 len = grub_strlen (name);
329 utf16 = grub_malloc (sizeof (grub_uint16_t) * len);
330 if (!utf16)
332 grub_free (utf8);
333 return grub_errno;
336 utf16len = grub_utf8_to_utf16 (utf16, len, utf8, len, NULL);
337 if (utf16len < 0)
339 grub_free (utf8);
340 grub_free (utf16);
341 return grub_errno;
344 err = grub_xnu_devprop_add_property (dev, utf8, utf16,
345 utf16len, data, datalen);
346 if (err)
348 grub_free (utf8);
349 grub_free (utf16);
350 return err;
353 return GRUB_ERR_NONE;
356 grub_err_t
357 grub_xnu_devprop_add_property_utf16 (struct grub_xnu_devprop_device_descriptor *dev,
358 grub_uint16_t *name, int namelen,
359 void *data, int datalen)
361 grub_uint8_t *utf8;
362 grub_uint16_t *utf16;
363 grub_err_t err;
365 utf16 = grub_malloc (sizeof (grub_uint16_t) * namelen);
366 if (!utf16)
367 return grub_errno;
368 grub_memcpy (utf16, name, sizeof (grub_uint16_t) * namelen);
370 utf8 = grub_malloc (namelen * 4 + 1);
371 if (!utf8)
373 grub_free (utf8);
374 return grub_errno;
377 *grub_utf16_to_utf8 ((grub_uint8_t *) utf8, name, namelen) = '\0';
379 err = grub_xnu_devprop_add_property (dev, utf8, utf16,
380 namelen, data, datalen);
381 if (err)
383 grub_free (utf8);
384 grub_free (utf16);
385 return err;
388 return GRUB_ERR_NONE;
391 static inline int
392 hextoval (char c)
394 if (c >= '0' && c <= '9')
395 return c - '0';
396 if (c >= 'a' && c <= 'z')
397 return c - 'a' + 10;
398 if (c >= 'A' && c <= 'Z')
399 return c - 'A' + 10;
400 return 0;
403 void
404 grub_cpu_xnu_unload (void)
406 struct grub_xnu_devprop_device_descriptor *dev1, *dev2;
408 for (dev1 = devices; dev1; )
410 dev2 = dev1->next;
411 grub_xnu_devprop_remove_device (dev1);
412 dev1 = dev2;
416 static grub_err_t
417 grub_cpu_xnu_fill_devprop (void)
419 struct grub_xnu_devtree_key *efikey;
420 int total_length = sizeof (struct grub_xnu_devprop_header);
421 struct grub_xnu_devtree_key *devprop;
422 struct grub_xnu_devprop_device_descriptor *device;
423 void *ptr;
424 struct grub_xnu_devprop_header *head;
425 void *t;
426 int numdevs = 0;
428 /* The key "efi". */
429 efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi");
430 if (! efikey)
431 return grub_errno;
433 for (device = devices; device; device = device->next)
435 struct property_descriptor *propdesc;
436 total_length += sizeof (struct grub_xnu_devprop_device_header);
437 total_length += device->pathlen;
439 for (propdesc = device->properties; propdesc; propdesc = propdesc->next)
441 total_length += sizeof (grub_uint32_t);
442 total_length += sizeof (grub_uint16_t)
443 * (propdesc->name16len + 1);
444 total_length += sizeof (grub_uint32_t);
445 total_length += propdesc->length;
447 numdevs++;
450 devprop = grub_xnu_create_value (&(efikey->first_child), "device-properties");
451 if (devprop)
453 devprop->data = grub_malloc (total_length);
454 devprop->datasize = total_length;
457 ptr = devprop->data;
458 head = ptr;
459 ptr = head + 1;
460 head->length = total_length;
461 head->alwaysone = 1;
462 head->num_devices = numdevs;
463 for (device = devices; device; )
465 struct grub_xnu_devprop_device_header *devhead;
466 struct property_descriptor *propdesc;
467 devhead = ptr;
468 devhead->num_values = 0;
469 ptr = devhead + 1;
471 grub_memcpy (ptr, device->path, device->pathlen);
472 ptr = (char *) ptr + device->pathlen;
474 for (propdesc = device->properties; propdesc; )
476 grub_uint32_t *len;
477 grub_uint16_t *name;
478 void *data;
480 len = ptr;
481 *len = 2 * propdesc->name16len + sizeof (grub_uint16_t)
482 + sizeof (grub_uint32_t);
483 ptr = len + 1;
485 name = ptr;
486 grub_memcpy (name, propdesc->name16, 2 * propdesc->name16len);
487 name += propdesc->name16len;
489 /* NUL terminator. */
490 *name = 0;
491 ptr = name + 1;
493 len = ptr;
494 *len = propdesc->length + sizeof (grub_uint32_t);
495 data = len + 1;
496 ptr = data;
497 grub_memcpy (ptr, propdesc->data, propdesc->length);
498 ptr = (char *) ptr + propdesc->length;
500 grub_free (propdesc->name);
501 grub_free (propdesc->name16);
502 grub_free (propdesc->data);
503 t = propdesc;
504 propdesc = propdesc->next;
505 grub_free (t);
506 devhead->num_values++;
509 devhead->length = (char *) ptr - (char *) devhead;
510 t = device;
511 device = device->next;
512 grub_free (t);
515 devices = 0;
517 return GRUB_ERR_NONE;
520 static grub_err_t
521 grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)),
522 int argc, char *args[])
524 grub_file_t file;
525 void *buf, *bufstart, *bufend;
526 struct grub_xnu_devprop_header *head;
527 grub_size_t size;
528 unsigned i, j;
530 if (argc != 1)
531 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
533 file = grub_gzfile_open (args[0], 1);
534 if (! file)
535 return grub_error (GRUB_ERR_FILE_NOT_FOUND,
536 "couldn't load device-propertie dump");
537 size = grub_file_size (file);
538 buf = grub_malloc (size);
539 if (!buf)
541 grub_file_close (file);
542 return grub_errno;
544 if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
546 grub_file_close (file);
547 return grub_errno;
549 grub_file_close (file);
551 bufstart = buf;
552 bufend = (char *) buf + size;
553 head = buf;
554 buf = head + 1;
555 for (i = 0; i < grub_le_to_cpu32 (head->num_devices) && buf < bufend; i++)
557 struct grub_efi_device_path *dp, *dpstart;
558 struct grub_xnu_devprop_device_descriptor *dev;
559 struct grub_xnu_devprop_device_header *devhead;
561 devhead = buf;
562 buf = devhead + 1;
563 dpstart = buf;
567 dp = buf;
568 buf = (char *) buf + GRUB_EFI_DEVICE_PATH_LENGTH (dp);
570 while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp) && buf < bufend);
572 dev = grub_xnu_devprop_add_device (dpstart, (char *) buf
573 - (char *) dpstart);
575 for (j = 0; j < grub_le_to_cpu32 (devhead->num_values) && buf < bufend;
576 j++)
578 grub_uint32_t *namelen;
579 grub_uint32_t *datalen;
580 grub_uint16_t *utf16;
581 void *data;
582 grub_err_t err;
584 namelen = buf;
585 buf = namelen + 1;
586 if (buf >= bufend)
587 break;
589 utf16 = buf;
590 buf = (char *) buf + *namelen - sizeof (grub_uint32_t);
591 if (buf >= bufend)
592 break;
594 datalen = buf;
595 buf = datalen + 1;
596 if (buf >= bufend)
597 break;
599 data = buf;
600 buf = (char *) buf + *datalen - sizeof (grub_uint32_t);
601 if (buf >= bufend)
602 break;
603 err = grub_xnu_devprop_add_property_utf16
604 (dev, utf16, (*namelen - sizeof (grub_uint32_t)
605 - sizeof (grub_uint16_t)) / sizeof (grub_uint16_t),
606 data, *datalen - sizeof (grub_uint32_t));
607 if (err)
609 grub_free (bufstart);
610 return err;
615 grub_free (bufstart);
616 return GRUB_ERR_NONE;
619 /* Fill device tree. */
620 /* FIXME: some entries may be platform-agnostic. Move them to loader/xnu.c. */
621 grub_err_t
622 grub_cpu_xnu_fill_devicetree (void)
624 struct grub_xnu_devtree_key *efikey;
625 struct grub_xnu_devtree_key *cfgtablekey;
626 struct grub_xnu_devtree_key *curval;
627 struct grub_xnu_devtree_key *runtimesrvkey;
628 struct grub_xnu_devtree_key *platformkey;
629 unsigned i, j;
631 /* The value "model". */
632 /* FIXME: may this value be sometimes different? */
633 curval = grub_xnu_create_value (&grub_xnu_devtree_root, "model");
634 if (! curval)
635 return grub_errno;
636 curval->datasize = sizeof ("ACPI");
637 curval->data = grub_strdup ("ACPI");
638 curval = grub_xnu_create_value (&grub_xnu_devtree_root, "compatible");
639 if (! curval)
640 return grub_errno;
641 curval->datasize = sizeof ("ACPI");
642 curval->data = grub_strdup ("ACPI");
644 /* The key "efi". */
645 efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi");
646 if (! efikey)
647 return grub_errno;
649 /* Information about firmware. */
650 curval = grub_xnu_create_value (&(efikey->first_child), "firmware-revision");
651 if (! curval)
652 return grub_errno;
653 curval->datasize = (SYSTEM_TABLE_SIZEOF (firmware_revision));
654 curval->data = grub_malloc (curval->datasize);
655 if (! curval->data)
656 return grub_errno;
657 grub_memcpy (curval->data, (SYSTEM_TABLE_VAR(firmware_revision)),
658 curval->datasize);
660 curval = grub_xnu_create_value (&(efikey->first_child), "firmware-vendor");
661 if (! curval)
662 return grub_errno;
663 curval->datasize =
664 2 * (utf16_strlen (SYSTEM_TABLE_PTR (firmware_vendor)) + 1);
665 curval->data = grub_malloc (curval->datasize);
666 if (! curval->data)
667 return grub_errno;
668 grub_memcpy (curval->data, SYSTEM_TABLE_PTR (firmware_vendor),
669 curval->datasize);
671 curval = grub_xnu_create_value (&(efikey->first_child), "firmware-abi");
672 if (! curval)
673 return grub_errno;
674 curval->datasize = sizeof ("EFI32");
675 curval->data = grub_malloc (curval->datasize);
676 if (! curval->data)
677 return grub_errno;
678 if (SIZEOF_OF_UINTN == 4)
679 grub_memcpy (curval->data, "EFI32", curval->datasize);
680 else
681 grub_memcpy (curval->data, "EFI64", curval->datasize);
683 /* The key "platform". */
684 platformkey = grub_xnu_create_key (&(efikey->first_child),
685 "platform");
686 if (! platformkey)
687 return grub_errno;
689 /* Pass FSB frequency to the kernel. */
690 curval = grub_xnu_create_value (&(platformkey->first_child), "FSBFrequency");
691 if (! curval)
692 return grub_errno;
693 curval->datasize = sizeof (grub_uint64_t);
694 curval->data = grub_malloc (curval->datasize);
695 if (!curval->data)
696 return grub_errno;
698 /* First see if user supplies the value. */
699 char *fsbvar = grub_env_get ("fsb");
700 if (! fsbvar)
701 *((grub_uint64_t *) curval->data) = 0;
702 else
703 *((grub_uint64_t *) curval->data) = readfrequency (fsbvar);
704 /* Try autodetect. */
705 if (! *((grub_uint64_t *) curval->data))
706 *((grub_uint64_t *) curval->data) = guessfsb ();
707 grub_dprintf ("xnu", "fsb autodetected as %llu\n",
708 (unsigned long long) *((grub_uint64_t *) curval->data));
710 cfgtablekey = grub_xnu_create_key (&(efikey->first_child),
711 "configuration-table");
712 if (!cfgtablekey)
713 return grub_errno;
715 /* Fill "configuration-table" key. */
716 for (i = 0; i < SYSTEM_TABLE (num_table_entries); i++)
718 void *ptr;
719 struct grub_xnu_devtree_key *curkey;
720 grub_efi_guid_t guid;
721 char guidbuf[64];
723 /* Retrieve current key. */
724 #ifdef GRUB_MACHINE_EFI
726 ptr = (void *)
727 grub_efi_system_table->configuration_table[i].vendor_table;
728 guid = grub_efi_system_table->configuration_table[i].vendor_guid;
730 #else
731 if (SIZEOF_OF_UINTN == 4)
733 ptr = UINT_TO_PTR (((grub_efiemu_configuration_table32_t *)
734 SYSTEM_TABLE_PTR (configuration_table))[i]
735 .vendor_table);
736 guid =
737 ((grub_efiemu_configuration_table32_t *)
738 SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid;
740 else
742 ptr = UINT_TO_PTR (((grub_efiemu_configuration_table64_t *)
743 SYSTEM_TABLE_PTR (configuration_table))[i]
744 .vendor_table);
745 guid =
746 ((grub_efiemu_configuration_table64_t *)
747 SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid;
749 #endif
751 /* The name of key for new table. */
752 grub_snprintf (guidbuf, sizeof (guidbuf), "%08x-%04x-%04x-%02x%02x-",
753 guid.data1, guid.data2, guid.data3, guid.data4[0],
754 guid.data4[1]);
755 for (j = 2; j < 8; j++)
756 grub_snprintf (guidbuf + grub_strlen (guidbuf),
757 sizeof (guidbuf) - grub_strlen (guidbuf),
758 "%02x", guid.data4[j]);
759 /* For some reason GUID has to be in uppercase. */
760 for (j = 0; guidbuf[j] ; j++)
761 if (guidbuf[j] >= 'a' && guidbuf[j] <= 'f')
762 guidbuf[j] += 'A' - 'a';
763 curkey = grub_xnu_create_key (&(cfgtablekey->first_child), guidbuf);
764 if (! curkey)
765 return grub_errno;
767 curval = grub_xnu_create_value (&(curkey->first_child), "guid");
768 if (! curval)
769 return grub_errno;
770 curval->datasize = sizeof (guid);
771 curval->data = grub_malloc (curval->datasize);
772 if (! curval->data)
773 return grub_errno;
774 grub_memcpy (curval->data, &guid, curval->datasize);
776 /* The value "table". */
777 curval = grub_xnu_create_value (&(curkey->first_child), "table");
778 if (! curval)
779 return grub_errno;
780 curval->datasize = SIZEOF_OF_UINTN;
781 curval->data = grub_malloc (curval->datasize);
782 if (! curval->data)
783 return grub_errno;
784 if (SIZEOF_OF_UINTN == 4)
785 *((grub_uint32_t *)curval->data) = PTR_TO_UINT32 (ptr);
786 else
787 *((grub_uint64_t *)curval->data) = PTR_TO_UINT64 (ptr);
789 /* Create alias. */
790 for (j = 0; j < sizeof (table_aliases) / sizeof (table_aliases[0]); j++)
791 if (grub_memcmp (&table_aliases[j].guid, &guid, sizeof (guid)) == 0)
792 break;
793 if (j != sizeof (table_aliases) / sizeof (table_aliases[0]))
795 curval = grub_xnu_create_value (&(curkey->first_child), "alias");
796 if (!curval)
797 return grub_errno;
798 curval->datasize = grub_strlen (table_aliases[j].name) + 1;
799 curval->data = grub_malloc (curval->datasize);
800 if (!curval->data)
801 return grub_errno;
802 grub_memcpy (curval->data, table_aliases[j].name, curval->datasize);
806 /* Create and fill "runtime-services" key. */
807 runtimesrvkey = grub_xnu_create_key (&(efikey->first_child),
808 "runtime-services");
809 if (! runtimesrvkey)
810 return grub_errno;
811 curval = grub_xnu_create_value (&(runtimesrvkey->first_child), "table");
812 if (! curval)
813 return grub_errno;
814 curval->datasize = SIZEOF_OF_UINTN;
815 curval->data = grub_malloc (curval->datasize);
816 if (! curval->data)
817 return grub_errno;
818 if (SIZEOF_OF_UINTN == 4)
819 *((grub_uint32_t *) curval->data)
820 = PTR_TO_UINT32 (SYSTEM_TABLE_PTR (runtime_services));
821 else
822 *((grub_uint64_t *) curval->data)
823 = PTR_TO_UINT64 (SYSTEM_TABLE_PTR (runtime_services));
825 return GRUB_ERR_NONE;
828 grub_err_t
829 grub_xnu_boot_resume (void)
831 struct grub_relocator32_state state;
833 state.esp = grub_xnu_stack;
834 state.eip = grub_xnu_entry_point;
835 state.eax = grub_xnu_arg1;
837 return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at,
838 state);
841 /* Boot xnu. */
842 grub_err_t
843 grub_xnu_boot (void)
845 struct grub_xnu_boot_params *bootparams_relloc;
846 grub_off_t bootparams_relloc_off;
847 grub_off_t mmap_relloc_off;
848 grub_err_t err;
849 grub_efi_uintn_t memory_map_size = 0;
850 grub_efi_memory_descriptor_t *memory_map;
851 grub_efi_uintn_t map_key = 0;
852 grub_efi_uintn_t descriptor_size = 0;
853 grub_efi_uint32_t descriptor_version = 0;
854 grub_uint64_t firstruntimepage, lastruntimepage;
855 grub_uint64_t curruntimepage;
856 void *devtree;
857 grub_size_t devtreelen;
858 int i;
859 struct grub_relocator32_state state;
861 err = grub_autoefi_prepare ();
862 if (err)
863 return err;
865 err = grub_cpu_xnu_fill_devprop ();
866 if (err)
867 return err;
869 err = grub_cpu_xnu_fill_devicetree ();
870 if (err)
871 return err;
873 err = grub_xnu_fill_devicetree ();
874 if (err)
875 return err;
877 /* Page-align to avoid following parts to be inadvertently freed. */
878 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
879 if (err)
880 return err;
882 /* Pass memory map to kernel. */
883 memory_map_size = 0;
884 memory_map = 0;
885 map_key = 0;
886 descriptor_size = 0;
887 descriptor_version = 0;
889 grub_dprintf ("xnu", "eip=%x\n", grub_xnu_entry_point);
891 const char *debug = grub_env_get ("debug");
893 if (debug && (grub_strword (debug, "all") || grub_strword (debug, "xnu")))
895 grub_printf ("Press any key to launch xnu\n");
896 grub_getkey ();
899 /* Relocate the boot parameters to heap. */
900 bootparams_relloc = grub_xnu_heap_malloc (sizeof (*bootparams_relloc));
901 if (! bootparams_relloc)
902 return grub_errno;
903 bootparams_relloc_off = (grub_uint8_t *) bootparams_relloc
904 - (grub_uint8_t *) grub_xnu_heap_start;
906 /* Set video. */
907 err = grub_xnu_set_video (bootparams_relloc);
908 if (err != GRUB_ERR_NONE)
910 grub_print_error ();
911 grub_errno = GRUB_ERR_NONE;
912 grub_printf ("Booting in blind mode\n");
914 bootparams_relloc->lfb_mode = 0;
915 bootparams_relloc->lfb_width = 0;
916 bootparams_relloc->lfb_height = 0;
917 bootparams_relloc->lfb_depth = 0;
918 bootparams_relloc->lfb_line_len = 0;
919 bootparams_relloc->lfb_base = 0;
922 if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
923 &map_key, &descriptor_size,
924 &descriptor_version) < 0)
925 return grub_errno;
927 /* We will do few allocations later. Reserve some space for possible
928 memory map growth. */
929 memory_map_size += 20 * descriptor_size;
930 memory_map = grub_xnu_heap_malloc (memory_map_size);
931 if (! memory_map)
932 return grub_errno;
933 mmap_relloc_off = (grub_uint8_t *) memory_map
934 - (grub_uint8_t *) grub_xnu_heap_start;
936 err = grub_xnu_writetree_toheap (&devtree, &devtreelen);
937 if (err)
938 return err;
939 bootparams_relloc = (struct grub_xnu_boot_params *)
940 (bootparams_relloc_off + (grub_uint8_t *) grub_xnu_heap_start);
942 grub_memcpy (bootparams_relloc->cmdline, grub_xnu_cmdline,
943 sizeof (bootparams_relloc->cmdline));
945 bootparams_relloc->devtree
946 = ((grub_uint8_t *) devtree - (grub_uint8_t *) grub_xnu_heap_start)
947 + grub_xnu_heap_will_be_at;
948 bootparams_relloc->devtreelen = devtreelen;
950 memory_map = (grub_efi_memory_descriptor_t *)
951 ((grub_uint8_t *) grub_xnu_heap_start + mmap_relloc_off);
953 if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
954 &map_key, &descriptor_size,
955 &descriptor_version) <= 0)
956 return grub_errno;
958 bootparams_relloc->efi_system_table
959 = PTR_TO_UINT32 (grub_autoefi_system_table);
961 firstruntimepage = (((grub_addr_t) grub_xnu_heap_will_be_at
962 + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1)
963 / GRUB_XNU_PAGESIZE) + 20;
964 curruntimepage = firstruntimepage;
966 for (i = 0; (unsigned) i < memory_map_size / descriptor_size; i++)
968 grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *)
969 ((char *) memory_map + descriptor_size * i);
971 curdesc->virtual_start = curdesc->physical_start;
973 if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA
974 || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE)
976 curdesc->virtual_start = curruntimepage << 12;
977 curruntimepage += curdesc->num_pages;
978 if (curdesc->physical_start
979 <= PTR_TO_UINT64 (grub_autoefi_system_table)
980 && curdesc->physical_start + (curdesc->num_pages << 12)
981 > PTR_TO_UINT64 (grub_autoefi_system_table))
982 bootparams_relloc->efi_system_table
983 = PTR_TO_UINT64 (grub_autoefi_system_table)
984 - curdesc->physical_start + curdesc->virtual_start;
985 if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit)
986 curdesc->virtual_start |= 0xffffff8000000000ULL;
990 lastruntimepage = curruntimepage;
992 bootparams_relloc->efi_mmap = grub_xnu_heap_will_be_at + mmap_relloc_off;
993 bootparams_relloc->efi_mmap_size = memory_map_size;
994 bootparams_relloc->efi_mem_desc_size = descriptor_size;
995 bootparams_relloc->efi_mem_desc_version = descriptor_version;
997 bootparams_relloc->heap_start = grub_xnu_heap_will_be_at;
998 bootparams_relloc->heap_size = grub_xnu_heap_size;
999 bootparams_relloc->efi_runtime_first_page = firstruntimepage;
1001 bootparams_relloc->efi_runtime_npages = lastruntimepage - firstruntimepage;
1002 bootparams_relloc->efi_uintnbits = SIZEOF_OF_UINTN * 8;
1004 bootparams_relloc->verminor = GRUB_XNU_BOOTARGS_VERMINOR;
1005 bootparams_relloc->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR;
1007 /* Parameters for asm helper. */
1008 grub_xnu_stack = bootparams_relloc->heap_start
1009 + bootparams_relloc->heap_size + GRUB_XNU_PAGESIZE;
1010 grub_xnu_arg1 = bootparams_relloc_off + grub_xnu_heap_will_be_at;
1012 if (! grub_autoefi_exit_boot_services (map_key))
1013 return grub_error (GRUB_ERR_IO, "can't exit boot services");
1015 grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
1016 descriptor_version,memory_map);
1018 state.eip = grub_xnu_entry_point;
1019 state.eax = grub_xnu_arg1;
1020 state.esp = grub_xnu_stack;
1021 return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at,
1022 state);
1025 static grub_command_t cmd_devprop_load;
1027 void
1028 grub_cpu_xnu_init (void)
1030 cmd_devprop_load = grub_register_command ("xnu_devprop_load",
1031 grub_cmd_devprop_load,
1032 0, N_("Load device-properties dump."));
1035 void
1036 grub_cpu_xnu_fini (void)
1038 grub_unregister_command (cmd_devprop_load);