Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / loader / xnu.c
blobc9885b1bcd7304785eab07e020208fc833732bc9
1 /* xnu.c - load xnu kernel. Thanks to Florian Idelberger for all the
2 time he spent testing this
3 */
4 /*
5 * GRUB -- GRand Unified Bootloader
6 * Copyright (C) 2009 Free Software Foundation, Inc.
8 * GRUB is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * GRUB is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
22 #include <grub/file.h>
23 #include <grub/xnu.h>
24 #include <grub/cpu/xnu.h>
25 #include <grub/mm.h>
26 #include <grub/dl.h>
27 #include <grub/loader.h>
28 #include <grub/machoload.h>
29 #include <grub/macho.h>
30 #include <grub/cpu/macho.h>
31 #include <grub/command.h>
32 #include <grub/misc.h>
33 #include <grub/extcmd.h>
34 #include <grub/env.h>
35 #include <grub/i18n.h>
37 GRUB_MOD_LICENSE ("GPLv3+");
39 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
40 #include <grub/autoefi.h>
41 #endif
43 struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0;
44 static int driverspackagenum = 0;
45 static int driversnum = 0;
46 int grub_xnu_is_64bit = 0;
47 int grub_xnu_darwin_version = 0;
49 grub_addr_t grub_xnu_heap_target_start = 0;
50 grub_size_t grub_xnu_heap_size = 0;
51 struct grub_relocator *grub_xnu_relocator;
53 static grub_err_t
54 grub_xnu_register_memory (const char *prefix, int *suffix,
55 grub_addr_t addr, grub_size_t size);
56 grub_err_t
57 grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target)
59 grub_err_t err;
60 grub_relocator_chunk_t ch;
62 err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch,
63 grub_xnu_heap_target_start
64 + grub_xnu_heap_size, size);
65 if (err)
66 return err;
68 *src = get_virtual_current_address (ch);
69 *target = grub_xnu_heap_target_start + grub_xnu_heap_size;
70 grub_xnu_heap_size += size;
71 grub_dprintf ("xnu", "val=%p\n", *src);
72 return GRUB_ERR_NONE;
75 /* Make sure next block of the heap will be aligned.
76 Please notice: aligned are pointers AFTER relocation
77 and not the current ones. */
78 grub_err_t
79 grub_xnu_align_heap (int align)
81 grub_xnu_heap_size
82 = ALIGN_UP (grub_xnu_heap_target_start+ grub_xnu_heap_size, align)
83 - grub_xnu_heap_target_start;
84 return GRUB_ERR_NONE;
87 /* Free subtree pointed by CUR. */
88 void
89 grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur)
91 struct grub_xnu_devtree_key *d;
92 while (cur)
94 grub_free (cur->name);
95 if (cur->datasize == -1)
96 grub_xnu_free_devtree (cur->first_child);
97 else if (cur->data)
98 grub_free (cur->data);
99 d = cur->next;
100 grub_free (cur);
101 cur = d;
105 /* Compute the size of device tree in xnu format. */
106 static grub_size_t
107 grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start,
108 const char *name)
110 grub_size_t ret;
111 struct grub_xnu_devtree_key *cur;
113 /* Key header. */
114 ret = 2 * sizeof (grub_uint32_t);
116 /* "name" value. */
117 ret += 32 + sizeof (grub_uint32_t)
118 + grub_strlen (name) + 4
119 - (grub_strlen (name) % 4);
121 for (cur = start; cur; cur = cur->next)
122 if (cur->datasize != -1)
124 int align_overhead;
126 align_overhead = 4 - (cur->datasize % 4);
127 if (align_overhead == 4)
128 align_overhead = 0;
129 ret += 32 + sizeof (grub_uint32_t) + cur->datasize + align_overhead;
131 else
132 ret += grub_xnu_writetree_get_size (cur->first_child, cur->name);
133 return ret;
136 /* Write devtree in XNU format at curptr assuming the head is named NAME.*/
137 static void *
138 grub_xnu_writetree_toheap_real (void *curptr,
139 struct grub_xnu_devtree_key *start,
140 const char *name)
142 struct grub_xnu_devtree_key *cur;
143 int nkeys = 0, nvals = 0;
144 for (cur = start; cur; cur = cur->next)
146 if (cur->datasize == -1)
147 nkeys++;
148 else
149 nvals++;
151 /* For the name. */
152 nvals++;
154 *((grub_uint32_t *) curptr) = nvals;
155 curptr = ((grub_uint32_t *) curptr) + 1;
156 *((grub_uint32_t *) curptr) = nkeys;
157 curptr = ((grub_uint32_t *) curptr) + 1;
159 /* First comes "name" value. */
160 grub_memset (curptr, 0, 32);
161 grub_memcpy (curptr, "name", 4);
162 curptr = ((grub_uint8_t *) curptr) + 32;
163 *((grub_uint32_t *)curptr) = grub_strlen (name) + 1;
164 curptr = ((grub_uint32_t *) curptr) + 1;
165 grub_memcpy (curptr, name, grub_strlen (name));
166 curptr = ((grub_uint8_t *) curptr) + grub_strlen (name);
167 grub_memset (curptr, 0, 4 - (grub_strlen (name) % 4));
168 curptr = ((grub_uint8_t *) curptr) + (4 - (grub_strlen (name) % 4));
170 /* Then the other values. */
171 for (cur = start; cur; cur = cur->next)
172 if (cur->datasize != -1)
174 int align_overhead;
176 align_overhead = 4 - (cur->datasize % 4);
177 if (align_overhead == 4)
178 align_overhead = 0;
179 grub_memset (curptr, 0, 32);
180 grub_strncpy (curptr, cur->name, 31);
181 curptr = ((grub_uint8_t *) curptr) + 32;
182 *((grub_uint32_t *) curptr) = cur->datasize;
183 curptr = ((grub_uint32_t *) curptr) + 1;
184 grub_memcpy (curptr, cur->data, cur->datasize);
185 curptr = ((grub_uint8_t *) curptr) + cur->datasize;
186 grub_memset (curptr, 0, align_overhead);
187 curptr = ((grub_uint8_t *) curptr) + align_overhead;
190 /* And then the keys. Recursively use this function. */
191 for (cur = start; cur; cur = cur->next)
192 if (cur->datasize == -1)
194 curptr = grub_xnu_writetree_toheap_real (curptr,
195 cur->first_child,
196 cur->name);
197 if (!curptr)
198 return 0;
200 return curptr;
203 grub_err_t
204 grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
206 struct grub_xnu_devtree_key *chosen;
207 struct grub_xnu_devtree_key *memorymap;
208 struct grub_xnu_devtree_key *driverkey;
209 struct grub_xnu_extdesc *extdesc;
210 grub_err_t err;
211 void *src;
213 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
214 if (err)
215 return err;
217 /* Device tree itself is in the memory map of device tree. */
218 /* Create a dummy value in memory-map. */
219 chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
220 if (! chosen)
221 return grub_errno;
222 memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
223 if (! memorymap)
224 return grub_errno;
226 driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
227 if (! driverkey)
228 return grub_errno;
229 driverkey->name = grub_strdup ("DeviceTree");
230 if (! driverkey->name)
231 return grub_errno;
232 driverkey->datasize = sizeof (*extdesc);
233 driverkey->next = memorymap->first_child;
234 memorymap->first_child = driverkey;
235 driverkey->data = extdesc
236 = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
237 if (! driverkey->data)
238 return grub_errno;
240 /* Allocate the space based on the size with dummy value. */
241 *size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/");
242 err = grub_xnu_heap_malloc (ALIGN_UP (*size + 1, GRUB_XNU_PAGESIZE),
243 &src, target);
244 if (err)
245 return err;
247 /* Put real data in the dummy. */
248 extdesc->addr = *target;
249 extdesc->size = (grub_uint32_t) *size;
251 /* Write the tree to heap. */
252 grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/");
253 return GRUB_ERR_NONE;
256 /* Find a key or value in parent key. */
257 struct grub_xnu_devtree_key *
258 grub_xnu_find_key (struct grub_xnu_devtree_key *parent, const char *name)
260 struct grub_xnu_devtree_key *cur;
261 for (cur = parent; cur; cur = cur->next)
262 if (grub_strcmp (cur->name, name) == 0)
263 return cur;
264 return 0;
267 struct grub_xnu_devtree_key *
268 grub_xnu_create_key (struct grub_xnu_devtree_key **parent, const char *name)
270 struct grub_xnu_devtree_key *ret;
271 ret = grub_xnu_find_key (*parent, name);
272 if (ret)
273 return ret;
274 ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
275 if (! ret)
276 return 0;
277 ret->name = grub_strdup (name);
278 if (! ret->name)
280 grub_free (ret);
281 return 0;
283 ret->datasize = -1;
284 ret->next = *parent;
285 *parent = ret;
286 return ret;
289 struct grub_xnu_devtree_key *
290 grub_xnu_create_value (struct grub_xnu_devtree_key **parent, const char *name)
292 struct grub_xnu_devtree_key *ret;
293 ret = grub_xnu_find_key (*parent, name);
294 if (ret)
296 if (ret->datasize == -1)
297 grub_xnu_free_devtree (ret->first_child);
298 else if (ret->datasize)
299 grub_free (ret->data);
300 ret->datasize = 0;
301 ret->data = 0;
302 return ret;
304 ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
305 if (! ret)
306 return 0;
307 ret->name = grub_strdup (name);
308 if (! ret->name)
310 grub_free (ret);
311 return 0;
313 ret->next = *parent;
314 *parent = ret;
315 return ret;
318 static grub_err_t
319 grub_xnu_unload (void)
321 grub_cpu_xnu_unload ();
323 grub_xnu_free_devtree (grub_xnu_devtree_root);
324 grub_xnu_devtree_root = 0;
326 /* Free loaded image. */
327 driversnum = 0;
328 driverspackagenum = 0;
329 grub_relocator_unload (grub_xnu_relocator);
330 grub_xnu_relocator = NULL;
331 grub_xnu_heap_target_start = 0;
332 grub_xnu_heap_size = 0;
333 grub_xnu_unlock ();
334 return GRUB_ERR_NONE;
337 static grub_err_t
338 grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
339 int argc, char *args[])
341 grub_err_t err;
342 grub_macho_t macho;
343 grub_uint32_t startcode, endcode;
344 int i;
345 char *ptr;
346 void *loadaddr;
347 grub_addr_t loadaddr_target;
349 if (argc < 1)
350 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
352 grub_xnu_unload ();
354 macho = grub_macho_open (args[0], 0);
355 if (! macho)
356 return grub_errno;
358 err = grub_macho_size32 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS,
359 args[0]);
360 if (err)
362 grub_macho_close (macho);
363 grub_xnu_unload ();
364 return err;
367 grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
368 (unsigned long) endcode, (unsigned long) startcode);
370 grub_xnu_relocator = grub_relocator_new ();
371 if (!grub_xnu_relocator)
372 return grub_errno;
373 grub_xnu_heap_target_start = startcode;
374 err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr,
375 &loadaddr_target);
377 if (err)
379 grub_macho_close (macho);
380 grub_xnu_unload ();
381 return err;
384 /* Load kernel. */
385 err = grub_macho_load32 (macho, args[0], (char *) loadaddr - startcode,
386 GRUB_MACHO_NOBSS, &grub_xnu_darwin_version);
387 if (err)
389 grub_macho_close (macho);
390 grub_xnu_unload ();
391 return err;
394 grub_xnu_entry_point = grub_macho_get_entry_point32 (macho, args[0]);
395 if (! grub_xnu_entry_point)
397 grub_macho_close (macho);
398 grub_xnu_unload ();
399 return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
402 grub_macho_close (macho);
404 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
405 if (err)
407 grub_xnu_unload ();
408 return err;
411 /* Copy parameters to kernel command line. */
412 ptr = grub_xnu_cmdline;
413 for (i = 1; i < argc; i++)
415 if (ptr + grub_strlen (args[i]) + 1
416 >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
417 break;
418 grub_memcpy (ptr, args[i], grub_strlen (args[i]));
419 ptr += grub_strlen (args[i]);
420 *ptr = ' ';
421 ptr++;
424 /* Replace last space by '\0'. */
425 if (ptr != grub_xnu_cmdline)
426 *(ptr - 1) = 0;
428 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
429 err = grub_efiemu_autocore ();
430 if (err)
431 return err;
432 #endif
434 grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
436 grub_xnu_lock ();
437 grub_xnu_is_64bit = 0;
439 return 0;
442 static grub_err_t
443 grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
444 int argc, char *args[])
446 grub_err_t err;
447 grub_macho_t macho;
448 grub_uint64_t startcode, endcode;
449 int i;
450 char *ptr;
451 void *loadaddr;
452 grub_addr_t loadaddr_target;
454 if (argc < 1)
455 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
457 grub_xnu_unload ();
459 macho = grub_macho_open (args[0], 1);
460 if (! macho)
461 return grub_errno;
463 err = grub_macho_size64 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS,
464 args[0]);
465 if (err)
467 grub_macho_close (macho);
468 grub_xnu_unload ();
469 return err;
472 startcode &= 0x0fffffff;
473 endcode &= 0x0fffffff;
475 grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
476 (unsigned long) endcode, (unsigned long) startcode);
478 grub_xnu_relocator = grub_relocator_new ();
479 if (!grub_xnu_relocator)
480 return grub_errno;
481 grub_xnu_heap_target_start = startcode;
482 err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr,
483 &loadaddr_target);
485 if (err)
487 grub_macho_close (macho);
488 grub_xnu_unload ();
489 return err;
492 /* Load kernel. */
493 err = grub_macho_load64 (macho, args[0], (char *) loadaddr - startcode,
494 GRUB_MACHO_NOBSS, &grub_xnu_darwin_version);
495 if (err)
497 grub_macho_close (macho);
498 grub_xnu_unload ();
499 return err;
502 grub_xnu_entry_point = grub_macho_get_entry_point64 (macho, args[0])
503 & 0x0fffffff;
504 if (! grub_xnu_entry_point)
506 grub_macho_close (macho);
507 grub_xnu_unload ();
508 return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
511 grub_macho_close (macho);
513 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
514 if (err)
516 grub_xnu_unload ();
517 return err;
520 /* Copy parameters to kernel command line. */
521 ptr = grub_xnu_cmdline;
522 for (i = 1; i < argc; i++)
524 if (ptr + grub_strlen (args[i]) + 1
525 >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
526 break;
527 grub_memcpy (ptr, args[i], grub_strlen (args[i]));
528 ptr += grub_strlen (args[i]);
529 *ptr = ' ';
530 ptr++;
533 /* Replace last space by '\0'. */
534 if (ptr != grub_xnu_cmdline)
535 *(ptr - 1) = 0;
537 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
538 err = grub_efiemu_autocore ();
539 if (err)
540 return err;
541 #endif
543 grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
545 grub_xnu_lock ();
546 grub_xnu_is_64bit = 1;
548 return 0;
551 /* Register a memory in a memory map under name PREFIXSUFFIX
552 and increment SUFFIX. */
553 static grub_err_t
554 grub_xnu_register_memory (const char *prefix, int *suffix,
555 grub_addr_t addr, grub_size_t size)
557 struct grub_xnu_devtree_key *chosen;
558 struct grub_xnu_devtree_key *memorymap;
559 struct grub_xnu_devtree_key *driverkey;
560 struct grub_xnu_extdesc *extdesc;
562 if (! grub_xnu_heap_size)
563 return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
565 chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
566 if (! chosen)
567 return grub_errno;
568 memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
569 if (! memorymap)
570 return grub_errno;
572 driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
573 if (! driverkey)
574 return grub_errno;
575 if (suffix)
576 driverkey->name = grub_xasprintf ("%s%d", prefix, (*suffix)++);
577 else
578 driverkey->name = grub_strdup (prefix);
579 if (!driverkey->name)
581 grub_free (driverkey);
582 return grub_errno;
584 driverkey->datasize = sizeof (*extdesc);
585 driverkey->next = memorymap->first_child;
586 driverkey->data = extdesc
587 = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
588 if (! driverkey->data)
590 grub_free (driverkey->name);
591 grub_free (driverkey);
592 return grub_errno;
594 memorymap->first_child = driverkey;
595 extdesc->addr = addr;
596 extdesc->size = (grub_uint32_t) size;
597 return GRUB_ERR_NONE;
600 static inline char *
601 get_name_ptr (char *name)
603 char *p = name, *p2;
604 /* Skip Info.plist. */
605 p2 = grub_strrchr (p, '/');
606 if (!p2)
607 return name;
608 if (p2 == name)
609 return name + 1;
610 p = p2 - 1;
612 p2 = grub_strrchr (p, '/');
613 if (!p2)
614 return name;
615 if (p2 == name)
616 return name + 1;
617 if (grub_memcmp (p2, "/Contents/", sizeof ("/Contents/") - 1) != 0)
618 return p2 + 1;
620 p = p2 - 1;
622 p2 = grub_strrchr (p, '/');
623 if (!p2)
624 return name;
625 return p2 + 1;
628 /* Load .kext. */
629 static grub_err_t
630 grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
631 const char *filename)
633 grub_macho_t macho;
634 grub_err_t err;
635 grub_file_t infoplist;
636 struct grub_xnu_extheader *exthead;
637 int neededspace = sizeof (*exthead);
638 grub_uint8_t *buf;
639 void *buf0;
640 grub_addr_t buf_target;
641 grub_size_t infoplistsize = 0, machosize = 0;
642 char *name, *nameend;
643 int namelen;
645 name = get_name_ptr (infoplistname);
646 nameend = grub_strchr (name, '/');
648 if (nameend)
649 namelen = nameend - name;
650 else
651 namelen = grub_strlen (name);
653 neededspace += namelen + 1;
655 if (! grub_xnu_heap_size)
656 return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
658 /* Compute the needed space. */
659 if (binaryfile)
661 macho = grub_macho_file (binaryfile, filename, grub_xnu_is_64bit);
662 if (!macho)
663 grub_file_close (binaryfile);
664 else
666 if (grub_xnu_is_64bit)
667 machosize = grub_macho_filesize64 (macho);
668 else
669 machosize = grub_macho_filesize32 (macho);
671 neededspace += machosize;
673 else
674 macho = 0;
676 if (infoplistname)
677 infoplist = grub_file_open (infoplistname);
678 else
679 infoplist = 0;
680 grub_errno = GRUB_ERR_NONE;
681 if (infoplist)
683 infoplistsize = grub_file_size (infoplist);
684 neededspace += infoplistsize + 1;
686 else
687 infoplistsize = 0;
689 /* Allocate the space. */
690 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
691 if (err)
692 goto fail;
693 err = grub_xnu_heap_malloc (neededspace, &buf0, &buf_target);
694 if (err)
695 goto fail;
696 buf = buf0;
698 exthead = (struct grub_xnu_extheader *) buf;
699 grub_memset (exthead, 0, sizeof (*exthead));
700 buf += sizeof (*exthead);
702 /* Load the binary. */
703 if (macho)
705 exthead->binaryaddr = buf_target + (buf - (grub_uint8_t *) buf0);
706 exthead->binarysize = machosize;
707 if (grub_xnu_is_64bit)
708 err = grub_macho_readfile64 (macho, filename, buf);
709 else
710 err = grub_macho_readfile32 (macho, filename, buf);
711 if (err)
712 goto fail;
713 grub_macho_close (macho);
714 buf += machosize;
716 grub_errno = GRUB_ERR_NONE;
718 /* Load the plist. */
719 if (infoplist)
721 exthead->infoplistaddr = buf_target + (buf - (grub_uint8_t *) buf0);
722 exthead->infoplistsize = infoplistsize + 1;
723 if (grub_file_read (infoplist, buf, infoplistsize)
724 != (grub_ssize_t) (infoplistsize))
726 grub_file_close (infoplist);
727 if (!grub_errno)
728 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
729 infoplistname);
730 return grub_errno;
732 grub_file_close (infoplist);
733 buf[infoplistsize] = 0;
734 buf += infoplistsize + 1;
736 grub_errno = GRUB_ERR_NONE;
738 exthead->nameaddr = (buf - (grub_uint8_t *) buf0) + buf_target;
739 exthead->namesize = namelen + 1;
740 grub_memcpy (buf, name, namelen);
741 buf[namelen] = 0;
742 buf += namelen + 1;
744 /* Announce to kernel */
745 return grub_xnu_register_memory ("Driver-", &driversnum, buf_target,
746 neededspace);
747 fail:
748 if (macho)
749 grub_macho_close (macho);
750 return err;
753 /* Load mkext. */
754 static grub_err_t
755 grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)),
756 int argc, char *args[])
758 grub_file_t file;
759 void *loadto;
760 grub_addr_t loadto_target;
761 grub_err_t err;
762 grub_off_t readoff = 0;
763 grub_ssize_t readlen = -1;
764 struct grub_macho_fat_header head;
765 struct grub_macho_fat_arch *archs;
766 int narchs, i;
768 if (argc != 1)
769 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
771 if (! grub_xnu_heap_size)
772 return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
774 file = grub_file_open (args[0]);
775 if (! file)
776 return grub_errno;
778 /* Sometimes caches are fat binary. Errgh. */
779 if (grub_file_read (file, &head, sizeof (head))
780 != (grub_ssize_t) (sizeof (head)))
782 /* I don't know the internal structure of package but
783 can hardly imagine a valid package shorter than 20 bytes. */
784 grub_file_close (file);
785 if (!grub_errno)
786 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
787 return grub_errno;
790 /* Find the corresponding architecture. */
791 if (grub_be_to_cpu32 (head.magic) == GRUB_MACHO_FAT_MAGIC)
793 narchs = grub_be_to_cpu32 (head.nfat_arch);
794 archs = grub_malloc (sizeof (struct grub_macho_fat_arch) * narchs);
795 if (! archs)
797 grub_file_close (file);
798 return grub_errno;
801 if (grub_file_read (file, archs,
802 sizeof (struct grub_macho_fat_arch) * narchs)
803 != (grub_ssize_t) sizeof(struct grub_macho_fat_arch) * narchs)
805 grub_free (archs);
806 if (!grub_errno)
807 grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file %s"),
808 args[0]);
809 return grub_errno;
811 for (i = 0; i < narchs; i++)
813 if (!grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32
814 (grub_be_to_cpu32 (archs[i].cputype)))
816 readoff = grub_be_to_cpu32 (archs[i].offset);
817 readlen = grub_be_to_cpu32 (archs[i].size);
819 if (grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64
820 (grub_be_to_cpu32 (archs[i].cputype)))
822 readoff = grub_be_to_cpu32 (archs[i].offset);
823 readlen = grub_be_to_cpu32 (archs[i].size);
826 grub_free (archs);
828 else
830 /* It's a flat file. Some sane people still exist. */
831 readoff = 0;
832 readlen = grub_file_size (file);
835 if (readlen == -1)
837 grub_file_close (file);
838 return grub_error (GRUB_ERR_BAD_OS, "no suitable architecture is found");
841 /* Allocate space. */
842 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
843 if (err)
845 grub_file_close (file);
846 return err;
849 err = grub_xnu_heap_malloc (readlen, &loadto, &loadto_target);
850 if (err)
852 grub_file_close (file);
853 return err;
856 /* Read the file. */
857 grub_file_seek (file, readoff);
858 if (grub_file_read (file, loadto, readlen) != (grub_ssize_t) (readlen))
860 grub_file_close (file);
861 if (!grub_errno)
862 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
863 return grub_errno;
865 grub_file_close (file);
867 /* Pass it to kernel. */
868 return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum,
869 loadto_target, readlen);
872 static grub_err_t
873 grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)),
874 int argc, char *args[])
876 grub_file_t file;
877 void *loadto;
878 grub_addr_t loadto_target;
879 grub_err_t err;
880 grub_size_t size;
882 if (argc != 1)
883 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
885 if (! grub_xnu_heap_size)
886 return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
888 file = grub_file_open (args[0]);
889 if (! file)
890 return grub_errno;
892 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
893 if (err)
894 return err;
896 size = grub_file_size (file);
898 err = grub_xnu_heap_malloc (size, &loadto, &loadto_target);
899 if (err)
900 return err;
901 if (grub_file_read (file, loadto, size) != (grub_ssize_t) (size))
903 grub_file_close (file);
904 if (!grub_errno)
905 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
906 return grub_errno;
908 return grub_xnu_register_memory ("RAMDisk", 0, loadto_target, size);
911 /* Returns true if the kext should be loaded according to plist
912 and osbundlereq. Also fill BINNAME. */
913 static int
914 grub_xnu_check_os_bundle_required (char *plistname,
915 const char *osbundlereq,
916 char **binname)
918 grub_file_t file;
919 char *buf = 0, *tagstart = 0, *ptr1 = 0, *keyptr = 0;
920 char *stringptr = 0, *ptr2 = 0;
921 grub_size_t size;
922 int depth = 0;
923 int ret;
924 int osbundlekeyfound = 0, binnamekeyfound = 0;
925 if (binname)
926 *binname = 0;
928 file = grub_file_open (plistname);
929 if (! file)
930 return 0;
932 size = grub_file_size (file);
933 buf = grub_malloc (size);
934 if (! buf)
936 grub_file_close (file);
937 return 0;
939 if (grub_file_read (file, buf, size) != (grub_ssize_t) (size))
941 grub_file_close (file);
942 if (!grub_errno)
943 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), plistname);
944 return 0;
946 grub_file_close (file);
948 /* Set the return value for the case when no OSBundleRequired tag is found. */
949 if (osbundlereq)
950 ret = grub_strword (osbundlereq, "all") || grub_strword (osbundlereq, "-");
951 else
952 ret = 1;
954 /* Parse plist. It's quite dirty and inextensible but does its job. */
955 for (ptr1 = buf; ptr1 < buf + size; ptr1++)
956 switch (*ptr1)
958 case '<':
959 tagstart = ptr1;
960 *ptr1 = 0;
961 if (keyptr && depth == 4
962 && grub_strcmp (keyptr, "OSBundleRequired") == 0)
963 osbundlekeyfound = 1;
964 if (keyptr && depth == 4 &&
965 grub_strcmp (keyptr, "CFBundleExecutable") == 0)
966 binnamekeyfound = 1;
967 if (stringptr && osbundlekeyfound && osbundlereq && depth == 4)
969 for (ptr2 = stringptr; *ptr2; ptr2++)
970 *ptr2 = grub_tolower (*ptr2);
971 ret = grub_strword (osbundlereq, stringptr)
972 || grub_strword (osbundlereq, "all");
974 if (stringptr && binnamekeyfound && binname && depth == 4)
976 if (*binname)
977 grub_free (*binname);
978 *binname = grub_strdup (stringptr);
981 *ptr1 = '<';
982 keyptr = 0;
983 stringptr = 0;
984 break;
985 case '>':
986 if (! tagstart)
988 grub_free (buf);
989 grub_error (GRUB_ERR_BAD_OS, "can't parse %s", plistname);
990 return 0;
992 *ptr1 = 0;
993 if (tagstart[1] == '?' || ptr1[-1] == '/')
995 osbundlekeyfound = 0;
996 *ptr1 = '>';
997 break;
999 if (depth == 3 && grub_strcmp (tagstart + 1, "key") == 0)
1000 keyptr = ptr1 + 1;
1001 if (depth == 3 && grub_strcmp (tagstart + 1, "string") == 0)
1002 stringptr = ptr1 + 1;
1003 else if (grub_strcmp (tagstart + 1, "/key") != 0)
1005 osbundlekeyfound = 0;
1006 binnamekeyfound = 0;
1008 *ptr1 = '>';
1010 if (tagstart[1] == '/')
1011 depth--;
1012 else
1013 depth++;
1014 break;
1016 grub_free (buf);
1018 return ret;
1021 /* Context for grub_xnu_scan_dir_for_kexts. */
1022 struct grub_xnu_scan_dir_for_kexts_ctx
1024 char *dirname;
1025 const char *osbundlerequired;
1026 int maxrecursion;
1029 /* Helper for grub_xnu_scan_dir_for_kexts. */
1030 static int
1031 grub_xnu_scan_dir_for_kexts_load (const char *filename,
1032 const struct grub_dirhook_info *info,
1033 void *data)
1035 struct grub_xnu_scan_dir_for_kexts_ctx *ctx = data;
1036 char *newdirname;
1038 if (! info->dir)
1039 return 0;
1040 if (filename[0] == '.')
1041 return 0;
1043 if (grub_strlen (filename) < 5 ||
1044 grub_memcmp (filename + grub_strlen (filename) - 5, ".kext", 5) != 0)
1045 return 0;
1047 newdirname
1048 = grub_malloc (grub_strlen (ctx->dirname) + grub_strlen (filename) + 2);
1050 /* It's a .kext. Try to load it. */
1051 if (newdirname)
1053 grub_strcpy (newdirname, ctx->dirname);
1054 newdirname[grub_strlen (newdirname) + 1] = 0;
1055 newdirname[grub_strlen (newdirname)] = '/';
1056 grub_strcpy (newdirname + grub_strlen (newdirname), filename);
1057 grub_xnu_load_kext_from_dir (newdirname, ctx->osbundlerequired,
1058 ctx->maxrecursion);
1059 if (grub_errno == GRUB_ERR_BAD_OS)
1060 grub_errno = GRUB_ERR_NONE;
1061 grub_free (newdirname);
1063 return 0;
1066 /* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */
1067 grub_err_t
1068 grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired,
1069 int maxrecursion)
1071 struct grub_xnu_scan_dir_for_kexts_ctx ctx = {
1072 .dirname = dirname,
1073 .osbundlerequired = osbundlerequired,
1074 .maxrecursion = maxrecursion
1076 grub_device_t dev;
1077 char *device_name;
1078 grub_fs_t fs;
1079 const char *path;
1081 if (! grub_xnu_heap_size)
1082 return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
1084 device_name = grub_file_get_device_name (dirname);
1085 dev = grub_device_open (device_name);
1086 if (dev)
1088 fs = grub_fs_probe (dev);
1089 path = grub_strchr (dirname, ')');
1090 if (! path)
1091 path = dirname;
1092 else
1093 path++;
1095 if (fs)
1096 (fs->dir) (dev, path, grub_xnu_scan_dir_for_kexts_load, &ctx);
1097 grub_device_close (dev);
1099 grub_free (device_name);
1101 return GRUB_ERR_NONE;
1104 /* Context for grub_xnu_load_kext_from_dir. */
1105 struct grub_xnu_load_kext_from_dir_ctx
1107 char *dirname;
1108 const char *osbundlerequired;
1109 int maxrecursion;
1110 char *plistname;
1111 char *newdirname;
1112 int usemacos;
1115 /* Helper for grub_xnu_load_kext_from_dir. */
1116 static int
1117 grub_xnu_load_kext_from_dir_load (const char *filename,
1118 const struct grub_dirhook_info *info,
1119 void *data)
1121 struct grub_xnu_load_kext_from_dir_ctx *ctx = data;
1123 if (grub_strlen (filename) > 15)
1124 return 0;
1125 grub_strcpy (ctx->newdirname + grub_strlen (ctx->dirname) + 1, filename);
1127 /* If the kext contains directory "Contents" all real stuff is in
1128 this directory. */
1129 if (info->dir && grub_strcasecmp (filename, "Contents") == 0)
1130 grub_xnu_load_kext_from_dir (ctx->newdirname, ctx->osbundlerequired,
1131 ctx->maxrecursion - 1);
1133 /* Directory "Plugins" contains nested kexts. */
1134 if (info->dir && grub_strcasecmp (filename, "Plugins") == 0)
1135 grub_xnu_scan_dir_for_kexts (ctx->newdirname, ctx->osbundlerequired,
1136 ctx->maxrecursion - 1);
1138 /* Directory "MacOS" contains executable, otherwise executable is
1139 on the top. */
1140 if (info->dir && grub_strcasecmp (filename, "MacOS") == 0)
1141 ctx->usemacos = 1;
1143 /* Info.plist is the file which governs our future actions. */
1144 if (! info->dir && grub_strcasecmp (filename, "Info.plist") == 0
1145 && ! ctx->plistname)
1146 ctx->plistname = grub_strdup (ctx->newdirname);
1147 return 0;
1150 /* Load extension DIRNAME. (extensions are directories in xnu) */
1151 grub_err_t
1152 grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
1153 int maxrecursion)
1155 struct grub_xnu_load_kext_from_dir_ctx ctx = {
1156 .dirname = dirname,
1157 .osbundlerequired = osbundlerequired,
1158 .maxrecursion = maxrecursion,
1159 .plistname = 0,
1160 .usemacos = 0
1162 grub_device_t dev;
1163 char *newpath;
1164 char *device_name;
1165 grub_fs_t fs;
1166 const char *path;
1167 char *binsuffix;
1168 grub_file_t binfile;
1170 ctx.newdirname = grub_malloc (grub_strlen (dirname) + 20);
1171 if (! ctx.newdirname)
1172 return grub_errno;
1173 grub_strcpy (ctx.newdirname, dirname);
1174 ctx.newdirname[grub_strlen (dirname)] = '/';
1175 ctx.newdirname[grub_strlen (dirname) + 1] = 0;
1176 device_name = grub_file_get_device_name (dirname);
1177 dev = grub_device_open (device_name);
1178 if (dev)
1180 fs = grub_fs_probe (dev);
1181 path = grub_strchr (dirname, ')');
1182 if (! path)
1183 path = dirname;
1184 else
1185 path++;
1187 newpath = grub_strchr (ctx.newdirname, ')');
1188 if (! newpath)
1189 newpath = ctx.newdirname;
1190 else
1191 newpath++;
1193 /* Look at the directory. */
1194 if (fs)
1195 (fs->dir) (dev, path, grub_xnu_load_kext_from_dir_load, &ctx);
1197 if (ctx.plistname && grub_xnu_check_os_bundle_required
1198 (ctx.plistname, osbundlerequired, &binsuffix))
1200 if (binsuffix)
1202 /* Open the binary. */
1203 char *binname = grub_malloc (grub_strlen (dirname)
1204 + grub_strlen (binsuffix)
1205 + sizeof ("/MacOS/"));
1206 grub_strcpy (binname, dirname);
1207 if (ctx.usemacos)
1208 grub_strcpy (binname + grub_strlen (binname), "/MacOS/");
1209 else
1210 grub_strcpy (binname + grub_strlen (binname), "/");
1211 grub_strcpy (binname + grub_strlen (binname), binsuffix);
1212 grub_dprintf ("xnu", "%s:%s\n", ctx.plistname, binname);
1213 binfile = grub_file_open (binname);
1214 if (! binfile)
1215 grub_errno = GRUB_ERR_NONE;
1217 /* Load the extension. */
1218 grub_xnu_load_driver (ctx.plistname, binfile,
1219 binname);
1220 grub_free (binname);
1221 grub_free (binsuffix);
1223 else
1225 grub_dprintf ("xnu", "%s:0\n", ctx.plistname);
1226 grub_xnu_load_driver (ctx.plistname, 0, 0);
1229 grub_free (ctx.plistname);
1230 grub_device_close (dev);
1232 grub_free (device_name);
1234 return GRUB_ERR_NONE;
1238 static int locked=0;
1239 static grub_dl_t my_mod;
1241 /* Load the kext. */
1242 static grub_err_t
1243 grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)),
1244 int argc, char *args[])
1246 grub_file_t binfile = 0;
1248 if (! grub_xnu_heap_size)
1249 return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
1251 if (argc == 2)
1253 /* User explicitly specified plist and binary. */
1254 if (grub_strcmp (args[1], "-") != 0)
1256 binfile = grub_file_open (args[1]);
1257 if (! binfile)
1258 return grub_errno;
1260 return grub_xnu_load_driver (grub_strcmp (args[0], "-") ? args[0] : 0,
1261 binfile, args[1]);
1264 /* load kext normally. */
1265 if (argc == 1)
1266 return grub_xnu_load_kext_from_dir (args[0], 0, 10);
1268 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1271 /* Load a directory containing kexts. */
1272 static grub_err_t
1273 grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)),
1274 int argc, char *args[])
1276 if (argc != 1 && argc != 2)
1277 return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory name required");
1279 if (! grub_xnu_heap_size)
1280 return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
1282 if (argc == 1)
1283 return grub_xnu_scan_dir_for_kexts (args[0],
1284 "console,root,local-root,network-root",
1285 10);
1286 else
1288 char *osbundlerequired = grub_strdup (args[1]), *ptr;
1289 grub_err_t err;
1290 if (! osbundlerequired)
1291 return grub_errno;
1292 for (ptr = osbundlerequired; *ptr; ptr++)
1293 *ptr = grub_tolower (*ptr);
1294 err = grub_xnu_scan_dir_for_kexts (args[0], osbundlerequired, 10);
1295 grub_free (osbundlerequired);
1296 return err;
1300 static inline int
1301 hextoval (char c)
1303 if (c >= '0' && c <= '9')
1304 return c - '0';
1305 if (c >= 'a' && c <= 'z')
1306 return c - 'a' + 10;
1307 if (c >= 'A' && c <= 'Z')
1308 return c - 'A' + 10;
1309 return 0;
1312 static inline void
1313 unescape (char *name, char *curdot, char *nextdot, int *len)
1315 char *ptr, *dptr;
1316 dptr = name;
1317 for (ptr = curdot; ptr < nextdot;)
1318 if (ptr + 2 < nextdot && *ptr == '%')
1320 *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2]));
1321 ptr += 3;
1322 dptr++;
1324 else
1326 *dptr = *ptr;
1327 ptr++;
1328 dptr++;
1330 *len = dptr - name;
1333 grub_err_t
1334 grub_xnu_fill_devicetree (void)
1336 struct grub_env_var *var;
1337 FOR_SORTED_ENV (var)
1339 char *nextdot = 0, *curdot;
1340 struct grub_xnu_devtree_key **curkey = &grub_xnu_devtree_root;
1341 struct grub_xnu_devtree_key *curvalue;
1342 char *name = 0, *data;
1343 int len;
1345 if (grub_memcmp (var->name, "XNU.DeviceTree.",
1346 sizeof ("XNU.DeviceTree.") - 1) != 0)
1347 continue;
1349 curdot = var->name + sizeof ("XNU.DeviceTree.") - 1;
1350 nextdot = grub_strchr (curdot, '.');
1351 if (nextdot)
1352 nextdot++;
1353 while (nextdot)
1355 name = grub_realloc (name, nextdot - curdot + 1);
1357 if (!name)
1358 return grub_errno;
1360 unescape (name, curdot, nextdot, &len);
1361 name[len - 1] = 0;
1363 curkey = &(grub_xnu_create_key (curkey, name)->first_child);
1365 curdot = nextdot;
1366 nextdot = grub_strchr (nextdot, '.');
1367 if (nextdot)
1368 nextdot++;
1371 nextdot = curdot + grub_strlen (curdot) + 1;
1373 name = grub_realloc (name, nextdot - curdot + 1);
1375 if (!name)
1376 return grub_errno;
1378 unescape (name, curdot, nextdot, &len);
1379 name[len] = 0;
1381 curvalue = grub_xnu_create_value (curkey, name);
1382 if (!curvalue)
1383 return grub_errno;
1384 grub_free (name);
1386 data = grub_malloc (grub_strlen (var->value) + 1);
1387 if (!data)
1388 return grub_errno;
1390 unescape (data, var->value, var->value + grub_strlen (var->value),
1391 &len);
1392 curvalue->datasize = len;
1393 curvalue->data = data;
1396 return grub_errno;
1399 struct grub_video_bitmap *grub_xnu_bitmap = 0;
1400 grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode;
1402 /* Option array indices. */
1403 #define XNU_SPLASH_CMD_ARGINDEX_MODE 0
1405 static const struct grub_arg_option xnu_splash_cmd_options[] =
1407 {"mode", 'm', 0, N_("Background image mode."), N_("stretch|normal"),
1408 ARG_TYPE_STRING},
1409 {0, 0, 0, 0, 0, 0}
1412 static grub_err_t
1413 grub_cmd_xnu_splash (grub_extcmd_context_t ctxt,
1414 int argc, char *args[])
1416 grub_err_t err;
1417 if (argc != 1)
1418 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1420 if (! grub_xnu_heap_size)
1421 return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
1423 if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set &&
1424 grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg,
1425 "stretch") == 0)
1426 grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH;
1427 else
1428 grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_CENTER;
1430 err = grub_video_bitmap_load (&grub_xnu_bitmap, args[0]);
1431 if (err)
1432 grub_xnu_bitmap = 0;
1434 return err;
1438 #ifndef GRUB_MACHINE_EMU
1439 static grub_err_t
1440 grub_cmd_xnu_resume (grub_command_t cmd __attribute__ ((unused)),
1441 int argc, char *args[])
1443 if (argc != 1)
1444 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1446 return grub_xnu_resume (args[0]);
1448 #endif
1450 void
1451 grub_xnu_lock (void)
1453 if (!locked)
1454 grub_dl_ref (my_mod);
1455 locked = 1;
1458 void
1459 grub_xnu_unlock (void)
1461 if (locked)
1462 grub_dl_unref (my_mod);
1463 locked = 0;
1466 static grub_command_t cmd_kernel64, cmd_kernel, cmd_mkext, cmd_kext;
1467 static grub_command_t cmd_kextdir, cmd_ramdisk, cmd_resume;
1468 static grub_extcmd_t cmd_splash;
1470 GRUB_MOD_INIT(xnu)
1472 cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0,
1473 N_("Load XNU image."));
1474 cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64,
1475 0, N_("Load 64-bit XNU image."));
1476 cmd_mkext = grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext, 0,
1477 N_("Load XNU extension package."));
1478 cmd_kext = grub_register_command ("xnu_kext", grub_cmd_xnu_kext, 0,
1479 N_("Load XNU extension."));
1480 cmd_kextdir = grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir,
1481 /* TRANSLATORS: OSBundleRequired is a
1482 variable name in xnu extensions
1483 manifests. It behaves mostly like
1484 GNU/Linux runlevels.
1486 N_("DIRECTORY [OSBundleRequired]"),
1487 /* TRANSLATORS: There are many extensions
1488 in extension directory. */
1489 N_("Load XNU extension directory."));
1490 cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0,
1491 /* TRANSLATORS: ramdisk here isn't identifier. It can be translated. */
1492 N_("Load XNU ramdisk. "
1493 "It will be available in OS as md0."));
1494 cmd_splash = grub_register_extcmd ("xnu_splash",
1495 grub_cmd_xnu_splash, 0, 0,
1496 N_("Load a splash image for XNU."),
1497 xnu_splash_cmd_options);
1499 #ifndef GRUB_MACHINE_EMU
1500 cmd_resume = grub_register_command ("xnu_resume", grub_cmd_xnu_resume,
1501 0, N_("Load an image of hibernated"
1502 " XNU."));
1503 #endif
1505 grub_cpu_xnu_init ();
1507 my_mod = mod;
1510 GRUB_MOD_FINI(xnu)
1512 #ifndef GRUB_MACHINE_EMU
1513 grub_unregister_command (cmd_resume);
1514 #endif
1515 grub_unregister_command (cmd_mkext);
1516 grub_unregister_command (cmd_kext);
1517 grub_unregister_command (cmd_kextdir);
1518 grub_unregister_command (cmd_ramdisk);
1519 grub_unregister_command (cmd_kernel);
1520 grub_unregister_extcmd (cmd_splash);
1521 grub_unregister_command (cmd_kernel64);
1523 grub_cpu_xnu_fini ();